feat(render3d): compute and indirect draws on Vulkan, and tree layers culled on the GPU (opt-in)
- Device: multiDrawIndirect, drawIndirectFirstInstance and drawIndirectCount where present. - Buffers carry storage and indirect usage; a GPU-owned buffer is never swapped under a draw. - Compute programs from shaders/compute.list (binding 0 parameters, 1.. storage buffers), built by `ludic-dev shaders`; gpu_compute / gpu_dispatch / gpu_draw_mesh_indirect in gpu.ludic. - R3D_VK_PROBE=1: a dispatch read back (OK on the RTX 3070 Ti). - scatter_cull.comp: a tree layer's frustum test and LOD split on the GPU, with the lit, prepass, impostor and shadow-LOD draws reading its records. Behind R3D_GPU_CULL=1 and off by default: at the camp it is slower (43.0 fps against 53.3), because the frame's cost is per-draw descriptor sets and it adds empty-level draws. Validation-clean; OpenGL frames unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
04cda22d19
commit
c1eb5f399f
11 changed files with 463 additions and 15 deletions
|
|
@ -37,6 +37,9 @@ function gvk_ext_in(props: bytes, n: int, want: string) -> bool {
|
|||
# Instance, the first discrete GPU (else the first listed), its first graphics queue, and a
|
||||
# device with the Tier 1 floor switched on. False, with gvk_why set, if any of it is missing:
|
||||
# the caller stays on OpenGL.
|
||||
var gvk_has_mdi: bool = false # multiDrawIndirect + drawIndirectFirstInstance
|
||||
var gvk_has_dic: bool = false # drawIndirectCount
|
||||
|
||||
function gvk_init() -> bool {
|
||||
if gvk_ready { return true }
|
||||
if Vk.open() == 0 { gvk_why = "no Vulkan loader"; return false }
|
||||
|
|
@ -145,6 +148,16 @@ function gvk_init() -> bool {
|
|||
Vk.put_i32(want2, VkPhysicalDeviceFeatures2_sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2)
|
||||
Vk.put_ptr(want2, VkPhysicalDeviceFeatures2_pNext, want12)
|
||||
if aniso { Vk.put_i32(want2, VkPhysicalDeviceFeatures2_features + VkPhysicalDeviceFeatures_samplerAnisotropy, 1) }
|
||||
# GPU-driven drawing: one indirect buffer holds a layer's draws, and a compute pass may write
|
||||
# how many of them there are. Asked for where the device has them; the renderer checks
|
||||
# gvk_has_mdi / gvk_has_dic before it takes that path.
|
||||
gvk_has_mdi = Vk.get_i32(f2, VkPhysicalDeviceFeatures2_features + VkPhysicalDeviceFeatures_multiDrawIndirect) == 1 and Vk.get_i32(f2, VkPhysicalDeviceFeatures2_features + VkPhysicalDeviceFeatures_drawIndirectFirstInstance) == 1
|
||||
if gvk_has_mdi {
|
||||
Vk.put_i32(want2, VkPhysicalDeviceFeatures2_features + VkPhysicalDeviceFeatures_multiDrawIndirect, 1)
|
||||
Vk.put_i32(want2, VkPhysicalDeviceFeatures2_features + VkPhysicalDeviceFeatures_drawIndirectFirstInstance, 1)
|
||||
}
|
||||
gvk_has_dic = Vk.get_i32(f12, VkPhysicalDeviceVulkan12Features_drawIndirectCount) == 1
|
||||
if gvk_has_dic { Vk.put_i32(want12, VkPhysicalDeviceVulkan12Features_drawIndirectCount, 1) }
|
||||
|
||||
Vk.put_i32(cnt, 0, 0)
|
||||
Vk.enumerate_device_extension_properties(gvk_pd, null, cnt, null)
|
||||
|
|
@ -186,7 +199,7 @@ function gvk_init() -> bool {
|
|||
|
||||
if not gvk_cmd_init() { return false }
|
||||
gvk_ready = true
|
||||
print(`r3d: vulkan on {gvk_device_name}, anisotropy up to {gvk_aniso_x(gvk_max_aniso)}x`)
|
||||
print(`r3d: vulkan on {gvk_device_name}, anisotropy up to {gvk_aniso_x(gvk_max_aniso)}x, multi-draw indirect {gvk_has_mdi}, indirect count {gvk_has_dic}`)
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue