Skip to content

Commit

Permalink
HnMaterial: improved standard static texture indexing
Browse files Browse the repository at this point in the history
Do not allocate slots for textures not used by the renderer,
e.g. PHYS_DESC when UseSeparateMetallicRoughnessTextures is true
  • Loading branch information
TheMostDiligent committed Apr 5, 2024
1 parent a462038 commit c0bfd10
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 56 deletions.
110 changes: 56 additions & 54 deletions Hydrogent/src/HnMaterial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,17 +614,20 @@ RefCntAutoPtr<IObject> HnMaterial::CreateSRBCache()
}

// If possible, applies standard texture indexing to reduce the number of shader permutations, e.g.:
// TexIds StdTexIds SRB
// 1 0 Atlas1
// 2 => 1 Atlas2
// 0 2 Atlas0
// 0 3 Atlas0
//
// TexIds StdTexIds SRB
// 2 0 Atlas2
// 0 => 1 Atlas0
// 1 2 Atlas1
// 2 3 Atlas2
// StdTexIds TexIds0 TexArray StdTexArray0
// 0 1 Atlas0 Atlas1
// 1 - - - - - >2 - . Atlas1 Atlas2
// 2 0 ' - ->Atlas2 Atlas0 X is the texture not used by the renderer, e.g. PHYS_DESC
// X -1 Null Atlas0 when UseSeparateMetallicRoughnessTextures is true.
// 3 0 Null
//
// StdTexIds TexIds1 TexArray StdTexArray1
// 0 2 Atlas0 Atlas2
// 1 0 Atlas1 Atlas0
// 2 1 . - ->Atlas2 Atlas1
// X -1 .' Null Atlas2
// 3 - - - - - >2 -' Null
//
//
// \note HnRenderPass always enables the following textures (see HnRenderPass::GetMaterialPSOFlags):
Expand All @@ -640,60 +643,58 @@ RefCntAutoPtr<IObject> HnMaterial::CreateSRBCache()
//
// For pipelines that use additional textures, we can still use standard indexing for the
// first TexturesArraySize PBR textures and use custom indexing for the rest.
static bool ApplyStandardStaticTextureIndexing(const Uint32 TexturesArraySize,
static bool ApplyStandardStaticTextureIndexing(const PBR_Renderer::CreateInfo& RendererSettings,
PBR_Renderer::StaticShaderTextureIdsArrayType& StaticShaderTexIds,
std::vector<ITexture*>& TexArray)
{
bool UseStandardIndexing = false;
if (TexturesArraySize >= StaticShaderTexIds.size())
{
// We can always use standard texture indexing if the texture array size is greater than the
// number of PBR textures. We can simply use one slot for each texture:
// BASE_COLOR -> 0
// NORMAL -> 1
// ...
// THICKNESS -> 16
UseStandardIndexing = true;
}
else
{
// Check if only the first TexturesArraySize PBR textures are used.
UseStandardIndexing = true;
for (size_t i = TexturesArraySize; i < StaticShaderTexIds.size(); ++i)
{
if (StaticShaderTexIds[i] != PBR_Renderer::InvalidMaterialTextureId)
{
UseStandardIndexing = false;
break;
}
}
}
const Uint32 TexturesArraySize = RendererSettings.MaterialTexturesArraySize;

if (!UseStandardIndexing)
return false;
PBR_Renderer::StaticShaderTextureIdsArrayType StdStaticShaderTexIds;
StdStaticShaderTexIds.fill(decltype(PBR_Renderer::InvalidMaterialTextureId){PBR_Renderer::InvalidMaterialTextureId});

// Remapped texture array
// StdTexArray StdTexIds TexIds TexArray
// Atlas2 0 2 . -> Atlas0
// Atlas0 - - - > 1 - - - - > 0 - ' Atlas1
// Atlas0 2 0 Atlas2
// Atlas1 3 1 Null
std::vector<ITexture*> StdTexArray(TexArray.size());
VERIFY_EXPR(StdTexArray.size() == TexturesArraySize);

PBR_Renderer::StaticShaderTextureIdsArrayType StdStaticShaderTexIds;
StdStaticShaderTexIds.fill(decltype(PBR_Renderer::InvalidMaterialTextureId){PBR_Renderer::InvalidMaterialTextureId});
// Skip texture attribs not used by the renderer.
const Uint32 DisabledAttribsMask = RendererSettings.UseSeparateMetallicRoughnessTextures ?
(1u << PBR_Renderer::TEXTURE_ATTRIB_ID_PHYS_DESC) :
(1u << PBR_Renderer::TEXTURE_ATTRIB_ID_METALLIC) | (1u << PBR_Renderer::TEXTURE_ATTRIB_ID_ROUGHNESS);

for (PBR_Renderer::StaticShaderTextureIdsArrayType::value_type i = 0; i < std::min<size_t>(StaticShaderTexIds.size(), TexturesArraySize); ++i)
Uint16 Slot = 0;
for (Uint32 TexAttribId = 0; TexAttribId < StaticShaderTexIds.size(); ++TexAttribId)
{
StdStaticShaderTexIds[i] = i;
if ((DisabledAttribsMask & (1 << TexAttribId)) != 0)
{
VERIFY(StaticShaderTexIds[TexAttribId] == PBR_Renderer::InvalidMaterialTextureId, "Disabled texture slot must not be used");
continue;
}

const auto TexId = StaticShaderTexIds[i];
if (TexId != PBR_Renderer::InvalidMaterialTextureId)
if (Slot < TexturesArraySize)
{
// Use first TexturesArraySize textures for standard indexing
StdStaticShaderTexIds[TexAttribId] = Slot;

// StdTexIds StdTexArray TexIds TexArray
// 0 [0] Atlas2 2 . - ->Atlas0
// 1 - - - >[1] Atlas0 - - - - >0 - ' Atlas1
// 2 [2] Atlas1 1 . - ->Atlas2
// X . ->[3] Atlas2 - . -1 .' Null
// 3 - ' ' - ->2 -' Null
const auto TexId = StaticShaderTexIds[TexAttribId];
if (TexId != PBR_Renderer::InvalidMaterialTextureId)
{
VERIFY(TexId < TexturesArraySize, "Texture index exceeds the array size. This must be a bug.");
VERIFY(TexArray[TexId] != nullptr, "Texture can't be null. This appears to be a bug.");
StdTexArray[Slot] = TexArray[TexId];
}

++Slot;
}
else if (StaticShaderTexIds[TexAttribId] != PBR_Renderer::InvalidMaterialTextureId)
{
VERIFY(TexId < TexturesArraySize, "Texture index exceeds the array size. This must be a bug.");
VERIFY(TexArray[TexId] != nullptr, "Texture can't be null. This appears to be a bug.");
StdTexArray[i] = TexArray[TexId];
// The texture doesn't fit into the standard array
return false;
}
}

Expand Down Expand Up @@ -722,8 +723,9 @@ void HnMaterial::UpdateSRB(HnRenderDelegate& RendererDelegate)
if (m_SRB)
return;

USD_Renderer& UsdRenderer = *RendererDelegate.GetUSDRenderer();
const Uint32 TexturesArraySize = UsdRenderer.GetSettings().MaterialTexturesArraySize;
const USD_Renderer& UsdRenderer = *RendererDelegate.GetUSDRenderer();
const PBR_Renderer::CreateInfo& RendererSettings = UsdRenderer.GetSettings();
const Uint32 TexturesArraySize = RendererSettings.MaterialTexturesArraySize;

// Texture array to bind to "g_MaterialTextures"
std::vector<ITexture*> TexArray;
Expand Down Expand Up @@ -878,7 +880,7 @@ void HnMaterial::UpdateSRB(HnRenderDelegate& RendererDelegate)
}

// Try to use standard texture indexing to reduce the number of shader permutations.
ApplyStandardStaticTextureIndexing(TexturesArraySize, StaticShaderTexIds, TexArray);
ApplyStandardStaticTextureIndexing(RendererSettings, StaticShaderTexIds, TexArray);

// Construct SRB key from texture atlas object ids
for (auto& Tex : TexArray)
Expand Down
2 changes: 1 addition & 1 deletion PBR/interface/PBR_Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ class PBR_Renderer
Uint32 NumThetaSamples = 32,
bool OptimizeSamples = true);

void CreateResourceBinding(IShaderResourceBinding** ppSRB, Uint32 Idx = 0);
void CreateResourceBinding(IShaderResourceBinding** ppSRB, Uint32 Idx = 0) const;

#define PSO_FLAG_BIT(Bit) (Uint64{1} << Uint64{Bit})
enum PSO_FLAGS : Uint64
Expand Down
2 changes: 1 addition & 1 deletion PBR/src/PBR_Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1533,7 +1533,7 @@ void PBR_Renderer::CreatePSO(PsoHashMapType& PsoHashMap, const GraphicsPipelineD
}
}

void PBR_Renderer::CreateResourceBinding(IShaderResourceBinding** ppSRB, Uint32 Idx)
void PBR_Renderer::CreateResourceBinding(IShaderResourceBinding** ppSRB, Uint32 Idx) const
{
m_ResourceSignatures[Idx]->CreateShaderResourceBinding(ppSRB, true);
}
Expand Down

0 comments on commit c0bfd10

Please sign in to comment.