From fa215514757ce2e4918416c81dadbd39ab7fe9db Mon Sep 17 00:00:00 2001 From: assiduous Date: Wed, 30 Oct 2024 20:46:28 -0700 Subject: [PATCH] PBR Renderer: added option to use structured buffer for joint transforms --- Hydrogent/src/HnMaterial.cpp | 2 +- PBR/interface/GLTF_PBR_Renderer.hpp | 1 + PBR/interface/PBR_Renderer.hpp | 14 ++++++ PBR/src/GLTF_PBR_Renderer.cpp | 1 + PBR/src/PBR_Renderer.cpp | 70 +++++++++++++++++++++----- Shaders/PBR/private/RenderPBR.vsh | 71 +++++++++++++++++++++++---- Shaders/PBR/public/PBR_Structures.fxh | 2 +- 7 files changed, 138 insertions(+), 23 deletions(-) diff --git a/Hydrogent/src/HnMaterial.cpp b/Hydrogent/src/HnMaterial.cpp index 09cdd8b5..9a833122 100644 --- a/Hydrogent/src/HnMaterial.cpp +++ b/Hydrogent/src/HnMaterial.cpp @@ -1133,7 +1133,7 @@ bool HnMaterial::UpdateSRB(HnRenderDelegate& RendererDelegate) const Uint32 PBRPrimitiveAttribsSize = UsdRenderer.GetPBRPrimitiveAttribsSize(PSOFlags); const Uint32 PrimitiveArraySize = std::max(UsdRenderer.GetSettings().PrimitiveArraySize, 1u); SRBCache->UpdatePrimitiveAttribsBufferRange(m_SRB, PBRPrimitiveAttribsSize * PrimitiveArraySize); - m_JointTransformsVar = m_SRB->GetVariableByName(SHADER_TYPE_VERTEX, "cbJointTransforms"); + m_JointTransformsVar = m_SRB->GetVariableByName(SHADER_TYPE_VERTEX, UsdRenderer.GetJointTransformsVarName()); VERIFY_EXPR(m_JointTransformsVar != nullptr || RendererSettings.MaxJointCount == 0); } else diff --git a/PBR/interface/GLTF_PBR_Renderer.hpp b/PBR/interface/GLTF_PBR_Renderer.hpp index b8271ca3..4e557602 100644 --- a/PBR/interface/GLTF_PBR_Renderer.hpp +++ b/PBR/interface/GLTF_PBR_Renderer.hpp @@ -254,6 +254,7 @@ class GLTF_PBR_Renderer : public PBR_Renderer const float4x4* NodeMatrix = nullptr; const float4x4* PrevNodeMatrix = nullptr; const Uint32 JointCount = 0; + const Uint32 FirstJoint = 0; const void* CustomData = nullptr; size_t CustomDataSize = 0; diff --git a/PBR/interface/PBR_Renderer.hpp b/PBR/interface/PBR_Renderer.hpp index 0efd0abe..7ebe4ad0 100644 --- a/PBR/interface/PBR_Renderer.hpp +++ b/PBR/interface/PBR_Renderer.hpp @@ -118,6 +118,16 @@ class PBR_Renderer SHADER_TEXTURE_ARRAY_MODE_DYNAMIC }; + /// Skinning joints buffer mode. + enum JOINTS_BUFFER_MODE : Uint8 + { + /// Joints are stored in a uniform buffer. + JOINTS_BUFFER_MODE_UNIFORM = 0, + + /// Joints are stored in a structured buffer. + JOINTS_BUFFER_MODE_STRUCTURED, + }; + /// Renderer create info struct CreateInfo { @@ -257,6 +267,9 @@ class PBR_Renderer /// If set to 0, the animation will be disabled. Uint32 MaxJointCount = 64; + /// Joints buffer mode. + JOINTS_BUFFER_MODE JointsBufferMode = JOINTS_BUFFER_MODE_UNIFORM; + /// The number of samples for BRDF LUT creation. Uint32 NumBRDFSamples = 512; @@ -706,6 +719,7 @@ class PBR_Renderer static Uint32 GetJointsDataSize(Uint32 MaxJointCount, bool UseSkinPreTransform, bool UsePrevFrameTransforms); Uint32 GetJointsDataSize(Uint32 JointCount, PSO_FLAGS PSOFlags) const; Uint32 GetJointsBufferSize() const; + const char* GetJointTransformsVarName() const; protected: ShaderMacroHelper DefineMacros(const PSOKey& Key) const; diff --git a/PBR/src/GLTF_PBR_Renderer.cpp b/PBR/src/GLTF_PBR_Renderer.cpp index bd43c3ea..069af9ab 100644 --- a/PBR/src/GLTF_PBR_Renderer.cpp +++ b/PBR/src/GLTF_PBR_Renderer.cpp @@ -748,6 +748,7 @@ void* GLTF_PBR_Renderer::WritePBRPrimitiveShaderAttribs(void* UNEXPECTED("Node matrix must not be null"); } pDstTransforms->JointCount = static_cast(AttribsData.JointCount); + pDstTransforms->FirstJoint = static_cast(AttribsData.FirstJoint); static_assert(sizeof(HLSL::GLTFNodeShaderTransforms) % 16 == 0, "Size of HLSL::GLTFNodeShaderTransforms must be a multiple of 16"); pDstPtr += sizeof(HLSL::GLTFNodeShaderTransforms); diff --git a/PBR/src/PBR_Renderer.cpp b/PBR/src/PBR_Renderer.cpp index 4a16a5be..9fa08c2a 100644 --- a/PBR/src/PBR_Renderer.cpp +++ b/PBR/src/PBR_Renderer.cpp @@ -255,6 +255,13 @@ Uint32 PBR_Renderer::GetJointsBufferSize() const 0; } +const char* PBR_Renderer::GetJointTransformsVarName() const +{ + return m_Settings.JointsBufferMode == JOINTS_BUFFER_MODE_UNIFORM ? + "cbJointTransforms" : + "g_JointTransforms"; +} + PBR_Renderer::PBR_Renderer(IRenderDevice* pDevice, IRenderStateCache* pStateCache, IDeviceContext* pCtx, @@ -434,7 +441,23 @@ PBR_Renderer::PBR_Renderer(IRenderDevice* pDevice, const Uint32 JointsBufferSize = GetJointsBufferSize(); if (!m_JointsBuffer) { - CreateUniformBuffer(pDevice, JointsBufferSize, "PBR joint transforms", &m_JointsBuffer); + BufferDesc JointsBuffDesc; + JointsBuffDesc.Name = "PBR joint transforms"; + JointsBuffDesc.Size = JointsBufferSize; + JointsBuffDesc.Usage = USAGE_DYNAMIC; + JointsBuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE; + if (m_Settings.JointsBufferMode == JOINTS_BUFFER_MODE_UNIFORM) + { + JointsBuffDesc.BindFlags = BIND_UNIFORM_BUFFER; + } + else + { + JointsBuffDesc.Mode = BUFFER_MODE_STRUCTURED; + JointsBuffDesc.BindFlags = BIND_SHADER_RESOURCE; + JointsBuffDesc.ElementByteStride = sizeof(float4x4); + } + pDevice->CreateBuffer(JointsBuffDesc, nullptr, &m_JointsBuffer); + VERIFY_EXPR(m_JointsBuffer); } else { @@ -444,7 +467,12 @@ PBR_Renderer::PBR_Renderer(IRenderDevice* pDevice, std::vector Barriers; Barriers.emplace_back(m_PBRPrimitiveAttribsCB, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_CONSTANT_BUFFER, STATE_TRANSITION_FLAG_UPDATE_STATE); if (m_JointsBuffer) - Barriers.emplace_back(m_JointsBuffer, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_CONSTANT_BUFFER, STATE_TRANSITION_FLAG_UPDATE_STATE); + { + const RESOURCE_STATE JointsBufferState = m_Settings.JointsBufferMode == JOINTS_BUFFER_MODE_UNIFORM ? + RESOURCE_STATE_CONSTANT_BUFFER : + RESOURCE_STATE_SHADER_RESOURCE; + Barriers.emplace_back(m_JointsBuffer, RESOURCE_STATE_UNKNOWN, JointsBufferState, STATE_TRANSITION_FLAG_UPDATE_STATE); + } pCtx->TransitionResourceStates(static_cast(Barriers.size()), Barriers.data()); } @@ -840,7 +868,7 @@ void PBR_Renderer::InitCommonSRBVars(IShaderResourceBinding* pSRB, if (BindPrimitiveAttribsBuffer) { - if (auto* pVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "cbPrimitiveAttribs")) + if (IShaderResourceVariable* pVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "cbPrimitiveAttribs")) { if (pVar->Get() == nullptr) pVar->Set(m_PBRPrimitiveAttribsCB); @@ -849,34 +877,45 @@ void PBR_Renderer::InitCommonSRBVars(IShaderResourceBinding* pSRB, if (m_Settings.MaxJointCount > 0) { - if (auto* pVar = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, "cbJointTransforms")) + if (IShaderResourceVariable* pVar = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, GetJointTransformsVarName())) { if (pVar->Get() == nullptr) { - const Uint32 JointsBufferSize = GetJointsBufferSize(); - pVar->SetBufferRange(m_JointsBuffer, 0, JointsBufferSize); + if (m_Settings.JointsBufferMode == JOINTS_BUFFER_MODE_UNIFORM) + { + const Uint32 JointsBufferSize = GetJointsBufferSize(); + pVar->SetBufferRange(m_JointsBuffer, 0, JointsBufferSize); + } + else if (m_Settings.JointsBufferMode == JOINTS_BUFFER_MODE_STRUCTURED) + { + pVar->Set(m_JointsBuffer->GetDefaultView(BUFFER_VIEW_SHADER_RESOURCE)); + } + else + { + UNEXPECTED("Unexpected joints buffer mode"); + } } } } if (pFrameAttribs != nullptr) { - if (auto* pVar = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, "cbFrameAttribs")) + if (IShaderResourceVariable* pVar = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, "cbFrameAttribs")) pVar->Set(pFrameAttribs); } if (m_Settings.EnableIBL) { - if (auto* pIrradianceMapPSVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_IrradianceMap")) + if (IShaderResourceVariable* pIrradianceMapPSVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_IrradianceMap")) pIrradianceMapPSVar->Set(m_pIrradianceCubeSRV); - if (auto* pPrefilteredEnvMap = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_PrefilteredEnvMap")) + if (IShaderResourceVariable* pPrefilteredEnvMap = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_PrefilteredEnvMap")) pPrefilteredEnvMap->Set(m_pPrefilteredEnvMapSRV); } if (m_Settings.EnableShadows && pShadowMap != nullptr) { - if (auto* pShadowMapVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_ShadowMap")) + if (IShaderResourceVariable* pShadowMapVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_ShadowMap")) pShadowMapVar->Set(pShadowMap); } } @@ -935,7 +974,12 @@ void PBR_Renderer::CreateSignature() .AddResource(SHADER_TYPE_VS_PS, "cbPrimitiveAttribs", SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE); if (m_Settings.MaxJointCount > 0) - SignatureDesc.AddResource(SHADER_TYPE_VERTEX, "cbJointTransforms", SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE); + { + const SHADER_RESOURCE_TYPE JointsBufferResType = m_Settings.JointsBufferMode == JOINTS_BUFFER_MODE_UNIFORM ? + SHADER_RESOURCE_TYPE_CONSTANT_BUFFER : + SHADER_RESOURCE_TYPE_BUFFER_SRV; + SignatureDesc.AddResource(SHADER_TYPE_VERTEX, GetJointTransformsVarName(), JointsBufferResType, SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE); + } std::unordered_set Samplers; if (!m_Device.GetDeviceInfo().IsGLDevice()) @@ -1125,6 +1169,10 @@ ShaderMacroHelper PBR_Renderer::DefineMacros(const PSOKey& Key) const ShaderMacroHelper Macros; Macros.Add("MAX_JOINT_COUNT", static_cast(m_Settings.MaxJointCount)); + Macros.Add("JOINTS_BUFFER_MODE_UNIFORM", static_cast(JOINTS_BUFFER_MODE_UNIFORM)); + Macros.Add("JOINTS_BUFFER_MODE_STRUCTURED", static_cast(JOINTS_BUFFER_MODE_STRUCTURED)); + Macros.Add("JOINTS_BUFFER_MODE", static_cast(m_Settings.JointsBufferMode)); + Macros.Add("USE_SKIN_PRE_TRANSFORM", m_Settings.UseSkinPreTransform); Macros.Add("TONE_MAPPING_MODE", "TONE_MAPPING_MODE_UNCHARTED2"); diff --git a/Shaders/PBR/private/RenderPBR.vsh b/Shaders/PBR/private/RenderPBR.vsh index 38fb0e93..1137196a 100644 --- a/Shaders/PBR/private/RenderPBR.vsh +++ b/Shaders/PBR/private/RenderPBR.vsh @@ -57,6 +57,9 @@ cbuffer cbPrimitiveAttribs #if MAX_JOINT_COUNT > 0 && USE_JOINTS + +#if JOINTS_BUFFER_MODE == JOINTS_BUFFER_MODE_UNIFORM + struct SkinnigData { #if USE_SKIN_PRE_TRANSFORM @@ -77,8 +80,55 @@ cbuffer cbJointTransforms { SkinnigData g_Skin; } + +float4x4 GetJointMatrix(int JointIndex, int FirstJoint) +{ + return g_Skin.Joints[JointIndex]; +} + +#if USE_SKIN_PRE_TRANSFORM +float4x4 GetSkinPretransform(int FirstJoint) +{ + return g_Skin.PreTransform; +} +#if COMPUTE_MOTION_VECTORS +float4x4 GetPrevSkinPretransform(int FirstJoint) +{ + return g_Skin.PrevPreTransform; +} +#endif +#endif + +#elif JOINTS_BUFFER_MODE == JOINTS_BUFFER_MODE_STRUCTURED + +StructuredBuffer g_JointTransforms; + +float4x4 GetJointMatrix(int JointIndex, int FirstJoint) +{ + JointIndex += FirstJoint; +#if USE_SKIN_PRE_TRANSFORM + JointIndex += 1; // Skip skin pre-transform +# if COMPUTE_MOTION_VECTORS + JointIndex += 1; // Skip skin pre-transform for previous frame +# endif #endif + return g_JointTransforms[JointIndex]; +} +float4x4 GetSkinPretransform(int FirstJoint) +{ + return g_JointTransforms[FirstJoint]; +} +float4x4 GetPrevSkinPretransform(int FirstJoint) +{ + return g_JointTransforms[FirstJoint + 1]; +} + +#endif // JOINTS_BUFFER_MODE == JOINTS_BUFFER_MODE_STRUCTURED + +#endif // MAX_JOINT_COUNT > 0 && USE_JOINTS + + float4 GetVertexColor(float3 Color) { return float4(Color, 1.0); @@ -103,32 +153,33 @@ void main(in VSInput VSIn, #if MAX_JOINT_COUNT > 0 && USE_JOINTS int JointCount = PRIMITIVE.Transforms.JointCount; + int FirstJoint = PRIMITIVE.Transforms.FirstJoint; if (JointCount > 0) { // Mesh is skinned float4x4 SkinMat = - VSIn.Weight0.x * g_Skin.Joints[int(VSIn.Joint0.x)] + - VSIn.Weight0.y * g_Skin.Joints[int(VSIn.Joint0.y)] + - VSIn.Weight0.z * g_Skin.Joints[int(VSIn.Joint0.z)] + - VSIn.Weight0.w * g_Skin.Joints[int(VSIn.Joint0.w)]; + VSIn.Weight0.x * GetJointMatrix(int(VSIn.Joint0.x), FirstJoint) + + VSIn.Weight0.y * GetJointMatrix(int(VSIn.Joint0.y), FirstJoint) + + VSIn.Weight0.z * GetJointMatrix(int(VSIn.Joint0.z), FirstJoint) + + VSIn.Weight0.w * GetJointMatrix(int(VSIn.Joint0.w), FirstJoint); Transform = mul(SkinMat, Transform); # if USE_SKIN_PRE_TRANSFORM { - Transform = mul(g_Skin.PreTransform, Transform); + Transform = mul(GetSkinPretransform(FirstJoint), Transform); } # endif # if COMPUTE_MOTION_VECTORS { float4x4 PrevSkinMat = - VSIn.Weight0.x * g_Skin.Joints[JointCount + int(VSIn.Joint0.x)] + - VSIn.Weight0.y * g_Skin.Joints[JointCount + int(VSIn.Joint0.y)] + - VSIn.Weight0.z * g_Skin.Joints[JointCount + int(VSIn.Joint0.z)] + - VSIn.Weight0.w * g_Skin.Joints[JointCount + int(VSIn.Joint0.w)]; + VSIn.Weight0.x * GetJointMatrix(JointCount + int(VSIn.Joint0.x), FirstJoint) + + VSIn.Weight0.y * GetJointMatrix(JointCount + int(VSIn.Joint0.y), FirstJoint) + + VSIn.Weight0.z * GetJointMatrix(JointCount + int(VSIn.Joint0.z), FirstJoint) + + VSIn.Weight0.w * GetJointMatrix(JointCount + int(VSIn.Joint0.w), FirstJoint); PrevTransform = mul(PrevSkinMat, PrevTransform); # if USE_SKIN_PRE_TRANSFORM { - PrevTransform = mul(g_Skin.PrevPreTransform, PrevTransform); + PrevTransform = mul(GetPrevSkinPretransform(FirstJoint), PrevTransform); } # endif } diff --git a/Shaders/PBR/public/PBR_Structures.fxh b/Shaders/PBR/public/PBR_Structures.fxh index 56e9cc32..b24b7107 100644 --- a/Shaders/PBR/public/PBR_Structures.fxh +++ b/Shaders/PBR/public/PBR_Structures.fxh @@ -73,7 +73,7 @@ struct GLTFNodeShaderTransforms float4x4 NodeMatrix; int JointCount; - float Dummy0; + int FirstJoint; // Index of the first joint in the joints buffer to start from float Dummy1; float Dummy2; };