Files
UnrealEngine/Engine/Source/ThirdParty/MaterialX/MaterialX-1.39.3/source/MaterialXGenMsl/MslResourceBindingContext.cpp
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

149 lines
5.6 KiB
C++

//
// Copyright Contributors to the MaterialX Project
// SPDX-License-Identifier: Apache-2.0
//
#include <MaterialXGenMsl/MslResourceBindingContext.h>
MATERIALX_NAMESPACE_BEGIN
//
// MslResourceBindingContext
//
MslResourceBindingContext::MslResourceBindingContext(
size_t uniformBindingLocation, size_t samplerBindingLocation) :
_hwInitUniformBindLocation(uniformBindingLocation),
_hwInitSamplerBindLocation(samplerBindingLocation)
{
}
void MslResourceBindingContext::initialize()
{
// Reset bind location counter.
_hwUniformBindLocation = _hwInitUniformBindLocation;
// Reset sampler bind location counter.
_hwSamplerBindLocation = _hwInitSamplerBindLocation;
}
void MslResourceBindingContext::emitDirectives(GenContext&, ShaderStage&)
{
}
void MslResourceBindingContext::emitResourceBindings(GenContext& context, const VariableBlock& uniforms, ShaderStage& stage)
{
const ShaderGenerator& generator = context.getShaderGenerator();
// First, emit all value uniforms in a block with single layout binding
bool hasValueUniforms = false;
for (auto uniform : uniforms.getVariableOrder())
{
if (uniform->getType() != Type::FILENAME)
{
hasValueUniforms = true;
break;
}
}
if (hasValueUniforms)
{
generator.emitLine("struct " + uniforms.getName(),
stage, false);
generator.emitScopeBegin(stage);
for (auto uniform : uniforms.getVariableOrder())
{
if (uniform->getType() != Type::FILENAME)
{
generator.emitLineBegin(stage);
generator.emitVariableDeclaration(uniform, EMPTY_STRING, context, stage, false);
generator.emitString(Syntax::SEMICOLON, stage);
generator.emitLineEnd(stage, false);
}
}
generator.emitScopeEnd(stage, true);
}
generator.emitLineBreak(stage);
}
void MslResourceBindingContext::emitStructuredResourceBindings(GenContext& context, const VariableBlock& uniforms,
ShaderStage& stage, const std::string& structInstanceName,
const std::string& arraySuffix)
{
const ShaderGenerator& generator = context.getShaderGenerator();
const size_t baseAlignment = 16;
// Values are adjusted based on
// https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
const std::unordered_map<TypeDesc, size_t, TypeDesc::Hasher> alignmentMap({ { Type::FLOAT, baseAlignment / 4 },
{ Type::INTEGER, baseAlignment / 4 },
{ Type::BOOLEAN, baseAlignment / 4 },
{ Type::COLOR3, baseAlignment },
{ Type::COLOR4, baseAlignment },
{ Type::VECTOR2, baseAlignment / 2 },
{ Type::VECTOR3, baseAlignment },
{ Type::VECTOR4, baseAlignment },
{ Type::MATRIX33, baseAlignment * 4 },
{ Type::MATRIX44, baseAlignment * 4 } });
// Get struct alignment and size
// alignment, uniform member index
vector<std::pair<size_t, size_t>> memberOrder;
size_t structSize = 0;
for (size_t i = 0; i < uniforms.size(); ++i)
{
auto it = alignmentMap.find(uniforms[i]->getType());
if (it == alignmentMap.end())
{
structSize += baseAlignment;
memberOrder.emplace_back(baseAlignment, i);
}
else
{
structSize += it->second;
memberOrder.emplace_back(it->second, i);
}
}
// Align up and determine number of padding floats to add
const size_t numPaddingfloats =
(((structSize + (baseAlignment - 1)) & ~(baseAlignment - 1)) - structSize) / 4;
// Sort order from largest to smallest
std::sort(memberOrder.begin(), memberOrder.end(),
[](const std::pair<size_t, size_t>& a, const std::pair<size_t, size_t>& b)
{
return a.first > b.first;
});
// Emit the struct
generator.emitLine("struct " + uniforms.getName(), stage, false);
generator.emitScopeBegin(stage);
for (size_t i = 0; i < uniforms.size(); ++i)
{
size_t variableIndex = memberOrder[i].second;
generator.emitLineBegin(stage);
generator.emitVariableDeclaration(
uniforms[variableIndex], EMPTY_STRING, context, stage, false);
generator.emitString(Syntax::SEMICOLON, stage);
generator.emitLineEnd(stage, false);
}
// Emit padding
for (size_t i = 0; i < numPaddingfloats; ++i)
{
generator.emitLine("float pad" + std::to_string(i), stage, true);
}
generator.emitScopeEnd(stage, true);
// Emit binding information
generator.emitLineBreak(stage);
generator.emitLine("struct " + uniforms.getName() + "_" +
stage.getName(),
stage, false);
generator.emitScopeBegin(stage);
generator.emitLine(uniforms.getName() + " " + structInstanceName + arraySuffix, stage);
generator.emitScopeEnd(stage, true);
}
MATERIALX_NAMESPACE_END