From 9f3c40232afb7877fc6a09ee4ed965d2f0d9e021 Mon Sep 17 00:00:00 2001 From: Tobias Frisch <tfrisch@uni-koblenz.de> Date: Fri, 27 Jan 2023 23:12:29 +0100 Subject: [PATCH] Adjust mesh shader example to use EXT extension Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de> --- .../mesh_shader/assets/shaders/common.inc | 2 +- .../mesh_shader/assets/shaders/meshlet.inc | 22 +-- .../mesh_shader/assets/shaders/shader.frag | 15 +- .../mesh_shader/assets/shaders/shader.mesh | 32 ++--- .../mesh_shader/assets/shaders/shader.task | 37 +++-- .../mesh_shader/assets/shaders/shader.vert | 18 ++- projects/mesh_shader/src/main.cpp | 35 +++-- src/vkcv/GraphicsPipelineManager.cpp | 133 +++++++++++++----- 8 files changed, 177 insertions(+), 117 deletions(-) diff --git a/projects/mesh_shader/assets/shaders/common.inc b/projects/mesh_shader/assets/shaders/common.inc index 280ffee2..962a814b 100644 --- a/projects/mesh_shader/assets/shaders/common.inc +++ b/projects/mesh_shader/assets/shaders/common.inc @@ -1,4 +1,4 @@ -struct ObjectMatrices{ +struct ObjectMatrices { mat4 model; mat4 mvp; }; \ No newline at end of file diff --git a/projects/mesh_shader/assets/shaders/meshlet.inc b/projects/mesh_shader/assets/shaders/meshlet.inc index 0594f62c..f79a0875 100644 --- a/projects/mesh_shader/assets/shaders/meshlet.inc +++ b/projects/mesh_shader/assets/shaders/meshlet.inc @@ -1,8 +1,14 @@ -struct Meshlet{ - uint vertexOffset; - uint vertexCount; - uint indexOffset; - uint indexCount; - vec3 meanPosition; - float boundingSphereRadius; -}; \ No newline at end of file + +struct Task { + uint meshletIndices[32]; + mat4 mvp; +}; + +struct Meshlet { + uint vertexOffset; + uint vertexCount; + uint indexOffset; + uint indexCount; + vec3 meanPosition; + float boundingSphereRadius; +}; diff --git a/projects/mesh_shader/assets/shaders/shader.frag b/projects/mesh_shader/assets/shaders/shader.frag index f4f6982f..399a680d 100644 --- a/projects/mesh_shader/assets/shaders/shader.frag +++ b/projects/mesh_shader/assets/shaders/shader.frag @@ -1,12 +1,12 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable -layout(location = 0) in vec3 passNormal; -layout(location = 1) in flat uint passTaskIndex; +layout(location = 0) in vec3 passNormal; +layout(location = 1) in flat uint passTaskIndex; + layout(location = 0) out vec3 outColor; -uint lowbias32(uint x) -{ +uint lowbias32(uint x) { x ^= x >> 16; x *= 0x7feb352dU; x ^= x >> 15; @@ -15,15 +15,16 @@ uint lowbias32(uint x) return x; } -float hashToFloat(uint hash){ +float hashToFloat(uint hash) { return (hash % 255) / 255.f; } -vec3 colorFromIndex(uint i){ +vec3 colorFromIndex(uint i) { return vec3( hashToFloat(lowbias32(i+0)), hashToFloat(lowbias32(i+1)), - hashToFloat(lowbias32(i+2))); + hashToFloat(lowbias32(i+2)) + ); } void main() { diff --git a/projects/mesh_shader/assets/shaders/shader.mesh b/projects/mesh_shader/assets/shaders/shader.mesh index a6b0cb62..0d97389b 100644 --- a/projects/mesh_shader/assets/shaders/shader.mesh +++ b/projects/mesh_shader/assets/shaders/shader.mesh @@ -13,32 +13,25 @@ layout(max_vertices=64, max_primitives=126) out; layout(location = 0) out vec3 passNormal[]; layout(location = 1) out uint passTaskIndex[]; -struct Vertex -{ - vec3 position; float padding0; - vec3 normal; float padding1; +struct Vertex { + vec3 position; + float padding0; + vec3 normal; + float padding1; }; -layout(std430, binding = 0) readonly buffer vertexBuffer -{ +layout(std430, binding = 0) readonly buffer vertexBuffer { Vertex vertices[]; }; -layout(std430, binding = 1) readonly buffer indexBuffer -{ +layout(std430, binding = 1) readonly buffer indexBuffer { uint localIndices[]; // breaks for 16 bit indices }; -layout(std430, binding = 2) readonly buffer meshletBuffer -{ +layout(std430, binding = 2) readonly buffer meshletBuffer { Meshlet meshlets[]; }; -struct Task { - uint meshletIndices[32]; - mat4 mvp; -}; - taskPayloadSharedEXT Task IN; void main() { @@ -46,17 +39,16 @@ void main() { Meshlet meshlet = meshlets[meshletIndex]; // set vertices - for(uint i = 0; i < 2; i++){ - + for (uint i = 0; i < 2; i++) { uint workIndex = gl_LocalInvocationID.x + 32 * i; - if(workIndex >= meshlet.vertexCount){ + if (workIndex >= meshlet.vertexCount) { break; } uint vertexIndex = meshlet.vertexOffset + workIndex; Vertex vertex = vertices[vertexIndex]; - gl_MeshVerticesEXT[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; } @@ -64,7 +56,7 @@ void main() { // set local indices for (uint i = 0; i < 12; i++) { uint workIndex = gl_LocalInvocationID.x + i * 32; - if(workIndex >= meshlet.indexCount){ + if (workIndex >= meshlet.indexCount) { break; } diff --git a/projects/mesh_shader/assets/shaders/shader.task b/projects/mesh_shader/assets/shaders/shader.task index a6b1ad61..be09706c 100644 --- a/projects/mesh_shader/assets/shaders/shader.task +++ b/projects/mesh_shader/assets/shaders/shader.task @@ -8,37 +8,30 @@ layout(local_size_x=32, local_size_y=1, local_size_z=1) in; -struct Task { - uint meshletIndices[32]; - mat4 mvp; -}; - taskPayloadSharedEXT Task OUT; -layout( push_constant ) uniform constants{ - uint matrixIndex; +layout( push_constant ) uniform constants { uint meshletCount; + uint matrixIndex; }; // TODO: reuse mesh stage binding at location 2 after required fix in framework -layout(std430, binding = 5) readonly buffer meshletBuffer -{ +layout(std430, binding = 5) readonly buffer meshletBuffer { Meshlet meshlets[]; }; -struct Plane{ - vec3 pointOnPlane; - float padding0; - vec3 normal; - float padding1; +struct Plane { + vec3 pointOnPlane; + float padding0; + vec3 normal; + float padding1; }; -layout(set=0, binding=3, std140) uniform cameraPlaneBuffer{ +layout(set=0, binding = 3, std140) uniform cameraPlaneBuffer { Plane cameraPlanes[6]; }; -layout(std430, binding = 4) readonly buffer matrixBuffer -{ +layout(std430, binding = 4) readonly buffer matrixBuffer { ObjectMatrices objectMatrices[]; }; @@ -46,9 +39,9 @@ shared uint taskCount; bool isSphereInsideFrustum(vec3 spherePos, float sphereRadius, Plane cameraPlanes[6]){ bool isInside = true; - for(int i = 0; i < 6; i++){ - Plane p = cameraPlanes[i]; - isInside = isInside && dot(p.normal, spherePos - p.pointOnPlane) - sphereRadius < 0; + for (int i = 0; i < 6; i++) { + Plane p = cameraPlanes[i]; + isInside = isInside && dot(p.normal, spherePos - p.pointOnPlane) - sphereRadius < 0; } return isInside; } @@ -64,6 +57,8 @@ void main() { if (gl_LocalInvocationID.x == 0) { taskCount = 0; } + + memoryBarrierShared(); // TODO: scaling support vec3 meshletPositionWorld = (vec4(meshlet.meanPosition, 1) * objectMatrices[matrixIndex].model).xyz; @@ -72,6 +67,8 @@ void main() { OUT.meshletIndices[outIndex] = gl_GlobalInvocationID.x; } + memoryBarrierShared(); + if (gl_LocalInvocationID.x == 0) { OUT.mvp = objectMatrices[matrixIndex].mvp; EmitMeshTasksEXT(taskCount, 1, 1); diff --git a/projects/mesh_shader/assets/shaders/shader.vert b/projects/mesh_shader/assets/shaders/shader.vert index fca50579..0da4f058 100644 --- a/projects/mesh_shader/assets/shaders/shader.vert +++ b/projects/mesh_shader/assets/shaders/shader.vert @@ -8,22 +8,20 @@ layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNormal; layout(location = 0) out vec3 passNormal; -layout(location = 1) out uint dummyOutput; +layout(location = 1) out flat uint passTaskIndex; -layout(std430, binding = 0) readonly buffer matrixBuffer -{ +layout(std430, binding = 0) readonly buffer matrixBuffer { ObjectMatrices objectMatrices[]; }; -layout( push_constant ) uniform constants{ - uint matrixIndex; +layout( push_constant ) uniform constants { uint padding; // pad to same size as mesh shader constants + uint matrixIndex; }; - void main() { - gl_Position = objectMatrices[matrixIndex].mvp * vec4(inPosition, 1.0); - passNormal = inNormal; - - dummyOutput = padding * 0; // padding must be used, else compiler shrinks constant size + passNormal = inNormal; + passTaskIndex = 0; + + gl_Position = objectMatrices[matrixIndex].mvp * vec4(inPosition, 1.0); } \ No newline at end of file diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp index 8afbbb26..23d8b028 100644 --- a/projects/mesh_shader/src/main.cpp +++ b/projects/mesh_shader/src/main.cpp @@ -94,8 +94,10 @@ int main(int argc, const char** argv) { applicationName, VK_MAKE_VERSION(0, 0, 1), { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, - features + features, + { VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME } ); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, 1280, 720, true); vkcv::Window &window = core.getWindow(windowHandle); @@ -106,7 +108,6 @@ int main(int argc, const char** argv) { vkcv::asset::loadScene(path, mesh); assert(!mesh.vertexGroups.empty()); - auto vertexBuffer = vkcv::buffer<uint8_t>( core, vkcv::BufferType::VERTEX, @@ -199,7 +200,7 @@ int main(int argc, const char** argv) { } vkcv::ShaderProgram bunnyShaderProgram{}; - vkcv::shader::GLSLCompiler compiler (vkcv::shader::GLSLCompileTarget::MESH_SHADING); + vkcv::shader::GLSLCompiler compiler; compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("assets/shaders/shader.vert"), [&bunnyShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { @@ -249,17 +250,19 @@ int main(int argc, const char** argv) { // mesh shader vkcv::ShaderProgram meshShaderProgram; - compiler.compile(vkcv::ShaderStage::TASK, std::filesystem::path("assets/shaders/shader.task"), + vkcv::shader::GLSLCompiler mesh_compiler (vkcv::shader::GLSLCompileTarget::MESH_SHADING); + + mesh_compiler.compile(vkcv::ShaderStage::TASK, std::filesystem::path("assets/shaders/shader.task"), [&meshShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { meshShaderProgram.addShader(shaderStage, path); }); - - compiler.compile(vkcv::ShaderStage::MESH, std::filesystem::path("assets/shaders/shader.mesh"), + + mesh_compiler.compile(vkcv::ShaderStage::MESH, std::filesystem::path("assets/shaders/shader.mesh"), [&meshShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { meshShaderProgram.addShader(shaderStage, path); }); - - compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("assets/shaders/shader.frag"), + + mesh_compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("assets/shaders/shader.frag"), [&meshShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { meshShaderProgram.addShader(shaderStage, path); }); @@ -343,11 +346,15 @@ int main(int argc, const char** argv) { matrixBuffer.fill({ objectMatrices }); - struct PushConstants { - uint32_t matrixIndex; + struct MeshletPushConstants { uint32_t meshletCount; + uint32_t matrixIndex; + }; + + MeshletPushConstants pushConstants { + static_cast<uint32_t>(meshShaderModelData.meshlets.size()), + 0 }; - PushConstants pushConstants{ 0, static_cast<uint32_t>(meshShaderModelData.meshlets.size()) }; if (updateFrustumPlanes) { const CameraPlanes cameraPlanes = computeCameraPlanes(camera); @@ -357,7 +364,7 @@ int main(int argc, const char** argv) { const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); - vkcv::PushConstants pushConstantData = vkcv::pushConstants<PushConstants>(); + vkcv::PushConstants pushConstantData = vkcv::pushConstants<MeshletPushConstants>(); pushConstantData.appendDrawcall(pushConstants); if (useMeshShader) { @@ -378,14 +385,14 @@ int main(int argc, const char** argv) { vkcv::InstanceDrawcall drawcall (vertexData); drawcall.useDescriptorSet(0, vertexShaderDescriptorSet); - core.recordDrawcallsToCmdStream( + /*core.recordDrawcallsToCmdStream( cmdStream, bunnyPipeline, pushConstantData, { drawcall }, { renderTargets }, windowHandle - ); + );*/ } core.prepareSwapchainImageForPresent(cmdStream); diff --git a/src/vkcv/GraphicsPipelineManager.cpp b/src/vkcv/GraphicsPipelineManager.cpp index 8747a5e9..767616f7 100644 --- a/src/vkcv/GraphicsPipelineManager.cpp +++ b/src/vkcv/GraphicsPipelineManager.cpp @@ -132,17 +132,24 @@ namespace vkcv { assert(outCreateInfo); std::vector<uint32_t> code = shaderProgram.getShaderBinary(stage); - vk::ShaderModuleCreateInfo vertexModuleInfo({}, code.size() * sizeof(uint32_t), - code.data()); + vk::ShaderModuleCreateInfo vertexModuleInfo( + {}, + code.size() * sizeof(uint32_t), + code.data() + ); vk::ShaderModule shaderModule; if (device.createShaderModule(&vertexModuleInfo, nullptr, &shaderModule) != vk::Result::eSuccess) return false; const static auto entryName = "main"; - - *outCreateInfo = vk::PipelineShaderStageCreateInfo({}, shaderStageToVkShaderStage(stage), - shaderModule, entryName, nullptr); + *outCreateInfo = vk::PipelineShaderStageCreateInfo( + vk::PipelineShaderStageCreateFlags(), + shaderStageToVkShaderStage(stage), + shaderModule, + entryName, + nullptr + ); return true; } @@ -157,7 +164,8 @@ namespace vkcv { static void fillVertexInputDescription( std::vector<vk::VertexInputAttributeDescription> &vertexAttributeDescriptions, std::vector<vk::VertexInputBindingDescription> &vertexBindingDescriptions, - const bool existsVertexShader, const GraphicsPipelineConfig &config) { + const bool existsVertexShader, + const GraphicsPipelineConfig &config) { if (existsVertexShader) { const VertexLayout &layout = config.getVertexLayout(); @@ -214,7 +222,9 @@ namespace vkcv { static vk::PipelineTessellationStateCreateInfo createPipelineTessellationStateCreateInfo(const GraphicsPipelineConfig &config) { vk::PipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo( - {}, config.getTesselationControlPoints()); + {}, + config.getTesselationControlPoints() + ); return pipelineTessellationStateCreateInfo; } @@ -235,8 +245,13 @@ namespace vkcv { scissor = vk::Rect2D({ 0, 0 }, { config.getWidth(), config.getHeight() }); - vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo({}, 1, &viewport, 1, - &scissor); + vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo( + {}, + 1, + &viewport, + 1, + &scissor + ); return pipelineViewportStateCreateInfo; } @@ -276,8 +291,18 @@ namespace vkcv { } vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo( - {}, config.isDepthClampingEnabled(), false, vk::PolygonMode::eFill, cullMode, - vk::FrontFace::eCounterClockwise, false, 0.f, 0.f, 0.f, 1.f); + {}, + config.isDepthClampingEnabled(), + false, + vk::PolygonMode::eFill, + cullMode, + vk::FrontFace::eCounterClockwise, + false, + 0.f, + 0.f, + 0.f, + 1.f + ); static vk::PipelineRasterizationConservativeStateCreateInfoEXT conservativeRasterization; @@ -376,11 +401,17 @@ namespace vkcv { static vk::PushConstantRange pushConstantRange; const size_t pushConstantsSize = config.getShaderProgram().getPushConstantsSize(); - pushConstantRange = - vk::PushConstantRange(vk::ShaderStageFlagBits::eAll, 0, pushConstantsSize); + pushConstantRange = vk::PushConstantRange( + vk::ShaderStageFlagBits::eAll, + 0, + pushConstantsSize + ); - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo({}, (descriptorSetLayouts), - (pushConstantRange)); + vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo ( + vk::PipelineLayoutCreateFlags(), + descriptorSetLayouts, + pushConstantRange + ); if (pushConstantsSize == 0) { pipelineLayoutCreateInfo.pushConstantRangeCount = 0; @@ -397,9 +428,17 @@ namespace vkcv { static vk::PipelineDepthStencilStateCreateInfo createPipelineDepthStencilStateCreateInfo(const GraphicsPipelineConfig &config) { const vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilCreateInfo( - vk::PipelineDepthStencilStateCreateFlags(), config.getDepthTest() != DepthTest::None, - config.isWritingDepth(), depthTestToVkCompareOp(config.getDepthTest()), false, false, - {}, {}, 0.0f, 1.0f); + vk::PipelineDepthStencilStateCreateFlags(), + config.getDepthTest() != DepthTest::None, + config.isWritingDepth(), + depthTestToVkCompareOp(config.getDepthTest()), + false, + false, + {}, + {}, + 0.0f, + 1.0f + ); return pipelineDepthStencilCreateInfo; } @@ -449,7 +488,7 @@ namespace vkcv { || (existsTaskShader && existsMeshShader)); if (!validGeometryStages) { - vkcv_log(LogLevel::ERROR, "Requires vertex or task and mesh shader"); + vkcv_log(LogLevel::ERROR, "Requires a valid geometry shader stage"); return {}; } @@ -613,13 +652,16 @@ namespace vkcv { } // pipeline layout - vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = - createPipelineLayoutCreateInfo(config, descriptorSetLayouts); + vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = createPipelineLayoutCreateInfo( + config, + descriptorSetLayouts + ); - vk::PipelineLayout vkPipelineLayout {}; - if (getCore().getContext().getDevice().createPipelineLayout(&pipelineLayoutCreateInfo, - nullptr, &vkPipelineLayout) - != vk::Result::eSuccess) { + const auto& pipelineLayout = ( + getCore().getContext().getDevice().createPipelineLayout(pipelineLayoutCreateInfo) + ); + + if (!pipelineLayout) { destroyShaderModules(); return {}; } @@ -637,33 +679,50 @@ namespace vkcv { break; } } + + const bool usesTesselation = ( + existsTessellationControlShader && + existsTessellationEvaluationShader + ); // Get all setting structs together and create the Pipeline const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo( - {}, static_cast<uint32_t>(shaderStages.size()), shaderStages.data(), - &pipelineVertexInputStateCreateInfo, - &pipelineInputAssemblyStateCreateInfo, - &pipelineTessellationStateCreateInfo, + {}, + static_cast<uint32_t>(shaderStages.size()), + shaderStages.data(), + existsVertexShader? &pipelineVertexInputStateCreateInfo : nullptr, + existsVertexShader? &pipelineInputAssemblyStateCreateInfo : nullptr, + usesTesselation? &pipelineTessellationStateCreateInfo : nullptr, &pipelineViewportStateCreateInfo, &pipelineRasterizationStateCreateInfo, &pipelineMultisampleStateCreateInfo, p_depthStencilCreateInfo, &pipelineColorBlendStateCreateInfo, &dynamicStateCreateInfo, - vkPipelineLayout, + pipelineLayout, pass, 0, {}, 0 ); - - vk::Pipeline vkPipeline {}; - if (getCore().getContext().getDevice().createGraphicsPipelines( - nullptr, 1, &graphicsPipelineCreateInfo, nullptr, &vkPipeline) - != vk::Result::eSuccess) { + + vkcv_log(LogLevel::RAW_INFO, "STAGES: %lu", shaderStages.size()); + for (const auto& shaderStage : shaderStages) { + vkcv_log(LogLevel::RAW_INFO, "STAGE: %s %s %s", + shaderStage.pName, + vk::to_string(shaderStage.stage).c_str(), + vk::to_string(shaderStage.flags).c_str() + ); + } + + auto pipelineResult = getCore().getContext().getDevice().createGraphicsPipeline( + nullptr, graphicsPipelineCreateInfo + ); + + if (pipelineResult.result != vk::Result::eSuccess) { // Catch runtime error if the creation of the pipeline fails. // Destroy everything to keep the memory clean. - getCore().getContext().getDevice().destroy(vkPipelineLayout); + getCore().getContext().getDevice().destroy(pipelineLayout); destroyShaderModules(); return {}; } @@ -672,7 +731,7 @@ namespace vkcv { destroyShaderModules(); // Hand over Handler to main Application - return add({ vkPipeline, vkPipelineLayout, config }); + return add({ pipelineResult.value, pipelineLayout, config }); } vk::Pipeline -- GitLab