feat(render3d): mesh-shader grass
The chunked grass path draws each chunk as one mesh-shader dispatch when the setting asks and the card has VK_EXT_mesh_shader: work group y is a tile, x a batch of 16 of its blades, and a blade the placement, density, frustum, water or slope tests reject emits nothing - the instanced path still runs its eight vertices to a degenerate position. grass.mesh generates the same blades as grass.vert (grass_blade_mesh(4)'s rows, the same hashes, sway and lighting normal), capped at the instanced path's 65535 a tile. Vulkan: VK_EXT_mesh_shader with meshShader, and maintenance4 (glslang's mesh stages declare LocalSizeId); vkCmdDrawMeshTasksEXT looked up per device, as the Streamline interposer exports none; a *.mesh program's pipeline takes the mesh stage and no vertex input, its bindings the mesh stage bit. gpu_has_mesh, gpu_draw_mesh_tasks; r3d_mesh_grass and R3D_MESH_GRASS / R3D_NO_MESH. bin/ludic-dev rebuilt: the committed binary predated the shader tool's mesh support and compiled grass.mesh as a vertex stage. PC (RTX 3070 Ti): the camp matches the chunked path; validation only the no-window present-id message. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
6525c11b3c
commit
750d13779d
10 changed files with 334 additions and 13 deletions
|
|
@ -58,6 +58,8 @@ function gvk_ext_in(props: bytes, n: int, want: string) -> bool {
|
|||
# the caller stays on OpenGL.
|
||||
var gvk_has_mdi: bool = false # multiDrawIndirect + drawIndirectFirstInstance
|
||||
var gvk_has_dic: bool = false # drawIndirectCount
|
||||
var gvk_has_mesh: bool = false # VK_EXT_mesh_shader with its meshShader feature on
|
||||
var gvk_mesh_fn: pointer = null # vkCmdDrawMeshTasksEXT: the device's own, the interposer exports none
|
||||
|
||||
function gvk_init() -> bool {
|
||||
if gvk_ready { return true }
|
||||
|
|
@ -161,6 +163,8 @@ function gvk_init() -> bool {
|
|||
Vk.put_i32(want13, VkPhysicalDeviceVulkan13Features_sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES)
|
||||
Vk.put_i32(want13, VkPhysicalDeviceVulkan13Features_dynamicRendering, 1)
|
||||
Vk.put_i32(want13, VkPhysicalDeviceVulkan13Features_synchronization2, 1)
|
||||
# maintenance4: glslang's mesh stages declare their work group size with LocalSizeId, which needs it
|
||||
if Vk.get_i32(f13, VkPhysicalDeviceVulkan13Features_maintenance4) == 1 { Vk.put_i32(want13, VkPhysicalDeviceVulkan13Features_maintenance4, 1) }
|
||||
# Streamline's hooks keep their own data on our objects (private data slots), and ask the device
|
||||
# to have the feature rather than turning it on themselves
|
||||
if gsl_on and Vk.get_i32(f13, VkPhysicalDeviceVulkan13Features_privateData) == 1 { Vk.put_i32(want13, VkPhysicalDeviceVulkan13Features_privateData, 1) }
|
||||
|
|
@ -198,6 +202,27 @@ function gvk_init() -> bool {
|
|||
let nde = Vk.get_i32(cnt, 0)
|
||||
let dexts = bytes(nde * VkExtensionProperties_sizeof + 8)
|
||||
Vk.enumerate_device_extension_properties(gvk_pd, null, cnt, dexts)
|
||||
# mesh-shader grass: the extension, and its meshShader feature asked for where the device has it.
|
||||
# R3D_NO_MESH=1 leaves it off.
|
||||
gvk_has_mesh = false
|
||||
if gvk_ext_in(dexts, nde, VK_EXT_MESH_SHADER_EXTENSION_NAME) and not Os.has_env("R3D_NO_MESH") {
|
||||
let fm = bytes(VkPhysicalDeviceMeshShaderFeaturesEXT_sizeof)
|
||||
Vk.zero(fm, VkPhysicalDeviceMeshShaderFeaturesEXT_sizeof)
|
||||
Vk.put_i32(fm, VkPhysicalDeviceMeshShaderFeaturesEXT_sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT)
|
||||
let qm = bytes(VkPhysicalDeviceFeatures2_sizeof)
|
||||
Vk.zero(qm, VkPhysicalDeviceFeatures2_sizeof)
|
||||
Vk.put_i32(qm, VkPhysicalDeviceFeatures2_sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2)
|
||||
Vk.put_ptr(qm, VkPhysicalDeviceFeatures2_pNext, fm)
|
||||
Vk.get_physical_device_features2(gvk_pd, qm)
|
||||
if Vk.get_i32(fm, VkPhysicalDeviceMeshShaderFeaturesEXT_meshShader) == 1 {
|
||||
let wm = bytes(VkPhysicalDeviceMeshShaderFeaturesEXT_sizeof)
|
||||
Vk.zero(wm, VkPhysicalDeviceMeshShaderFeaturesEXT_sizeof)
|
||||
Vk.put_i32(wm, VkPhysicalDeviceMeshShaderFeaturesEXT_sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT)
|
||||
Vk.put_i32(wm, VkPhysicalDeviceMeshShaderFeaturesEXT_meshShader, 1)
|
||||
Vk.put_ptr(want13, VkPhysicalDeviceVulkan13Features_pNext, wm)
|
||||
gvk_has_mesh = true
|
||||
}
|
||||
}
|
||||
let prio = bytes(4)
|
||||
Vk.put_i32(prio, 0, 0x3F800000)
|
||||
let qci = bytes(VkDeviceQueueCreateInfo_sizeof)
|
||||
|
|
@ -226,6 +251,7 @@ function gvk_init() -> bool {
|
|||
gvk_has_hdr_meta = gvk_ext_in(dexts, nde, VK_EXT_HDR_METADATA_EXTENSION_NAME) and Vk.has("vkSetHdrMetadataEXT") == 1
|
||||
if gvk_has_hdr_meta { Vk.put_ptr(dext_names, n_dext * 8, VK_EXT_HDR_METADATA_EXTENSION_NAME); n_dext += 1 }
|
||||
}
|
||||
if gvk_has_mesh { Vk.put_ptr(dext_names, n_dext * 8, VK_EXT_MESH_SHADER_EXTENSION_NAME); n_dext += 1 }
|
||||
if n_dext > 0 {
|
||||
Vk.put_i32(dci, VkDeviceCreateInfo_enabledExtensionCount, n_dext)
|
||||
Vk.put_ptr(dci, VkDeviceCreateInfo_ppEnabledExtensionNames, dext_names)
|
||||
|
|
@ -236,12 +262,16 @@ function gvk_init() -> bool {
|
|||
Vk.get_device_queue(gvk_dev, gvk_family, 0, out)
|
||||
gvk_queue = Vk.get_ptr(out, 0)
|
||||
gsl_probe_device(gvk_pd)
|
||||
if gvk_has_mesh {
|
||||
gvk_mesh_fn = Vk.get_device_proc_addr(gvk_dev, "vkCmdDrawMeshTasksEXT")
|
||||
if gvk_mesh_fn == null { gvk_has_mesh = false }
|
||||
}
|
||||
gvk_mp = bytes(VkPhysicalDeviceMemoryProperties_sizeof)
|
||||
Vk.get_physical_device_memory_properties(gvk_pd, gvk_mp)
|
||||
|
||||
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, multi-draw indirect {gvk_has_mdi}, indirect count {gvk_has_dic}`)
|
||||
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}, mesh shaders {gvk_has_mesh}`)
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue