diff --git a/external/slang b/external/slang index febbeb1..4b8ceed 160000 --- a/external/slang +++ b/external/slang @@ -1 +1 @@ -Subproject commit febbeb140bea65180ff4be9b164207c582235d4d +Subproject commit 4b8ceed9d64f0878501189a40c1fd89f74c7f9ce diff --git a/res/shaders/LightCulling.slang b/res/shaders/LightCulling.slang index 82d19eb..225868c 100644 --- a/res/shaders/LightCulling.slang +++ b/res/shaders/LightCulling.slang @@ -5,7 +5,6 @@ import LightEnv; struct ComputeShaderInput { uint3 groupID : SV_GroupID; - uint3 groupThreadID : SV_GroupThreadID; uint3 dispatchThreadID : SV_DispatchThreadID; uint groupIndex : SV_GroupIndex; }; diff --git a/res/shaders/MeshletPass.slang b/res/shaders/MeshletPass.slang index f8d35eb..5826642 100644 --- a/res/shaders/MeshletPass.slang +++ b/res/shaders/MeshletPass.slang @@ -22,12 +22,12 @@ void meshMain( out indices uint3 indices[MAX_PRIMITIVES], out primitives PrimitiveAttributes prim[MAX_PRIMITIVES] ) { - uint instanceId = meshPayload.instanceId; // meshlet number relative to start for this instance uint meshletNumber = meshPayload.culledMeshlets[groupID]; - InstanceData inst = pScene.instances[instanceId]; + uint meshletId = meshPayload.cullingOffset + meshletNumber; + InstanceData inst = pScene.instances[meshPayload.instanceId]; MeshletDescription m = pScene.meshletInfos[meshPayload.meshletOffset + meshletNumber]; - MeshletCullingInfo cull = pScene.culledMeshlets[meshPayload.cullingOffset + meshletNumber]; + MeshletCullingInfo cull = pScene.culledMeshlets[meshletId]; SetMeshOutputCounts(m.vertexCount, m.primitiveCount); for(uint i = threadID; i < MAX_PRIMITIVES; i += MESH_GROUP_SIZE) @@ -40,7 +40,7 @@ void meshMain( indices[p] = uint3(local_idx0, local_idx1, local_idx2); prim[p].cull = cull.triangleCulled(p); #ifdef VISIBILITY - prim[p].prim = encodePrimitive(p, meshletNumber, instanceId); + prim[p].prim = encodePrimitive(p, meshletId); #endif } } diff --git a/res/shaders/VisibilityCompute.slang b/res/shaders/VisibilityCompute.slang new file mode 100644 index 0000000..21ae6dd --- /dev/null +++ b/res/shaders/VisibilityCompute.slang @@ -0,0 +1,42 @@ +import Common; +import Scene; + +struct VisibilityCullingData +{ + Texture2D visibilityTexture; + RWStructuredBuffer cullingInfos; +}; +ParameterBlock pVisibilityParams; + +groupshared MeshletCullingInfo cullInfo; + +[numthreads(BLOCK_SIZE, 1, 1)] +[shader("compute")] +void computeMain( + uint threadID: SV_GroupIndex, + uint groupID: SV_GroupID, +){ + 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]; + } +} \ No newline at end of file diff --git a/res/shaders/lib/Scene.slang b/res/shaders/lib/Scene.slang index 24ac04d..520db96 100644 --- a/res/shaders/lib/Scene.slang +++ b/res/shaders/lib/Scene.slang @@ -20,11 +20,11 @@ struct MeshData uint32_t numIndices; }; -static const uint64_t MAX_VERTICES = 256; -static const uint64_t MAX_PRIMITIVES = 256; -static const uint64_t TASK_GROUP_SIZE = 128; -static const uint64_t MESH_GROUP_SIZE = 32; -static const uint64_t MAX_MESHLETS_PER_INSTANCE = 2048; +static const uint32_t MAX_VERTICES = 256; +static const uint32_t MAX_PRIMITIVES = 256; +static const uint32_t TASK_GROUP_SIZE = 128; +static const uint32_t MESH_GROUP_SIZE = 32; +static const uint32_t MAX_MESHLETS_PER_INSTANCE = 2048; struct InstanceData { @@ -34,12 +34,12 @@ struct InstanceData struct MeshletCullingInfo { - uint64_t visible[MAX_PRIMITIVES / 64]; + uint32_t visible[MAX_PRIMITIVES / 32]; // lookup if a specific triangle is visible bool triangleVisible(uint32_t primIndex) { - uint32_t arrIdx = primIndex / 64; - uint32_t cullIdx = primIndex % 64; + uint32_t arrIdx = primIndex / 32; + uint32_t cullIdx = primIndex % 32; return (visible[arrIdx] & (1 << cullIdx)) != 0; } bool triangleCulled(uint32_t primIndex) @@ -72,19 +72,17 @@ struct Scene layout(set = 2) ParameterBlock pScene; -uint32_t encodePrimitive(uint32_t primitiveId, uint32_t meshletId, uint32_t instanceId) +uint32_t encodePrimitive(uint32_t primitiveId, uint32_t meshletId) { - return primitiveId + (meshletId * uint(MAX_PRIMITIVES)) + (instanceId * uint(MAX_MESHLETS_PER_INSTANCE * MAX_PRIMITIVES)); + return primitiveId + (meshletId * uint(MAX_PRIMITIVES)); } -uint3 decodePrimitive(uint64_t encoded) +uint2 decodePrimitive(uint32_t encoded) { uint prim = uint(encoded % MAX_PRIMITIVES); encoded = encoded / MAX_PRIMITIVES; - uint meshletId = uint(encoded % MAX_MESHLETS_PER_INSTANCE); - encoded = encoded / MAX_MESHLETS_PER_INSTANCE; - uint instanceId = uint(encoded); - return uint3(prim, meshletId, instanceId); + uint meshletId = uint(encoded); + return uint2(prim, meshletId); } struct MeshPayload diff --git a/src/Engine/Graphics/RenderPass/CMakeLists.txt b/src/Engine/Graphics/RenderPass/CMakeLists.txt index 78eef0e..d613008 100644 --- a/src/Engine/Graphics/RenderPass/CMakeLists.txt +++ b/src/Engine/Graphics/RenderPass/CMakeLists.txt @@ -20,7 +20,9 @@ target_sources(Engine TextPass.h TextPass.cpp UIPass.h - UIPass.cpp) + UIPass.cpp + VisibilityPass.h + VisibilityPass.cpp) target_sources(Engine PUBLIC FILE_SET HEADERS @@ -35,4 +37,5 @@ target_sources(Engine RenderPass.h SkyboxRenderPass.h TextPass.h - UIPass.h) \ No newline at end of file + UIPass.h + VisibilityPass.h) \ No newline at end of file diff --git a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp index 0a8886c..18508b2 100644 --- a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp +++ b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp @@ -40,7 +40,9 @@ void LightCullingPass::beginFrame(const Component::Camera& cam) .owner = Gfx::QueueType::COMPUTE } }; + oLightIndexCounter->rotateBuffer(sizeof(uint32)); oLightIndexCounter->updateContents(counterReset); + tLightIndexCounter->rotateBuffer(sizeof(uint32)); tLightIndexCounter->updateContents(counterReset); oLightIndexCounter->pipelineBarrier( Gfx::SE_ACCESS_MEMORY_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, diff --git a/src/Engine/Graphics/RenderPass/VisibilityPass.cpp b/src/Engine/Graphics/RenderPass/VisibilityPass.cpp new file mode 100644 index 0000000..6353059 --- /dev/null +++ b/src/Engine/Graphics/RenderPass/VisibilityPass.cpp @@ -0,0 +1,63 @@ +#include "VisibilityPass.h" + +using namespace Seele; + +VisibilityPass::VisibilityPass(Gfx::PGraphics graphics, PScene scene) + : RenderPass(graphics, scene) +{ +} + +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) +} + +void VisibilityPass::render() +{ + +} + +void VisibilityPass::endFrame() +{ + +} + +void VisibilityPass::publishOutputs() +{ + visibilityDescriptor = graphcis->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(); + + visibilityLayout = graphics->createPipelineLayout("VisibilityLayout"); + visibilityLayout->addDescriptorLayout(viewParamsLayout); + visibilityLayout->addDescriptorLayout(visibilityDescriptor); + + ShaderCreateInfo createInfo = { + .name = "Visibility", + .mainModule = "VisibilityCompute", + .entryPoint = "computeMain", + .rootSignature = visibilityLayout, + }; + visibilityShader = graphics->createComputeShader(createInfo); + visibilityLayout->create(); + + Gfx::ComputePipelineCreateInfo pipelineInfo; + pipelineInfo.computeShader = visibilityShader; + pipelineInfo.pipelineLayout = std::move(visibilityLayout); + visibilityPipeline = graphics->createComputePipeline(std::move(pipelineInfo)); +} + +void VisibilityPass::createRenderPass() +{ + visibilityAttachment = resources->requestRenderTarget("VISIBILITY"); +} diff --git a/src/Engine/Graphics/RenderPass/VisibilityPass.h b/src/Engine/Graphics/RenderPass/VisibilityPass.h new file mode 100644 index 0000000..5e4b620 --- /dev/null +++ b/src/Engine/Graphics/RenderPass/VisibilityPass.h @@ -0,0 +1,30 @@ +#pragma once +#include "RenderPass.h" + +namespace Seele +{ +class VisibilityPass : public RenderPass +{ +public: + VisibilityPass(Gfx::PGraphics graphics, PScene scene); + VisibilityPass(VisibilityPass&&) = default; + VisibilityPass& operator=(VisibilityPass&&) = default; + virtual ~VisibilityPass(); + virtual void beginFrame(const Component::Camera& cam) override; + virtual void render() override; + virtual void endFrame() override; + virtual void publishOutputs() override; + virtual void createRenderPass() override; + uint64 allocate +private: + Gfx::RenderTargetAttachment visibilityAttachment; + Gfx::PDescriptorSet visibilitySet; + Gfx::ODescriptorLayout visibilityDescriptor; + Gfx::OPipelineLayout visibilityLayout; + Gfx::PComputePipeline visibilityPipeline; + + // Holds culling information for every meshlet for each instance + Gfx::OShaderBuffer cullingBuffer; +}; +DEFINE_REF(VisibilityPass) +} \ No newline at end of file diff --git a/src/Engine/Graphics/VertexData.h b/src/Engine/Graphics/VertexData.h index 9c4fe38..c5415d4 100644 --- a/src/Engine/Graphics/VertexData.h +++ b/src/Engine/Graphics/VertexData.h @@ -117,8 +117,6 @@ namespace Seele Gfx::OShaderBuffer meshletBuffer; Gfx::OShaderBuffer vertexIndicesBuffer; Gfx::OShaderBuffer primitiveIndicesBuffer; - // Holds culling information for every meshlet for each instance - Gfx::OShaderBuffer cullingBuffer; Gfx::OShaderBuffer cullingOffsetBuffer; // for legacy pipeline Gfx::OIndexBuffer indexBuffer;