From 0320764b148dc73d6c5143323cf1bdde048d983f Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 6 Nov 2023 19:33:31 -0800 Subject: [PATCH 1/4] bugfix: remove parllax from pre/post z pass Signed-off-by: Michael Pollind --- HPL2/include/graphics/RendererDeferred.h | 1 + HPL2/resource/ShaderList.fsl | 12 ++++- HPL2/resource/pbr.h.fsl | 17 +++++++ HPL2/resource/solid_diffuse.frag.fsl | 32 +++++++++++- HPL2/resource/solid_z.frag.fsl | 57 ---------------------- HPL2/resource/solid_z.vert.fsl | 28 +++++------ HPL2/resource/solid_z_cut.vert.fsl | 30 ++++++++++++ HPL2/resource/solid_z_shadow.frag.fsl | 56 +++++++++++++++++++++ HPL2/resource/solid_z_shadow.vert.fsl | 28 +++++++++++ HPL2/sources/graphics/RendererDeferred.cpp | 55 ++++++++++++--------- 10 files changed, 220 insertions(+), 96 deletions(-) create mode 100644 HPL2/resource/pbr.h.fsl create mode 100644 HPL2/resource/solid_z_cut.vert.fsl create mode 100644 HPL2/resource/solid_z_shadow.frag.fsl create mode 100644 HPL2/resource/solid_z_shadow.vert.fsl diff --git a/HPL2/include/graphics/RendererDeferred.h b/HPL2/include/graphics/RendererDeferred.h index 352138452..6d11c4d1c 100644 --- a/HPL2/include/graphics/RendererDeferred.h +++ b/HPL2/include/graphics/RendererDeferred.h @@ -597,6 +597,7 @@ namespace hpl { std::array, ForgeRenderer::SwapChainLength> m_lightResources{}; // z pass SharedShader m_zPassShader; + SharedShader m_zPassShadowShader; SharedPipeline m_zPassPipelineCCW; SharedPipeline m_zPassPipelineCW; diff --git a/HPL2/resource/ShaderList.fsl b/HPL2/resource/ShaderList.fsl index c7c365a84..f8a077aa7 100644 --- a/HPL2/resource/ShaderList.fsl +++ b/HPL2/resource/ShaderList.fsl @@ -1,11 +1,19 @@ /// Copyright © 2009-2020 Frictional Games /// Copyright 2023 Michael Pollind /// SPDX-License-Identifier: GPL-3.0 - -#vert solid_z.vert +#vert solid_z_shadow.vert #include "solid_z.vert.fsl" #end +#frag solid_z_shadow.frag + #define ALPHA_REJECT 0.5 + #include "solid_z_shadow.frag.fsl" +#end + +#vert solid_z_shadow.vert + #include "solid_z_shadow.vert.fsl" +#end + #frag solid_z.frag #define SEARCH_SAMPLE_COUNT 4 #define PARALLAX_ENABLED 1 diff --git a/HPL2/resource/pbr.h.fsl b/HPL2/resource/pbr.h.fsl new file mode 100644 index 000000000..7e7b5e658 --- /dev/null +++ b/HPL2/resource/pbr.h.fsl @@ -0,0 +1,17 @@ +// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf +// +float3 F_Schlick (float3 f0 , float f90 , float u ){ + return f0 + ( f90 - f0 ) * pow (1. f - u , 5. f ) ; +} + +float Fr_DisneyDiffuse(float NdotV ,float NdotL ,float LdotH ,float linearRoughness) +{ + float energyBias = lerp (0 , 0.5 , linearRoughness ) ; + float energyFactor = lerp (1.0 , 1.0 / 1.51 , linearRoughness ) ; + float fd90 = energyBias + 2.0 * LdotH * LdotH * linearRoughness ; + float3 f0 = float3 (1.0 f , 1.0 f , 1.0 f ) ; + float lightScatter = F_Schlick ( f0 , fd90 , NdotL ) * r ; + float viewScatter = F_Schlick ( f0 , fd90 , NdotV ) * r ; + + return lightScatter * viewScatter * energyFactor ; +} diff --git a/HPL2/resource/solid_diffuse.frag.fsl b/HPL2/resource/solid_diffuse.frag.fsl index b54a34054..416cf026d 100644 --- a/HPL2/resource/solid_diffuse.frag.fsl +++ b/HPL2/resource/solid_diffuse.frag.fsl @@ -43,8 +43,38 @@ PsOut PS_MAIN(PsIn In) } #endif + float diffuseAlpha; + if(HasAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + if(IsAlphaSingleChannel(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).r; + } else { + diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).a; + } + } else { + diffuseAlpha = 1.0; + } + + const float dissolveAmount = Get(uniformObjectBuffer)[Get(objectId)].dissolveAmount; + + if(dissolveAmount < 1.0 || HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig) || HasDissolveFilter(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + float2 vDissolveCoords = In.Position.xy * (1.0/128.0); //128 = size of dissolve texture. + float fDissolve = SampleTex2D(dissolveMap, Get(dissolveSampler), vDissolveCoords).x; + + if(HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + //Get in 0.75 - 1 range + fDissolve = fDissolve*0.25 + 0.75; + + float fDissolveAlpha = SampleTex2D(Get(dissolveAlphaMap), Get(materialSampler), texCoord.xy).r; + fDissolve -= (0.25 - fDissolveAlpha * 0.25); + } else { + //Get in 0.5 - 1 range. + fDissolve = fDissolve*0.5 + 0.5; + } + diffuseAlpha = fDissolve - (1.0 - (dissolveAmount * diffuseAlpha)) * 0.5; + } + float4 diffuseColor = SampleTex2D(Get(diffuseMap), Get(materialSampler), texCoord.xy); - if(diffuseColor.w < ALPHA_REJECT ) { + if(diffuseColor.w < ALPHA_REJECT || diffuseAlpha < ALPHA_REJECT) { discard; } diff --git a/HPL2/resource/solid_z.frag.fsl b/HPL2/resource/solid_z.frag.fsl index 8dd45d547..ca6b482b2 100644 --- a/HPL2/resource/solid_z.frag.fsl +++ b/HPL2/resource/solid_z.frag.fsl @@ -8,67 +8,10 @@ STRUCT(PsIn) { DATA(float4, Position, SV_Position); - DATA(float3, pos, POSITION); - DATA(float2, uv, TEXCOORD0); - DATA(float3, normal, NORMAL); - DATA(float3, tangent, TANGENT); - DATA(float3, bitangent, BITANGENT); }; float4 PS_MAIN(PsIn In) { INIT_MAIN; - float2 texCoord = In.uv.xy; - uint materialID = Get(uniformObjectBuffer)[Get(objectId)].materialID; - - #ifdef PARALLAX_ENABLED - if(HasHeight(Get(uniformMaterialBuffer)[materialID].materialConfig)) { - texCoord.xy += ParallaxAdvance(texCoord, - 0.0, - 8.0, - Get(uniformMaterialBuffer)[materialID].heightMapScale * PARALLAX_MULTIPLIER, - In.pos, - In.normal, - In.tangent, - In.bitangent, - IsHeightMapSingleChannel(Get(uniformMaterialBuffer)[materialID].materialConfig)); - } - #endif - - float diffuseAlpha; - if(HasAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { - if(IsAlphaSingleChannel(Get(uniformMaterialBuffer)[materialID].materialConfig)) { - diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).r; - } else { - diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).a; - } - } else { - diffuseAlpha = 1.0; - } - - const float dissolveAmount = Get(uniformObjectBuffer)[Get(objectId)].dissolveAmount; - - if(dissolveAmount < 1.0 || HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig) || HasDissolveFilter(Get(uniformMaterialBuffer)[materialID].materialConfig)) { - float2 vDissolveCoords = In.Position.xy * (1.0/128.0); //128 = size of dissolve texture. - float fDissolve = SampleTex2D(dissolveMap, Get(dissolveSampler), vDissolveCoords).x; - - if(HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { - //Get in 0.75 - 1 range - fDissolve = fDissolve*0.25 + 0.75; - - float fDissolveAlpha = SampleTex2D(Get(dissolveAlphaMap), Get(materialSampler), texCoord.xy).r; - fDissolve -= (0.25 - fDissolveAlpha * 0.25); - } else { - //Get in 0.5 - 1 range. - fDissolve = fDissolve*0.5 + 0.5; - } - diffuseAlpha = fDissolve - (1.0 - (dissolveAmount * diffuseAlpha)) * 0.5; - } - - - if(diffuseAlpha < ALPHA_REJECT) { - discard; - } - RETURN(float4(0,0,0,0)); } diff --git a/HPL2/resource/solid_z.vert.fsl b/HPL2/resource/solid_z.vert.fsl index b38064b70..9bf8213ef 100644 --- a/HPL2/resource/solid_z.vert.fsl +++ b/HPL2/resource/solid_z.vert.fsl @@ -5,19 +5,19 @@ STRUCT(VSInput) { DATA(float3, Position, POSITION); - DATA(float2, TexCoord, TEXCOORD0); - DATA(float3, Normal, NORMAL); - DATA(float3, Tangent, TANGENT); + // DATA(float2, TexCoord, TEXCOORD0); + // DATA(float3, Normal, NORMAL); + // DATA(float3, Tangent, TANGENT); }; STRUCT(VSOutput) { DATA(float4, Position, SV_Position); - DATA(float3, pos, POSITION); - DATA(float2, uv, TEXCOORD0); - DATA(float3, normal, NORMAL); - DATA(float3, tangent, TANGENT); - DATA(float3, bitangent, BITANGENT); + // DATA(float3, pos, POSITION); + // DATA(float2, uv, TEXCOORD0); + // DATA(float3, normal, NORMAL); + // DATA(float3, tangent, TANGENT); + // DATA(float3, bitangent, BITANGENT); }; VSOutput VS_MAIN(VSInput In) @@ -28,14 +28,14 @@ VSOutput VS_MAIN(VSInput In) float4x4 modelView = mul(Get(viewMat), Get(uniformObjectBuffer)[Get(objectId)].modelMat); float4x4 modelViewPrj = mul(Get(projMat), modelView); - Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; +// Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; Out.Position = mul(modelViewPrj , float4(In.Position.xyz, 1.0)); - Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; + // Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; - float3x3 normalMat = ToNormalMat(Get(uniformObjectBuffer)[Get(objectId)].invModelMat, Get(invViewMat)); - Out.normal = normalize(mul(normalMat, In.Normal.xyz)); - Out.tangent = normalize(mul(normalMat, In.Tangent.xyz)); - Out.bitangent = normalize(mul(normalMat, cross(In.Tangent.xyz, In.Normal.xyz))); + // float3x3 normalMat = ToNormalMat(Get(uniformObjectBuffer)[Get(objectId)].invModelMat, Get(invViewMat)); + // Out.normal = normalize(mul(normalMat, In.Normal.xyz)); + // Out.tangent = normalize(mul(normalMat, In.Tangent.xyz)); + // Out.bitangent = normalize(mul(normalMat, cross(In.Tangent.xyz, In.Normal.xyz))); RETURN(Out); } diff --git a/HPL2/resource/solid_z_cut.vert.fsl b/HPL2/resource/solid_z_cut.vert.fsl new file mode 100644 index 000000000..618dc7a05 --- /dev/null +++ b/HPL2/resource/solid_z_cut.vert.fsl @@ -0,0 +1,30 @@ +#define MATERIAL_SOLID 1 +#include "deferred_resources.h.fsl" +#include "deferred_common.h.fsl" + +STRUCT(VSInput) +{ + DATA(float3, Position, POSITION); + DATA(float2, TexCoord, TEXCOORD0); +}; + +STRUCT(VSOutput) +{ + DATA(float4, Position, SV_Position); + DATA(float3, pos, POSITION); + DATA(float2, uv, TEXCOORD0); +}; + +VSOutput VS_MAIN(VSInput In) +{ + INIT_MAIN; + VSOutput Out; + + float4x4 modelView = mul(Get(viewMat), Get(uniformObjectBuffer)[Get(objectId)].modelMat); + float4x4 modelViewPrj = mul(Get(projMat), modelView); + + Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; + Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; + + RETURN(Out); +} diff --git a/HPL2/resource/solid_z_shadow.frag.fsl b/HPL2/resource/solid_z_shadow.frag.fsl new file mode 100644 index 000000000..21b56b788 --- /dev/null +++ b/HPL2/resource/solid_z_shadow.frag.fsl @@ -0,0 +1,56 @@ +/// Copyright © 2009-2020 Frictional Games +/// Copyright 2023 Michael Pollind +/// SPDX-License-Identifier: GPL-3.0 +#define MATERIAL_SOLID 1 +#include "deferred_resources.h.fsl" +#include "deferred_common.h.fsl" + +STRUCT(PsIn) +{ + DATA(float4, Position, SV_Position); + DATA(float3, pos, POSITION); + DATA(float2, uv, TEXCOORD0); +}; + +float4 PS_MAIN(PsIn In) +{ + INIT_MAIN; + float2 texCoord = In.uv.xy; + uint materialID = Get(uniformObjectBuffer)[Get(objectId)].materialID; + float diffuseAlpha; + if(HasAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + if(IsAlphaSingleChannel(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).r; + } else { + diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).a; + } + } else { + diffuseAlpha = 1.0; + } + + const float dissolveAmount = Get(uniformObjectBuffer)[Get(objectId)].dissolveAmount; + + if(dissolveAmount < 1.0 || HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig) || HasDissolveFilter(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + float2 vDissolveCoords = In.Position.xy * (1.0/128.0); //128 = size of dissolve texture. + float fDissolve = SampleTex2D(dissolveMap, Get(dissolveSampler), vDissolveCoords).x; + + if(HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + //Get in 0.75 - 1 range + fDissolve = fDissolve*0.25 + 0.75; + + float fDissolveAlpha = SampleTex2D(Get(dissolveAlphaMap), Get(materialSampler), texCoord.xy).r; + fDissolve -= (0.25 - fDissolveAlpha * 0.25); + } else { + //Get in 0.5 - 1 range. + fDissolve = fDissolve*0.5 + 0.5; + } + diffuseAlpha = fDissolve - (1.0 - (dissolveAmount * diffuseAlpha)) * 0.5; + } + + + if(diffuseAlpha < ALPHA_REJECT) { + discard; + } + + RETURN(float4(0,0,0,0)); +} diff --git a/HPL2/resource/solid_z_shadow.vert.fsl b/HPL2/resource/solid_z_shadow.vert.fsl new file mode 100644 index 000000000..c95ad3249 --- /dev/null +++ b/HPL2/resource/solid_z_shadow.vert.fsl @@ -0,0 +1,28 @@ +#define MATERIAL_SOLID 1 +#include "deferred_resources.h.fsl" +#include "deferred_common.h.fsl" + +STRUCT(VSInput) +{ + DATA(float3, Position, POSITION); + DATA(float2, TexCoord, TEXCOORD0); +}; + +STRUCT(VSOutput) +{ + DATA(float4, Position, SV_Position); + DATA(float3, pos, POSITION); +}; + +VSOutput VS_MAIN(VSInput In) +{ + INIT_MAIN; + VSOutput Out; + + float4x4 modelView = mul(Get(viewMat), Get(uniformObjectBuffer)[Get(objectId)].modelMat); + float4x4 modelViewPrj = mul(Get(projMat), modelView); + + Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; + Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; + RETURN(Out); +} diff --git a/HPL2/sources/graphics/RendererDeferred.cpp b/HPL2/sources/graphics/RendererDeferred.cpp index b414e075d..b95291716 100644 --- a/HPL2/sources/graphics/RendererDeferred.cpp +++ b/HPL2/sources/graphics/RendererDeferred.cpp @@ -187,14 +187,10 @@ namespace hpl { } } - //////////////////////// - // Iterate children for (auto& childNode : apNode->GetChildNodes()) { walkShadowCasters(childNode, frustumCollision); } - ///////////////////////////// - // Iterate objects for (auto& object : apNode->GetObjects()) { // Check so visible and shadow caster if (rendering::detail::IsObjectIsVisible(object, eRenderableFlag_ShadowCaster, clipPlanes) == false || @@ -1133,6 +1129,13 @@ namespace hpl { //---------------- Diffuse Pipeline ------------------------ { // z pass + m_zPassShadowShader.Load(forgeRenderer->Rend(), [&](Shader** shader) { + ShaderLoadDesc loadDesc = {}; + loadDesc.mStages[0].pFileName = "solid_z_shadow.vert"; + loadDesc.mStages[1].pFileName = "solid_z_shadow.frag"; + addShader(forgeRenderer->Rend(), &loadDesc, shader); + return true; + }); m_zPassShader.Load(forgeRenderer->Rend(), [&](Shader** shader) { ShaderLoadDesc loadDesc = {}; loadDesc.mStages[0].pFileName = "solid_z.vert"; @@ -1301,8 +1304,8 @@ namespace hpl { DepthStateDesc depthStateDesc = {}; depthStateDesc.mDepthTest = true; - depthStateDesc.mDepthWrite = false; - depthStateDesc.mDepthFunc = CMP_EQUAL; + depthStateDesc.mDepthWrite = true; + depthStateDesc.mDepthFunc = CMP_LEQUAL; std::array colorFormats = { ColorBufferFormat, NormalBufferFormat, PositionBufferFormat, SpecularBufferFormat }; @@ -1537,7 +1540,7 @@ namespace hpl { pipelineSettings.mDepthStencilFormat = ShadowDepthBufferFormat; pipelineSettings.mSampleQuality = 0; pipelineSettings.pRootSignature = m_materialRootSignature.m_handle; - pipelineSettings.pShaderProgram = m_zPassShader.m_handle; + pipelineSettings.pShaderProgram = m_zPassShadowShader.m_handle; pipelineSettings.pRasterizerState = &rasterizerStateDesc; pipelineSettings.pVertexLayout = &vertexLayout; addPipeline(forgeRenderer->Rend(), &pipelineDesc, pipeline); @@ -1564,7 +1567,7 @@ namespace hpl { pipelineSettings.mDepthStencilFormat = ShadowDepthBufferFormat; pipelineSettings.mSampleQuality = 0; pipelineSettings.pRootSignature = m_materialRootSignature.m_handle; - pipelineSettings.pShaderProgram = m_zPassShader.m_handle; + pipelineSettings.pShaderProgram = m_zPassShadowShader.m_handle; pipelineSettings.pRasterizerState = &rasterizerStateDesc; pipelineSettings.pVertexLayout = &vertexLayout; addPipeline(forgeRenderer->Rend(), &pipelineDesc, pipeline); @@ -2760,9 +2763,7 @@ namespace hpl { cMaterial* pMaterial = pObject->GetMaterial(); const ShaderMaterialData& descriptor = pMaterial->Descriptor(); std::array targets = { eVertexBufferElement_Position, - eVertexBufferElement_Texture0, - eVertexBufferElement_Normal, - eVertexBufferElement_Texture1Tangent }; + eVertexBufferElement_Texture0 }; DrawPacket packet = pObject->ResolveDrawPacket(frame, targets); if (packet.m_type == DrawPacket::Unknown || descriptor.m_id == MaterialID::Unknown) { return; @@ -3240,6 +3241,23 @@ namespace hpl { ASSERT(depthBuffer && "Depth buffer not created"); ASSERT(hiZBuffer && "Depth buffer not created"); + auto isValidForPreAndPostZ = [](cMaterial* material, iRenderable* renderable ) { + if (!material) { + return false; + } + if(renderable->GetCoverageAmount() < 1.0) { + return false; + } + if(cMaterial::IsTranslucent(material->Descriptor().m_id)) { + return false; + } + if(material->GetImage(eMaterialTexture_Alpha)) { + return false; + } + + return true; + }; + FenceStatus fenceStatus; getFenceStatus(frame.m_renderer->Rend(), m_prePassFence.m_handle, &fenceStatus); if (fenceStatus == FENCE_STATUS_INCOMPLETE) { @@ -3407,14 +3425,11 @@ namespace hpl { reinterpret_cast(updateDesc.pMappedData)[1] = float4(boundBoxMax.x, boundBoxMax.y, boundBoxMax.z, 0.0f); endUpdateResource(&updateDesc, nullptr); - if (!test.m_preZPass || !pMaterial || cMaterial::IsTranslucent(pMaterial->Descriptor().m_id)) { + if (!test.m_preZPass || !isValidForPreAndPostZ(pMaterial, test.m_renderable)) { continue; } - std::array targets = { eVertexBufferElement_Position, - eVertexBufferElement_Texture0, - eVertexBufferElement_Normal, - eVertexBufferElement_Texture1Tangent }; + std::array targets = { eVertexBufferElement_Position}; DrawPacket packet = test.m_renderable->ResolveDrawPacket(frame, targets); if (packet.m_type == DrawPacket::Unknown) { continue; @@ -3646,13 +3661,10 @@ namespace hpl { renderable->GetCoverageAmount() >= 1 ? eMaterialRenderMode_Z : eMaterialRenderMode_Z_Dissolve; cMaterial* pMaterial = renderable->GetMaterial(); - if (!pMaterial || cMaterial::IsTranslucent(pMaterial->Descriptor().m_id)) { + if (!isValidForPreAndPostZ(pMaterial, renderable)) { continue; } - std::array targets = { eVertexBufferElement_Position, - eVertexBufferElement_Texture0, - eVertexBufferElement_Normal, - eVertexBufferElement_Texture1Tangent }; + std::array targets = { eVertexBufferElement_Position }; DrawPacket drawPacket = renderable->ResolveDrawPacket(frame, targets); if (drawPacket.m_type == DrawPacket::Unknown) { continue; @@ -3991,7 +4003,6 @@ namespace hpl { // Setup far plane coordinates /////////////////////////// - // Occlusion testing m_rendererList.BeginAndReset(afFrameTime, apFrustum); cmdPreAndPostZ( frame.m_cmd, From bc9feb435501fa5ee0b11b838d660d026d977b3f Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 7 Nov 2023 07:02:06 -0800 Subject: [PATCH 2/4] fix Signed-off-by: Michael Pollind --- HPL2/resource/solid_z.vert.fsl | 15 --------------- HPL2/resource/solid_z_shadow.vert.fsl | 1 + 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/HPL2/resource/solid_z.vert.fsl b/HPL2/resource/solid_z.vert.fsl index 9bf8213ef..3c7e39f07 100644 --- a/HPL2/resource/solid_z.vert.fsl +++ b/HPL2/resource/solid_z.vert.fsl @@ -5,19 +5,11 @@ STRUCT(VSInput) { DATA(float3, Position, POSITION); - // DATA(float2, TexCoord, TEXCOORD0); - // DATA(float3, Normal, NORMAL); - // DATA(float3, Tangent, TANGENT); }; STRUCT(VSOutput) { DATA(float4, Position, SV_Position); - // DATA(float3, pos, POSITION); - // DATA(float2, uv, TEXCOORD0); - // DATA(float3, normal, NORMAL); - // DATA(float3, tangent, TANGENT); - // DATA(float3, bitangent, BITANGENT); }; VSOutput VS_MAIN(VSInput In) @@ -28,14 +20,7 @@ VSOutput VS_MAIN(VSInput In) float4x4 modelView = mul(Get(viewMat), Get(uniformObjectBuffer)[Get(objectId)].modelMat); float4x4 modelViewPrj = mul(Get(projMat), modelView); -// Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; Out.Position = mul(modelViewPrj , float4(In.Position.xyz, 1.0)); - // Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; - - // float3x3 normalMat = ToNormalMat(Get(uniformObjectBuffer)[Get(objectId)].invModelMat, Get(invViewMat)); - // Out.normal = normalize(mul(normalMat, In.Normal.xyz)); - // Out.tangent = normalize(mul(normalMat, In.Tangent.xyz)); - // Out.bitangent = normalize(mul(normalMat, cross(In.Tangent.xyz, In.Normal.xyz))); RETURN(Out); } diff --git a/HPL2/resource/solid_z_shadow.vert.fsl b/HPL2/resource/solid_z_shadow.vert.fsl index c95ad3249..b480e68e3 100644 --- a/HPL2/resource/solid_z_shadow.vert.fsl +++ b/HPL2/resource/solid_z_shadow.vert.fsl @@ -12,6 +12,7 @@ STRUCT(VSOutput) { DATA(float4, Position, SV_Position); DATA(float3, pos, POSITION); + DATA(float2, uv, TEXCOORD0); }; VSOutput VS_MAIN(VSInput In) From 47db28e09ead77d15540b03a27f0aab452be48c2 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 7 Nov 2023 20:56:51 -0800 Subject: [PATCH 3/4] feat: add shadow cache implementation Signed-off-by: Michael Pollind --- HPL2/include/graphics/IndexPool.h | 2 + HPL2/include/graphics/RendererDeferred.h | 2 + HPL2/include/graphics/ShadowCache.h | 69 ++++++++ HPL2/resource/solid_z_shadow.vert.fsl | 1 + HPL2/sources/graphics/IndexPool.cpp | 3 +- HPL2/sources/graphics/RendererDeferred.cpp | 3 +- HPL2/sources/graphics/ShadowCache.cpp | 192 +++++++++++++++++++++ 7 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 HPL2/include/graphics/ShadowCache.h create mode 100644 HPL2/sources/graphics/ShadowCache.cpp diff --git a/HPL2/include/graphics/IndexPool.h b/HPL2/include/graphics/IndexPool.h index ae63a6f51..f8762b499 100644 --- a/HPL2/include/graphics/IndexPool.h +++ b/HPL2/include/graphics/IndexPool.h @@ -14,12 +14,14 @@ namespace hpl { IndexPool(uint32_t reserve); uint32_t requestId(); + inline uint32_t reserve() {return m_reserve;} void returnId(uint32_t); private: struct IdRange { uint32_t m_start; uint32_t m_end; }; + uint32_t m_reserve; folly::small_vector m_avaliable; }; diff --git a/HPL2/include/graphics/RendererDeferred.h b/HPL2/include/graphics/RendererDeferred.h index 6d11c4d1c..01a08a45d 100644 --- a/HPL2/include/graphics/RendererDeferred.h +++ b/HPL2/include/graphics/RendererDeferred.h @@ -20,6 +20,7 @@ #include "engine/RTTI.h" +#include "graphics/ShadowCache.h" #include "scene/Viewport.h" #include "scene/World.h" #include "windowing/NativeWindow.h" @@ -708,5 +709,6 @@ namespace hpl { cRenderList m_reflectionRendererList; std::unique_ptr m_hbaoPlusPipeline; std::shared_ptr m_debug; + ShadowCache m_shadowCache; }; }; // namespace hpl diff --git a/HPL2/include/graphics/ShadowCache.h b/HPL2/include/graphics/ShadowCache.h new file mode 100644 index 000000000..f3f196635 --- /dev/null +++ b/HPL2/include/graphics/ShadowCache.h @@ -0,0 +1,69 @@ +#pragma once + +#include "graphics/IndexPool.h" +#include +#include + +#include + +#include +#include +#include + + +namespace hpl { + class ShadowCache { + public: + + struct ShadowGroup { + public: + static constexpr uint8_t IsLeaf = 0x1; + static constexpr uint8_t HasLeafs = 0x2; + static constexpr uint8_t HasGroups = 0x4; + + uint16_t m_idx; + + uint16_t m_x; + uint16_t m_y; + uint32_t m_age; + + uint16_t m_parent; // the parent of the cache entry + uint16_t m_child; // the start of the group + + // linked list for all cut levels at the same cut + uint16_t m_next; + uint16_t m_prev; + + uint8_t m_flags; + uint8_t m_occupyMask: 4; // mask for the entires occuped + uint8_t m_slot: 4; // the slot index + uint8_t m_level; + + uint16_t m_hashes[4]; + }; + + + struct CutLevel { + uint16_t m_begin = UINT16_MAX; + }; + + ShadowCache(uint32_t width, uint32_t height, uint32_t hDivisions, uint32_t vDivision, uint8_t maxCuts); + void reset(uint32_t age); + uint4 find(uint16_t hash, uint8_t level, uint32_t age); + private: + ShadowGroup* allocGroup(); + ShadowCache::ShadowGroup* createCut(ShadowGroup* group); + + void freeGroup(ShadowGroup* group); + void freeChildren(ShadowGroup* group); + + void updateAge(ShadowCache::ShadowGroup* current, uint32_t age); + void insertAfter(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp); + void insertBefore(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp); + + uint2 m_quadSize; + hpl::IndexPool m_pool; + std::vector m_alloc; // a reserved pool of entries will contain the max possible i.e all the quads are at its lowest cut + std::vector m_cut; // cut levels for each quad + }; +} diff --git a/HPL2/resource/solid_z_shadow.vert.fsl b/HPL2/resource/solid_z_shadow.vert.fsl index b480e68e3..870795ddc 100644 --- a/HPL2/resource/solid_z_shadow.vert.fsl +++ b/HPL2/resource/solid_z_shadow.vert.fsl @@ -24,6 +24,7 @@ VSOutput VS_MAIN(VSInput In) float4x4 modelViewPrj = mul(Get(projMat), modelView); Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; + Out.Position = mul(modelViewPrj, float4(In.Position.xyz, 1.0)); Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; RETURN(Out); } diff --git a/HPL2/sources/graphics/IndexPool.cpp b/HPL2/sources/graphics/IndexPool.cpp index a4a0a7cf7..6a27eadb2 100644 --- a/HPL2/sources/graphics/IndexPool.cpp +++ b/HPL2/sources/graphics/IndexPool.cpp @@ -7,7 +7,8 @@ namespace hpl { - IndexPool::IndexPool(uint32_t reserve) { + IndexPool::IndexPool(uint32_t reserve): + m_reserve(reserve) { m_avaliable.push_back({0, reserve - 1}); } diff --git a/HPL2/sources/graphics/RendererDeferred.cpp b/HPL2/sources/graphics/RendererDeferred.cpp index b95291716..cd37bdfd6 100644 --- a/HPL2/sources/graphics/RendererDeferred.cpp +++ b/HPL2/sources/graphics/RendererDeferred.cpp @@ -508,7 +508,8 @@ namespace hpl { cRendererDeferred::cRendererDeferred(cGraphics* apGraphics, cResources* apResources, std::shared_ptr debug) : iRenderer("Deferred", apGraphics, apResources) - , m_debug(debug) { + , m_debug(debug) + , m_shadowCache(8192, 4096, 8, 4, 3) { m_hbaoPlusPipeline = std::make_unique(); //////////////////////////////////// // Set up render specific things diff --git a/HPL2/sources/graphics/ShadowCache.cpp b/HPL2/sources/graphics/ShadowCache.cpp new file mode 100644 index 000000000..3dc8717af --- /dev/null +++ b/HPL2/sources/graphics/ShadowCache.cpp @@ -0,0 +1,192 @@ +#include "graphics/ShadowCache.h" +#include "graphics/IndexPool.h" +#include +#include +#include + +namespace hpl { + + void ShadowCache::insertAfter(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp) { + ASSERT(current); + ASSERT(grp); + uint16_t nextIdx = current->m_next; + + current->m_next = grp->m_idx; + grp->m_prev = current->m_idx; + + grp->m_next = nextIdx; + if(nextIdx != UINT16_MAX) { + m_alloc[nextIdx].m_prev = grp->m_idx; + } + } + void ShadowCache::insertBefore(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp) { + ASSERT(current); + ASSERT(grp); + uint16_t prevIdx = current->m_prev; + + current->m_prev = grp->m_idx; + grp->m_next = current->m_idx; + + grp->m_prev = prevIdx; + if(prevIdx != UINT16_MAX) { + m_alloc[prevIdx].m_next = grp->m_idx; + } + } + ShadowCache::ShadowCache(uint32_t width, uint32_t height, uint32_t hDivisions, uint32_t vDivision, uint8_t maxCuts): + m_quadSize(width/vDivision, height/ hDivisions), + m_pool((std::pow(std::max(1, (static_cast(maxCuts) - 2)), 4) + 1) * hDivisions * vDivision) { + ASSERT(m_pool.reserve() > std::numeric_limits::max()); + m_alloc.resize(m_pool.reserve()); + m_cut.resize(maxCuts); + ShadowCache::ShadowGroup* previous = nullptr; + for(size_t x = 0; x < hDivisions; x++) { + for(size_t y = 0; y < vDivision; y++) { + ShadowCache::ShadowGroup* entry = allocGroup(); + entry->m_x = m_quadSize.x * x; + entry->m_y = m_quadSize.y * y; + if(previous != nullptr) { + insertAfter(previous, entry); + } + if(previous == nullptr) { + m_cut[0].m_begin = entry->m_idx; + } + previous = entry; + } + } + } + + ShadowCache::ShadowGroup* ShadowCache::createCut(ShadowGroup* group) { + ShadowGroup* child = allocGroup(); + child->m_parent = group->m_idx; + if (group->m_child == UINT16_MAX) { + group->m_child = child->m_idx; + child->m_parent = group->m_idx; + } else { + insertAfter(&m_alloc[group->m_child], child); + } + child->m_level = group->m_level + 1; + bool found = false; + for (uint8_t i = 0; i < 4; i++) { + if ((group->m_occupyMask & (1 << i)) == 0) { + group->m_occupyMask |= (1 << i); // we are going to set this entry is occupied + uint16_t x = (i % 2); + uint16_t y = (i / 2); + child->m_slot = i; // we assign the slot we occupy for this cut + uint2 quadSize = m_quadSize / (1 << child->m_level); + group->m_x = group->m_x + (x * quadSize.x); + group->m_y = group->m_y + (y * quadSize.y); + group->m_flags |= ShadowGroup::HasGroups; + found = true; + break; + } + } + ASSERT(found); + auto& nextCut = m_cut[child->m_level]; + if (nextCut.m_begin == UINT16_MAX) { + nextCut.m_begin = child->m_idx; + } else { + insertBefore(&m_alloc[nextCut.m_begin], group); + } + + return child; + } + + uint4 ShadowCache::find(uint16_t hash, uint8_t level, uint32_t age) { + auto findGroupInCut = [&](ShadowGroup* group) { + ShadowGroup* result = nullptr; + for (uint16_t i = group->m_idx; i != UINT16_MAX; i = m_alloc[i].m_next) { + for(size_t k = 0; k < 4; k++) { + // we found a matching hash + if(m_alloc[i].m_hashes[k] == hash) { + result = &m_alloc[i]; + goto exit; + } + } + if (result == nullptr || m_alloc[i].m_age < result->m_age) { + result = &m_alloc[i]; + } + } + exit: + return result; + }; + const uint8_t targetLevel = level == 0? 0: level - 1; + auto& targetCut = m_cut[targetLevel]; + + ShadowGroup* group = findGroupInCut(&m_alloc[targetCut.m_begin]); + if(level == 0) { + freeChildren(group); + group->m_flags |= ShadowGroup::IsLeaf; + group->m_hashes[0] = hash; + group->m_age = age; + return uint4(group->m_x, group->m_y, m_quadSize.x, m_quadSize.y); + } else { + + } + return uint4(0,0,0,0); + } + + ShadowCache::ShadowGroup* ShadowCache::allocGroup() { + uint32_t index = m_pool.requestId(); + ShadowGroup* entry = &m_alloc[index]; + std::memset(entry, 0, sizeof(ShadowGroup)); + entry->m_parent = UINT16_MAX; + entry->m_child = UINT16_MAX; + entry->m_next = UINT16_MAX; + entry->m_prev = UINT16_MAX; + entry->m_idx = index; + return entry; + } + + void ShadowCache::updateAge(ShadowCache::ShadowGroup* current, uint32_t age) { + for(uint16_t i = current->m_idx; i != UINT16_MAX; i = m_alloc[i].m_parent) { + if(age > current->m_age ) { + current->m_age = age; + } + } + } + + void ShadowCache::freeChildren(ShadowCache::ShadowGroup* grp) { + if(grp->m_child != UINT16_MAX) { + for(uint32_t i = grp->m_child; i != UINT16_MAX && m_alloc[i].m_parent == grp->m_idx; i = m_alloc[i].m_next) { + m_alloc[i].m_parent = UINT16_MAX; // we invalidate the parent + freeGroup(&m_alloc[i]); + } + } + std::memset(grp->m_hashes, 0, sizeof(grp->m_hashes)); + grp->m_occupyMask = 0; + grp->m_flags &= ~(ShadowGroup::HasLeafs | ShadowGroup::HasGroups); + } + void ShadowCache::freeGroup(ShadowCache::ShadowGroup* grp) { + for(auto& cut: m_cut) { + if(cut.m_begin == grp->m_idx) { + cut.m_begin = grp->m_next; // we assign the next if UINT16_MAX then that is accepted the layer is now empty + } + } + if(grp->m_child != UINT16_MAX) { + for(uint32_t i = grp->m_child; i != UINT16_MAX && m_alloc[i].m_parent == grp->m_idx; i = m_alloc[i].m_next) { + m_alloc[i].m_parent = UINT16_MAX; // we invalidate the parent + freeGroup(&m_alloc[i]); + } + } + if(grp->m_parent != UINT16_MAX) { + auto* parent = &m_alloc[grp->m_parent]; + parent->m_occupyMask &= ~(1 << grp->m_slot); // we clear the occupy slot + if(parent->m_child == grp->m_idx) { + // if the next child has a mismatched index we've exausted cuts + if(grp->m_next != UINT16_MAX && m_alloc[grp->m_next].m_parent == parent->m_idx) { + parent->m_child = grp->m_next; + } + + } + } + if(grp->m_prev != UINT16_MAX && grp->m_next != UINT16_MAX) { + m_alloc[grp->m_prev].m_next = m_alloc[grp->m_next].m_idx; + m_alloc[grp->m_next].m_prev = m_alloc[grp->m_prev].m_idx; + } else if(grp->m_prev != UINT16_MAX) { + m_alloc[grp->m_prev].m_next = UINT16_MAX; + } else if(grp->m_next != UINT16_MAX) { + m_alloc[grp->m_next].m_prev = UINT16_MAX; + } + m_pool.returnId(grp->m_idx); + } +} From 8bc02e8f555ba202bfec153c25f9c7607ba0878a Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 8 Nov 2023 21:23:45 -0800 Subject: [PATCH 4/4] feat: simplify shadow cache Signed-off-by: Michael Pollind --- HPL2/include/graphics/CommandBufferPool.h | 71 ++++++ HPL2/include/graphics/RendererDeferred.h | 7 +- HPL2/include/graphics/ShadowCache.h | 175 +++++++++---- HPL2/sources/graphics/RendererDeferred.cpp | 280 +++++++++++---------- HPL2/sources/graphics/ShadowCache.cpp | 191 +------------- 5 files changed, 357 insertions(+), 367 deletions(-) create mode 100644 HPL2/include/graphics/CommandBufferPool.h diff --git a/HPL2/include/graphics/CommandBufferPool.h b/HPL2/include/graphics/CommandBufferPool.h new file mode 100644 index 000000000..959d06f88 --- /dev/null +++ b/HPL2/include/graphics/CommandBufferPool.h @@ -0,0 +1,71 @@ +#pragma once + +#include "graphics/ForgeHandles.h" +#include "graphics/Renderer.h" +#include + +#include "Common_3/Graphics/Interfaces/IGraphics.h" +#include "FixPreprocessor.h" + +namespace hpl { + template + class CommandBufferPool { + public: + struct PoolEntry { + public: + SharedCmdPool m_pool; + SharedCmd m_cmd; + SharedFence m_fence; + }; + CommandBufferPool() {} + CommandBufferPool(CommandBufferPool&&) = default; + CommandBufferPool(const CommandBufferPool&) = delete; + + void operator=(const CommandBufferPool&) = delete; + CommandBufferPool& operator=(CommandBufferPool&&) = default; + + CommandBufferPool(Renderer* renderer, Queue* queue): m_renderer(renderer){ + for(auto& entry: m_pool) { + entry.m_pool.Load(renderer, [&](CmdPool** pool) { + CmdPoolDesc cmdPoolDesc = {}; + cmdPoolDesc.pQueue = queue; + addCmdPool(renderer, &cmdPoolDesc, pool); + return true; + }); + entry.m_cmd.Load(renderer, [&](Cmd** cmd) { + CmdDesc cmdDesc = {}; + cmdDesc.pPool = entry.m_pool.m_handle; + addCmd(renderer, &cmdDesc, cmd); + return true; + }); + entry.m_fence.Load(renderer, [&](Fence** fence) { + addFence(renderer, fence); + return true; + }); + } + } + + void waitAll() { + for(auto& entry: m_pool) { + FenceStatus status{}; + getFenceStatus(m_renderer, entry.m_fence.m_handle, &status); + if(status == FENCE_STATUS_INCOMPLETE) { + waitForFences(m_renderer, 1, &entry.m_handle); + } + } + } + PoolEntry* findAvaliableEntry() { + for(auto& entry: m_pool) { + FenceStatus status{}; + getFenceStatus(m_renderer, entry.m_fence.m_handle, &status); + if(status == FENCE_STATUS_COMPLETE) { + return &entry; + } + } + return nullptr; + } + private: + Renderer* m_renderer; + std::array m_pool; + }; +} diff --git a/HPL2/include/graphics/RendererDeferred.h b/HPL2/include/graphics/RendererDeferred.h index 01a08a45d..48b3f1b8e 100644 --- a/HPL2/include/graphics/RendererDeferred.h +++ b/HPL2/include/graphics/RendererDeferred.h @@ -20,6 +20,7 @@ #include "engine/RTTI.h" +#include "graphics/CommandBufferPool.h" #include "graphics/ShadowCache.h" #include "scene/Viewport.h" #include "scene/World.h" @@ -458,6 +459,11 @@ namespace hpl { std::unique_ptr m_box; std::array, eShadowMapResolution_LastEnum> m_shadowMapData; + + SharedRenderTarget m_shadowTarget; + ShadowCache m_shadowCache; + CommandBufferPool<16> m_shadowCmdPool; + UniqueViewportData m_boundViewportData; SharedTexture m_shadowJitterTexture; @@ -709,6 +715,5 @@ namespace hpl { cRenderList m_reflectionRendererList; std::unique_ptr m_hbaoPlusPipeline; std::shared_ptr m_debug; - ShadowCache m_shadowCache; }; }; // namespace hpl diff --git a/HPL2/include/graphics/ShadowCache.h b/HPL2/include/graphics/ShadowCache.h index f3f196635..f7c0c3506 100644 --- a/HPL2/include/graphics/ShadowCache.h +++ b/HPL2/include/graphics/ShadowCache.h @@ -2,6 +2,7 @@ #include "graphics/IndexPool.h" #include +#include #include #include @@ -10,60 +11,146 @@ #include #include - namespace hpl { + template class ShadowCache { public: + static constexpr uint32_t MinimumAge = 3; + static constexpr uint4 InvalidQuad = uint4(0, 0, 0, 0); + struct ShadowSlot { + uint32_t m_age = 0; + uint16_t m_hash = 0; + MetaInfo m_info = {}; + }; - struct ShadowGroup { + struct ShadowContainer { public: - static constexpr uint8_t IsLeaf = 0x1; - static constexpr uint8_t HasLeafs = 0x2; - static constexpr uint8_t HasGroups = 0x4; - - uint16_t m_idx; + uint16_t m_x = 0; + uint16_t m_y = 0; + uint8_t m_level = 0; + uint32_t m_age = 0; + folly::small_vector m_slots; + }; - uint16_t m_x; - uint16_t m_y; + ShadowCache() = default; + ShadowCache(uint32_t width, uint32_t height, uint32_t numColumns, uint32_t numRows, uint8_t maxLevels) + : m_maxLevels(maxLevels) + , m_numRows(numRows) + , m_numColumns(numColumns) + , m_size(width, height) + , m_quadSize(width / numColumns, height / numRows) { + m_containers.resize(numColumns * numRows); + for(size_t i = 0; i < m_containers.size(); i++) { + m_containers[i].m_slots.resize(1); + m_containers[i].m_x = m_quadSize.x * (i % numColumns); + m_containers[i].m_y = m_quadSize.y * (i / numColumns); + } + + } + struct ShadowMapResult { + public: + ShadowMapResult(ShadowCache* cache, ShadowContainer* container, uint32_t slotIdx, uint32_t age) + : m_cache(cache) + , m_container(container) + , m_slotIdx(slotIdx) + , m_age(age) { + } + // mark shadowmap as used + void Mark() { + m_container->m_age = m_age; + m_container->m_slots[m_slotIdx].m_age = m_age; + } + + inline float4 NormalizedRect() { + uint4 quad = Rect(); + return float4( + static_cast(quad.x) / static_cast(m_cache->m_size.x), + static_cast(quad.y) / static_cast(m_cache->m_size.y), + static_cast(quad.z) / static_cast(m_cache->m_size.x), + static_cast(quad.w) / static_cast(m_cache->m_size.y)); + } + + inline MetaInfo& Meta() { + return m_container->m_slots[m_slotIdx].m_info; + } + + inline uint4 Rect() { + const uint8_t div = (1 << m_container->m_level); + const uint2 size = (m_cache->m_quadSize / div); + return uint4( + m_container->m_x + ((m_slotIdx % div) * size.x), + m_container->m_y + ((m_slotIdx / div) * size.y), + size.x, size.y); + } + + private: + ShadowCache* m_cache; + ShadowContainer* m_container; + size_t m_slotIdx; uint32_t m_age; - - uint16_t m_parent; // the parent of the cache entry - uint16_t m_child; // the start of the group - - // linked list for all cut levels at the same cut - uint16_t m_next; - uint16_t m_prev; - - uint8_t m_flags; - uint8_t m_occupyMask: 4; // mask for the entires occuped - uint8_t m_slot: 4; // the slot index - uint8_t m_level; - - uint16_t m_hashes[4]; }; + std::optional Search(uint16_t hash, uint8_t targetLevel, uint32_t age) { + uint8_t level = std::min(m_maxLevels, targetLevel); + const uint8_t divisions = (1 << level); + uint2 shadowSize = m_quadSize / divisions; + struct Candidate { + ShadowContainer* m_container; + uint32_t m_slotIdx; + }; + + Candidate bestCandidate{}; + ShadowContainer* replaceCandidate = nullptr; + for (auto& container : m_containers) { + if (container.m_level == level) { + for (size_t i = 0; i < (divisions * divisions); i++) { + auto& slot = container.m_slots[i]; + if (age - container.m_age > MinimumAge && + (bestCandidate.m_container == nullptr || + bestCandidate.m_container->m_slots[bestCandidate.m_slotIdx].m_age > slot.m_age)) { + bestCandidate.m_container = &container; + bestCandidate.m_slotIdx = i; + if (slot.m_hash == hash) { + return ShadowMapResult(this, &container, i, age); + } + } + } + } else { + if (age - container.m_age > MinimumAge && (replaceCandidate == nullptr || replaceCandidate->m_age > container.m_age)) { + replaceCandidate = &container; + } + } + } + if (bestCandidate.m_container != nullptr) { + return ShadowMapResult(this, bestCandidate.m_container, bestCandidate.m_slotIdx, age); + } + + if (replaceCandidate) { + replaceCandidate->m_level = level; + replaceCandidate->m_slots.clear(); + replaceCandidate->m_slots.resize(divisions * divisions); + return ShadowMapResult(this, replaceCandidate, 0, age); + } + + return std::nullopt; + } + + inline uint2 quadSize() { + return m_quadSize; + } + inline uint2 size() { + return m_size; + } + inline uint8_t maxLevels() { + return m_maxLevels; + } - struct CutLevel { - uint16_t m_begin = UINT16_MAX; - }; - - ShadowCache(uint32_t width, uint32_t height, uint32_t hDivisions, uint32_t vDivision, uint8_t maxCuts); - void reset(uint32_t age); - uint4 find(uint16_t hash, uint8_t level, uint32_t age); private: - ShadowGroup* allocGroup(); - ShadowCache::ShadowGroup* createCut(ShadowGroup* group); - - void freeGroup(ShadowGroup* group); - void freeChildren(ShadowGroup* group); - - void updateAge(ShadowCache::ShadowGroup* current, uint32_t age); - void insertAfter(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp); - void insertBefore(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp); - + uint8_t m_maxLevels; + uint16_t m_numRows; + uint16_t m_numColumns; + uint2 m_size; uint2 m_quadSize; - hpl::IndexPool m_pool; - std::vector m_alloc; // a reserved pool of entries will contain the max possible i.e all the quads are at its lowest cut - std::vector m_cut; // cut levels for each quad + std::vector m_containers; }; -} +} // namespace hpl diff --git a/HPL2/sources/graphics/RendererDeferred.cpp b/HPL2/sources/graphics/RendererDeferred.cpp index cd37bdfd6..5ef811c75 100644 --- a/HPL2/sources/graphics/RendererDeferred.cpp +++ b/HPL2/sources/graphics/RendererDeferred.cpp @@ -21,10 +21,13 @@ #include "engine/Event.h" #include "engine/Interface.h" +#include "graphics/CommandBufferPool.h" #include "graphics/DebugDraw.h" #include "graphics/DrawPacket.h" #include "graphics/ForgeHandles.h" +#include "graphics/ForgeRenderer.h" #include "graphics/MaterialResource.h" +#include "graphics/ShadowCache.h" #include "math/cFrustum.h" #include "scene/ParticleEmitter.h" #include "scene/Viewport.h" @@ -527,6 +530,7 @@ namespace hpl { m_dissolveImage = mpResources->GetTextureManager()->Create2DImage("core_dissolve.tga", false); auto* forgeRenderer = Interface::Get(); + m_shadowCmdPool = CommandBufferPool<16>(forgeRenderer->Rend(), forgeRenderer->GetGraphicsQueue()); m_occlusionUniformBuffer.Load([&](Buffer** buffer) { BufferLoadDesc desc = {}; desc.mDesc.mDescriptors = DESCRIPTOR_TYPE_BUFFER; @@ -2408,6 +2412,23 @@ namespace hpl { return shadowMapData; }; + m_shadowTarget.Load(forgeRenderer->Rend(), [&](RenderTarget** target) { + RenderTargetDesc renderTarget = {}; + renderTarget.mArraySize = 1; + renderTarget.mClearValue.depth = 1.0f; + renderTarget.mDepth = 1; + renderTarget.mFormat = ShadowDepthBufferFormat; + renderTarget.mWidth = m_shadowCache.size().x; + renderTarget.mHeight = m_shadowCache.size().y; + renderTarget.mDescriptors = DESCRIPTOR_TYPE_TEXTURE; + renderTarget.mSampleCount = SAMPLE_COUNT_1; + renderTarget.mSampleQuality = 0; + renderTarget.mStartState = RESOURCE_STATE_SHADER_RESOURCE; + renderTarget.pName = "ShadowMaps RTs"; + addRenderTarget(forgeRenderer->Rend(), &renderTarget, target); + return true; + }); + for (size_t i = 0; i < 32; ++i) { m_shadowMapData[eShadowMapResolution_High].emplace_back(createShadowMap(shadowSizes[startSize + eShadowMapResolution_High])); } @@ -2531,6 +2552,8 @@ namespace hpl { AdditionalLightPassOptions options) { uint32_t materialObjectIndex = getDescriptorIndexFromName(m_materialRootSignature.m_handle, "materialRootConstant"); + + folly::small_vector occlusionPlanes; if (apWorld->GetFogActive() && apWorld->GetFogColor().a >= 1.0f && apWorld->GetFogCulling()) { cPlanef fogPlane; @@ -2655,147 +2678,132 @@ namespace hpl { cFrustum* pLightFrustum = pLightSpot->GetFrustum(); std::vector shadowCasters; if (castShadow && detail::SetupShadowMapRendering(shadowCasters, apWorld, pLightFrustum, pLightSpot, occlusionPlanes)) { - auto findBestShadowMap = [&](eShadowMapResolution resolution, iLight* light) -> cRendererDeferred::ShadowMapData* { - auto& shadowMapVec = m_shadowMapData[resolution]; - uint32_t maxFrameDistance = 0; - size_t bestIndex = 0; - for (size_t i = 0; i < shadowMapVec.size(); ++i) { - auto& shadowMap = shadowMapVec[i]; - if (shadowMap.m_light == light) { - shadowMap.m_frameCount = frame.m_currentFrame; - return &shadowMap; - } - - const uint32_t frameDist = frame.m_currentFrame - shadowMap.m_frameCount; - if (frameDist > maxFrameDistance) { - maxFrameDistance = frameDist; - bestIndex = i; - } - } - shadowMapVec[bestIndex].m_frameCount = frame.m_currentFrame; - return &shadowMapVec[bestIndex]; - }; - auto* shadowMapData = findBestShadowMap(shadowMapResolution, pLightSpot); - if (shadowMapData) { - deferredLight.m_shadowMapData = shadowMapData; - // testing if the shadow map needs to be updated - if (shadowMapData->m_transformCount != pLightSpot->GetTransformUpdateCount() || [&]() -> bool { - // Check if texture map and light are valid - if (pLightSpot->GetOcclusionCullShadowCasters()) { - return true; + const int count = pLightSpot->GetTransformUpdateCount(); + uint32_t id = folly::hash::fnv32_buf(&pLightSpot, sizeof(void*)); + if (auto result = m_shadowCache.Search(id, shadowMapResolution, frame.m_currentFrame)) { + auto poolEntry = m_shadowCmdPool.findAvaliableEntry(); + if (poolEntry) { + auto& meta = result->Meta(); + result->Mark(); // mark the slot for this frame + + if (meta.m_transformCount != pLightSpot->GetTransformUpdateCount() || [&]() -> bool { + // Check if texture map and light are valid + if (pLightSpot->GetOcclusionCullShadowCasters()) { + return true; + } + + if (pLightSpot->GetLightType() == eLightType_Spot && + (pLightSpot->GetAspect() != meta.m_aspect || pLightSpot->GetFOV() != meta.m_fov)) { + return true; + } + return !pLightSpot->ShadowCastersAreUnchanged(shadowCasters); + }()) { + meta.m_light = pLightSpot; + meta.m_transformCount = pLightSpot->GetTransformUpdateCount(); + meta.m_radius = pLightSpot->GetRadius(); + meta.m_aspect = pLightSpot->GetAspect(); + meta.m_fov = pLightSpot->GetFOV(); + + pLightSpot->SetShadowCasterCacheFromVec(shadowCasters); + + resetCmdPool(frame.m_renderer->Rend(), poolEntry->m_pool.m_handle); + + beginCmd(poolEntry->m_cmd.m_handle); + { + cmdBindRenderTargets(poolEntry->m_cmd.m_handle, 0, NULL, NULL, NULL, NULL, NULL, -1, -1); + std::array rtBarriers = { + RenderTargetBarrier{ m_shadowTarget.m_handle, + RESOURCE_STATE_SHADER_RESOURCE, + RESOURCE_STATE_DEPTH_WRITE }, + }; + cmdResourceBarrier( + poolEntry->m_cmd.m_handle, 0, NULL, 0, NULL, rtBarriers.size(), rtBarriers.data()); } - if (pLightSpot->GetLightType() == eLightType_Spot && - (pLightSpot->GetAspect() != shadowMapData->m_aspect || - pLightSpot->GetFOV() != shadowMapData->m_fov)) { - return true; + LoadActionsDesc loadActions = {}; + loadActions.mLoadActionDepth = LOAD_ACTION_CLEAR; + loadActions.mLoadActionStencil = LOAD_ACTION_DONTCARE; + loadActions.mClearDepth = { .depth = 1.0f, .stencil = 0 }; + cmdBindRenderTargets( + poolEntry->m_cmd.m_handle, + 0, + NULL, + m_shadowTarget.m_handle, + &loadActions, + NULL, + NULL, + -1, + -1); + uint4 rectangle = result->Rect(); + cmdSetViewport( + poolEntry->m_cmd.m_handle, + static_cast(rectangle.x), + static_cast(rectangle.y + rectangle.w), + static_cast(rectangle.z), + -static_cast(rectangle.w), + 0.0f, + 1.0f); + cmdSetScissor( + poolEntry->m_cmd.m_handle, + 0, + 0, + rectangle.z, + rectangle.w); + cmdBindPipeline( + poolEntry->m_cmd.m_handle, + options.m_invert ? m_zPassShadowPipelineCCW.m_handle : m_zPassShadowPipelineCW.m_handle); + + uint32_t shadowFrameIndex = updateFrameDescriptor( + frame, + poolEntry->m_cmd.m_handle, + apWorld, + { .m_size = float2(outputBuffer->mWidth, outputBuffer->mHeight), + .m_viewMat = pLightFrustum->GetViewMatrix(), + .m_projectionMat = pLightFrustum->GetProjectionMatrix() }); + cmdBindDescriptorSet( + poolEntry->m_cmd.m_handle, + shadowFrameIndex, + m_materialSet.m_frameSet[frame.m_frameIndex].m_handle); + for (auto& pObject : shadowCasters) { + eMaterialRenderMode renderMode = + pObject->GetCoverageAmount() >= 1 ? eMaterialRenderMode_Z : eMaterialRenderMode_Z_Dissolve; + cMaterial* pMaterial = pObject->GetMaterial(); + const ShaderMaterialData& descriptor = pMaterial->Descriptor(); + std::array targets = { eVertexBufferElement_Position, eVertexBufferElement_Texture0 }; + DrawPacket packet = pObject->ResolveDrawPacket(frame, targets); + if (packet.m_type == DrawPacket::Unknown || descriptor.m_id == MaterialID::Unknown) { + return; + } + MaterialRootConstant materialConst = {}; + uint32_t instance = + cmdBindMaterialAndObject(poolEntry->m_cmd.m_handle, frame, pMaterial, pObject); + materialConst.objectId = instance; + DrawPacket::cmdBindBuffers(poolEntry->m_cmd.m_handle, frame.m_resourcePool, &packet); + cmdBindPushConstants( + poolEntry->m_cmd.m_handle, + m_materialRootSignature.m_handle, + materialObjectIndex, + &materialConst); + cmdDrawIndexed(poolEntry->m_cmd.m_handle, packet.numberOfIndecies(), 0, 0); } - return !pLightSpot->ShadowCastersAreUnchanged(shadowCasters); - }()) { - shadowMapData->m_light = pLightSpot; - shadowMapData->m_transformCount = pLightSpot->GetTransformUpdateCount(); - shadowMapData->m_radius = pLightSpot->GetRadius(); - shadowMapData->m_aspect = pLightSpot->GetAspect(); - shadowMapData->m_fov = pLightSpot->GetFOV(); - - pLightSpot->SetShadowCasterCacheFromVec(shadowCasters); - - FenceStatus fenceStatus; - getFenceStatus(frame.m_renderer->Rend(), shadowMapData->m_shadowFence.m_handle, &fenceStatus); - if (fenceStatus == FENCE_STATUS_INCOMPLETE) - waitForFences(frame.m_renderer->Rend(), 1, &shadowMapData->m_shadowFence.m_handle); - resetCmdPool(frame.m_renderer->Rend(), shadowMapData->m_pool.m_handle); - - beginCmd(shadowMapData->m_cmd.m_handle); - { - cmdBindRenderTargets(shadowMapData->m_cmd.m_handle, 0, NULL, NULL, NULL, NULL, NULL, -1, -1); - std::array rtBarriers = { - RenderTargetBarrier{ - shadowMapData->m_target.m_handle, RESOURCE_STATE_SHADER_RESOURCE, RESOURCE_STATE_DEPTH_WRITE }, - }; - cmdResourceBarrier( - shadowMapData->m_cmd.m_handle, 0, NULL, 0, NULL, rtBarriers.size(), rtBarriers.data()); - } - - LoadActionsDesc loadActions = {}; - loadActions.mLoadActionDepth = LOAD_ACTION_CLEAR; - loadActions.mLoadActionStencil = LOAD_ACTION_DONTCARE; - loadActions.mClearDepth = { .depth = 1.0f, .stencil = 0 }; - cmdBindRenderTargets( - shadowMapData->m_cmd.m_handle, - 0, - NULL, - shadowMapData->m_target.m_handle, - &loadActions, - NULL, - NULL, - -1, - -1); - cmdSetViewport( - shadowMapData->m_cmd.m_handle, - 0.0f, - static_cast(shadowMapData->m_target.m_handle->mHeight), - static_cast(shadowMapData->m_target.m_handle->mWidth), - -static_cast(shadowMapData->m_target.m_handle->mHeight), - 0.0f, - 1.0f); - cmdSetScissor( - shadowMapData->m_cmd.m_handle, - 0, - 0, - shadowMapData->m_target.m_handle->mWidth, - shadowMapData->m_target.m_handle->mHeight); - cmdBindPipeline( - shadowMapData->m_cmd.m_handle, - options.m_invert ? m_zPassShadowPipelineCCW.m_handle : m_zPassShadowPipelineCW.m_handle); - - uint32_t shadowFrameIndex = updateFrameDescriptor( - frame, - shadowMapData->m_cmd.m_handle, - apWorld, - { .m_size = float2(outputBuffer->mWidth, outputBuffer->mHeight), - .m_viewMat = pLightFrustum->GetViewMatrix(), - .m_projectionMat = pLightFrustum->GetProjectionMatrix() }); - cmdBindDescriptorSet( - shadowMapData->m_cmd.m_handle, shadowFrameIndex, m_materialSet.m_frameSet[frame.m_frameIndex].m_handle); - for (auto& pObject : shadowCasters) { - eMaterialRenderMode renderMode = - pObject->GetCoverageAmount() >= 1 ? eMaterialRenderMode_Z : eMaterialRenderMode_Z_Dissolve; - cMaterial* pMaterial = pObject->GetMaterial(); - const ShaderMaterialData& descriptor = pMaterial->Descriptor(); - std::array targets = { eVertexBufferElement_Position, - eVertexBufferElement_Texture0 }; - DrawPacket packet = pObject->ResolveDrawPacket(frame, targets); - if (packet.m_type == DrawPacket::Unknown || descriptor.m_id == MaterialID::Unknown) { - return; + { + cmdBindRenderTargets(poolEntry->m_cmd.m_handle, 0, NULL, NULL, NULL, NULL, NULL, -1, -1); + std::array rtBarriers = { + RenderTargetBarrier{ m_shadowTarget.m_handle, + RESOURCE_STATE_DEPTH_WRITE, + RESOURCE_STATE_SHADER_RESOURCE }, + }; + cmdResourceBarrier( + poolEntry->m_cmd.m_handle, 0, NULL, 0, NULL, rtBarriers.size(), rtBarriers.data()); } - MaterialRootConstant materialConst = {}; - uint32_t instance = cmdBindMaterialAndObject(shadowMapData->m_cmd.m_handle, frame, pMaterial, pObject); - materialConst.objectId = instance; - DrawPacket::cmdBindBuffers(shadowMapData->m_cmd.m_handle, frame.m_resourcePool, &packet); - cmdBindPushConstants( - shadowMapData->m_cmd.m_handle, - m_materialRootSignature.m_handle, - materialObjectIndex, - &materialConst); - cmdDrawIndexed(shadowMapData->m_cmd.m_handle, packet.numberOfIndecies(), 0, 0); - } - { - cmdBindRenderTargets(shadowMapData->m_cmd.m_handle, 0, NULL, NULL, NULL, NULL, NULL, -1, -1); - std::array rtBarriers = { - RenderTargetBarrier{ - shadowMapData->m_target.m_handle, RESOURCE_STATE_DEPTH_WRITE, RESOURCE_STATE_SHADER_RESOURCE }, - }; - cmdResourceBarrier( - shadowMapData->m_cmd.m_handle, 0, NULL, 0, NULL, rtBarriers.size(), rtBarriers.data()); + endCmd(poolEntry->m_cmd.m_handle); + QueueSubmitDesc submitDesc = {}; + submitDesc.mCmdCount = 1; + submitDesc.ppCmds = &poolEntry->m_cmd.m_handle; + submitDesc.pSignalFence = poolEntry->m_fence.m_handle; + submitDesc.mSubmitDone = true; + queueSubmit(frame.m_renderer->GetGraphicsQueue(), &submitDesc); } - endCmd(shadowMapData->m_cmd.m_handle); - QueueSubmitDesc submitDesc = {}; - submitDesc.mCmdCount = 1; - submitDesc.ppCmds = &shadowMapData->m_cmd.m_handle; - submitDesc.pSignalFence = shadowMapData->m_shadowFence.m_handle; - submitDesc.mSubmitDone = true; - queueSubmit(frame.m_renderer->GetGraphicsQueue(), &submitDesc); } } } diff --git a/HPL2/sources/graphics/ShadowCache.cpp b/HPL2/sources/graphics/ShadowCache.cpp index 3dc8717af..6830b06ba 100644 --- a/HPL2/sources/graphics/ShadowCache.cpp +++ b/HPL2/sources/graphics/ShadowCache.cpp @@ -1,192 +1,11 @@ #include "graphics/ShadowCache.h" -#include "graphics/IndexPool.h" +#include #include #include #include +#include +#include -namespace hpl { - - void ShadowCache::insertAfter(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp) { - ASSERT(current); - ASSERT(grp); - uint16_t nextIdx = current->m_next; - - current->m_next = grp->m_idx; - grp->m_prev = current->m_idx; - - grp->m_next = nextIdx; - if(nextIdx != UINT16_MAX) { - m_alloc[nextIdx].m_prev = grp->m_idx; - } - } - void ShadowCache::insertBefore(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp) { - ASSERT(current); - ASSERT(grp); - uint16_t prevIdx = current->m_prev; - - current->m_prev = grp->m_idx; - grp->m_next = current->m_idx; - - grp->m_prev = prevIdx; - if(prevIdx != UINT16_MAX) { - m_alloc[prevIdx].m_next = grp->m_idx; - } - } - ShadowCache::ShadowCache(uint32_t width, uint32_t height, uint32_t hDivisions, uint32_t vDivision, uint8_t maxCuts): - m_quadSize(width/vDivision, height/ hDivisions), - m_pool((std::pow(std::max(1, (static_cast(maxCuts) - 2)), 4) + 1) * hDivisions * vDivision) { - ASSERT(m_pool.reserve() > std::numeric_limits::max()); - m_alloc.resize(m_pool.reserve()); - m_cut.resize(maxCuts); - ShadowCache::ShadowGroup* previous = nullptr; - for(size_t x = 0; x < hDivisions; x++) { - for(size_t y = 0; y < vDivision; y++) { - ShadowCache::ShadowGroup* entry = allocGroup(); - entry->m_x = m_quadSize.x * x; - entry->m_y = m_quadSize.y * y; - if(previous != nullptr) { - insertAfter(previous, entry); - } - if(previous == nullptr) { - m_cut[0].m_begin = entry->m_idx; - } - previous = entry; - } - } - } - - ShadowCache::ShadowGroup* ShadowCache::createCut(ShadowGroup* group) { - ShadowGroup* child = allocGroup(); - child->m_parent = group->m_idx; - if (group->m_child == UINT16_MAX) { - group->m_child = child->m_idx; - child->m_parent = group->m_idx; - } else { - insertAfter(&m_alloc[group->m_child], child); - } - child->m_level = group->m_level + 1; - bool found = false; - for (uint8_t i = 0; i < 4; i++) { - if ((group->m_occupyMask & (1 << i)) == 0) { - group->m_occupyMask |= (1 << i); // we are going to set this entry is occupied - uint16_t x = (i % 2); - uint16_t y = (i / 2); - child->m_slot = i; // we assign the slot we occupy for this cut - uint2 quadSize = m_quadSize / (1 << child->m_level); - group->m_x = group->m_x + (x * quadSize.x); - group->m_y = group->m_y + (y * quadSize.y); - group->m_flags |= ShadowGroup::HasGroups; - found = true; - break; - } - } - ASSERT(found); - auto& nextCut = m_cut[child->m_level]; - if (nextCut.m_begin == UINT16_MAX) { - nextCut.m_begin = child->m_idx; - } else { - insertBefore(&m_alloc[nextCut.m_begin], group); - } - - return child; - } - - uint4 ShadowCache::find(uint16_t hash, uint8_t level, uint32_t age) { - auto findGroupInCut = [&](ShadowGroup* group) { - ShadowGroup* result = nullptr; - for (uint16_t i = group->m_idx; i != UINT16_MAX; i = m_alloc[i].m_next) { - for(size_t k = 0; k < 4; k++) { - // we found a matching hash - if(m_alloc[i].m_hashes[k] == hash) { - result = &m_alloc[i]; - goto exit; - } - } - if (result == nullptr || m_alloc[i].m_age < result->m_age) { - result = &m_alloc[i]; - } - } - exit: - return result; - }; - const uint8_t targetLevel = level == 0? 0: level - 1; - auto& targetCut = m_cut[targetLevel]; - - ShadowGroup* group = findGroupInCut(&m_alloc[targetCut.m_begin]); - if(level == 0) { - freeChildren(group); - group->m_flags |= ShadowGroup::IsLeaf; - group->m_hashes[0] = hash; - group->m_age = age; - return uint4(group->m_x, group->m_y, m_quadSize.x, m_quadSize.y); - } else { - - } - return uint4(0,0,0,0); - } - - ShadowCache::ShadowGroup* ShadowCache::allocGroup() { - uint32_t index = m_pool.requestId(); - ShadowGroup* entry = &m_alloc[index]; - std::memset(entry, 0, sizeof(ShadowGroup)); - entry->m_parent = UINT16_MAX; - entry->m_child = UINT16_MAX; - entry->m_next = UINT16_MAX; - entry->m_prev = UINT16_MAX; - entry->m_idx = index; - return entry; - } - - void ShadowCache::updateAge(ShadowCache::ShadowGroup* current, uint32_t age) { - for(uint16_t i = current->m_idx; i != UINT16_MAX; i = m_alloc[i].m_parent) { - if(age > current->m_age ) { - current->m_age = age; - } - } - } - - void ShadowCache::freeChildren(ShadowCache::ShadowGroup* grp) { - if(grp->m_child != UINT16_MAX) { - for(uint32_t i = grp->m_child; i != UINT16_MAX && m_alloc[i].m_parent == grp->m_idx; i = m_alloc[i].m_next) { - m_alloc[i].m_parent = UINT16_MAX; // we invalidate the parent - freeGroup(&m_alloc[i]); - } - } - std::memset(grp->m_hashes, 0, sizeof(grp->m_hashes)); - grp->m_occupyMask = 0; - grp->m_flags &= ~(ShadowGroup::HasLeafs | ShadowGroup::HasGroups); - } - void ShadowCache::freeGroup(ShadowCache::ShadowGroup* grp) { - for(auto& cut: m_cut) { - if(cut.m_begin == grp->m_idx) { - cut.m_begin = grp->m_next; // we assign the next if UINT16_MAX then that is accepted the layer is now empty - } - } - if(grp->m_child != UINT16_MAX) { - for(uint32_t i = grp->m_child; i != UINT16_MAX && m_alloc[i].m_parent == grp->m_idx; i = m_alloc[i].m_next) { - m_alloc[i].m_parent = UINT16_MAX; // we invalidate the parent - freeGroup(&m_alloc[i]); - } - } - if(grp->m_parent != UINT16_MAX) { - auto* parent = &m_alloc[grp->m_parent]; - parent->m_occupyMask &= ~(1 << grp->m_slot); // we clear the occupy slot - if(parent->m_child == grp->m_idx) { - // if the next child has a mismatched index we've exausted cuts - if(grp->m_next != UINT16_MAX && m_alloc[grp->m_next].m_parent == parent->m_idx) { - parent->m_child = grp->m_next; - } +#include "Common_3/Graphics/Interfaces/IGraphics.h" +#include "graphics/IndexPool.h" - } - } - if(grp->m_prev != UINT16_MAX && grp->m_next != UINT16_MAX) { - m_alloc[grp->m_prev].m_next = m_alloc[grp->m_next].m_idx; - m_alloc[grp->m_next].m_prev = m_alloc[grp->m_prev].m_idx; - } else if(grp->m_prev != UINT16_MAX) { - m_alloc[grp->m_prev].m_next = UINT16_MAX; - } else if(grp->m_next != UINT16_MAX) { - m_alloc[grp->m_next].m_prev = UINT16_MAX; - } - m_pool.returnId(grp->m_idx); - } -}