diff --git a/include/vkcv/Drawcall.hpp b/include/vkcv/Drawcall.hpp index 08e436ae52d44c3514b504ae2d573d7c447fab80..5b2298149e84bd3af6eed574b4ccd838e38df3da 100644 --- a/include/vkcv/Drawcall.hpp +++ b/include/vkcv/Drawcall.hpp @@ -8,6 +8,7 @@ #include <vector> #include "DescriptorSetUsage.hpp" +#include "DispatchSize.hpp" #include "Handles.hpp" #include "VertexData.hpp" @@ -78,12 +79,12 @@ namespace vkcv { */ class TaskDrawcall : public Drawcall { private: - uint32_t m_taskCount; + DispatchSize m_taskSize; public: - explicit TaskDrawcall(uint32_t taskCount = 1); + explicit TaskDrawcall(const DispatchSize& taskSize = DispatchSize(1)); - [[nodiscard]] uint32_t getTaskCount() const; + [[nodiscard]] DispatchSize getTaskSize() const; }; } // namespace vkcv diff --git a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp index cebc8bb73297de07899d611b7bf467a93f2bffca..e3fa7b8511918c0c25e01b0bae993394203c0611 100644 --- a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp @@ -15,6 +15,7 @@ namespace vkcv::shader { enum class GLSLCompileTarget { SUBGROUP_OP, RAY_TRACING, + MESH_SHADING, UNKNOWN }; diff --git a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp index da5153154bca62384b185fbc1b8c3357c55a3d3e..e469152fa4023f505959239ed47f5dcacf108923 100644 --- a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp +++ b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp @@ -132,6 +132,14 @@ namespace vkcv::shader { resources.maxCullDistances = 8; resources.maxCombinedClipAndCullDistances = 8; resources.maxSamples = 4; + resources.maxMeshOutputVerticesNV = 256; + resources.maxMeshOutputPrimitivesNV = 512; + resources.maxMeshWorkGroupSizeX_NV = 32; + resources.maxMeshWorkGroupSizeY_NV = 1; + resources.maxMeshWorkGroupSizeZ_NV = 1; + resources.maxTaskWorkGroupSizeX_NV = 32; + resources.maxTaskWorkGroupSizeY_NV = 1; + resources.maxTaskWorkGroupSizeZ_NV = 1; resources.maxMeshOutputVerticesEXT = 256; resources.maxMeshOutputPrimitivesEXT = 512; resources.maxMeshWorkGroupSizeX_EXT = 32; @@ -173,6 +181,10 @@ namespace vkcv::shader { shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_2); shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4); break; + case GLSLCompileTarget::MESH_SHADING: + shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_1); + shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4); + break; default: break; } diff --git a/projects/mesh_shader/assets/shaders/shader.mesh b/projects/mesh_shader/assets/shaders/shader.mesh index 30c98610f4776204ff526c57c1f793e371194629..a6b0cb624a3e52ff9858070c0b249515d7131247 100644 --- a/projects/mesh_shader/assets/shaders/shader.mesh +++ b/projects/mesh_shader/assets/shaders/shader.mesh @@ -1,11 +1,11 @@ #version 460 #extension GL_ARB_separate_shader_objects : enable #extension GL_GOOGLE_include_directive : enable -#extension GL_NV_mesh_shader : require +#extension GL_EXT_mesh_shader : require #include "meshlet.inc" -layout(local_size_x=32) in; +layout(local_size_x=32, local_size_y=1, local_size_z=1) in; layout(triangles) out; layout(max_vertices=64, max_primitives=126) out; @@ -34,13 +34,14 @@ layout(std430, binding = 2) readonly buffer meshletBuffer Meshlet meshlets[]; }; -taskNV in Task { - uint meshletIndices[32]; - mat4 mvp; -} IN; +struct Task { + uint meshletIndices[32]; + mat4 mvp; +}; + +taskPayloadSharedEXT Task IN; void main() { - uint meshletIndex = IN.meshletIndices[gl_WorkGroupID.x]; Meshlet meshlet = meshlets[meshletIndex]; @@ -55,24 +56,23 @@ void main() { uint vertexIndex = meshlet.vertexOffset + workIndex; Vertex vertex = vertices[vertexIndex]; - gl_MeshVerticesNV[workIndex].gl_Position = IN.mvp * vec4(vertex.position, 1); + gl_MeshVerticesEXT[workIndex].gl_Position = IN.mvp * vec4(vertex.position, 1); passNormal[workIndex] = vertex.normal; passTaskIndex[workIndex] = meshletIndex; } // set local indices - for(uint i = 0; i < 12; i++){ - + for (uint i = 0; i < 12; i++) { uint workIndex = gl_LocalInvocationID.x + i * 32; if(workIndex >= meshlet.indexCount){ break; - } + } - uint indexBufferIndex = meshlet.indexOffset + workIndex; - gl_PrimitiveIndicesNV[workIndex] = localIndices[indexBufferIndex]; + uint indexBufferIndex = meshlet.indexOffset + workIndex; + gl_PrimitiveTriangleIndicesEXT[workIndex] = uvec3(localIndices[indexBufferIndex]); } - if(gl_LocalInvocationID.x == 0){ - gl_PrimitiveCountNV = meshlet.indexCount / 3; + if (gl_LocalInvocationID.x == 0) { + SetMeshOutputsEXT(64, meshlet.indexCount / 3); } } \ No newline at end of file diff --git a/projects/mesh_shader/assets/shaders/shader.task b/projects/mesh_shader/assets/shaders/shader.task index 7a692e98e6384767191d76cef940e295ca127d62..a6b1ad61a9d691bf91f604eadc0d277dbf738d43 100644 --- a/projects/mesh_shader/assets/shaders/shader.task +++ b/projects/mesh_shader/assets/shaders/shader.task @@ -1,17 +1,19 @@ #version 460 #extension GL_ARB_separate_shader_objects : enable -#extension GL_NV_mesh_shader : require +#extension GL_EXT_mesh_shader : require #extension GL_GOOGLE_include_directive : enable #include "meshlet.inc" #include "common.inc" -layout(local_size_x=32) in; +layout(local_size_x=32, local_size_y=1, local_size_z=1) in; -taskNV out Task { - uint meshletIndices[32]; - mat4 mvp; -} OUT; +struct Task { + uint meshletIndices[32]; + mat4 mvp; +}; + +taskPayloadSharedEXT Task OUT; layout( push_constant ) uniform constants{ uint matrixIndex; @@ -52,27 +54,26 @@ bool isSphereInsideFrustum(vec3 spherePos, float sphereRadius, Plane cameraPlane } void main() { - - if(gl_LocalInvocationID.x >= meshletCount){ + if (gl_LocalInvocationID.x >= meshletCount) { return; } uint meshletIndex = gl_GlobalInvocationID.x; Meshlet meshlet = meshlets[meshletIndex]; - if(gl_LocalInvocationID.x == 0){ + if (gl_LocalInvocationID.x == 0) { taskCount = 0; } // TODO: scaling support vec3 meshletPositionWorld = (vec4(meshlet.meanPosition, 1) * objectMatrices[matrixIndex].model).xyz; - if(isSphereInsideFrustum(meshletPositionWorld, meshlet.boundingSphereRadius, cameraPlanes)){ + if (isSphereInsideFrustum(meshletPositionWorld, meshlet.boundingSphereRadius, cameraPlanes)) { uint outIndex = atomicAdd(taskCount, 1); OUT.meshletIndices[outIndex] = gl_GlobalInvocationID.x; } - if(gl_LocalInvocationID.x == 0){ - gl_TaskCountNV = taskCount; + if (gl_LocalInvocationID.x == 0) { OUT.mvp = objectMatrices[matrixIndex].mvp; + EmitMeshTasksEXT(taskCount, 1, 1); } } \ No newline at end of file diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp index df2a0ec0a6b9ab5793605ceb3e6a357e9591f354..8afbbb26fdbdf18602ebb0028bc47aeacf2fd4da 100644 --- a/projects/mesh_shader/src/main.cpp +++ b/projects/mesh_shader/src/main.cpp @@ -81,7 +81,7 @@ int main(int argc, const char** argv) { const std::string applicationName = "Mesh shader"; vkcv::Features features; - features.requireExtension(VK_EXT_MESH_SHADER_EXTENSION_NAME); + features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); features.requireExtensionFeature<vk::PhysicalDeviceMeshShaderFeaturesEXT>( VK_EXT_MESH_SHADER_EXTENSION_NAME, [](vk::PhysicalDeviceMeshShaderFeaturesEXT& features) { @@ -199,7 +199,7 @@ int main(int argc, const char** argv) { } vkcv::ShaderProgram bunnyShaderProgram{}; - vkcv::shader::GLSLCompiler compiler; + vkcv::shader::GLSLCompiler compiler (vkcv::shader::GLSLCompileTarget::MESH_SHADING); compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("assets/shaders/shader.vert"), [&bunnyShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index d28f566908162d17f953c2cb0199e1849f114343..d31a9ff3c47cc8717f89861b27f2c0dc3af37f42 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -598,9 +598,9 @@ namespace vkcv { const PushConstants &pushConstantData, size_t drawcallIndex, const TaskDrawcall &drawcall) { - static PFN_vkCmdDrawMeshTasksNV cmdDrawMeshTasks = - reinterpret_cast<PFN_vkCmdDrawMeshTasksNV>( - core.getContext().getDevice().getProcAddr("vkCmdDrawMeshTasksNV")); + static PFN_vkCmdDrawMeshTasksEXT cmdDrawMeshTasks = + reinterpret_cast<PFN_vkCmdDrawMeshTasksEXT>( + core.getContext().getDevice().getProcAddr("vkCmdDrawMeshTasksEXT")); if (!cmdDrawMeshTasks) { vkcv_log(LogLevel::ERROR, "Mesh shader drawcalls are not supported"); @@ -619,8 +619,14 @@ namespace vkcv { pushConstantData.getSizePerDrawcall(), pushConstantData.getDrawcallData(drawcallIndex)); } - - cmdDrawMeshTasks(VkCommandBuffer(cmdBuffer), drawcall.getTaskCount(), 0); + + const auto& groupSize = drawcall.getTaskSize(); + cmdDrawMeshTasks( + VkCommandBuffer(cmdBuffer), + groupSize.x(), + groupSize.y(), + groupSize.z() + ); } void Core::recordMeshShaderDrawcalls(const CommandStreamHandle &cmdStreamHandle, @@ -640,7 +646,7 @@ namespace vkcv { auto recordFunction = [&](const vk::CommandBuffer &cmdBuffer) { for (size_t i = 0; i < drawcalls.size(); i++) { recordMeshShaderDrawcall(*this, *m_DescriptorSetManager, cmdBuffer, pipelineLayout, - pushConstantData, i, drawcalls [i]); + pushConstantData, i, drawcalls[i]); } }; diff --git a/src/vkcv/Drawcall.cpp b/src/vkcv/Drawcall.cpp index b45cb6ecc8a31d098d65791ede15badb3dc24bec..73142b5545a7485e62e8e26e36e9d1f494960aa4 100644 --- a/src/vkcv/Drawcall.cpp +++ b/src/vkcv/Drawcall.cpp @@ -55,10 +55,10 @@ namespace vkcv { return m_drawCount; } - TaskDrawcall::TaskDrawcall(uint32_t taskCount) : Drawcall(), m_taskCount(taskCount) {} - - uint32_t TaskDrawcall::getTaskCount() const { - return m_taskCount; + TaskDrawcall::TaskDrawcall(const DispatchSize& taskSize) : Drawcall(), m_taskSize(taskSize) {} + + DispatchSize TaskDrawcall::getTaskSize() const { + return m_taskSize; } } // namespace vkcv diff --git a/src/vkcv/GraphicsPipelineManager.cpp b/src/vkcv/GraphicsPipelineManager.cpp index 4ac862e4105fd7707f0e0f4d09ae3670d58c4fcc..8747a5e95a0ea62591167c6e46265aacd8c1b624 100644 --- a/src/vkcv/GraphicsPipelineManager.cpp +++ b/src/vkcv/GraphicsPipelineManager.cpp @@ -115,9 +115,9 @@ namespace vkcv { case ShaderStage::COMPUTE: return vk::ShaderStageFlagBits::eCompute; case ShaderStage::TASK: - return vk::ShaderStageFlagBits::eTaskNV; + return vk::ShaderStageFlagBits::eTaskEXT; case ShaderStage::MESH: - return vk::ShaderStageFlagBits::eMeshNV; + return vk::ShaderStageFlagBits::eMeshEXT; default: vkcv_log(LogLevel::ERROR, "Unknown shader stage"); return vk::ShaderStageFlagBits::eAll; @@ -641,11 +641,21 @@ namespace vkcv { // Get all setting structs together and create the Pipeline const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo( {}, static_cast<uint32_t>(shaderStages.size()), shaderStages.data(), - &pipelineVertexInputStateCreateInfo, &pipelineInputAssemblyStateCreateInfo, - &pipelineTessellationStateCreateInfo, &pipelineViewportStateCreateInfo, - &pipelineRasterizationStateCreateInfo, &pipelineMultisampleStateCreateInfo, - p_depthStencilCreateInfo, &pipelineColorBlendStateCreateInfo, &dynamicStateCreateInfo, - vkPipelineLayout, pass, 0, {}, 0); + &pipelineVertexInputStateCreateInfo, + &pipelineInputAssemblyStateCreateInfo, + &pipelineTessellationStateCreateInfo, + &pipelineViewportStateCreateInfo, + &pipelineRasterizationStateCreateInfo, + &pipelineMultisampleStateCreateInfo, + p_depthStencilCreateInfo, + &pipelineColorBlendStateCreateInfo, + &dynamicStateCreateInfo, + vkPipelineLayout, + pass, + 0, + {}, + 0 + ); vk::Pipeline vkPipeline {}; if (getCore().getContext().getDevice().createGraphicsPipelines( diff --git a/src/vkcv/SwapchainManager.cpp b/src/vkcv/SwapchainManager.cpp index 27efa5031853552ab9a2926d37ba3cb64cdbdc6c..7586f9ada50c03997ede4b8db542e247785d54b1 100644 --- a/src/vkcv/SwapchainManager.cpp +++ b/src/vkcv/SwapchainManager.cpp @@ -175,6 +175,12 @@ namespace vkcv { static bool createVulkanSwapchain(const Context &context, const Window &window, SwapchainEntry &entry) { + if (!context.getFeatureManager().isExtensionActive(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { + vkcv_log(LogLevel::WARNING, "Extension required to create a swapchain: '%s'", + VK_KHR_SWAPCHAIN_EXTENSION_NAME); + return false; + } + const vk::PhysicalDevice &physicalDevice = context.getPhysicalDevice(); const vk::Device &device = context.getDevice(); diff --git a/src/vkcv/WindowManager.cpp b/src/vkcv/WindowManager.cpp index 058ee21933ee00df49bd158ded4e8a38979f67c3..077b9ec3cc200003c5f5ee5c7a90d523e80c8b66 100644 --- a/src/vkcv/WindowManager.cpp +++ b/src/vkcv/WindowManager.cpp @@ -33,6 +33,11 @@ namespace vkcv { static_cast<int>(windowHeight), resizeable); SwapchainHandle swapchainHandle = swapchainManager.createSwapchain(*window); + + if (!swapchainHandle) { + delete window; + return {}; + } if (resizeable) { const event_handle<int, int> &resizeHandle =