Skip to content

Commit

Permalink
PBR Renderer: added option to use structured buffer for joint transforms
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Oct 31, 2024
1 parent a2247e1 commit fa21551
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Hydrogent/src/HnMaterial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions PBR/interface/GLTF_PBR_Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
14 changes: 14 additions & 0 deletions PBR/interface/PBR_Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions PBR/src/GLTF_PBR_Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,7 @@ void* GLTF_PBR_Renderer::WritePBRPrimitiveShaderAttribs(void*
UNEXPECTED("Node matrix must not be null");
}
pDstTransforms->JointCount = static_cast<int>(AttribsData.JointCount);
pDstTransforms->FirstJoint = static_cast<int>(AttribsData.FirstJoint);

static_assert(sizeof(HLSL::GLTFNodeShaderTransforms) % 16 == 0, "Size of HLSL::GLTFNodeShaderTransforms must be a multiple of 16");
pDstPtr += sizeof(HLSL::GLTFNodeShaderTransforms);
Expand Down
70 changes: 59 additions & 11 deletions PBR/src/PBR_Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
{
Expand All @@ -444,7 +467,12 @@ PBR_Renderer::PBR_Renderer(IRenderDevice* pDevice,
std::vector<StateTransitionDesc> 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<Uint32>(Barriers.size()), Barriers.data());
}

Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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<std::string> Samplers;
if (!m_Device.GetDeviceInfo().IsGLDevice())
Expand Down Expand Up @@ -1125,6 +1169,10 @@ ShaderMacroHelper PBR_Renderer::DefineMacros(const PSOKey& Key) const

ShaderMacroHelper Macros;
Macros.Add("MAX_JOINT_COUNT", static_cast<int>(m_Settings.MaxJointCount));
Macros.Add("JOINTS_BUFFER_MODE_UNIFORM", static_cast<int>(JOINTS_BUFFER_MODE_UNIFORM));
Macros.Add("JOINTS_BUFFER_MODE_STRUCTURED", static_cast<int>(JOINTS_BUFFER_MODE_STRUCTURED));
Macros.Add("JOINTS_BUFFER_MODE", static_cast<int>(m_Settings.JointsBufferMode));

Macros.Add("USE_SKIN_PRE_TRANSFORM", m_Settings.UseSkinPreTransform);
Macros.Add("TONE_MAPPING_MODE", "TONE_MAPPING_MODE_UNCHARTED2");

Expand Down
71 changes: 61 additions & 10 deletions Shaders/PBR/private/RenderPBR.vsh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<float4x4> 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);
Expand All @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion Shaders/PBR/public/PBR_Structures.fxh
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down

0 comments on commit fa21551

Please sign in to comment.