diff --git a/res/shaders/DepthCullingTask.slang b/res/shaders/DepthCullingTask.slang index 3108b5a..04aab52 100644 --- a/res/shaders/DepthCullingTask.slang +++ b/res/shaders/DepthCullingTask.slang @@ -3,17 +3,18 @@ import Scene; groupshared MeshPayload p; groupshared uint head; +groupshared MeshData mesh; [numthreads(TASK_GROUP_SIZE, 1, 1)] [shader("amplification")] void taskMain( - uint threadID: SV_GroupIndex, + uint threadID: SV_GroupThreadID, uint groupID: SV_GroupID, ) { - MeshData mesh = pScene.meshData[pOffsets.instanceOffset + groupID]; if (threadID == 0) { head = 0; + mesh = pScene.meshData[pOffsets.instanceOffset + groupID]; p.instanceId = pOffsets.instanceOffset + groupID; p.meshletOffset = mesh.meshletOffset; p.cullingOffset = pScene.cullingOffsets[p.instanceId]; @@ -24,8 +25,8 @@ void taskMain( uint m = p.meshletOffset + i; uint cull = p.cullingOffset + i; MeshletDescription meshlet = pScene.meshletInfos[m]; - MeshletCullingInfo culling = pScene.culledMeshlets[cull]; - if(false) + MeshletCullingInfo culling = pScene.cullingInfos[cull]; + //if(!culling.anyVisible()) { uint index; InterlockedAdd(head, 1, index); diff --git a/res/shaders/DrawListTask.slang b/res/shaders/DrawListTask.slang index 44259dc..9e718c3 100644 --- a/res/shaders/DrawListTask.slang +++ b/res/shaders/DrawListTask.slang @@ -8,7 +8,7 @@ groupshared MeshData mesh; [numthreads(TASK_GROUP_SIZE, 1, 1)] [shader("amplification")] void taskMain( - uint threadID: SV_GroupIndex, + uint threadID: SV_GroupThreadID, uint groupID: SV_GroupID, ) { if (threadID == 0) @@ -25,7 +25,7 @@ void taskMain( uint m = p.meshletOffset + i; uint cull = p.cullingOffset + i; MeshletDescription meshlet = pScene.meshletInfos[m]; - MeshletCullingInfo culling = pScene.culledMeshlets[cull]; + MeshletCullingInfo culling = pScene.cullingInfos[cull]; if(culling.anyVisible()) { uint index; diff --git a/res/shaders/MeshletPass.slang b/res/shaders/MeshletPass.slang index 5826642..845a1ff 100644 --- a/res/shaders/MeshletPass.slang +++ b/res/shaders/MeshletPass.slang @@ -15,7 +15,7 @@ struct PrimitiveAttributes [outputtopology("triangle")] [shader("mesh")] void meshMain( - in uint threadID: SV_GroupIndex, + in uint threadID: SV_GroupThreadID, in uint groupID: SV_GroupID, in payload MeshPayload meshPayload, out vertices FragmentParameter vertices[MAX_VERTICES], @@ -27,7 +27,7 @@ void meshMain( uint meshletId = meshPayload.cullingOffset + meshletNumber; InstanceData inst = pScene.instances[meshPayload.instanceId]; MeshletDescription m = pScene.meshletInfos[meshPayload.meshletOffset + meshletNumber]; - MeshletCullingInfo cull = pScene.culledMeshlets[meshletId]; + MeshletCullingInfo cull = pScene.cullingInfos[meshletId]; SetMeshOutputCounts(m.vertexCount, m.primitiveCount); for(uint i = threadID; i < MAX_PRIMITIVES; i += MESH_GROUP_SIZE) diff --git a/res/shaders/VisibilityCompute.slang b/res/shaders/VisibilityCompute.slang index 21ae6dd..6011c88 100644 --- a/res/shaders/VisibilityCompute.slang +++ b/res/shaders/VisibilityCompute.slang @@ -8,35 +8,15 @@ struct VisibilityCullingData }; ParameterBlock pVisibilityParams; -groupshared MeshletCullingInfo cullInfo; - -[numthreads(BLOCK_SIZE, 1, 1)] +[numthreads(BLOCK_SIZE, BLOCK_SIZE, 1)] [shader("compute")] void computeMain( - uint threadID: SV_GroupIndex, - uint groupID: SV_GroupID, + uint3 dispatchThreadID: SV_DispatchThreadID, ){ - if (threadID < MAX_PRIMITIVES / 32) - { - cullInfo.visible[threadID] = 0; - } - GroupMemoryBarrierWithGroupSync(); - for (uint y = 0; y < pViewParams.screenDimensions.y; y++) - { - for (uint x = threadID; x < pViewParams.screenDimensions.x; x += BLOCK_SIZE) - { - int3 texCoords = int3(x, y, 0); - uint encoded = pVisibilityParams.visibilityTexture.Load(texCoords).r; - uint2 decoded = decodePrimitive(encoded); - uint base = decoded.y == groupID ? 1 : 0; - uint arrIdx = decoded.x / 32; - uint bit = decoded.x % 32; - cullInfo.visible[arrIdx] |= (base << bit); - } - } - GroupMemoryBarrierWithGroupSync(); - if (threadID < MAX_PRIMITIVES / 32) - { - pVisibilityParams.cullingInfos[groupID].visible[threadID] = cullInfo.visible[threadID]; - } + int3 texCoords = int3(dispatchThreadID.xy, 0); + uint encoded = pVisibilityParams.visibilityTexture.Load(texCoords).r; + uint2 decoded = decodePrimitive(encoded); + uint arrIdx = decoded.x / 32; + uint bit = decoded.x % 32; + pVisibilityParams.cullingInfos[decoded.y].visible[arrIdx] |= (1 << bit); } \ No newline at end of file diff --git a/res/shaders/lib/Scene.slang b/res/shaders/lib/Scene.slang index 520db96..22cc2de 100644 --- a/res/shaders/lib/Scene.slang +++ b/res/shaders/lib/Scene.slang @@ -66,10 +66,10 @@ struct Scene StructuredBuffer meshletInfos; StructuredBuffer primitiveIndices; StructuredBuffer vertexIndices; - StructuredBuffer culledMeshlets; StructuredBuffer cullingOffsets; + StructuredBuffer cullingInfos; }; -layout(set = 2) +layout(set=2) ParameterBlock pScene; uint32_t encodePrimitive(uint32_t primitiveId, uint32_t meshletId) diff --git a/src/Engine/Graphics/Buffer.h b/src/Engine/Graphics/Buffer.h index 1b4bc6a..4350883 100644 --- a/src/Engine/Graphics/Buffer.h +++ b/src/Engine/Graphics/Buffer.h @@ -89,6 +89,8 @@ public: bool writeOnly = true) = 0; virtual void unmap() = 0; + virtual void clear() = 0; + protected: // Inherited via QueueOwnedResource virtual void executeOwnershipBarrier(QueueType newOwner) = 0; diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index 33b9e6e..7df987f 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -85,19 +85,6 @@ void BasePass::beginFrame(const Component::Camera& cam) void BasePass::render() { - oLightIndexList->pipelineBarrier( - Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - tLightIndexList->pipelineBarrier( - Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - oLightGrid->pipelineBarrier( - Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - tLightGrid->pipelineBarrier( - Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - opaqueCulling->updateBuffer(0, oLightIndexList); opaqueCulling->updateTexture(1, oLightGrid); transparentCulling->updateBuffer(0, tLightIndexList); @@ -112,6 +99,8 @@ void BasePass::render() permutation.setViewCulling(useViewCulling); for (VertexData* vertexData : VertexData::getList()) { + vertexData->getInstanceDataSet()->updateBuffer(6, cullingBuffer); + vertexData->getInstanceDataSet()->writeChanges(); permutation.setVertexData(vertexData->getTypeName()); const auto& materials = vertexData->getMaterialData(); for (const auto& materialData : materials) @@ -176,11 +165,11 @@ void BasePass::render() Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); command->bindPipeline(pipeline); } - command->bindDescriptor(vertexData->getVertexDataSet()); command->bindDescriptor(viewParamsSet); + command->bindDescriptor(vertexData->getVertexDataSet()); + command->bindDescriptor(vertexData->getInstanceDataSet()); command->bindDescriptor(scene->getLightEnvironment()->getDescriptorSet()); command->bindDescriptor(opaqueCulling); - command->bindDescriptor(vertexData->getInstanceDataSet()); for (const auto& drawCall : materialData.instances) { command->bindDescriptor(drawCall.materialInstance->getDescriptorSet()); @@ -221,6 +210,8 @@ void BasePass::publishOutputs() void BasePass::createRenderPass() { + cullingBuffer = resources->requestBuffer("CULLINGBUFFER"); + depthAttachment = resources->requestRenderTarget("DEPTHPREPASS_DEPTH"); depthAttachment.setLoadOp(Gfx::SE_ATTACHMENT_LOAD_OP_LOAD); depthAttachment.setInitialLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL); diff --git a/src/Engine/Graphics/RenderPass/BasePass.h b/src/Engine/Graphics/RenderPass/BasePass.h index aa7f992..9366568 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.h +++ b/src/Engine/Graphics/RenderPass/BasePass.h @@ -32,6 +32,8 @@ private: PCameraActor source; Gfx::OPipelineLayout basePassLayout; Gfx::ODescriptorLayout lightCullingLayout; + + Gfx::PShaderBuffer cullingBuffer; }; DEFINE_REF(BasePass) } // namespace Seele diff --git a/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp b/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp index 45a72b8..1887082 100644 --- a/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp +++ b/src/Engine/Graphics/RenderPass/CachedDepthPass.cpp @@ -66,6 +66,8 @@ void CachedDepthPass::render() for (VertexData *vertexData : VertexData::getList()) { permutation.setVertexData(vertexData->getTypeName()); + vertexData->getInstanceDataSet()->updateBuffer(6, cullingBuffer); + vertexData->getInstanceDataSet()->writeChanges(); // Create Pipeline(VertexData) // Descriptors: @@ -120,8 +122,8 @@ void CachedDepthPass::render() Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); command->bindPipeline(pipeline); } - command->bindDescriptor(vertexData->getVertexDataSet()); command->bindDescriptor(viewParamsSet); + command->bindDescriptor(vertexData->getVertexDataSet()); command->bindDescriptor(vertexData->getInstanceDataSet()); uint32 offset = 0; command->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_VERTEX_BIT, 0, sizeof(VertexData::DrawCallOffsets), &offset); @@ -205,6 +207,8 @@ void CachedDepthPass::publishOutputs() void CachedDepthPass::createRenderPass() { + cullingBuffer = resources->requestBuffer("CULLINGBUFFER"); + Gfx::RenderTargetLayout layout = Gfx::RenderTargetLayout{ .colorAttachments = {visibilityAttachment}, .depthAttachment = depthAttachment, diff --git a/src/Engine/Graphics/RenderPass/CachedDepthPass.h b/src/Engine/Graphics/RenderPass/CachedDepthPass.h index cdba89d..810f9d2 100644 --- a/src/Engine/Graphics/RenderPass/CachedDepthPass.h +++ b/src/Engine/Graphics/RenderPass/CachedDepthPass.h @@ -21,6 +21,8 @@ private: Gfx::OTexture2D depthBuffer; Gfx::OTexture2D visibilityBuffer; Gfx::OPipelineLayout depthPrepassLayout; + + Gfx::PShaderBuffer cullingBuffer; }; DEFINE_REF(CachedDepthPass) } \ No newline at end of file diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp index 2ec112d..69344ce 100644 --- a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp +++ b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp @@ -66,6 +66,8 @@ void DepthPrepass::render() for (VertexData *vertexData : VertexData::getList()) { permutation.setVertexData(vertexData->getTypeName()); + vertexData->getInstanceDataSet()->updateBuffer(6, cullingBuffer); + vertexData->getInstanceDataSet()->writeChanges(); // Create Pipeline(VertexData) // Descriptors: // ViewData => global, static @@ -119,14 +121,14 @@ void DepthPrepass::render() Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo)); command->bindPipeline(pipeline); } - command->bindDescriptor(vertexData->getVertexDataSet()); command->bindDescriptor(viewParamsSet); + command->bindDescriptor(vertexData->getVertexDataSet()); command->bindDescriptor(vertexData->getInstanceDataSet()); uint32 offset = 0; command->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_VERTEX_BIT, 0, sizeof(VertexData::DrawCallOffsets), &offset); if (graphics->supportMeshShading()) { - //command->drawMesh(vertexData->getNumInstances(), 1, 1); + command->drawMesh(vertexData->getNumInstances(), 1, 1); } else { @@ -174,6 +176,13 @@ void DepthPrepass::render() Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT ); + // Sync culling reads to compute write + cullingBuffer->pipelineBarrier( + Gfx::SE_ACCESS_SHADER_READ_BIT, + Gfx::SE_PIPELINE_STAGE_MESH_SHADER_BIT_EXT, + Gfx::SE_ACCESS_SHADER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT + ); } void DepthPrepass::endFrame() @@ -186,13 +195,15 @@ void DepthPrepass::publishOutputs() void DepthPrepass::createRenderPass() { + cullingBuffer = resources->requestBuffer("CULLINGBUFFER"); + depthAttachment = resources->requestRenderTarget("DEPTHPREPASS_DEPTH"); depthAttachment.setInitialLayout(Gfx::SE_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); depthAttachment.setFinalLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL); depthAttachment.setLoadOp(Gfx::SE_ATTACHMENT_LOAD_OP_LOAD); visibilityAttachment = resources->requestRenderTarget("VISIBILITY"); visibilityAttachment.setInitialLayout(Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - visibilityAttachment.setFinalLayout(Gfx::SE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + visibilityAttachment.setFinalLayout(Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); visibilityAttachment.setLoadOp(Gfx::SE_ATTACHMENT_LOAD_OP_LOAD); Gfx::RenderTargetLayout layout = Gfx::RenderTargetLayout{ diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.h b/src/Engine/Graphics/RenderPass/DepthPrepass.h index 2eac270..c5cd744 100644 --- a/src/Engine/Graphics/RenderPass/DepthPrepass.h +++ b/src/Engine/Graphics/RenderPass/DepthPrepass.h @@ -20,6 +20,8 @@ private: Gfx::RenderTargetAttachment depthAttachment; Gfx::RenderTargetAttachment visibilityAttachment; Gfx::OPipelineLayout depthPrepassLayout; + + Gfx::PShaderBuffer cullingBuffer; }; DEFINE_REF(DepthPrepass) } // namespace Seele diff --git a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp index 18508b2..6d11158 100644 --- a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp +++ b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp @@ -81,6 +81,19 @@ void LightCullingPass::render() commands.add(std::move(computeCommand)); //std::cout << "Execute" << std::endl; graphics->executeCommands(std::move(commands)); + + oLightIndexList->pipelineBarrier( + Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + tLightIndexList->pipelineBarrier( + Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + oLightGrid->pipelineBarrier( + Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + tLightGrid->pipelineBarrier( + Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); } void LightCullingPass::endFrame() diff --git a/src/Engine/Graphics/RenderPass/VisibilityPass.cpp b/src/Engine/Graphics/RenderPass/VisibilityPass.cpp index 6353059..df9f872 100644 --- a/src/Engine/Graphics/RenderPass/VisibilityPass.cpp +++ b/src/Engine/Graphics/RenderPass/VisibilityPass.cpp @@ -1,4 +1,5 @@ #include "VisibilityPass.h" +#include "Graphics/Shader.h" using namespace Seele; @@ -15,15 +16,46 @@ VisibilityPass::~VisibilityPass() void VisibilityPass::beginFrame(const Component::Camera& cam) { RenderPass::beginFrame(cam); - visibilityDescriptor->reset(); - visibilitySet = visibilityDescriptor->allocateDescriptorSet(); - visibilitySet->updateTexture(0, visibilityAttachment->getTexture()); - visibliitySet->updateBuffer(StaticMeshVertexData::getInstance()->get) + + //Array cullingData(VertexData::getMeshletCount()); + //std::memset(cullingData.data(), 0xffff, cullingData.size() * sizeof(VertexData::MeshletCullingInfo)); + + //cullingBuffer->updateContents(ShaderBufferCreateInfo{ + // .sourceData = { + // .size = VertexData::getMeshletCount() * sizeof(VertexData::MeshletCullingInfo), + // .data = (uint8 *)cullingData.data(), + // }, + // .numElements = VertexData::getMeshletCount()}); + //cullingBuffer->pipelineBarrier( + // Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, + // Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, + // Gfx::SE_ACCESS_MEMORY_WRITE_BIT, + // Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + } void VisibilityPass::render() { + cullingBuffer->rotateBuffer(VertexData::getMeshletCount() * sizeof(VertexData::MeshletCullingInfo)); + cullingBuffer->clear(); + visibilityDescriptor->reset(); + visibilitySet = visibilityDescriptor->allocateDescriptorSet(); + visibilitySet->updateTexture(0, visibilityAttachment.getTexture()); + visibilitySet->updateBuffer(1, cullingBuffer); + visibilitySet->writeChanges(); + + Gfx::OComputeCommand command = graphics->createComputeCommand("VisibilityCommand"); + command->bindPipeline(visibilityPipeline); + command->bindDescriptor({viewParamsSet, visibilitySet}); + command->dispatch(threadGroupSize.x, threadGroupSize.y, threadGroupSize.z); + Array commands; + commands.add(std::move(command)); + graphics->executeCommands(std::move(commands)); + + cullingBuffer->pipelineBarrier( + Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_TASK_SHADER_BIT_EXT); } void VisibilityPass::endFrame() @@ -32,8 +64,11 @@ void VisibilityPass::endFrame() } void VisibilityPass::publishOutputs() -{ - visibilityDescriptor = graphcis->createDescriptorLayout("pVisibilityParams"); +{ + uint32_t viewportWidth = viewport->getWidth(); + uint32_t viewportHeight = viewport->getHeight(); + threadGroupSize = glm::ceil(glm::vec3(viewportWidth / (float)BLOCK_SIZE, viewportHeight / (float)BLOCK_SIZE, 1)); + visibilityDescriptor = graphics->createDescriptorLayout("pVisibilityParams"); visibilityDescriptor->addDescriptorBinding(Gfx::DescriptorBinding{ .binding = 0, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, }); visibilityDescriptor->addDescriptorBinding(Gfx::DescriptorBinding{ .binding = 1, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, .access = Gfx::SE_DESCRIPTOR_ACCESS_READ_WRITE_BIT, }); visibilityDescriptor->create(); @@ -55,6 +90,9 @@ void VisibilityPass::publishOutputs() pipelineInfo.computeShader = visibilityShader; pipelineInfo.pipelineLayout = std::move(visibilityLayout); visibilityPipeline = graphics->createComputePipeline(std::move(pipelineInfo)); + + cullingBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{.dynamic = true, .name = "CullingBuffer"}); + resources->registerBufferOutput("CULLINGBUFFER", cullingBuffer); } void VisibilityPass::createRenderPass() diff --git a/src/Engine/Graphics/RenderPass/VisibilityPass.h b/src/Engine/Graphics/RenderPass/VisibilityPass.h index 5e4b620..21e843d 100644 --- a/src/Engine/Graphics/RenderPass/VisibilityPass.h +++ b/src/Engine/Graphics/RenderPass/VisibilityPass.h @@ -15,16 +15,18 @@ public: virtual void endFrame() override; virtual void publishOutputs() override; virtual void createRenderPass() override; - uint64 allocate private: + static constexpr uint32 BLOCK_SIZE = 32; Gfx::RenderTargetAttachment visibilityAttachment; Gfx::PDescriptorSet visibilitySet; Gfx::ODescriptorLayout visibilityDescriptor; Gfx::OPipelineLayout visibilityLayout; + Gfx::OComputeShader visibilityShader; Gfx::PComputePipeline visibilityPipeline; // Holds culling information for every meshlet for each instance Gfx::OShaderBuffer cullingBuffer; + glm::uvec3 threadGroupSize; }; DEFINE_REF(VisibilityPass) } \ No newline at end of file diff --git a/src/Engine/Graphics/Shader.cpp b/src/Engine/Graphics/Shader.cpp index fcf8ac0..b775b67 100644 --- a/src/Engine/Graphics/Shader.cpp +++ b/src/Engine/Graphics/Shader.cpp @@ -36,12 +36,13 @@ void ShaderCompiler::registerVertexData(VertexData *vd) void ShaderCompiler::registerRenderPass(std::string name, PassConfig config) { - passes[name] = config; + passes[name] = std::move(config); compile(); } ShaderPermutation ShaderCompiler::getTemplate(std::string name) { + std::scoped_lock lock(shadersLock); ShaderPermutation permutation; PassConfig &pass = passes[name]; if (pass.useMeshShading) diff --git a/src/Engine/Graphics/VertexData.cpp b/src/Engine/Graphics/VertexData.cpp index e4c443e..32556e8 100644 --- a/src/Engine/Graphics/VertexData.cpp +++ b/src/Engine/Graphics/VertexData.cpp @@ -12,370 +12,365 @@ using namespace Seele; constexpr static uint64 NUM_DEFAULT_ELEMENTS = 1024 * 1024; +Map VertexData::instanceIdMap; +uint64 VertexData::instanceCount = 0; +uint64 VertexData::meshletCount = 0; void VertexData::resetMeshData() { - std::unique_lock l(materialDataLock); - for (auto &mat : materialData) - { - for (auto &inst : mat.instances) + std::unique_lock l(materialDataLock); + for (auto &mat : materialData) { - inst.instanceData.clear(); - inst.instanceMeshData.clear(); + for (auto &inst : mat.instances) + { + inst.instanceData.clear(); + inst.instanceMeshData.clear(); + } + if (mat.material != nullptr) + { + mat.material->getDescriptorLayout()->reset(); + } } - if (mat.material != nullptr) + if (dirty) { - mat.material->getDescriptorLayout()->reset(); + updateBuffers(); + dirty = false; } - } - if (dirty) - { - updateBuffers(); - dirty = false; - } } -void VertexData::updateMesh(PMesh mesh, Component::Transform &transform) +void VertexData::updateMesh(entt::entity id, uint32 meshIndex, PMesh mesh, Component::Transform &transform) { - std::unique_lock l(materialDataLock); - PMaterialInstance referencedInstance = mesh->referencedMaterial->getHandle(); - PMaterial mat = referencedInstance->getBaseMaterial(); - if (materialData.size() <= mat->getId()) - { - materialData.resize(mat->getId() + 1); - } - MaterialData &matData = materialData[mat->getId()]; - matData.material = mat; - if (matData.instances.size() <= referencedInstance->getId()) - { - matData.instances.resize(referencedInstance->getId() + 1); - } - BatchedDrawCall &matInstanceData = matData.instances[referencedInstance->getId()]; - matInstanceData.materialInstance = referencedInstance; + std::unique_lock l(materialDataLock); + PMaterialInstance referencedInstance = mesh->referencedMaterial->getHandle(); + PMaterial mat = referencedInstance->getBaseMaterial(); + if (materialData.size() <= mat->getId()) + { + materialData.resize(mat->getId() + 1); + } + MaterialData &matData = materialData[mat->getId()]; + matData.material = mat; + if (matData.instances.size() <= referencedInstance->getId()) + { + matData.instances.resize(referencedInstance->getId() + 1); + } + BatchedDrawCall &matInstanceData = matData.instances[referencedInstance->getId()]; + matInstanceData.materialInstance = referencedInstance; - Matrix4 transformMatrix = transform.toMatrix() * mesh->transform; - matInstanceData.instanceData.add(InstanceData{ - .transformMatrix = transformMatrix, - .inverseTransformMatrix = glm::inverse(transformMatrix), - }); - const auto &data = meshData[mesh->id]; - matInstanceData.instanceMeshData.add(data); - referencedInstance->updateDescriptor(); - 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}); - } + Matrix4 transformMatrix = transform.toMatrix() * mesh->transform; + matInstanceData.instanceData.add(InstanceData{ + .transformMatrix = transformMatrix, + .inverseTransformMatrix = glm::inverse(transformMatrix), + }); + const auto &data = meshData[mesh->id]; + auto [instanceId, meshletOffset] = getCullingMapping(id, meshIndex, data.numMeshlets); + matInstanceData.instanceMeshData.add(data); + matInstanceData.cullingOffsets.add(meshletOffset); + referencedInstance->updateDescriptor(); + 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}); + } } void VertexData::createDescriptors() { - std::unique_lock l(materialDataLock); + std::unique_lock l(materialDataLock); - instanceData.clear(); - instanceMeshData.clear(); + instanceData.clear(); + instanceMeshData.clear(); - uint32 numMeshlets = 0; - Array cullingOffsets; - for (auto &mat : materialData) - { - for (auto &instance : mat.instances) + uint32 numMeshlets = 0; + Array cullingOffsets; + for (auto &mat : materialData) { - instance.offsets.instanceOffset = instanceData.size(); - // instance.offsets.cullingCounterOffset = cullingOffsets.size(); - // instance.numMeshlets = 0; - for (size_t i = 0; i < instance.instanceData.size(); ++i) - { - cullingOffsets.add(numMeshlets); - instanceData.add(instance.instanceData[i]); - instanceMeshData.add(instance.instanceMeshData[i]); - // instance.numMeshlets += instance.instanceMeshData[i].numMeshlets; - // cullingOffsets.add(numMeshlets); - numMeshlets += instance.instanceMeshData[i].numMeshlets; - } + for (auto &instance : mat.instances) + { + instance.offsets.instanceOffset = instanceData.size(); + // instance.offsets.cullingCounterOffset = cullingOffsets.size(); + // instance.numMeshlets = 0; + for (size_t i = 0; i < instance.instanceData.size(); ++i) + { + cullingOffsets.add(instance.cullingOffsets[i]); + instanceData.add(instance.instanceData[i]); + instanceMeshData.add(instance.instanceMeshData[i]); + // instance.numMeshlets += instance.instanceMeshData[i].numMeshlets; + // cullingOffsets.add(numMeshlets); + numMeshlets += instance.instanceMeshData[i].numMeshlets; + } + } } - } - Array cullingData(numMeshlets); - std::memset(cullingData.data(), 0xffff, cullingData.size() * sizeof(MeshletCullingInfo)); - cullingOffsetBuffer->rotateBuffer(cullingOffsets.size() * sizeof(uint32)); - cullingOffsetBuffer->updateContents(ShaderBufferCreateInfo{ - .sourceData = { - .size = cullingOffsets.size() * sizeof(uint32), - .data = (uint8 *)cullingOffsets.data(), - }, - .numElements = cullingOffsets.size()}); - cullingOffsetBuffer->pipelineBarrier( - Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, - Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, - Gfx::SE_ACCESS_MEMORY_READ_BIT, - Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + cullingOffsetBuffer->rotateBuffer(cullingOffsets.size() * sizeof(uint32)); + cullingOffsetBuffer->updateContents(ShaderBufferCreateInfo{ + .sourceData = { + .size = cullingOffsets.size() * sizeof(uint32), + .data = (uint8 *)cullingOffsets.data(), + }, + .numElements = cullingOffsets.size()}); + cullingOffsetBuffer->pipelineBarrier( + Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, + Gfx::SE_ACCESS_MEMORY_READ_BIT, + Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT); - cullingBuffer->rotateBuffer(cullingData.size() * sizeof(MeshletCullingInfo)); - cullingBuffer->updateContents(ShaderBufferCreateInfo{ - .sourceData = { - .size = cullingData.size() * sizeof(MeshletCullingInfo), - .data = (uint8 *)cullingData.data(), - }, - .numElements = cullingData.size()}); - cullingBuffer->pipelineBarrier( - Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, - Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, - Gfx::SE_ACCESS_MEMORY_WRITE_BIT, - Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + instanceBuffer->rotateBuffer(instanceData.size() * sizeof(InstanceData)); + instanceBuffer->updateContents(ShaderBufferCreateInfo{ + .sourceData = { + .size = instanceData.size() * sizeof(InstanceData), + .data = (uint8 *)instanceData.data(), + }, + .numElements = instanceData.size()}); + instanceBuffer->pipelineBarrier( + Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, + Gfx::SE_ACCESS_MEMORY_READ_BIT, + Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT); - instanceBuffer->rotateBuffer(instanceData.size() * sizeof(InstanceData)); - instanceBuffer->updateContents(ShaderBufferCreateInfo{ - .sourceData = { - .size = instanceData.size() * sizeof(InstanceData), - .data = (uint8 *)instanceData.data(), - }, - .numElements = instanceData.size()}); - instanceBuffer->pipelineBarrier( - Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, - Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, - Gfx::SE_ACCESS_MEMORY_READ_BIT, - Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT); - - instanceMeshDataBuffer->rotateBuffer(sizeof(MeshData) * instanceMeshData.size()); - instanceMeshDataBuffer->updateContents(ShaderBufferCreateInfo{ - .sourceData = { - .size = sizeof(MeshData) * instanceMeshData.size(), - .data = (uint8 *)instanceMeshData.data(), - }, - .numElements = instanceMeshData.size()}); - instanceMeshDataBuffer->pipelineBarrier( - Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, - Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, - Gfx::SE_ACCESS_MEMORY_READ_BIT, - Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT); - instanceDataLayout->reset(); - descriptorSet = instanceDataLayout->allocateDescriptorSet(); - descriptorSet->updateBuffer(0, instanceBuffer); - descriptorSet->updateBuffer(1, instanceMeshDataBuffer); - descriptorSet->updateBuffer(2, meshletBuffer); - descriptorSet->updateBuffer(3, primitiveIndicesBuffer); - descriptorSet->updateBuffer(4, vertexIndicesBuffer); - descriptorSet->updateBuffer(5, cullingBuffer); - descriptorSet->updateBuffer(6, cullingOffsetBuffer); - - descriptorSet->writeChanges(); + instanceMeshDataBuffer->rotateBuffer(sizeof(MeshData) * instanceMeshData.size()); + instanceMeshDataBuffer->updateContents(ShaderBufferCreateInfo{ + .sourceData = { + .size = sizeof(MeshData) * instanceMeshData.size(), + .data = (uint8 *)instanceMeshData.data(), + }, + .numElements = instanceMeshData.size()}); + instanceMeshDataBuffer->pipelineBarrier( + Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, + Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, + Gfx::SE_ACCESS_MEMORY_READ_BIT, + Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + instanceDataLayout->reset(); + descriptorSet = instanceDataLayout->allocateDescriptorSet(); + descriptorSet->updateBuffer(0, instanceBuffer); + descriptorSet->updateBuffer(1, instanceMeshDataBuffer); + descriptorSet->updateBuffer(2, meshletBuffer); + descriptorSet->updateBuffer(3, primitiveIndicesBuffer); + descriptorSet->updateBuffer(4, vertexIndicesBuffer); + descriptorSet->updateBuffer(5, cullingOffsetBuffer); } void VertexData::loadMesh(MeshId id, Array loadedIndices, Array loadedMeshlets) { - assert(loadedMeshlets.size() < 2048); - std::unique_lock l(vertexDataLock); - meshlets.reserve(meshlets.size() + loadedMeshlets.size()); - vertexIndices.reserve(vertexIndices.size() + loadedMeshlets.size() * Gfx::numVerticesPerMeshlet); - primitiveIndices.reserve(primitiveIndices.size() + loadedMeshlets.size() * Gfx::numPrimitivesPerMeshlet * 3); - uint32 meshletOffset = meshlets.size(); - AABB meshAABB; - for (uint32 i = 0; i < loadedMeshlets.size(); ++i) - { - 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], - }); - } - meshData[id] = MeshData{ - .bounding = meshAABB, //.toSphere(), - .numMeshlets = (uint32)loadedMeshlets.size(), - .meshletOffset = meshletOffset, - .firstIndex = (uint32)indices.size(), - .numIndices = (uint32)loadedIndices.size(), - }; + assert(loadedMeshlets.size() < 2048); + std::unique_lock l(vertexDataLock); + meshlets.reserve(meshlets.size() + loadedMeshlets.size()); + vertexIndices.reserve(vertexIndices.size() + loadedMeshlets.size() * Gfx::numVerticesPerMeshlet); + primitiveIndices.reserve(primitiveIndices.size() + loadedMeshlets.size() * Gfx::numPrimitivesPerMeshlet * 3); + uint32 meshletOffset = meshlets.size(); + AABB meshAABB; + for (uint32 i = 0; i < loadedMeshlets.size(); ++i) + { + 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], + }); + } + meshData[id] = MeshData{ + .bounding = meshAABB, //.toSphere(), + .numMeshlets = (uint32)loadedMeshlets.size(), + .meshletOffset = meshletOffset, + .firstIndex = (uint32)indices.size(), + .numIndices = (uint32)loadedIndices.size(), + }; - if (!graphics->supportMeshShading()) - { - indices.resize(indices.size() + loadedIndices.size()); - std::memcpy(indices.data() + meshData[id].firstIndex, loadedIndices.data(), loadedIndices.size() * sizeof(uint32)); - indexBuffer = graphics->createIndexBuffer(IndexBufferCreateInfo{ + if (!graphics->supportMeshShading()) + { + indices.resize(indices.size() + loadedIndices.size()); + std::memcpy(indices.data() + meshData[id].firstIndex, loadedIndices.data(), loadedIndices.size() * sizeof(uint32)); + indexBuffer = graphics->createIndexBuffer(IndexBufferCreateInfo{ + .sourceData = { + .size = sizeof(uint32) * indices.size(), + .data = (uint8 *)indices.data(), + }, + .indexType = Gfx::SE_INDEX_TYPE_UINT32, + .name = "IndexBuffer", + }); + } + meshletBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ .sourceData = { - .size = sizeof(uint32) * indices.size(), - .data = (uint8 *)indices.data(), + .size = sizeof(MeshletDescription) * meshlets.size(), + .data = (uint8 *)meshlets.data()}, + .numElements = meshlets.size(), + .dynamic = false, + .name = "MeshletBuffer"}); + + vertexIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .sourceData = { + .size = sizeof(uint32) * vertexIndices.size(), + .data = (uint8 *)vertexIndices.data(), }, - .indexType = Gfx::SE_INDEX_TYPE_UINT32, - .name = "IndexBuffer", + .numElements = vertexIndices.size(), + .dynamic = false, + .name = "VertexIndicesBuffer"}); + + primitiveIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .sourceData = { + .size = sizeof(uint8) * primitiveIndices.size(), + .data = (uint8 *)primitiveIndices.data(), + }, + .numElements = primitiveIndices.size(), + .dynamic = false, + .name = "PrimitiveIndicesBuffer", }); - } - meshletBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ - .sourceData = { - .size = sizeof(MeshletDescription) * meshlets.size(), - .data = (uint8 *)meshlets.data()}, - .numElements = meshlets.size(), - .dynamic = false, - .name = "MeshletBuffer"}); - - vertexIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ - .sourceData = { - .size = sizeof(uint32) * vertexIndices.size(), - .data = (uint8 *)vertexIndices.data(), - }, - .numElements = vertexIndices.size(), - .dynamic = false, - .name = "VertexIndicesBuffer"}); - - primitiveIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ - .sourceData = { - .size = sizeof(uint8) * primitiveIndices.size(), - .data = (uint8 *)primitiveIndices.data(), - }, - .numElements = primitiveIndices.size(), - .dynamic = false, - .name = "PrimitiveIndicesBuffer", - }); } MeshId VertexData::allocateVertexData(uint64 numVertices) { - std::unique_lock l(vertexDataLock); - MeshId res{idCounter++}; - meshOffsets[res] = head; - meshVertexCounts[res] = numVertices; - head += numVertices; - if (head > verticesAllocated) - { - verticesAllocated = std::max(head, verticesAllocated + NUM_DEFAULT_ELEMENTS); - resizeBuffers(); - } - return res; + std::unique_lock l(vertexDataLock); + MeshId res{idCounter++}; + meshOffsets[res] = head; + meshVertexCounts[res] = numVertices; + head += numVertices; + if (head > verticesAllocated) + { + verticesAllocated = std::max(head, verticesAllocated + NUM_DEFAULT_ELEMENTS); + resizeBuffers(); + } + return res; } uint64 VertexData::getMeshOffset(MeshId id) { - return meshOffsets[id]; + return meshOffsets[id]; } uint64 VertexData::getMeshVertexCount(MeshId id) { - return meshVertexCounts[id]; + return meshVertexCounts[id]; } List vertexDataList; List VertexData::getList() { - return vertexDataList; + return vertexDataList; } VertexData *VertexData::findByTypeName(std::string name) { - for (auto vd : vertexDataList) - { - if (vd->getTypeName() == name) + for (auto vd : vertexDataList) { - return vd; + if (vd->getTypeName() == name) + { + return vd; + } } - } - return nullptr; + return nullptr; } void VertexData::init(Gfx::PGraphics _graphics) { - graphics = _graphics; - verticesAllocated = NUM_DEFAULT_ELEMENTS; - instanceDataLayout = graphics->createDescriptorLayout("pScene"); + graphics = _graphics; + verticesAllocated = NUM_DEFAULT_ELEMENTS; + instanceDataLayout = graphics->createDescriptorLayout("pScene"); - // instanceData - 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, - }); - // meshletData - 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}); - // 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}); + // instanceData + 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, + }); + // meshletData + 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}); + // vertexIndices + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{.binding = 4, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER}); + // cullingOffset + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{.binding = 5, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER}); + // cullingInfos + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{.binding = 6, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER}); - cullingOffsetBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ - .dynamic = true, - .name = "MeshletOffset", - }); - cullingBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ - .dynamic = true, - .name = "MeshletCulling", - }); - instanceBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ - .dynamic = true, - .name = "InstanceBuffer", - }); - instanceMeshDataBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ - .dynamic = true, - .name = "MeshDataBuffer", - }); - instanceDataLayout->create(); - resizeBuffers(); - graphics->getShaderCompiler()->registerVertexData(this); + instanceDataLayout->create(); + + cullingOffsetBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .dynamic = true, + .name = "MeshletOffset", + }); + instanceBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .dynamic = true, + .name = "InstanceBuffer", + }); + instanceMeshDataBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .dynamic = true, + .name = "MeshDataBuffer", + }); + resizeBuffers(); + graphics->getShaderCompiler()->registerVertexData(this); } void VertexData::destroy() { - instanceBuffer = nullptr; - instanceMeshDataBuffer = nullptr; - instanceDataLayout = nullptr; - meshletBuffer = nullptr; - vertexIndicesBuffer = nullptr; - primitiveIndicesBuffer = nullptr; - indexBuffer = nullptr; - meshData.clear(); - materialData.clear(); + instanceBuffer = nullptr; + instanceMeshDataBuffer = nullptr; + instanceDataLayout = nullptr; + meshletBuffer = nullptr; + vertexIndicesBuffer = nullptr; + primitiveIndicesBuffer = nullptr; + indexBuffer = nullptr; + meshData.clear(); + materialData.clear(); +} + +VertexData::CullingMapping VertexData::getCullingMapping(entt::entity id, uint32 meshIndex, uint32 numMeshlets) +{ + MeshMapping key = MeshMapping{.id = id, .meshId = meshIndex}; + if (!instanceIdMap.contains(key)) + { + instanceIdMap[key] = CullingMapping{.instanceId = instanceCount++, .cullingOffset = uint32(meshletCount)}; + meshletCount += numMeshlets; + } + return instanceIdMap[key]; } VertexData::VertexData() diff --git a/src/Engine/Graphics/VertexData.h b/src/Engine/Graphics/VertexData.h index c5415d4..50ec11a 100644 --- a/src/Engine/Graphics/VertexData.h +++ b/src/Engine/Graphics/VertexData.h @@ -7,6 +7,7 @@ #include "Graphics/Descriptor.h" #include "Graphics/Buffer.h" #include "Meshlet.h" +#include constexpr uint64 MAX_TEXCOORDS = 8; @@ -56,6 +57,7 @@ namespace Seele DrawCallOffsets offsets; Array instanceData; Array instanceMeshData; + Array cullingOffsets; }; struct MaterialData { @@ -63,7 +65,7 @@ namespace Seele Array instances; }; void resetMeshData(); - void updateMesh(PMesh mesh, Component::Transform &transform); + void updateMesh(entt::entity id, uint32 meshIndex, PMesh mesh, Component::Transform &transform); void createDescriptors(); void loadMesh(MeshId id, Array indices, Array meshlets); MeshId allocateVertexData(uint64 numVertices); @@ -87,6 +89,15 @@ namespace Seele virtual void init(Gfx::PGraphics graphics); virtual void destroy(); + struct CullingMapping + { + uint64 instanceId; + uint32 cullingOffset; + }; + static CullingMapping getCullingMapping(entt::entity id, uint32 meshIndex, uint32 numMeshlets); + static uint64 getInstanceCount() { return instanceCount; } + static uint64 getMeshletCount() { return meshletCount; } + protected: virtual void resizeBuffers() = 0; virtual void updateBuffers() = 0; @@ -111,6 +122,17 @@ namespace Seele Array primitiveIndices; Array vertexIndices; Array indices; + + struct MeshMapping + { + entt::entity id; + uint32 meshId; + auto operator<=>(const MeshMapping& other) const = default; + }; + static Map instanceIdMap; + static uint64 instanceCount; + static uint64 meshletCount; + Gfx::PGraphics graphics; Gfx::ODescriptorLayout instanceDataLayout; // for mesh shading diff --git a/src/Engine/Graphics/Vulkan/Buffer.cpp b/src/Engine/Graphics/Vulkan/Buffer.cpp index 4c14ab3..522ef20 100644 --- a/src/Engine/Graphics/Vulkan/Buffer.cpp +++ b/src/Engine/Graphics/Vulkan/Buffer.cpp @@ -389,6 +389,11 @@ void *ShaderBuffer::mapRegion(uint64 offset, uint64 size, bool writeOnly) { void ShaderBuffer::unmap() { Vulkan::Buffer::unmap(); } +void ShaderBuffer::clear() +{ + vkCmdFillBuffer(graphics->getQueueCommands(owner)->getCommands()->getHandle(), Vulkan::Buffer::getHandle(), 0, VK_WHOLE_SIZE, 0); +} + void ShaderBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner) { Gfx::QueueOwnedResource::transferOwnership(newOwner); } diff --git a/src/Engine/Graphics/Vulkan/Buffer.h b/src/Engine/Graphics/Vulkan/Buffer.h index 7ba09cb..11eda84 100644 --- a/src/Engine/Graphics/Vulkan/Buffer.h +++ b/src/Engine/Graphics/Vulkan/Buffer.h @@ -133,6 +133,8 @@ public: virtual void *mapRegion(uint64 offset, uint64 size, bool writeOnly) override; virtual void unmap() override; + virtual void clear() override; + protected: // Inherited via Vulkan::Buffer virtual VkAccessFlags getSourceAccessMask() override; diff --git a/src/Engine/System/ComponentSystem.h b/src/Engine/System/ComponentSystem.h index 7703f1a..844c8ed 100644 --- a/src/Engine/System/ComponentSystem.h +++ b/src/Engine/System/ComponentSystem.h @@ -27,10 +27,11 @@ public: void setupView(Dependencies) { //List> work; - registry.view().each([&](Components&... comp, Deps&... deps){ + registry.view().each([&](entt::entity id, Components&... comp, Deps&... deps){ //work.add([&]() { (accessComponent(deps), ...); update(comp...); + update(id, comp...); //}); }); //getThreadPool().runAndWait(std::move(work)); @@ -41,7 +42,8 @@ public: setupView((getDependencies() | ...)); } virtual void update() override {} - virtual void update(Components&... components) = 0; + virtual void update(Components&... components) {} + virtual void update(entt::entity id, Components&... components) {} }; } // namespace System } // namespace Seele diff --git a/src/Engine/System/MeshUpdater.cpp b/src/Engine/System/MeshUpdater.cpp index ace1b8e..21eddac 100644 --- a/src/Engine/System/MeshUpdater.cpp +++ b/src/Engine/System/MeshUpdater.cpp @@ -14,10 +14,10 @@ MeshUpdater::~MeshUpdater() { } -void MeshUpdater::update(Component::Transform& transform, Component::Mesh& comp) +void MeshUpdater::update(entt::entity id, Component::Transform& transform, Component::Mesh& comp) { - for (auto& mesh : comp.asset->meshes) + for (uint32 i = 0; i < comp.asset->meshes.size(); ++i) { - mesh->vertexData->updateMesh(mesh, transform); + comp.asset->meshes[i]->vertexData->updateMesh(id, i, comp.asset->meshes[i], transform); } } diff --git a/src/Engine/System/MeshUpdater.h b/src/Engine/System/MeshUpdater.h index c9f6dee..44d52f9 100644 --- a/src/Engine/System/MeshUpdater.h +++ b/src/Engine/System/MeshUpdater.h @@ -12,7 +12,7 @@ class MeshUpdater : public ComponentSystem