Fixing Depth culling out of bounds errors

This commit is contained in:
Dynamitos
2024-08-29 11:23:55 +02:00
parent 6eb114e892
commit 0be1a3cbde
9 changed files with 136 additions and 44 deletions
+19
View File
@@ -0,0 +1,19 @@
struct DepthDebugData
{
uint mipLevel;
uint mipOffset;
int2 mipDimensions;
int2 screenCornerMin;
int2 screenCornerMax;
int2 origScreenMin;
int2 origScreenMax;
};
struct DepthData
{
//uint bufferLength;
Texture2D<float> texture;
RWStructuredBuffer<float> buffer;
//globallycoherent RWStructuredBuffer<uint> debugHead;
//globallycoherent RWStructuredBuffer<DepthDebugData> debugData;
};
+36 -17
View File
@@ -1,6 +1,7 @@
import Common; import Common;
import Scene; import Scene;
import Bounding; import Bounding;
import DepthCommon;
groupshared MeshPayload p; groupshared MeshPayload p;
groupshared uint head; groupshared uint head;
@@ -10,37 +11,55 @@ groupshared Frustum viewFrustum;
groupshared float4x4 modelViewProjection; groupshared float4x4 modelViewProjection;
groupshared bool meshVisible; groupshared bool meshVisible;
struct DepthData //void writeDebug(uint mipLevel, uint mipOffset, int2 mipDimensions, int2 screenMin, int2 screenMax, int2 origScreenMin, int2 origScreenMax)
{ //{
Texture2D<float> texture; // uint index = 0;
RWStructuredBuffer<float> buffer; // InterlockedAdd(pDepthAttachment.debugHead[0], 1, index);
} // index = min(index, 10000);
// {
// pDepthAttachment.debugData[index].mipLevel = mipLevel;
// pDepthAttachment.debugData[index].mipOffset = mipOffset;
// pDepthAttachment.debugData[index].mipDimensions = mipDimensions;
// pDepthAttachment.debugData[index].screenCornerMax = screenMax;
// pDepthAttachment.debugData[index].screenCornerMin = screenMin;
// pDepthAttachment.debugData[index].origScreenMax = origScreenMax;
// pDepthAttachment.debugData[index].origScreenMin = origScreenMin;
// }
//}
ParameterBlock<DepthData> pDepthAttachment; ParameterBlock<DepthData> pDepthAttachment;
bool isBoxVisible(AABB bounding) bool isBoxVisible(AABB bounding)
{ {
uint2 mipDimensions = uint2(uint(pViewParams.screenDimensions.x), uint(pViewParams.screenDimensions.y)); int2 mipDimensions = uint2(uint(pViewParams.screenDimensions.x), uint(pViewParams.screenDimensions.y));
// now we calculate what mip level we need to only sample up to 4 texels covering the entire meshlet // now we calculate what mip level we need to only sample up to 4 texels covering the entire meshlet
uint2 screenCornerMin = mipDimensions; int2 screenCornerMin = mipDimensions;
uint2 screenCornerMax = uint2(0, 0); int2 screenCornerMax = uint2(0, 0);
// lower values are closer // lower values are closer
float maxDepth = bounding.projectScreenDepth(modelViewProjection, screenCornerMin, screenCornerMax); float maxDepth = bounding.projectScreenDepth(modelViewProjection, screenCornerMin, screenCornerMax);
uint mipOffset = 0; uint mipOffset = 0;
// uint mipLevel = 0;
// int2 origScreenMin = screenCornerMin;
// int2 origScreenMax = screenCornerMax;
// in theory this wouldnt work if no corner was in screen, as min would be greater that max, however we verified that with view culling // in theory this wouldnt work if no corner was in screen, as min would be greater that max, however we verified that with view culling
while(screenCornerMax.x - screenCornerMin.x > 1 || screenCornerMax.y - screenCornerMin.y > 1) while(screenCornerMax.x - screenCornerMin.x > 1 || screenCornerMax.y - screenCornerMin.y > 1)
{ {
// mipLevel++;
mipOffset += mipDimensions.x * mipDimensions.y; mipOffset += mipDimensions.x * mipDimensions.y;
mipDimensions = uint2(mipDimensions.x + 1, mipDimensions.y + 1) / 2; mipDimensions = int2(mipDimensions.x + 1, mipDimensions.y + 1) / 2;
screenCornerMin = uint2(screenCornerMin.x + 1, screenCornerMin.y + 1) / 2; screenCornerMin = int2(screenCornerMin.x + 1, screenCornerMin.y + 1) / 2;
screenCornerMax = uint2(screenCornerMax.x, screenCornerMax.y) / 2; screenCornerMax = int2(screenCornerMax.x, screenCornerMax.y) / 2;
} }
uint i0 = mipOffset + (screenCornerMin.y * mipDimensions.x) + screenCornerMin.x;
uint i1 = mipOffset + (screenCornerMin.y * mipDimensions.x) + screenCornerMax.x;
uint i2 = mipOffset + (screenCornerMax.y * mipDimensions.x) + screenCornerMin.x;
uint i3 = mipOffset + (screenCornerMax.y * mipDimensions.x) + screenCornerMax.x;
// now we sample 4 texels from the depth at the calculated mip level, this should give us the screen extent of the meshlet // now we sample 4 texels from the depth at the calculated mip level, this should give us the screen extent of the meshlet
float d1 = pDepthAttachment.buffer[mipOffset + (screenCornerMin.y * mipDimensions.x) + screenCornerMin.x]; float d1 = pDepthAttachment.buffer[i0];
float d2 = pDepthAttachment.buffer[mipOffset + (screenCornerMin.y * mipDimensions.x) + screenCornerMax.x]; float d2 = pDepthAttachment.buffer[i1];
float d3 = pDepthAttachment.buffer[mipOffset + (screenCornerMax.y * mipDimensions.x) + screenCornerMin.x]; float d3 = pDepthAttachment.buffer[i2];
float d4 = pDepthAttachment.buffer[mipOffset + (screenCornerMax.y * mipDimensions.x) + screenCornerMax.x]; float d4 = pDepthAttachment.buffer[i3];
// we want to check if the minimum depth (the value farthest away) is smaller than the maximum bounding box depth // we want to check if the minimum depth (the value farthest away) is smaller than the maximum bounding box depth
// otherwise, there is no way for the meshlet to be visible // otherwise, there is no way for the meshlet to be visible
@@ -102,7 +121,7 @@ void taskMain(
{ {
#ifdef DEPTH_CULLING #ifdef DEPTH_CULLING
// if the meshlet bounding box is behind the cached depth buffer, we skip // if the meshlet bounding box is behind the cached depth buffer, we skip
//if(isBoxVisible(meshlet.bounding)) if(isBoxVisible(meshlet.bounding))
#endif #endif
{ {
uint index; uint index;
+1 -5
View File
@@ -1,10 +1,6 @@
import Common; import Common;
import DepthCommon;
struct DepthData
{
Texture2D<float> texture;
RWStructuredBuffer<float> buffer;
}
ParameterBlock<DepthData> pDepthAttachment; ParameterBlock<DepthData> pDepthAttachment;
struct MipParam struct MipParam
+4 -3
View File
@@ -51,7 +51,7 @@ struct AABB
} }
return result; return result;
} }
float projectScreenDepth(float4x4 mvp, inout uint2 screenCornerMin, inout uint2 screenCornerMax) float projectScreenDepth(float4x4 mvp, inout int2 screenCornerMin, inout int2 screenCornerMax)
{ {
float maxDepth = 0; float maxDepth = 0;
float4 corners[8]; float4 corners[8];
@@ -67,8 +67,9 @@ struct AABB
{ {
float4 clipCorner = mul(mvp, corners[i]); float4 clipCorner = mul(mvp, corners[i]);
float4 screenCorner = clipToScreen(clipCorner); float4 screenCorner = clipToScreen(clipCorner);
screenCornerMin = uint2(min(screenCornerMin.x, uint(screenCorner.x)), min(screenCornerMin.y, uint(screenCorner.y))); int2 screenCoords = int2(clamp(int(screenCorner.x), 0, int(pViewParams.screenDimensions.x)), clamp(int(screenCorner.y), 0, int(pViewParams.screenDimensions.y)));
screenCornerMax = uint2(max(screenCornerMax.x, uint(screenCorner.x)), max(screenCornerMax.y, uint(screenCorner.y))); screenCornerMin = int2(min(screenCornerMin.x, screenCoords.x), min(screenCornerMin.y, screenCoords.y));
screenCornerMax = int2(max(screenCornerMax.x, screenCoords.x), max(screenCornerMax.y, screenCoords.y));
maxDepth = max(maxDepth, screenCorner.z); maxDepth = max(maxDepth, screenCorner.z);
} }
return maxDepth; return maxDepth;
+1 -1
View File
@@ -472,7 +472,7 @@ void BasePass::createRenderPass() {
oLightGrid = resources->requestTexture("LIGHTCULLING_OLIGHTGRID"); oLightGrid = resources->requestTexture("LIGHTCULLING_OLIGHTGRID");
tLightGrid = resources->requestTexture("LIGHTCULLING_TLIGHTGRID"); tLightGrid = resources->requestTexture("LIGHTCULLING_TLIGHTGRID");
waterRenderer->setViewport(viewport, renderPass); //waterRenderer->setViewport(viewport, renderPass);
// Debug rendering // Debug rendering
{ {
@@ -6,6 +6,10 @@ using namespace Seele;
DepthCullingPass::DepthCullingPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics, scene) { DepthCullingPass::DepthCullingPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics, scene) {
depthAttachmentLayout = graphics->createDescriptorLayout("pDepthAttachment"); depthAttachmentLayout = graphics->createDescriptorLayout("pDepthAttachment");
//depthAttachmentLayout->addDescriptorBinding(Gfx::DescriptorBinding{
// .binding = 0,
// .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
//});
depthAttachmentLayout->addDescriptorBinding(Gfx::DescriptorBinding{ depthAttachmentLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 0, .binding = 0,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
@@ -16,6 +20,16 @@ DepthCullingPass::DepthCullingPass(Gfx::PGraphics graphics, PScene scene) : Rend
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.shaderStages = Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_COMPUTE_BIT, .shaderStages = Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_COMPUTE_BIT,
}); });
//depthAttachmentLayout->addDescriptorBinding(Gfx::DescriptorBinding{
// .binding = 3,
// .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
// .shaderStages = Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_COMPUTE_BIT,
//});
//depthAttachmentLayout->addDescriptorBinding(Gfx::DescriptorBinding{
// .binding = 4,
// .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
// .shaderStages = Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_COMPUTE_BIT,
//});
depthAttachmentLayout->create(); depthAttachmentLayout->create();
depthCullingLayout = graphics->createPipelineLayout("DepthPrepassLayout"); depthCullingLayout = graphics->createPipelineLayout("DepthPrepassLayout");
@@ -73,9 +87,15 @@ void DepthCullingPass::render() {
Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT,
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT); Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
//uint32 reset = 0;
//debugHead->updateContents(0, sizeof(uint32), &reset);
Gfx::PDescriptorSet set = depthAttachmentLayout->allocateDescriptorSet(); Gfx::PDescriptorSet set = depthAttachmentLayout->allocateDescriptorSet();
//set->updateBuffer(0, debugUniform);
set->updateTexture(0, Gfx::PTexture2D(depthAttachment.getTexture())); set->updateTexture(0, Gfx::PTexture2D(depthAttachment.getTexture()));
set->updateBuffer(1, depthMipBuffer); set->updateBuffer(1, depthMipBuffer);
//set->updateBuffer(3, debugHead);
//set->updateBuffer(4, debugData);
set->writeChanges(); set->writeChanges();
timestamps->begin(); timestamps->begin();
@@ -221,7 +241,33 @@ void DepthCullingPass::publishOutputs() {
width = std::max((width + 1) / 2, 1u); width = std::max((width + 1) / 2, 1u);
height = std::max((height + 1) / 2, 1u); height = std::max((height + 1) / 2, 1u);
} }
ShaderBufferCreateInfo depthMipInfo = {
//debugUniform = graphics->createUniformBuffer(UniformBufferCreateInfo{
// .sourceData =
// {
// .size = sizeof(uint32),
// .data = (uint8*)&bufferSize,
// },
//});
//uint32 reset = 0;
//debugHead = graphics->createShaderBuffer(ShaderBufferCreateInfo{
// .sourceData =
// {
// .size = sizeof(uint32),
// .data = (uint8*)&reset,
// },
//
//});
//debugData = graphics->createShaderBuffer(ShaderBufferCreateInfo{
// .sourceData =
// {
// .size = sizeof(DepthDebugData) * 10000,
// .data = nullptr,
// },
//});
//graphics->waitDeviceIdle();
depthMipBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData = .sourceData =
{ {
.size = bufferSize * sizeof(uint32), .size = bufferSize * sizeof(uint32),
@@ -229,17 +275,14 @@ void DepthCullingPass::publishOutputs() {
}, },
.numElements = bufferSize, .numElements = bufferSize,
.name = "DepthMipBuffer", .name = "DepthMipBuffer",
}; });
depthMipBuffer = graphics->createShaderBuffer(depthMipInfo);
ShaderCompilationInfo mipComputeInfo = { graphics->beginShaderCompilation(ShaderCompilationInfo{
.name = "DepthMipCompute", .name = "DepthMipCompute",
.modules = {"DepthMipGen"}, .modules = {"DepthMipGen"},
.entryPoints = {{"initialReduce", "DepthMipGen"}, {"reduceLevel", "DepthMipGen"}}, .entryPoints = {{"initialReduce", "DepthMipGen"}, {"reduceLevel", "DepthMipGen"}},
.rootSignature = depthComputeLayout, .rootSignature = depthComputeLayout,
}; });
graphics->beginShaderCompilation(mipComputeInfo);
depthInitialReduceShader = graphics->createComputeShader({0}); depthInitialReduceShader = graphics->createComputeShader({0});
depthComputeLayout->create(); depthComputeLayout->create();
@@ -25,6 +25,15 @@ class DepthCullingPass : public RenderPass {
UVector2 srcMipDim; UVector2 srcMipDim;
UVector2 dstMipDim; UVector2 dstMipDim;
}; };
struct DepthDebugData {
uint32 mipLevel;
uint32 mipOffset;
UVector2 mipDimensions;
UVector2 screenCornerMin;
UVector2 screenCornerMax;
};
Array<uint32> mipOffsets; Array<uint32> mipOffsets;
Array<UVector2> mipDims; Array<UVector2> mipDims;
Gfx::OShaderBuffer depthMipBuffer; Gfx::OShaderBuffer depthMipBuffer;
@@ -41,6 +50,10 @@ class DepthCullingPass : public RenderPass {
Gfx::OComputeShader depthMipGenShader; Gfx::OComputeShader depthMipGenShader;
Gfx::PComputePipeline depthMipGen; Gfx::PComputePipeline depthMipGen;
//Gfx::OUniformBuffer debugUniform;
//Gfx::OShaderBuffer debugHead;
//Gfx::OShaderBuffer debugData;
Gfx::PShaderBuffer cullingBuffer; Gfx::PShaderBuffer cullingBuffer;
}; };
DEFINE_REF(DepthCullingPass) DEFINE_REF(DepthCullingPass)
+1
View File
@@ -774,6 +774,7 @@ void Graphics::pickPhysicalDevice() {
.pNext = &features11, .pNext = &features11,
.features = .features =
{ {
//.robustBufferAccess = true,
.geometryShader = true, .geometryShader = true,
.fillModeNonSolid = true, .fillModeNonSolid = true,
.wideLines = true, .wideLines = true,
+11 -11
View File
@@ -37,25 +37,25 @@ void Material::init(Gfx::PGraphics graphics) {
layout = graphics->createDescriptorLayout("pMaterial"); layout = graphics->createDescriptorLayout("pMaterial");
layout->addDescriptorBinding(Gfx::DescriptorBinding{ layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 0, .binding = 0,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.bindingFlags = Gfx::SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT,
.shaderStages = Gfx::SE_SHADER_STAGE_FRAGMENT_BIT | Gfx::SE_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
});
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 1,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 512, .descriptorCount = 512,
.bindingFlags = Gfx::SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, .bindingFlags = Gfx::SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT,
.shaderStages = Gfx::SE_SHADER_STAGE_FRAGMENT_BIT | Gfx::SE_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, .shaderStages = Gfx::SE_SHADER_STAGE_FRAGMENT_BIT | Gfx::SE_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
}); });
layout->addDescriptorBinding(Gfx::DescriptorBinding{ layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 1, .binding = 2,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER,
.descriptorCount = 512, .descriptorCount = 512,
.bindingFlags = Gfx::SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, .bindingFlags = Gfx::SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT,
.shaderStages = Gfx::SE_SHADER_STAGE_FRAGMENT_BIT | Gfx::SE_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, .shaderStages = Gfx::SE_SHADER_STAGE_FRAGMENT_BIT | Gfx::SE_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
}); });
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 2,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.bindingFlags = Gfx::SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT,
.shaderStages = Gfx::SE_SHADER_STAGE_FRAGMENT_BIT | Gfx::SE_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
});
layout->create(); layout->create();
floatBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ floatBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.dynamic = true, .dynamic = true,
@@ -76,17 +76,17 @@ void Material::updateDescriptor() {
Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
layout->reset(); layout->reset();
set = layout->allocateDescriptorSet(); set = layout->allocateDescriptorSet();
set->updateBuffer(0, floatBuffer);
for (uint32 i = 0; i < textures.size(); ++i) { for (uint32 i = 0; i < textures.size(); ++i) {
if (textures[i] != nullptr) { if (textures[i] != nullptr) {
set->updateTexture(0, i, textures[i]); set->updateTexture(1, i, textures[i]);
} }
} }
for (uint32 i = 0; i < samplers.size(); ++i) { for (uint32 i = 0; i < samplers.size(); ++i) {
if (samplers[i] != nullptr) { if (samplers[i] != nullptr) {
set->updateSampler(1, i, samplers[i]); set->updateSampler(2, i, samplers[i]);
} }
} }
set->updateBuffer(2, floatBuffer);
set->writeChanges(); set->writeChanges();
} }