diff --git a/res/shaders/terrain/CBT.slang b/res/shaders/terrain/CBT.slang index c4e28dd..e1932ca 100644 --- a/res/shaders/terrain/CBT.slang +++ b/res/shaders/terrain/CBT.slang @@ -230,7 +230,6 @@ uint bit_count(uint depth, uint element) // decodes the position of the i-th one in the bitfield uint decode_bit(uint handle) { -#if defined(NAIVE_DECODE) uint bitID = 1; for (uint currentDepth = 0; currentDepth < WAVE_TREE_DEPTH; ++currentDepth) { @@ -242,65 +241,11 @@ uint decode_bit(uint handle) } return (bitID ^ OCBT_NUM_ELEMENTS); -#else - uint currentDepth = 0; - uint heapElementID = 1u; - for (currentDepth = 0; currentDepth < FIRST_VIRTUAL_LEVEL; ++currentDepth) - { - // Read the left element - uint heapValue = get_heap_element(2u * heapElementID); - - // Does it fall in the right or left subtree? - uint b = handle < heapValue ? 0u : 1u; - - // Pick a subtree - heapElementID = 2u * heapElementID + b; - - // Move the iterator to exclude the right subtree if required - handle -= heapValue * b; - } - - // Align with the internal depth - currentDepth++; - - // Ok we have our subtree, now we need to pick the right bit - uint64_t heapValue = pParams.bitFieldBuffer[heapElementID - OCBT_LAST_LEVEL_SIZE * 2]; - uint64_t mask = 0xffffffff; - uint32_t bitCount = 32; - for (; currentDepth < (WAVE_TREE_DEPTH + 1); ++currentDepth) - { - // Figure out the location of the first bit of this element - uint real_heap_id = 2 * heapElementID - 1; - uint level_first_element = (1u << currentDepth) - 1; - uint id_in_level = real_heap_id - level_first_element; - uint first_bit = bitCount * id_in_level; - uint local_id = first_bit % 64; - uint64_t target_bits = (heapValue >> local_id) & mask; - uint32_t high = uint(target_bits >> 32); - uint32_t low = uint(target_bits); - uint heapValue = countbits(high) + countbits(low); - - // Does it fall in the right or left subtree? - uint b = handle < heapValue ? 0u : 1u; - - // Pick a subtree - heapElementID = 2u * heapElementID + b; - - // Move the iterator to exclude the right subtree if required - handle -= heapValue * b; - - // Adjust the mask and bitcount - bitCount /= 2; - mask = mask >> bitCount; - } - return (heapElementID ^ OCBT_NUM_ELEMENTS); -#endif } // decodes the position of the i-th zero in the bitfield uint decode_bit_complement(uint handle) { -#if defined(NAIVE_DECODE) uint bitID = 1u; uint c = OCBT_NUM_ELEMENTS / 2u; @@ -314,54 +259,6 @@ uint decode_bit_complement(uint handle) } return (bitID ^ OCBT_NUM_ELEMENTS); -#else - uint heapElementID = 1u; - uint c = OCBT_NUM_ELEMENTS / 2u; - uint currentDepth = 0; - - for (currentDepth = 0; currentDepth < FIRST_VIRTUAL_LEVEL; ++currentDepth) - { - uint heapValue = c - get_heap_element(2u * heapElementID); - uint b = handle < heapValue ? 0u : 1u; - - heapElementID = 2u * heapElementID + b; - handle -= heapValue * b; - c /= 2u; - } - - // Align with the internal depth - currentDepth++; - - // Ok we have our subtree, now we need to pick the right bit - uint64_t heapValue = pParams.bitFieldBuffer[heapElementID - OCBT_LAST_LEVEL_SIZE * 2]; - uint64_t mask = 0xffffffff; - uint32_t bitCount = 32; - for (; currentDepth < (WAVE_TREE_DEPTH + 1); ++currentDepth) - { - // Figure out the location of the first bit of this element - uint real_heap_id = 2 * heapElementID - 1; - uint level_first_element = (1u << currentDepth) - 1; - uint id_in_level = real_heap_id - level_first_element; - uint first_bit = bitCount * id_in_level; - uint local_id = first_bit % 64; - uint64_t target_bits = (heapValue >> local_id) & mask; - uint32_t high = uint(target_bits >> 32); - uint32_t low = uint(target_bits); - uint heapValue = c - (countbits(high) + countbits(low)); - - uint b = handle < heapValue ? 0u : 1u; - - heapElementID = 2u * heapElementID + b; - handle -= heapValue * b; - c /= 2u; - - // Adjust the mask and bitcount - bitCount /= 2; - mask = mask >> bitCount; - } - - return (heapElementID ^ OCBT_NUM_ELEMENTS); -#endif } void reduce(uint groupIndex) @@ -578,11 +475,7 @@ void load_shared_memory_to_buffer(uint groupIndex) // Load the bitfield to the LDS for (uint e = 0; e < BUFFER_ELEMENT_PER_LANE; ++e) { -#ifdef AMD uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + e; -#else - uint target_element = groupIndex + WORKGROUP_SIZE * e; -#endif if (target_element < OCBT_TREE_NUM_SLOTS) pParams.cbtBuffer[target_element] = gs_cbtTree[target_element]; } diff --git a/res/shaders/terrain/CBTCompute.slang b/res/shaders/terrain/CBTCompute.slang index 756f424..e76da52 100644 --- a/res/shaders/terrain/CBTCompute.slang +++ b/res/shaders/terrain/CBTCompute.slang @@ -41,7 +41,7 @@ void Split(uint dispatchID : SV_DispatchThreadID) uint currentID = pParams.classificationBuffer[CLASSIFY_COUNTER_OFFSET + dispatchID]; // Split the element - SplitElement(currentID, pParams.geometry.baseDepth, dispatchID); + SplitElement(currentID, pParams.geometry.baseDepth); } [numthreads(1, 1, 1)] @@ -74,7 +74,7 @@ void Bisect(uint groupIndex : SV_GroupIndex, uint dispatchID : SV_DispatchThread return; // Operation the bisection of this element - BisectElement(pParams.allocateBuffer[1 + dispatchID]); + BisectElement(pParams.allocateBuffer[1 + dispatchID], dispatchID); } [numthreads(WORKGROUP_SIZE, 1, 1)] diff --git a/res/shaders/terrain/Parameters.slang b/res/shaders/terrain/Parameters.slang index b4bcbf8..2c13d9d 100644 --- a/res/shaders/terrain/Parameters.slang +++ b/res/shaders/terrain/Parameters.slang @@ -29,39 +29,64 @@ struct UpdateCB struct DebugStruct { - int maxRequiredMemory; - int usedMemory; - uint memoryChange; - uint twinID; + uint4 indices; + uint baseHeapID; + uint subdivision; + uint propagateLocation; + uint numSiblings; }; struct ComputeParams { + // 0 ConstantBuffer geometry; + // 1 ConstantBuffer update; + // 2 RWStructuredBuffer currentVertexBuffer; + // 3 StructuredBuffer indexedBisectorBuffer; + // 4 RWStructuredBuffer indirectDrawBuffer; + // 5 RWStructuredBuffer heapIDBuffer; + // 6 RWStructuredBuffer bisectorDataBuffer; + // 7 RWStructuredBuffer classificationBuffer; + // 8 RWStructuredBuffer allocateBuffer; + // 9 RWStructuredBuffer indirectDispatchBuffer; + // 10 RWStructuredBuffer neighboursBuffer; + // 11 RWStructuredBuffer neighboursOutputBuffer; + // 12 RWStructuredBuffer memoryBuffer; + // 13 RWStructuredBuffer cbtBuffer; + // 14 RWStructuredBuffer bitFieldBuffer; + // 15 RWStructuredBuffer propagateBuffer; + // 16 RWStructuredBuffer simplifyBuffer; + // 17 RWStructuredBuffer validationBuffer; + // 18 RWStructuredBuffer bisectorIndicesBuffer; + // 19 RWStructuredBuffer visibleBisectorIndices; + // 20 RWStructuredBuffer modifiedBisectorIndices; + // 21 RWStructuredBuffer lebPositionBuffer; + // 22 StructuredBuffer lebMatrixCache; + // 23 globallycoherent RWStructuredBuffer debugBuffer; }; ParameterBlock pParams; diff --git a/res/shaders/terrain/update_utils.slang b/res/shaders/terrain/update_utils.slang index b8e90d7..8751e95 100644 --- a/res/shaders/terrain/update_utils.slang +++ b/res/shaders/terrain/update_utils.slang @@ -46,7 +46,7 @@ int ClassifyBisector(in BisectorGeometry tri, uint depth) float3 triNormal = normalize(cross(tri.p[2] - tri.p[1], tri.p[0] - tri.p[1])); float3 triCenter = (tri.p[0] + tri.p[1] + tri.p[2]) / 3.0; float3 viewDir = normalize(-triCenter); - float FdotV = dot(viewDir, -pViewParams.cameraForward_WS.xyz); + float FdotV = dot(viewDir, pViewParams.cameraForward_WS.xyz); float VdotN = dot(viewDir, triNormal); // Here we don't use 0 as it introduces stability issues at grazing angles @@ -183,12 +183,8 @@ void ClassifyElement(uint currentID, BisectorGeometry bis, uint totalNumElements pParams.bisectorDataBuffer[currentID] = cbisectorData; } -void SplitElement(uint currentID, uint baseDepth, uint dispatchID) +void SplitElement(uint currentID, uint baseDepth) { - DebugStruct debug; - debug.maxRequiredMemory = 0; - debug.usedMemory = 0; - debug.memoryChange = 0; // Get the neighbors information uint4 cNeighbors = pParams.neighboursBuffer[currentID]; @@ -226,13 +222,10 @@ void SplitElement(uint currentID, uint baseDepth, uint dispatchID) else if (pParams.neighboursBuffer[twinID].z == currentID) maxRequiredMemory = 2; - debug.maxRequiredMemory = maxRequiredMemory; - debug.twinID = twinID; // Try to reserve int remainingMemory; InterlockedAdd(pParams.memoryBuffer[1], -maxRequiredMemory, remainingMemory); - debug.memoryChange = -maxRequiredMemory; // Did someone manage to sneak-in while we were trying to pick the memory, add it back and try again if (remainingMemory < maxRequiredMemory) { @@ -321,13 +314,8 @@ void SplitElement(uint currentID, uint baseDepth, uint dispatchID) } } } - int change = maxRequiredMemory - usedMemory; - // Add back the unused memory (in case) - InterlockedAdd(pParams.memoryBuffer[1], change, remainingMemory); - debug.memoryChange += change; - debug.usedMemory = usedMemory; - pParams.debugBuffer[dispatchID] = debug; + InterlockedAdd(pParams.memoryBuffer[1], maxRequiredMemory - usedMemory, remainingMemory); } void AllocateElement(uint currentID) @@ -415,11 +403,15 @@ void evaluate_neighbors(uint currentID, uint bisectorID, out uint resX, out uint } } -void BisectElement(uint currentID) +void BisectElement(uint currentID, uint dispatchID) { + DebugStruct debug; // If this bisector is not allocated or not subdivided, stop right away uint64_t baseHeapID = pParams.heapIDBuffer[currentID]; BisectorData cBisectorData = pParams.bisectorDataBuffer[currentID]; + debug.baseHeapID = baseHeapID; + debug.subdivision = cBisectorData.subdivisionPattern; + debug.propagateLocation = 0; if (baseHeapID == 0 || cBisectorData.subdivisionPattern == NO_SPLIT) return; @@ -437,6 +429,11 @@ void BisectElement(uint currentID) uint siblingID1 = cBisectorData.indices[1]; uint siblingID2 = cBisectorData.indices[2]; + debug.indices[0] = cBisectorData.indices[0]; + debug.indices[1] = cBisectorData.indices[1]; + debug.indices[2] = cBisectorData.indices[2]; + debug.indices[3] = 0; + // Simple subdivision (along the main axis) if (currentSubdiv == CENTER_SPLIT) { @@ -461,6 +458,11 @@ void BisectElement(uint currentID) // Keep track of the parent BisectorData modifiedBisector = cBisectorData; + modifiedBisector.indices[0] = cBisectorData.indices[0]; + modifiedBisector.indices[1] = cBisectorData.indices[1]; + modifiedBisector.indices[2] = cBisectorData.indices[2]; + modifiedBisector.subdivisionPattern = cBisectorData.subdivisionPattern; + modifiedBisector.bisectorState = cBisectorData.bisectorState; modifiedBisector.propagationID = currentID; modifiedBisector.problematicNeighbor = INVALID_POINTER; @@ -472,9 +474,10 @@ void BisectElement(uint currentID) pParams.bisectorDataBuffer[siblingID0] = modifiedBisector; // Mark this for propagation - uint targetLocation; + uint targetLocation = 0; InterlockedAdd(pParams.propagateBuffer[0], 1, targetLocation); pParams.propagateBuffer[2 + targetLocation] = siblingID0; + debug.propagateLocation = targetLocation; } else if (currentSubdiv == RIGHT_DOUBLE_SPLIT) { @@ -507,6 +510,11 @@ void BisectElement(uint currentID) // Keep track of the parent BisectorData modifiedBisector = cBisectorData; + modifiedBisector.indices[0] = cBisectorData.indices[0]; + modifiedBisector.indices[1] = cBisectorData.indices[1]; + modifiedBisector.indices[2] = cBisectorData.indices[2]; + modifiedBisector.subdivisionPattern = cBisectorData.subdivisionPattern; + modifiedBisector.bisectorState = cBisectorData.bisectorState; modifiedBisector.propagationID = currentID; // Lower the element down the tree and update it's sibling @@ -525,9 +533,10 @@ void BisectElement(uint currentID) pParams.bisectorDataBuffer[siblingID1] = modifiedBisector; // Mark this for propagation - uint targetLocation; + uint targetLocation = 0; InterlockedAdd(pParams.propagateBuffer[0], 1, targetLocation); pParams.propagateBuffer[2 + targetLocation] = siblingID0; + debug.propagateLocation = targetLocation; } else if (currentSubdiv == LEFT_DOUBLE_SPLIT) { @@ -560,6 +569,11 @@ void BisectElement(uint currentID) // Keep track of the parent BisectorData modifiedBisector = cBisectorData; + modifiedBisector.indices[0] = cBisectorData.indices[0]; + modifiedBisector.indices[1] = cBisectorData.indices[1]; + modifiedBisector.indices[2] = cBisectorData.indices[2]; + modifiedBisector.subdivisionPattern = cBisectorData.subdivisionPattern; + modifiedBisector.bisectorState = cBisectorData.bisectorState; modifiedBisector.propagationID = currentID; // Lower the element down the tree and update it's sibling @@ -616,6 +630,11 @@ void BisectElement(uint currentID) // Keep track of the parent BisectorData modifiedBisector = cBisectorData; + modifiedBisector.indices[0] = cBisectorData.indices[0]; + modifiedBisector.indices[1] = cBisectorData.indices[1]; + modifiedBisector.indices[2] = cBisectorData.indices[2]; + modifiedBisector.subdivisionPattern = cBisectorData.subdivisionPattern; + modifiedBisector.bisectorState = cBisectorData.bisectorState; modifiedBisector.propagationID = currentID; // Lower the element down the tree and update it's sibling @@ -641,6 +660,8 @@ void BisectElement(uint currentID) // How many bits do we need to raise uint numSiblings = countbits(currentSubdiv); + debug.numSiblings = numSiblings; + pParams.debugBuffer[dispatchID] = debug; for (uint siblingIdx = 0; siblingIdx < numSiblings; ++siblingIdx) { set_bit_atomic_buffer(cBisectorData.indices[siblingIdx], true); diff --git a/src/Engine/Component/Camera.cpp b/src/Engine/Component/Camera.cpp index 6c1940b..f544071 100644 --- a/src/Engine/Component/Camera.cpp +++ b/src/Engine/Component/Camera.cpp @@ -48,6 +48,6 @@ void Camera::buildViewMatrix() { Vector lookAt = eyePos + getTransform().getForward(); viewMatrix = glm::lookAt(eyePos, lookAt, Vector(0, 1, 0)); cameraPos = eyePos; - cameraForward = getTransform().getForward(); + cameraForward = -getTransform().getForward(); bNeedsViewBuild = false; } diff --git a/src/Engine/Graphics/CBT/CBT.cpp b/src/Engine/Graphics/CBT/CBT.cpp index 8d5d265..f4b5f25 100644 --- a/src/Engine/Graphics/CBT/CBT.cpp +++ b/src/Engine/Graphics/CBT/CBT.cpp @@ -503,7 +503,6 @@ void MeshUpdater::update(CBTMesh& mesh, Gfx::PDescriptorSet viewParamsSet, Gfx:: set->updateBuffer(NEIGHBOURS_BUFFER, 0, currentNeighborsBuffer); set->updateBuffer(MEMORY_BUFFER, 0, memoryBuffer); set->updateBuffer(ALLOCATE_BUFFER, 0, mesh.allocateBuffer); - set->updateBuffer(DEBUG_BUFFER, 0, debugBuffer); set->writeChanges(); Gfx::OComputeCommand splitCmd = graphics->createComputeCommand("Split"); splitCmd->bindPipeline(split); @@ -581,6 +580,7 @@ void MeshUpdater::update(CBTMesh& mesh, Gfx::PDescriptorSet viewParamsSet, Gfx:: set->updateBuffer(NEIGHBOURS_BUFFER, 0, currentNeighborsBuffer); set->updateBuffer(NEIGHBOURS_OUTPUT_BUFFER, 0, nextNeighborsBuffer); set->updateBuffer(PROPAGATE_BUFFER, 0, mesh.propagateBuffer); + set->updateBuffer(DEBUG_BUFFER, 0, debugBuffer); set->writeChanges(); Gfx::OComputeCommand bisectCmd = graphics->createComputeCommand("Bisect"); bisectCmd->bindPipeline(bisect); diff --git a/src/Engine/Graphics/Graphics.h b/src/Engine/Graphics/Graphics.h index 2117048..6769a04 100644 --- a/src/Engine/Graphics/Graphics.h +++ b/src/Engine/Graphics/Graphics.h @@ -88,6 +88,8 @@ class Graphics { virtual PComputePipeline createComputePipeline(ComputePipelineCreateInfo createInfo) = 0; virtual OSampler createSampler(const SamplerCreateInfo& createInfo) = 0; + virtual OComputeShader createComputeShaderFromBinary(std::string_view binaryName) = 0; + virtual ODescriptorLayout createDescriptorLayout(const std::string& name = "") = 0; virtual OPipelineLayout createPipelineLayout(const std::string& name = "", PPipelineLayout baseLayout = nullptr) = 0; diff --git a/src/Engine/Graphics/Vulkan/Graphics.cpp b/src/Engine/Graphics/Vulkan/Graphics.cpp index eb20260..c8849a4 100644 --- a/src/Engine/Graphics/Vulkan/Graphics.cpp +++ b/src/Engine/Graphics/Vulkan/Graphics.cpp @@ -284,6 +284,12 @@ Gfx::OSampler Graphics::createSampler(const SamplerCreateInfo& createInfo) { return new Sampler(this, vkInfo); } +Gfx::OComputeShader Graphics::createComputeShaderFromBinary(std::string_view binaryName) { + OComputeShader shader = new ComputeShader(this); + shader->create(binaryName); + return shader; +} + Gfx::ODescriptorLayout Graphics::createDescriptorLayout(const std::string& name) { return new DescriptorLayout(this, name); } Gfx::OPipelineLayout Graphics::createPipelineLayout(const std::string& name, Gfx::PPipelineLayout baseLayout) { diff --git a/src/Engine/Graphics/Vulkan/Graphics.h b/src/Engine/Graphics/Vulkan/Graphics.h index ebff45c..fc27c83 100644 --- a/src/Engine/Graphics/Vulkan/Graphics.h +++ b/src/Engine/Graphics/Vulkan/Graphics.h @@ -66,6 +66,8 @@ class Graphics : public Gfx::Graphics { virtual Gfx::PRayTracingPipeline createRayTracingPipeline(Gfx::RayTracingPipelineCreateInfo createInfo) override; virtual Gfx::PComputePipeline createComputePipeline(Gfx::ComputePipelineCreateInfo createInfo) override; virtual Gfx::OSampler createSampler(const SamplerCreateInfo& createInfo) override; + + virtual Gfx::OComputeShader createComputeShaderFromBinary(std::string_view binaryName) override; virtual Gfx::ODescriptorLayout createDescriptorLayout(const std::string& name = "") override; virtual Gfx::OPipelineLayout createPipelineLayout(const std::string& name = "", Gfx::PPipelineLayout baseLayout = nullptr) override; diff --git a/src/Engine/Graphics/Vulkan/Shader.cpp b/src/Engine/Graphics/Vulkan/Shader.cpp index 91213cd..af35c7c 100644 --- a/src/Engine/Graphics/Vulkan/Shader.cpp +++ b/src/Engine/Graphics/Vulkan/Shader.cpp @@ -4,6 +4,7 @@ #include "slang-com-ptr.h" #include "slang.h" #include "stdlib.h" +#include #include using namespace Seele; @@ -32,4 +33,20 @@ void Shader::create(const ShaderCreateInfo& createInfo) { VK_CHECK(vkCreateShaderModule(graphics->getDevice(), &moduleInfo, nullptr, &module)); hash = CRC::Calculate(kernelBlob->getBufferPointer(), kernelBlob->getBufferSize(), CRC::CRC_32(), hash); -} \ No newline at end of file +} + +void Shader::create(std::string_view binary) { + std::ifstream stream(binary.data(), std::ios::binary | std::ios::ate); + uint64 fullSize = stream.tellg(); + stream.seekg(0, std::ios::beg); + Array buffer(fullSize); + stream.read((char*)buffer.data(), fullSize); + VkShaderModuleCreateInfo moduleInfo = { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .codeSize = buffer.size() / sizeof(uint32), + .pCode = (uint32*)buffer.data(), + }; + VK_CHECK(vkCreateShaderModule(graphics->getDevice(), &moduleInfo, nullptr, &module)); +} diff --git a/src/Engine/Graphics/Vulkan/Shader.h b/src/Engine/Graphics/Vulkan/Shader.h index 2b2cc3c..da6950e 100644 --- a/src/Engine/Graphics/Vulkan/Shader.h +++ b/src/Engine/Graphics/Vulkan/Shader.h @@ -14,6 +14,7 @@ class Shader { virtual ~Shader(); void create(const ShaderCreateInfo& createInfo); + void create(std::string_view binary); constexpr VkShaderModule getModuleHandle() const { return module; } constexpr const char* getEntryPointName() const {