Add a std140 padding helper class.
Using a helper class keeps our main parser stateless as we define
std140 structs which need padding. The only functional change
should be that we no longer use a global counter for struct padding
hidden variables, but a local padding per-struct.
BUG=angle:466
Change-Id: I8b92d65884b86571c8b2f052b0cba6150a4bbab0
Reviewed-on: https://chromium-review.googlesource.com/202911
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Reviewed-by: Nicolas Capens <nicolascapens@chromium.org>
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 112069b..f552ec1 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -25,6 +25,119 @@
namespace sh
{
+class OutputHLSL::Std140PaddingHelper
+{
+ public:
+ explicit Std140PaddingHelper(const std::map<TString, int> &structElementIndexes)
+ : mPaddingCounter(0),
+ mElementIndex(0),
+ mStructElementIndexes(structElementIndexes)
+ {}
+
+ int elementIndex() const { return mElementIndex; }
+
+ int prePadding(const TType &type)
+ {
+ if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
+ {
+ // no padding needed, HLSL will align the field to a new register
+ mElementIndex = 0;
+ return 0;
+ }
+
+ const GLenum glType = glVariableType(type);
+ const int numComponents = gl::UniformComponentCount(glType);
+
+ if (numComponents >= 4)
+ {
+ // no padding needed, HLSL will align the field to a new register
+ mElementIndex = 0;
+ return 0;
+ }
+
+ if (mElementIndex + numComponents > 4)
+ {
+ // no padding needed, HLSL will align the field to a new register
+ mElementIndex = numComponents;
+ return 0;
+ }
+
+ const int alignment = numComponents == 3 ? 4 : numComponents;
+ const int paddingOffset = (mElementIndex % alignment);
+ const int paddingCount = (paddingOffset != 0 ? (alignment - paddingOffset) : 0);
+
+ mElementIndex += paddingCount;
+ mElementIndex += numComponents;
+ mElementIndex %= 4;
+
+ return paddingCount;
+ }
+
+ TString prePaddingString(const TType &type)
+ {
+ int paddingCount = prePadding(type);
+
+ TString padding;
+
+ for (int paddingIndex = 0; paddingIndex < paddingCount; paddingIndex++)
+ {
+ padding += " float pad_" + str(mPaddingCounter++) + ";\n";
+ }
+
+ return padding;
+ }
+
+ TString postPaddingString(const TType &type, bool useHLSLRowMajorPacking)
+ {
+ if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
+ {
+ return "";
+ }
+
+ int numComponents = 0;
+
+ if (type.isMatrix())
+ {
+ // 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.getStruct())
+ {
+ const TString &structName = structureTypeName(*type.getStruct(), useHLSLRowMajorPacking, true);
+ numComponents = mStructElementIndexes.find(structName)->second;
+
+ if (numComponents == 0)
+ {
+ return "";
+ }
+ }
+ else
+ {
+ const GLenum glType = glVariableType(type);
+ numComponents = gl::UniformComponentCount(glType);
+ }
+
+ TString padding;
+ for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
+ {
+ padding += " float pad_" + str(mPaddingCounter++) + ";\n";
+ }
+ return padding;
+ }
+
+ private:
+ int mPaddingCounter;
+ int mElementIndex;
+ const std::map<TString, int> &mStructElementIndexes;
+};
+
TString OutputHLSL::TextureFunction::name() const
{
TString name = "gl_texture";
@@ -163,7 +276,6 @@
mSamplerRegister = 0;
mInterfaceBlockRegister = 2; // Reserve registers for the default uniform block and driver constants
- mPaddingCounter = 0;
}
OutputHLSL::~OutputHLSL()
@@ -316,7 +428,7 @@
{
TString hlsl;
- int elementIndex = 0;
+ Std140PaddingHelper padHelper(mStd140StructElementIndexes);
for (unsigned int typeIndex = 0; typeIndex < interfaceBlock.fields().size(); typeIndex++)
{
@@ -326,7 +438,7 @@
if (blockStorage == EbsStd140)
{
// 2 and 3 component vector types in some cases need pre-padding
- hlsl += std140PrePaddingString(fieldType, &elementIndex);
+ hlsl += padHelper.prePaddingString(fieldType);
}
hlsl += " " + interfaceBlockFieldTypeString(field, blockStorage) +
@@ -336,7 +448,7 @@
if (blockStorage == EbsStd140)
{
const bool useHLSLRowMajorPacking = (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor);
- hlsl += std140PostPaddingString(fieldType, useHLSLRowMajorPacking);
+ hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking);
}
}
@@ -377,99 +489,6 @@
return hlsl;
}
-TString OutputHLSL::std140PrePaddingString(const TType &type, int *elementIndex)
-{
- if (type.getBasicType() == EbtStruct || type.isMatrix() || type.isArray())
- {
- // no padding needed, HLSL will align the field to a new register
- *elementIndex = 0;
- return "";
- }
-
- const GLenum glType = glVariableType(type);
- const int numComponents = gl::UniformComponentCount(glType);
-
- if (numComponents >= 4)
- {
- // no padding needed, HLSL will align the field to a new register
- *elementIndex = 0;
- return "";
- }
-
- if (*elementIndex + numComponents > 4)
- {
- // no padding needed, HLSL will align the field to a new register
- *elementIndex = numComponents;
- return "";
- }
-
- TString padding;
-
- const int alignment = numComponents == 3 ? 4 : numComponents;
- const int paddingOffset = (*elementIndex % alignment);
-
- if (paddingOffset != 0)
- {
- // padding is neccessary
- for (int paddingIndex = paddingOffset; paddingIndex < alignment; paddingIndex++)
- {
- padding += " float pad_" + str(mPaddingCounter++) + ";\n";
- }
-
- *elementIndex += (alignment - paddingOffset);
- }
-
- *elementIndex += numComponents;
- *elementIndex %= 4;
-
- return padding;
-}
-
-TString OutputHLSL::std140PostPaddingString(const TType &type, bool useHLSLRowMajorPacking)
-{
- if (!type.isMatrix() && !type.isArray() && type.getBasicType() != EbtStruct)
- {
- return "";
- }
-
- int numComponents = 0;
-
- if (type.isMatrix())
- {
- // 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.getStruct())
- {
- const TString &structName = structureTypeName(*type.getStruct(), useHLSLRowMajorPacking, true);
- numComponents = mStd140StructElementIndexes[structName];
-
- if (numComponents == 0)
- {
- return "";
- }
- }
- else
- {
- const GLenum glType = glVariableType(type);
- numComponents = gl::UniformComponentCount(glType);
- }
-
- TString padding;
- for (int paddingOffset = numComponents; paddingOffset < 4; paddingOffset++)
- {
- padding += " float pad_" + str(mPaddingCounter++) + ";\n";
- }
- return padding;
-}
-
// Use the same layout for packed and shared
void setBlockLayout(gl::InterfaceBlock *interfaceBlock, gl::BlockLayoutType newLayout)
{
@@ -3401,25 +3420,27 @@
string += declareString + "\n"
"{\n";
- int elementIndex = 0;
+ Std140PaddingHelper padHelper(mStd140StructElementIndexes);
for (unsigned int i = 0; i < fields.size(); i++)
{
const TField &field = *fields[i];
const TType &fieldType = *field.type();
const TStructure *fieldStruct = fieldType.getStruct();
- const TString &fieldTypeString = fieldStruct ? structureTypeName(*fieldStruct, useHLSLRowMajorPacking, useStd140Packing) : typeString(fieldType);
+ const TString &fieldTypeString = fieldStruct ?
+ structureTypeName(*fieldStruct, useHLSLRowMajorPacking, useStd140Packing) :
+ typeString(fieldType);
if (useStd140Packing)
{
- string += std140PrePaddingString(*field.type(), &elementIndex);
+ string += padHelper.prePaddingString(fieldType);
}
string += " " + fieldTypeString + " " + decorateField(field.name(), structure) + arrayString(fieldType) + ";\n";
if (useStd140Packing)
{
- string += std140PostPaddingString(*field.type(), useHLSLRowMajorPacking);
+ string += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking);
}
}
@@ -3728,17 +3749,17 @@
void OutputHLSL::storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking)
{
- int elementIndex = 0;
+ Std140PaddingHelper padHelper(mStd140StructElementIndexes);
const TFieldList &fields = structure.fields();
for (unsigned int i = 0; i < fields.size(); i++)
{
- std140PrePaddingString(*fields[i]->type(), &elementIndex);
+ padHelper.prePadding(*fields[i]->type());
}
// Add remaining element index to the global map, for use with nested structs in standard layouts
const TString &structName = structureTypeName(structure, useHLSLRowMajorPacking, true);
- mStd140StructElementIndexes[structName] = elementIndex;
+ mStd140StructElementIndexes[structName] = padHelper.elementIndex();
}
const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)