Add padding to nested structs packed with standard layout, to address HLSL's more liberal packing rules.
TRAC #23327
Signed-off-by: Geoff Lang
Signed-off-by: Shannon Woods
Authored-by: Jamie Madill
diff --git a/src/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
index 4737400..d93b68d 100644
--- a/src/compiler/OutputHLSL.cpp
+++ b/src/compiler/OutputHLSL.cpp
@@ -323,7 +323,7 @@
return padding;
}
-TString OutputHLSL::std140PostPaddingString(const TType &type)
+TString OutputHLSL::std140PostPaddingString(const TType &type, bool useHLSLRowMajorPacking)
{
if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
{
@@ -334,13 +334,25 @@
if (type.isMatrix())
{
- const bool isRowMajorMatrix = (type.getLayoutQualifier().matrixPacking == EmpRowMajor);
+ // This method can also be called from structureString, which does not use layout qualifiers.
+ // Thus, use the method parameter for determining the matrix packing.
+ //
+ // Note HLSL row major packing corresponds to GL API column-major, and vice-versa, since we
+ // wish to always transpose GL matrices to play well with HLSL's matrix array indexing.
+ //
+ const bool isRowMajorMatrix = !useHLSLRowMajorPacking;
const GLenum glType = glVariableType(type);
numComponents = gl::MatrixComponentCount(glType, isRowMajorMatrix);
}
else if (type.getBasicType() == EbtStruct)
{
- // TODO
+ const TString &structName = structureTypeName(type, useHLSLRowMajorPacking, true);
+ numComponents = mStd140StructElementIndexes[structName];
+
+ if (numComponents == 0)
+ {
+ return "";
+ }
}
else
{
@@ -378,7 +390,8 @@
// must pad out after matrices and arrays, where HLSL usually allows itself room to pack stuff
if (blockStorage == EbsStd140)
{
- hlsl += std140PostPaddingString(memberType);
+ const bool useHLSLRowMajorPacking = (memberType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
+ hlsl += std140PostPaddingString(memberType, useHLSLRowMajorPacking);
}
}
@@ -2928,13 +2941,19 @@
if (useStd140Packing)
{
- structure += std140PostPaddingString(field);
+ structure += std140PostPaddingString(field, useHLSLRowMajorPacking);
}
}
// Nameless structs do not finish with a semicolon and newline, to leave room for an instance variable
structure += (isNameless ? "} " : "};\n");
+ // Add remaining element index to the global map, for use with nested structs in standard layouts
+ if (useStd140Packing)
+ {
+ mStd140StructElementIndexes[structName] = elementIndex;
+ }
+
return structure;
}
diff --git a/src/compiler/OutputHLSL.h b/src/compiler/OutputHLSL.h
index baa4675..b097410 100644
--- a/src/compiler/OutputHLSL.h
+++ b/src/compiler/OutputHLSL.h
@@ -198,7 +198,7 @@
TString interfaceBlockStructString(const TType &interfaceBlockType);
TString interfaceBlockString(const TType &interfaceBlockType, unsigned int registerIndex, unsigned int arrayIndex);
TString std140PrePaddingString(const TType &type, int *elementIndex);
- TString std140PostPaddingString(const TType &type);
+ TString std140PostPaddingString(const TType &type, bool useHLSLRowMajorPacking);
static GLenum glVariableType(const TType &type);
static GLenum glVariablePrecision(const TType &type);
@@ -210,6 +210,7 @@
ActiveInterfaceBlocks mActiveInterfaceBlocks;
ActiveShaderVariables mActiveOutputVariables;
ActiveShaderVariables mActiveAttributes;
+ std::map<TString, int> mStd140StructElementIndexes;
};
}