diff --git a/res/shaders/MeshletPass.slang b/res/shaders/MeshletPass.slang index 49ef1a5..70632d3 100644 --- a/res/shaders/MeshletPass.slang +++ b/res/shaders/MeshletPass.slang @@ -1,63 +1,8 @@ import Common; -import BRDF; import Scene; import VertexData; import MaterialParameter; -struct MeshPayload -{ - uint instanceId[MAX_MESHLETS_PER_MESH]; - uint meshletId[MAX_MESHLETS_PER_MESH]; -}; - -groupshared MeshPayload p; -groupshared uint head; -groupshared Frustum viewFrustum; - -[numthreads(TASK_GROUP_SIZE, 1, 1)] -[outputtopology("triangle")] -[shader("amplification")] -void taskMain( - uint threadID: SV_GroupIndex, - uint groupID: SV_GroupID -){ - InstanceData instance = pScene.instances[groupID]; - if(threadID == 0) - { - head = 0; - float3 origin = viewToModel(instance.inverseTransformMatrix, float4(0, 0, 0, 1)).xyz; - const float offset = 0.0f; - float3 corners[4] = { - screenToModel(instance.inverseTransformMatrix, float4(offset, offset, -1.0f, 1.0f)).xyz, - screenToModel(instance.inverseTransformMatrix, float4(pViewParams.screenDimensions.x - offset, offset, -1.0f, 1.0f)).xyz, - screenToModel(instance.inverseTransformMatrix, float4(offset, pViewParams.screenDimensions.y - offset, -1.0f, 1.0f)).xyz, - screenToModel(instance.inverseTransformMatrix, float4(pViewParams.screenDimensions - float2(offset, offset), -1.0f, 1.0f)).xyz - }; - viewFrustum.sides[0] = computePlane(origin, corners[2], corners[0]); - viewFrustum.sides[1] = computePlane(origin, corners[1], corners[3]); - viewFrustum.sides[2] = computePlane(origin, corners[0], corners[1]); - viewFrustum.sides[3] = computePlane(origin, corners[3], corners[2]); - } - GroupMemoryBarrierWithGroupSync(); - MeshData mesh = pScene.meshData[groupID]; - for(uint i = threadID; i < MAX_MESHLETS_PER_MESH; i += TASK_GROUP_SIZE) - { - if(i < mesh.numMeshlets) - { - uint m = mesh.meshletOffset + i; - MeshletDescription meshlet = pScene.meshletInfos[m]; - if(meshlet.bounding.insideFrustum(viewFrustum)) - { - uint index; - InterlockedAdd(head, 1, index); - p.meshletId[index] = m; - p.instanceId[index] = groupID; - } - } - } - GroupMemoryBarrierWithGroupSync(); - DispatchMesh(head, 1, 1, p); -} struct PrimitiveAttributes { @@ -74,9 +19,8 @@ void meshMain( out vertices FragmentParameter vertices[MAX_VERTICES], out indices uint3 indices[MAX_PRIMITIVES] ){ - InstanceData inst = pScene.instances[meshPayload.instanceId[groupID]]; - MeshData md = pScene.meshData[meshPayload.instanceId[groupID]]; - MeshletDescription m = pScene.meshletInfos[meshPayload.meshletId[groupID]]; + InstanceData inst = pScene.instances[meshPayload.instanceId]; + MeshletDescription m = pScene.meshletInfos[pScene.culledMeshlets[meshPayload.cullingOffset + groupID]]; SetMeshOutputCounts(m.vertexCount, m.primitiveCount); for(uint i = threadID; i < MAX_PRIMITIVES; i += MESH_GROUP_SIZE) @@ -97,7 +41,6 @@ void meshMain( VertexAttributes attr = pVertexData.getAttributes(m.indicesOffset + vertexIndex); attr.meshletId = -1; vertices[v] = attr.getParameter(inst.transformMatrix); - //vertices[v].vertexColor = m.color; } } } \ No newline at end of file diff --git a/res/shaders/ViewCullingTask.slang b/res/shaders/ViewCullingTask.slang new file mode 100644 index 0000000..0f6133f --- /dev/null +++ b/res/shaders/ViewCullingTask.slang @@ -0,0 +1,49 @@ +import Common; +import Scene; + +groupshared MeshPayload p; +groupshared uint head; +groupshared Frustum viewFrustum; + +[numthreads(TASK_GROUP_SIZE, 1, 1)] +[outputtopology("triangle")] +[shader("amplification")] +void taskMain( + uint threadID: SV_GroupIndex, + uint groupID: SV_GroupID +){ + InstanceData instance = pScene.instances[pOffsets.instanceOffset + groupID]; + MeshData mesh = pScene.meshData[pOffsets.instanceOffset + groupID]; + if(threadID == 0) + { + head = 0; + float3 origin = viewToModel(instance.inverseTransformMatrix, float4(0, 0, 0, 1)).xyz; + const float offset = 0.0f; + float3 corners[4] = { + screenToModel(instance.inverseTransformMatrix, float4(offset, offset, -1.0f, 1.0f)).xyz, + screenToModel(instance.inverseTransformMatrix, float4(pViewParams.screenDimensions.x - offset, offset, -1.0f, 1.0f)).xyz, + screenToModel(instance.inverseTransformMatrix, float4(offset, pViewParams.screenDimensions.y - offset, -1.0f, 1.0f)).xyz, + screenToModel(instance.inverseTransformMatrix, float4(pViewParams.screenDimensions - float2(offset, offset), -1.0f, 1.0f)).xyz + }; + viewFrustum.sides[0] = computePlane(origin, corners[2], corners[0]); + viewFrustum.sides[1] = computePlane(origin, corners[1], corners[3]); + viewFrustum.sides[2] = computePlane(origin, corners[0], corners[1]); + viewFrustum.sides[3] = computePlane(origin, corners[3], corners[2]); + p.instanceId = pOffsets.instanceOffset + groupID; + p.cullingOffset = pScene.cullingOffsets[pOffsets.cullingCounterOffset + groupID]; + } + GroupMemoryBarrierWithGroupSync(); + for(uint i = threadID; i < mesh.numMeshlets; i += TASK_GROUP_SIZE) + { + uint m = mesh.meshletOffset + i; + MeshletDescription meshlet = pScene.meshletInfos[m]; + //if(meshlet.bounding.insideFrustum(viewFrustum)) + { + uint index; + InterlockedAdd(head, 1, index); + pScene.culledMeshlets[p.cullingOffset + index] = m; + } + } + GroupMemoryBarrierWithGroupSync(); + DispatchMesh(head, 1, 1, p); +} \ No newline at end of file diff --git a/res/shaders/lib/Scene.slang b/res/shaders/lib/Scene.slang index a9f1587..ac619c3 100644 --- a/res/shaders/lib/Scene.slang +++ b/res/shaders/lib/Scene.slang @@ -24,7 +24,6 @@ static const uint MAX_VERTICES = 256; static const uint MAX_PRIMITIVES = 256; static const uint TASK_GROUP_SIZE = 128; static const uint MESH_GROUP_SIZE = 32; -static const uint MAX_MESHLETS_PER_MESH = 512; struct InstanceData { @@ -32,6 +31,14 @@ struct InstanceData float4x4 inverseTransformMatrix; }; +struct DrawCallOffsets +{ + uint32_t instanceOffset; + uint32_t cullingCounterOffset; +}; +layout(push_constant) +ConstantBuffer pOffsets; + struct Scene { StructuredBuffer instances; @@ -39,7 +46,15 @@ struct Scene StructuredBuffer meshletInfos; StructuredBuffer primitiveIndices; StructuredBuffer vertexIndices; + StructuredBuffer cullingOffsets; + RWStructuredBuffer culledMeshlets; }; layout(set=2) ParameterBlock pScene; +struct MeshPayload +{ + uint instanceId; + uint cullingOffset; +}; + diff --git a/src/Engine/Containers/Array.h b/src/Engine/Containers/Array.h index f66a338..06aff60 100644 --- a/src/Engine/Containers/Array.h +++ b/src/Engine/Containers/Array.h @@ -645,10 +645,7 @@ private: else { // And move the current elements into that one - for(size_type i = 0; i < arraySize; ++i) - { - newData[i] = std::forward(_data[i]); - } + std::uninitialized_move(begin(), end(), Iterator(newData)); // As well as default initialize the others for (size_type i = arraySize; i < allocated; ++i) { diff --git a/src/Engine/Graphics/Command.h b/src/Engine/Graphics/Command.h index 2f5c812..b18b690 100644 --- a/src/Engine/Graphics/Command.h +++ b/src/Engine/Graphics/Command.h @@ -18,7 +18,7 @@ public: virtual void bindDescriptor(const Array& sets, Array dynamicOffsets = {}) = 0; virtual void bindVertexBuffer(const Array& buffer) = 0; virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) = 0; - virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) = 0; + virtual void pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) = 0; virtual void draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) = 0; virtual void drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, uint32 firstInstance) = 0; virtual void drawMesh(uint32 groupX, uint32 groupY, uint32 groupZ) = 0; @@ -34,7 +34,7 @@ public: virtual void bindPipeline(Gfx::PComputePipeline pipeline) = 0; virtual void bindDescriptor(Gfx::PDescriptorSet set, Array dynamicOffsets = {}) = 0; virtual void bindDescriptor(const Array& sets, Array dynamicOffsets = {}) = 0; - virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) = 0; + virtual void pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) = 0; virtual void dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) = 0; std::string name; }; diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index 1b04dfe..e69985c 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -16,7 +16,7 @@ using namespace Seele; -BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) +BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics, scene) { basePassLayout = graphics->createPipelineLayout("BasePassLayout"); @@ -32,10 +32,15 @@ BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) lightCullingLayout->create(); basePassLayout->addDescriptorLayout(lightCullingLayout); + basePassLayout->addPushConstants(Gfx::SePushConstantRange{ + .stageFlags = Gfx::SE_SHADER_STAGE_TASK_BIT_EXT, + .offset = 0, + .size = sizeof(VertexData::DrawCallOffsets), + }); if (graphics->supportMeshShading()) { - graphics->getShaderCompiler()->registerRenderPass(basePassLayout, "BasePass", "MeshletPass", true, true, "BasePass", true, true, "MeshletPass"); + graphics->getShaderCompiler()->registerRenderPass(basePassLayout, "BasePass", "MeshletPass", true, true, "BasePass", true, true, "ViewCullingTask"); } else { @@ -47,7 +52,7 @@ BasePass::~BasePass() { } -void BasePass::beginFrame(const Component::Camera& cam) +void BasePass::beginFrame(const Component::Camera& cam) { RenderPass::beginFrame(cam); @@ -56,7 +61,7 @@ void BasePass::beginFrame(const Component::Camera& cam) transparentCulling = lightCullingLayout->allocateDescriptorSet(); } -void BasePass::render() +void BasePass::render() { oLightIndexList->pipelineBarrier( Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, @@ -81,122 +86,135 @@ void BasePass::render() graphics->beginRenderPass(renderPass); Array commands; - Gfx::ShaderPermutation permutation; - if (graphics->supportMeshShading()) + Gfx::ShaderPermutation permutation; + if (graphics->supportMeshShading()) + { + permutation.setTaskFile("ViewCullingTask"); + permutation.setMeshFile("MeshletPass"); + } + else + { + permutation.setVertexFile("LegacyPass"); + } + permutation.setFragmentFile("BasePass"); + for (VertexData* vertexData : VertexData::getList()) + { + permutation.setVertexData(vertexData->getTypeName()); + const auto& materials = vertexData->getMaterialData(); + for (const auto& materialData : materials) { - permutation.setTaskFile("MeshletPass"); - permutation.setMeshFile("MeshletPass"); - } - else - { - permutation.setVertexFile("LegacyPass"); - } - permutation.setFragmentFile("BasePass"); - for (VertexData* vertexData : VertexData::getList()) - { - permutation.setVertexData(vertexData->getTypeName()); - const auto& materials = vertexData->getMaterialData(); - for (const auto& materialData : materials) + // material not used for any active meshes, skip + if (materialData.instances.size() == 0) + continue; + // Create Pipeline(Material, VertexData) + // Descriptors: + // ViewData => global, static + // VertexData => per meshtype + // SceneData => per material instance + // LightEnv => provided by scene + // Material => per material + // LightCulling => calculated by pass + permutation.setMaterial(materialData.material->getName()); + Gfx::PermutationId id(permutation); + + Gfx::ORenderCommand command = graphics->createRenderCommand("BaseRender"); + command->setViewport(viewport); + + const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id); + assert(collection != nullptr); + if (graphics->supportMeshShading()) { - // Create Pipeline(Material, VertexData) - // Descriptors: - // ViewData => global, static - // VertexData => per meshtype - // SceneData => per material instance - // LightEnv => provided by scene - // Material => per material - // LightCulling => calculated by pass - permutation.setMaterial(materialData.material->getName()); - Gfx::PermutationId id(permutation); - - Gfx::ORenderCommand command = graphics->createRenderCommand("BaseRender"); - command->setViewport(viewport); - - const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id); - assert(collection != nullptr); + Gfx::MeshPipelineCreateInfo pipelineInfo; + pipelineInfo.taskShader = collection->taskShader; + pipelineInfo.meshShader = collection->meshShader; + pipelineInfo.fragmentShader = collection->fragmentShader; + pipelineInfo.pipelineLayout = collection->pipelineLayout; + pipelineInfo.renderPass = renderPass; + pipelineInfo.depthStencilState.depthCompareOp = Gfx::SE_COMPARE_OP_GREATER_OR_EQUAL; + pipelineInfo.multisampleState.samples = viewport->getSamples(); + pipelineInfo.colorBlend.attachmentCount = 2; + Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); + command->bindPipeline(pipeline); + } + else + { + Gfx::LegacyPipelineCreateInfo pipelineInfo; + pipelineInfo.vertexShader = collection->vertexShader; + pipelineInfo.fragmentShader = collection->fragmentShader; + pipelineInfo.pipelineLayout = collection->pipelineLayout; + pipelineInfo.renderPass = renderPass; + pipelineInfo.depthStencilState.depthCompareOp = Gfx::SE_COMPARE_OP_GREATER_OR_EQUAL; + pipelineInfo.multisampleState.samples = viewport->getSamples(); + pipelineInfo.colorBlend.attachmentCount = 1; + Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); + command->bindPipeline(pipeline); + } + command->bindDescriptor(vertexData->getVertexDataSet()); + command->bindDescriptor(viewParamsSet); + command->bindDescriptor(scene->getLightEnvironment()->getDescriptorSet()); + command->bindDescriptor(opaqueCulling); + for (const auto& drawCall : materialData.instances) + { + command->bindDescriptor(drawCall.materialInstance->getDescriptorSet()); + command->bindDescriptor(vertexData->getInstanceDataSet()); + command->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT, 0, sizeof(VertexData::DrawCallOffsets), &drawCall.offsets); if (graphics->supportMeshShading()) { - Gfx::MeshPipelineCreateInfo pipelineInfo; - pipelineInfo.taskShader = collection->taskShader; - pipelineInfo.meshShader = collection->meshShader; - pipelineInfo.fragmentShader = collection->fragmentShader; - pipelineInfo.pipelineLayout = collection->pipelineLayout; - pipelineInfo.renderPass = renderPass; - pipelineInfo.depthStencilState.depthCompareOp = Gfx::SE_COMPARE_OP_GREATER_OR_EQUAL; - pipelineInfo.multisampleState.samples = viewport->getSamples(); - pipelineInfo.colorBlend.attachmentCount = 1; - Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); - command->bindPipeline(pipeline); + command->drawMesh(drawCall.numMeshes, 1, 1); } else { - Gfx::LegacyPipelineCreateInfo pipelineInfo; - pipelineInfo.vertexShader = collection->vertexShader; - pipelineInfo.fragmentShader = collection->fragmentShader; - pipelineInfo.pipelineLayout = collection->pipelineLayout; - pipelineInfo.renderPass = renderPass; - pipelineInfo.depthStencilState.depthCompareOp = Gfx::SE_COMPARE_OP_GREATER_OR_EQUAL; - pipelineInfo.multisampleState.samples = viewport->getSamples(); - pipelineInfo.colorBlend.attachmentCount = 1; - Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); - command->bindPipeline(pipeline); + //command->bindIndexBuffer(vertexData->getIndexBuffer()); + //uint32 instanceOffset = 0; + //for (const auto& meshData : vertexData->getMeshData(instance.meshId)) + //{ + // if (meshData.numIndices > 0) + // { + // command->drawIndexed(meshData.numIndices, 1, meshData.firstIndex, meshData.indicesOffset, instanceOffset); + // } + // instanceOffset++; + //} } - command->bindDescriptor(vertexData->getVertexDataSet()); - command->bindDescriptor(viewParamsSet); - command->bindDescriptor(scene->getLightEnvironment()->getDescriptorSet()); - command->bindDescriptor(opaqueCulling); - for (const auto& instance : materialData.instances) - { - command->bindDescriptor(instance.materialInstance->getDescriptorSet()); - command->bindDescriptor(vertexData->getInstanceDataSet(), {instance.descriptorOffset, instance.descriptorOffset}); - if (graphics->supportMeshShading()) - { - command->drawMesh(vertexData->getMeshData(instance.meshId).size(), 1, 1); - } - else - { - //command->bindIndexBuffer(vertexData->getIndexBuffer()); - //uint32 instanceOffset = 0; - //for (const auto& meshData : vertexData->getMeshData(instance.meshId)) - //{ - // if (meshData.numIndices > 0) - // { - // command->drawIndexed(meshData.numIndices, 1, meshData.firstIndex, meshData.indicesOffset, instanceOffset); - // } - // instanceOffset++; - //} - } - } - commands.add(std::move(command)); } + commands.add(std::move(command)); } - - + } + graphics->executeCommands(std::move(commands)); graphics->endRenderPass(); } -void BasePass::endFrame() +void BasePass::endFrame() { } -void BasePass::publishOutputs() +void BasePass::publishOutputs() { colorAttachment = Gfx::RenderTargetAttachment(viewport, - Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - Gfx::SE_ATTACHMENT_LOAD_OP_LOAD, Gfx::SE_ATTACHMENT_STORE_OP_STORE); + Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE); resources->registerRenderPassOutput("BASEPASS_COLOR", colorAttachment); + + meshletIdTexture = graphics->createTexture2D(TextureCreateInfo{ + .format = Gfx::SE_FORMAT_R32_UINT, + .width = viewport->getWidth(), + .height = viewport->getHeight(), + .usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_STORAGE_BIT, + }); + meshletIdAttachment = Gfx::RenderTargetAttachment(meshletIdTexture, + Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE); + resources->registerRenderPassOutput("BASEPASS_MESHLETID", meshletIdAttachment); } -void BasePass::createRenderPass() +void BasePass::createRenderPass() { depthAttachment = resources->requestRenderTarget("DEPTHPREPASS_DEPTH"); - meshletIdAttachment = resources->requestRenderTarget("BASEPASS_MESHLETID"); depthAttachment.setLoadOp(Gfx::SE_ATTACHMENT_LOAD_OP_LOAD); - depthAttachment.setInitialLayout(Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + depthAttachment.setInitialLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL); depthAttachment.setFinalLayout(Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); Gfx::RenderTargetLayout layout = Gfx::RenderTargetLayout{ - .colorAttachments = { colorAttachment, meshletIdAttachment }, + .colorAttachments = { colorAttachment, meshletIdAttachment }, .depthAttachment = depthAttachment, }; Array dependency = { @@ -213,7 +231,7 @@ void BasePass::createRenderPass() .dstSubpass = 0, .srcStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, .dstStage = Gfx::SE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .srcAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .srcAccess = Gfx::SE_ACCESS_NONE, .dstAccess = Gfx::SE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, }, { diff --git a/src/Engine/Graphics/RenderPass/BasePass.h b/src/Engine/Graphics/RenderPass/BasePass.h index ee900d4..c80c72e 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.h +++ b/src/Engine/Graphics/RenderPass/BasePass.h @@ -25,6 +25,7 @@ private: Gfx::PShaderBuffer tLightIndexList; Gfx::PTexture2D oLightGrid; Gfx::PTexture2D tLightGrid; + Gfx::OTexture2D meshletIdTexture; Gfx::PDescriptorSet opaqueCulling; Gfx::PDescriptorSet transparentCulling; diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp index d408613..abf0ba0 100644 --- a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp +++ b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp @@ -18,9 +18,14 @@ DepthPrepass::DepthPrepass(Gfx::PGraphics graphics, PScene scene) { depthPrepassLayout = graphics->createPipelineLayout("DepthPrepassLayout"); depthPrepassLayout->addDescriptorLayout(viewParamsLayout); + depthPrepassLayout->addPushConstants(Gfx::SePushConstantRange{ + .stageFlags = Gfx::SE_SHADER_STAGE_TASK_BIT_EXT, + .offset = 0, + .size = sizeof(VertexData::DrawCallOffsets), + }); if (graphics->supportMeshShading()) { - graphics->getShaderCompiler()->registerRenderPass(depthPrepassLayout, "DepthPass", "MeshletPass", false, false, "", true, true, "MeshletPass"); + graphics->getShaderCompiler()->registerRenderPass(depthPrepassLayout, "DepthPass", "MeshletPass", false, false, "", true, true, "ViewCullingTask"); } else { @@ -45,7 +50,7 @@ void DepthPrepass::render() Gfx::ShaderPermutation permutation; if (graphics->supportMeshShading()) { - permutation.setTaskFile("MeshletPass"); + permutation.setTaskFile("ViewCullingTask"); permutation.setMeshFile("MeshletPass"); } else @@ -58,14 +63,17 @@ void DepthPrepass::render() const auto& materials = vertexData->getMaterialData(); for (const auto& materialData : materials) { + // material not used for any active meshes, skip + if (materialData.instances.size() == 0) + continue; // Create Pipeline(VertexData) // Descriptors: // ViewData => global, static // VertexData => per meshtype - // SceneData => per material instance + // SceneData => per meshtype Gfx::PermutationId id(permutation); - Gfx::ORenderCommand command = graphics->createRenderCommand("BaseRender"); + Gfx::ORenderCommand command = graphics->createRenderCommand("DepthRender"); command->setViewport(viewport); const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id); @@ -105,12 +113,13 @@ void DepthPrepass::render() } command->bindDescriptor(vertexData->getVertexDataSet()); command->bindDescriptor(viewParamsSet); - for (const auto& instance : materialData.instances) + for (const auto& drawCall : materialData.instances) { - command->bindDescriptor(vertexData->getInstanceDataSet(), { instance.descriptorOffset, instance.descriptorOffset }); + command->bindDescriptor(vertexData->getInstanceDataSet()); + command->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT, 0, sizeof(VertexData::DrawCallOffsets), &drawCall.offsets); if (graphics->supportMeshShading()) { - command->drawMesh(vertexData->getMeshData(instance.meshId).size(), 1, 1); + command->drawMesh(drawCall.numMeshes, 1, 1); } else { @@ -140,14 +149,24 @@ void DepthPrepass::endFrame() void DepthPrepass::publishOutputs() { + // If we render to a part of an image, the depth buffer itself must + // still match the size of the whole image or their coordinate systems go out of sync + TextureCreateInfo depthBufferInfo = { + .format = Gfx::SE_FORMAT_D32_SFLOAT, + .width = viewport->getOwner()->getFramebufferWidth(), + .height = viewport->getOwner()->getFramebufferHeight(), + .usage = Gfx::SE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + }; + depthBuffer = graphics->createTexture2D(depthBufferInfo); + depthAttachment = + Gfx::RenderTargetAttachment(depthBuffer, + Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_GENERAL, + Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE); + resources->registerRenderPassOutput("DEPTHPREPASS_DEPTH", depthAttachment); } void DepthPrepass::createRenderPass() { - depthAttachment = resources->requestRenderTarget("DEPTHPREPASS_DEPTH"); - depthAttachment.setLoadOp(Gfx::SE_ATTACHMENT_LOAD_OP_LOAD); - depthAttachment.setInitialLayout(Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - depthAttachment.setFinalLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL); Gfx::RenderTargetLayout layout = Gfx::RenderTargetLayout{ .depthAttachment = depthAttachment, }; diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.h b/src/Engine/Graphics/RenderPass/DepthPrepass.h index cc19630..84f6737 100644 --- a/src/Engine/Graphics/RenderPass/DepthPrepass.h +++ b/src/Engine/Graphics/RenderPass/DepthPrepass.h @@ -18,6 +18,9 @@ public: virtual void createRenderPass() override; private: Gfx::RenderTargetAttachment depthAttachment; + + Gfx::OTexture2D depthBuffer; + Gfx::OPipelineLayout depthPrepassLayout; }; DEFINE_REF(DepthPrepass) diff --git a/src/Engine/Graphics/RenderPass/StaticBasePass.cpp b/src/Engine/Graphics/RenderPass/StaticBasePass.cpp index 238f5ce..3b8283a 100644 --- a/src/Engine/Graphics/RenderPass/StaticBasePass.cpp +++ b/src/Engine/Graphics/RenderPass/StaticBasePass.cpp @@ -163,16 +163,6 @@ void StaticBasePass::publishOutputs() Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE); resources->registerRenderPassOutput("BASEPASS_COLOR", colorAttachment); - meshletIdTexture = graphics->createTexture2D(TextureCreateInfo{ - .format = Gfx::SE_FORMAT_R32_UINT, - .width = viewport->getWidth(), - .height = viewport->getHeight(), - .usage = Gfx::SE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_STORAGE_BIT, - }); - meshletIdAttachment = Gfx::RenderTargetAttachment(meshletIdTexture, - Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE); - resources->registerRenderPassOutput("BASEPASS_MESHLETID", meshletIdAttachment); } void StaticBasePass::createRenderPass() diff --git a/src/Engine/Graphics/RenderPass/StaticDepthPrepass.cpp b/src/Engine/Graphics/RenderPass/StaticDepthPrepass.cpp index 831f0b2..a875e6e 100644 --- a/src/Engine/Graphics/RenderPass/StaticDepthPrepass.cpp +++ b/src/Engine/Graphics/RenderPass/StaticDepthPrepass.cpp @@ -132,20 +132,7 @@ void StaticDepthPrepass::endFrame() void StaticDepthPrepass::publishOutputs() { - // If we render to a part of an image, the depth buffer itself must - // still match the size of the whole image or their coordinate systems go out of sync - TextureCreateInfo depthBufferInfo = { - .format = Gfx::SE_FORMAT_D32_SFLOAT, - .width = viewport->getOwner()->getFramebufferWidth(), - .height = viewport->getOwner()->getFramebufferHeight(), - .usage = Gfx::SE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, - }; - depthBuffer = graphics->createTexture2D(depthBufferInfo); - depthAttachment = - Gfx::RenderTargetAttachment(depthBuffer, - Gfx::SE_IMAGE_LAYOUT_UNDEFINED, Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE); - resources->registerRenderPassOutput("DEPTHPREPASS_DEPTH", depthAttachment); + } void StaticDepthPrepass::createRenderPass() diff --git a/src/Engine/Graphics/RenderPass/TextPass.cpp b/src/Engine/Graphics/RenderPass/TextPass.cpp index 1a6e1c2..ceeacf8 100644 --- a/src/Engine/Graphics/RenderPass/TextPass.cpp +++ b/src/Engine/Graphics/RenderPass/TextPass.cpp @@ -85,7 +85,7 @@ void TextPass::render() command->bindDescriptor({generalSet, resource.textureArraySet}); //command->bindVertexBuffer({resource.vertexBuffer}); - command->pushConstants(pipelineLayout, Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(TextData), &resource.textData); + command->pushConstants(Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(TextData), &resource.textData); //command->draw(4, static_cast(resource.vertexBuffer->getNumVertices()), 0, 0); } commands.add(std::move(command)); diff --git a/src/Engine/Graphics/StaticMeshVertexData.cpp b/src/Engine/Graphics/StaticMeshVertexData.cpp index a1c35db..6e3846b 100644 --- a/src/Engine/Graphics/StaticMeshVertexData.cpp +++ b/src/Engine/Graphics/StaticMeshVertexData.cpp @@ -228,14 +228,13 @@ void StaticMeshVertexData::registerStaticMesh(const Array& meshes, const Array ids; // Get references to loaded meshlets const auto& meshData = VertexData::getMeshData(mapped); - for (const auto& md : meshData) + + for (size_t i = 0; i < meshData.numMeshlets; ++i) { - for (size_t i = 0; i < md.numMeshlets; ++i) - { - ids.add(md.meshletOffset + i); - } + ids.add(meshData.meshletOffset + i); } + // Get Static instance array PMaterialInstance instance = mesh->referencedMaterial->getHandle(); PMaterial baseMat = instance->getBaseMaterial(); diff --git a/src/Engine/Graphics/VertexData.cpp b/src/Engine/Graphics/VertexData.cpp index 25d0c7f..eb5b471 100644 --- a/src/Engine/Graphics/VertexData.cpp +++ b/src/Engine/Graphics/VertexData.cpp @@ -18,7 +18,10 @@ void VertexData::resetMeshData() std::unique_lock l(materialDataLock); for (auto& mat : materialData) { - mat.material->getDescriptorLayout()->reset(); + if (mat.material != nullptr) + { + mat.material->getDescriptorLayout()->reset(); + } } materialData.clear(); if (dirty) @@ -35,63 +38,64 @@ void VertexData::updateMesh(PMesh mesh, Component::Transform& transform) PMaterial mat = referencedInstance->getBaseMaterial(); if (materialData.size() <= mat->getId()) { - materialData.resize(mat->getId()); + materialData.resize(mat->getId() + 1); } MaterialData& matData = materialData[mat->getId()]; matData.material = mat; - MaterialInstanceData& matInstanceData = matData.instances[referencedInstance->getId()]; - matInstanceData.descriptorOffset = instanceData.size(); - matInstanceData.numMeshes = 0; - matInstanceData.meshId = mesh->id; - for (const auto& data : meshData[mesh->id]) + if (matData.instances.size() <= referencedInstance->getId()) { - Matrix4 transformMatrix = transform.toMatrix() * mesh->transform; - instanceData.add(InstanceData { - .transformMatrix = transformMatrix, - .inverseTransformMatrix = glm::inverse(transformMatrix), - }); - instanceMeshData.add(data); - matInstanceData.numMeshes++; - for (size_t i = 0; i < 0; ++i) - { - auto bounding = meshlets[data.meshletOffset + i].bounding; - StaticArray corners; - Vector min = bounding.min;//bounding.center - bounding.radius * Vector(1, 1, 1); - Vector max = bounding.max;//bounding.center + bounding.radius * Vector(1, 1, 1); - corners[0] = transformMatrix * Vector4(min.x, min.y, min.z, 1); - corners[1] = transformMatrix * Vector4(min.x, min.y, max.z, 1); - corners[2] = transformMatrix * Vector4(min.x, max.y, min.z, 1); - corners[3] = transformMatrix * Vector4(min.x, max.y, max.z, 1); - corners[4] = transformMatrix * Vector4(max.x, min.y, min.z, 1); - corners[5] = transformMatrix * Vector4(max.x, min.y, max.z, 1); - corners[6] = transformMatrix * Vector4(max.x, max.y, min.z, 1); - corners[7] = transformMatrix * Vector4(max.x, max.y, max.z, 1); - addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); - } + matData.instances.resize(referencedInstance->getId() + 1); } + BatchedDrawCall& matInstanceData = matData.instances[referencedInstance->getId()]; + const auto& data = meshData[mesh->id]; + + Matrix4 transformMatrix = transform.toMatrix() * mesh->transform; + matInstanceData.instanceData.add(InstanceData{ + .transformMatrix = transformMatrix, + .inverseTransformMatrix = glm::inverse(transformMatrix), + }); + matInstanceData.instanceMeshData.add(data); + matInstanceData.numMeshes++; + for (size_t i = 0; i < 0; ++i) + { + auto bounding = meshlets[data.meshletOffset + i].bounding; + StaticArray corners; + Vector min = bounding.min;//bounding.center - bounding.radius * Vector(1, 1, 1); + Vector max = bounding.max;//bounding.center + bounding.radius * Vector(1, 1, 1); + corners[0] = transformMatrix * Vector4(min.x, min.y, min.z, 1); + corners[1] = transformMatrix * Vector4(min.x, min.y, max.z, 1); + corners[2] = transformMatrix * Vector4(min.x, max.y, min.z, 1); + corners[3] = transformMatrix * Vector4(min.x, max.y, max.z, 1); + corners[4] = transformMatrix * Vector4(max.x, min.y, min.z, 1); + corners[5] = transformMatrix * Vector4(max.x, min.y, max.z, 1); + corners[6] = transformMatrix * Vector4(max.x, max.y, min.z, 1); + corners[7] = transformMatrix * Vector4(max.x, max.y, max.z, 1); + addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); + addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); + } + matInstanceData.materialInstance = referencedInstance; referencedInstance->updateDescriptor(); } @@ -99,6 +103,47 @@ void VertexData::updateMesh(PMesh mesh, Component::Transform& transform) void VertexData::createDescriptors() { std::unique_lock l(materialDataLock); + + instanceData.clear(); + instanceMeshData.clear(); + + uint32 numMeshlets = 0; + Array cullingOffsets; + for (auto& mat : materialData) + { + for (auto& instance : mat.instances) + { + instance.offsets.instanceOffset = instanceData.size(); + instance.offsets.cullingCounterOffset = cullingOffsets.size(); + instance.numMeshes = instance.instanceData.size(); + instance.numMeshlets = 0; + for (size_t i = 0; i < instance.instanceData.size(); ++i) + { + instanceData.add(instance.instanceData[i]); + instanceMeshData.add(instance.instanceMeshData[i]); + instance.numMeshlets += instance.instanceMeshData[i].numMeshlets; + cullingOffsets.add(numMeshlets); + numMeshlets += instance.numMeshlets; + } + } + } + cullingOffsetBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .sourceData = { + .size = cullingOffsets.size() * sizeof(uint32), + .data = (uint8*)cullingOffsets.data(), + }, + .numElements = cullingOffsets.size(), + .name = "MeshletOffset" + }); + cullingBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .sourceData = { + .size = numMeshlets * sizeof(uint32), + }, + .numElements = numMeshlets, + .name = "MeshletCulling" + }); + + instanceDataLayout->reset(); instanceBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ .sourceData = { @@ -137,6 +182,8 @@ void VertexData::createDescriptors() descriptorSet->updateBuffer(2, meshletBuffer); descriptorSet->updateBuffer(3, primitiveIndicesBuffer); descriptorSet->updateBuffer(4, vertexIndicesBuffer); + descriptorSet->updateBuffer(5, cullingOffsetBuffer); + descriptorSet->updateBuffer(6, cullingBuffer); descriptorSet->writeChanges(); } @@ -147,45 +194,40 @@ void VertexData::loadMesh(MeshId id, Array loadedIndices, Array meshlets.reserve(meshlets.size() + loadedMeshlets.size()); vertexIndices.reserve(vertexIndices.size() + loadedMeshlets.size() * Gfx::numVerticesPerMeshlet); primitiveIndices.reserve(primitiveIndices.size() + loadedMeshlets.size() * Gfx::numPrimitivesPerMeshlet * 3); - uint32 currentMesh = 0; - while (currentMesh < loadedMeshlets.size()) + uint32 meshletOffset = meshlets.size(); + AABB meshAABB; + for (uint32 i = 0; i < loadedMeshlets.size(); ++i) { - uint32 numMeshlets = std::min(512, loadedMeshlets.size() - currentMesh); - uint32 meshletOffset = meshlets.size(); - AABB meshAABB; - for (uint32 i = 0; i < numMeshlets; ++i) - { - Meshlet& m = loadedMeshlets[currentMesh + i]; - meshAABB = meshAABB.combine(m.boundingBox); - uint32 vertexOffset = vertexIndices.size(); - vertexIndices.resize(vertexOffset + m.numVertices); - std::memcpy(vertexIndices.data() + vertexOffset, m.uniqueVertices, m.numVertices * sizeof(uint32)); - uint32 primitiveOffset = primitiveIndices.size(); - primitiveIndices.resize(primitiveOffset + (m.numPrimitives * 3)); - std::memcpy(primitiveIndices.data() + primitiveOffset, m.primitiveLayout, m.numPrimitives * 3 * sizeof(uint8)); - meshlets.add(MeshletDescription{ - .bounding = m.boundingBox,//.toSphere(), - .vertexCount = m.numVertices, - .primitiveCount = m.numPrimitives, - .vertexOffset = vertexOffset, - .primitiveOffset = primitiveOffset, - .color = Vector((float)rand() / RAND_MAX,(float)rand() / RAND_MAX,(float)rand() / RAND_MAX), - .indicesOffset = (uint32)meshOffsets[id], - }); - } - meshData[id].add(MeshData{ - .bounding = meshAABB,//.toSphere(), - .numMeshlets = numMeshlets, - .meshletOffset = meshletOffset, + Meshlet& m = loadedMeshlets[i]; + meshAABB = meshAABB.combine(m.boundingBox); + uint32 vertexOffset = vertexIndices.size(); + vertexIndices.resize(vertexOffset + m.numVertices); + std::memcpy(vertexIndices.data() + vertexOffset, m.uniqueVertices, m.numVertices * sizeof(uint32)); + uint32 primitiveOffset = primitiveIndices.size(); + primitiveIndices.resize(primitiveOffset + (m.numPrimitives * 3)); + std::memcpy(primitiveIndices.data() + primitiveOffset, m.primitiveLayout, m.numPrimitives * 3 * sizeof(uint8)); + meshlets.add(MeshletDescription{ + .bounding = m.boundingBox,//.toSphere(), + .vertexCount = m.numVertices, + .primitiveCount = m.numPrimitives, + .vertexOffset = vertexOffset, + .primitiveOffset = primitiveOffset, + .color = Vector((float)rand() / RAND_MAX,(float)rand() / RAND_MAX,(float)rand() / RAND_MAX), + .indicesOffset = (uint32)meshOffsets[id], }); - currentMesh += numMeshlets; } - meshData[id][0].firstIndex = indices.size(); - meshData[id][0].numIndices = loadedIndices.size(); + meshData[id] = MeshData{ + .bounding = meshAABB,//.toSphere(), + .numMeshlets = (uint32)loadedMeshlets.size(), + .meshletOffset = meshletOffset, + }; + + meshData[id].firstIndex = indices.size(); + meshData[id].numIndices = loadedIndices.size(); if (!graphics->supportMeshShading()) { indices.resize(indices.size() + loadedIndices.size()); - std::memcpy(indices.data() + meshData[id][0].firstIndex, loadedIndices.data(), loadedIndices.size() * sizeof(uint32)); + std::memcpy(indices.data() + meshData[id].firstIndex, loadedIndices.data(), loadedIndices.size() * sizeof(uint32)); indexBuffer = graphics->createIndexBuffer(IndexBufferCreateInfo{ .sourceData = { .size = sizeof(uint32) * indices.size(), @@ -204,7 +246,7 @@ void VertexData::loadMesh(MeshId id, Array loadedIndices, Array .numElements = meshlets.size(), .dynamic = false, .name = "MeshletBuffer" - }); + }); vertexIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ .sourceData = { .size = sizeof(uint32) * vertexIndices.size(), @@ -213,7 +255,7 @@ void VertexData::loadMesh(MeshId id, Array loadedIndices, Array .numElements = vertexIndices.size(), .dynamic = false, .name = "VertexIndicesBuffer" - }); + }); primitiveIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ .sourceData = { .size = sizeof(uint8) * primitiveIndices.size(), @@ -222,7 +264,7 @@ void VertexData::loadMesh(MeshId id, Array loadedIndices, Array .numElements = primitiveIndices.size(), .dynamic = false, .name = "PrimitiveIndicesBuffer", - }); + }); } MeshId VertexData::allocateVertexData(uint64 numVertices) @@ -276,16 +318,20 @@ void VertexData::init(Gfx::PGraphics _graphics) instanceDataLayout = graphics->createDescriptorLayout("pScene"); // instanceData - instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{.binding = 0, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,}); + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{ .binding = 0, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, }); // meshData - instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{.binding = 1, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,}); + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{ .binding = 1, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, }); // meshletData - instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{.binding = 2, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER}); + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{ .binding = 2, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER }); // primitiveIndices - instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{.binding = 3, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER}); - // vetexIndices - instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{.binding = 4, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER}); - + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{ .binding = 3, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER }); + // vertexIndices + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{ .binding = 4, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER }); + // cullingList + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{ .binding = 5, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER }); + // cullingOffset + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{ .binding = 6, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER }); + instanceDataLayout->create(); resizeBuffers(); graphics->getShaderCompiler()->registerVertexData(this); diff --git a/src/Engine/Graphics/VertexData.h b/src/Engine/Graphics/VertexData.h index 27c6f39..09536ff 100644 --- a/src/Engine/Graphics/VertexData.h +++ b/src/Engine/Graphics/VertexData.h @@ -41,17 +41,24 @@ public: uint32 firstIndex = 0; uint32 numIndices = 0; }; - struct MaterialInstanceData + struct DrawCallOffsets + { + uint32 instanceOffset = 0; + uint32 cullingCounterOffset = 0; + }; + struct BatchedDrawCall { PMaterialInstance materialInstance; - uint32 descriptorOffset; - uint64 numMeshes; - MeshId meshId; + uint64 numMeshes = 0; + uint64 numMeshlets = 0; + DrawCallOffsets offsets; + Array instanceData; + Array instanceMeshData; }; struct MaterialData { PMaterial material; - Array instances; + Array instances; }; void resetMeshData(); void updateMesh(PMesh mesh, Component::Transform& transform); @@ -70,7 +77,7 @@ public: Gfx::PDescriptorLayout getInstanceDataLayout() { return instanceDataLayout; } Gfx::PDescriptorSet getInstanceDataSet() { return descriptorSet; } const Array& getMaterialData() const { return materialData; } - const Array& getMeshData(MeshId id) { return meshData[id]; } + const MeshData& getMeshData(MeshId id) { return meshData[id]; } static List getList(); static VertexData* findByTypeName(std::string name); virtual void init(Gfx::PGraphics graphics); @@ -92,7 +99,7 @@ protected: std::mutex materialDataLock; Array materialData; std::mutex vertexDataLock; - Map> meshData; + Map meshData; Map meshOffsets; Map meshVertexCounts; Array meshlets; @@ -105,6 +112,9 @@ protected: Gfx::OShaderBuffer meshletBuffer; Gfx::OShaderBuffer vertexIndicesBuffer; Gfx::OShaderBuffer primitiveIndicesBuffer; + // temporary meshlet culling buffer, passed from task to mesh shader + Gfx::OShaderBuffer cullingBuffer; + Gfx::OShaderBuffer cullingOffsetBuffer; // for legacy pipeline Gfx::OIndexBuffer indexBuffer; // Material data diff --git a/src/Engine/Graphics/Vulkan/Command.cpp b/src/Engine/Graphics/Vulkan/Command.cpp index 2102556..9255266 100644 --- a/src/Engine/Graphics/Vulkan/Command.cpp +++ b/src/Engine/Graphics/Vulkan/Command.cpp @@ -317,10 +317,10 @@ void RenderCommand::bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) vkCmdBindIndexBuffer(handle, buf->getHandle(), 0, cast(buf->getIndexType())); } -void RenderCommand::pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) +void RenderCommand::pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) { assert(threadId == std::this_thread::get_id()); - vkCmdPushConstants(handle, layout.cast()->getHandle(), stage, offset, size, data); + vkCmdPushConstants(handle, pipeline->getLayout(), stage, offset, size, data); } void RenderCommand::draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) @@ -443,10 +443,10 @@ void ComputeCommand::bindDescriptor(const Array& descriptor delete[] sets; } -void ComputeCommand::pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) +void ComputeCommand::pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) { assert(threadId == std::this_thread::get_id()); - vkCmdPushConstants(handle, layout.cast()->getHandle(), stage, offset, size, data); + vkCmdPushConstants(handle, pipeline->getLayout(), stage, offset, size, data); } void ComputeCommand::dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) diff --git a/src/Engine/Graphics/Vulkan/Command.h b/src/Engine/Graphics/Vulkan/Command.h index 510e7f8..7cd8243 100644 --- a/src/Engine/Graphics/Vulkan/Command.h +++ b/src/Engine/Graphics/Vulkan/Command.h @@ -76,7 +76,7 @@ public: virtual void bindDescriptor(const Array& descriptorSets, Array dynamicOffsets) override; virtual void bindVertexBuffer(const Array& buffers) override; virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) override; - virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, + virtual void pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) override; virtual void draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) override; virtual void drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, @@ -110,7 +110,7 @@ public: virtual void bindPipeline(Gfx::PComputePipeline pipeline) override; virtual void bindDescriptor(Gfx::PDescriptorSet set, Array dynamicOffsets) override; virtual void bindDescriptor(const Array& sets, Array dynamicOffsets) override; - virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, + virtual void pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) override; virtual void dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) override; diff --git a/src/Engine/Graphics/Vulkan/Descriptor.cpp b/src/Engine/Graphics/Vulkan/Descriptor.cpp index 538c282..da506a0 100644 --- a/src/Engine/Graphics/Vulkan/Descriptor.cpp +++ b/src/Engine/Graphics/Vulkan/Descriptor.cpp @@ -184,7 +184,7 @@ void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PUniformBuffer uniformBu .dstBinding = binding, .dstArrayElement = 0, .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorType = cast(layout->getBindings()[binding].descriptorType), .pBufferInfo = &bufferInfos.back(), }); @@ -203,7 +203,6 @@ void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PShaderBuffer shaderBuff .offset = 0, .range = vulkanBuffer->getSize(), }); - writeDescriptors.add(VkWriteDescriptorSet{ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, @@ -211,7 +210,7 @@ void DescriptorSet::updateBuffer(uint32_t binding, Gfx::PShaderBuffer shaderBuff .dstBinding = binding, .dstArrayElement = 0, .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorType = cast(layout->getBindings()[binding].descriptorType), .pBufferInfo = &bufferInfos.back(), }); @@ -238,7 +237,7 @@ void DescriptorSet::updateBuffer(uint32_t binding, uint32 index, Gfx::PShaderBuf .dstBinding = binding, .dstArrayElement = index, .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .descriptorType = cast(layout->getBindings()[binding].descriptorType), .pBufferInfo = &bufferInfos.back(), }); diff --git a/src/Engine/Graphics/slang-compile.cpp b/src/Engine/Graphics/slang-compile.cpp index 9d86add..6298bfb 100644 --- a/src/Engine/Graphics/slang-compile.cpp +++ b/src/Engine/Graphics/slang-compile.cpp @@ -16,15 +16,16 @@ Slang::ComPtr Seele::generateShader(const ShaderCreateInfo& create } slang::SessionDesc sessionDesc; sessionDesc.flags = 0; - StaticArray option; + StaticArray option; option[0].name = slang::CompilerOptionName::IgnoreCapabilities; - option[0].value = slang::CompilerOptionValue(); option[0].value.kind = slang::CompilerOptionValueKind::Int; option[0].value.intValue0 = 1; option[1].name = slang::CompilerOptionName::EmitSpirvViaGLSL; - option[1].value = slang::CompilerOptionValue(); option[1].value.kind = slang::CompilerOptionValueKind::Int; option[1].value.intValue0 = 1; + option[2].name = slang::CompilerOptionName::DebugInformationFormat; + option[2].value.kind = slang::CompilerOptionValueKind::Int; + option[2].value.intValue0 = 0; sessionDesc.compilerOptionEntries = option.data(); sessionDesc.compilerOptionEntryCount = option.size(); sessionDesc.defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_COLUMN_MAJOR; @@ -61,7 +62,7 @@ Slang::ComPtr Seele::generateShader(const ShaderCreateInfo& create modules.add(mainModule); CHECK_DIAGNOSTICS(); - mainModule->findEntryPointByName(createInfo.entryPoint.c_str(), entrypoint.writeRef()); + CHECK_RESULT(mainModule->findEntryPointByName(createInfo.entryPoint.c_str(), entrypoint.writeRef())); modules.add(entrypoint); Slang::ComPtr moduleComposition; diff --git a/src/Engine/Material/Material.cpp b/src/Engine/Material/Material.cpp index 14e282b..fa6f294 100644 --- a/src/Engine/Material/Material.cpp +++ b/src/Engine/Material/Material.cpp @@ -114,6 +114,7 @@ void Material::load(ArchiveBuffer& buffer) layout->addDescriptorBinding(Gfx::DescriptorBinding{.binding = binding, .descriptorType = descriptorType, .textureType = textureType, .descriptorCount = descriptorCount, .bindingFlags = bindingFlags, .shaderStages = shaderStages,}); } layout->create(); + materialId = materialIdCounter++; } void Material::compile() diff --git a/src/Engine/System/MeshUpdater.cpp b/src/Engine/System/MeshUpdater.cpp index 4f48727..ace1b8e 100644 --- a/src/Engine/System/MeshUpdater.cpp +++ b/src/Engine/System/MeshUpdater.cpp @@ -18,9 +18,6 @@ void MeshUpdater::update(Component::Transform& transform, Component::Mesh& comp) { for (auto& mesh : comp.asset->meshes) { - if (!comp.isStatic) - { - mesh->vertexData->updateMesh(mesh, transform); - } + mesh->vertexData->updateMesh(mesh, transform); } } diff --git a/src/Engine/Window/GameView.cpp b/src/Engine/Window/GameView.cpp index 78562c4..ae74dc8 100644 --- a/src/Engine/Window/GameView.cpp +++ b/src/Engine/Window/GameView.cpp @@ -18,10 +18,10 @@ GameView::GameView(Gfx::PGraphics graphics, PWindow window, const ViewportCreate , gameInterface(dllPath) { reloadGame(); - renderGraph.addPass(new StaticDepthPrepass(graphics, scene)); + //renderGraph.addPass(new StaticDepthPrepass(graphics, scene)); renderGraph.addPass(new DepthPrepass(graphics, scene)); renderGraph.addPass(new LightCullingPass(graphics, scene)); - renderGraph.addPass(new StaticBasePass(graphics, scene)); + //renderGraph.addPass(new StaticBasePass(graphics, scene)); renderGraph.addPass(new BasePass(graphics, scene)); //renderGraph.addPass(new DebugPass(graphics, scene)); //renderGraph.addPass(new SkyboxRenderPass(graphics, scene));