Commit 8c78ce4b by Jamie Madill Committed by Commit Bot

Use visitor pattern for Shader Variable APIs.

In many places in ANGLE we need to traverse a ShaderVariable tree. We do this to store uniform offset and other information, to flatten the tree of uniforms for the front-end, or to produce active variable lists for uniform and shader storage blocks. In each case, we would write separate tree traversal code. This patch introduces a shared visitor pattern for all of the shader variable tree traversal instances. With that get more common code. Also it is easier to write new variable traversals. ProgramD3D and ProgramLinkedResources in particular get nice simplificiations. The visitor object recieves callbacks from the traversal when entering structs, array elements, and new variables. The visitor can treat these differently depending on the use case. A common visitor that constructs full variable names is used as a base class in several places. Also moves the 'isRowMajorLayout' from sh::InterfaceBlockField to sh::ShaderVariable. This allows us to forgo using templates in several call sites. Bug: angleproject:3024 Change-Id: I472d81ec775e2eee92fb3d2eb0ca83860221ba2e Reviewed-on: https://chromium-review.googlesource.com/c/1358722 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent e321940c
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 202 #define ANGLE_SH_VERSION 203
enum ShShaderSpec enum ShShaderSpec
{ {
......
...@@ -106,7 +106,7 @@ struct ShaderVariable ...@@ -106,7 +106,7 @@ struct ShaderVariable
// If no match is found, return false. // If no match is found, return false.
bool findInfoByMappedName(const std::string &mappedFullName, bool findInfoByMappedName(const std::string &mappedFullName,
const ShaderVariable **leafVar, const ShaderVariable **leafVar,
std::string* originalFullName) const; std::string *originalFullName) const;
bool isBuiltIn() const; bool isBuiltIn() const;
bool isEmulatedBuiltIn() const; bool isEmulatedBuiltIn() const;
...@@ -125,7 +125,14 @@ struct ShaderVariable ...@@ -125,7 +125,14 @@ struct ShaderVariable
// int a[3][4]; // int a[3][4];
// then the flattenedOffsetInParentArrays of a[2] would be 2. // then the flattenedOffsetInParentArrays of a[2] would be 2.
// and flattenedOffsetInParentArrays of a[2][1] would be 2*4 + 1 = 9. // and flattenedOffsetInParentArrays of a[2][1] would be 2*4 + 1 = 9.
unsigned int flattenedOffsetInParentArrays; int parentArrayIndex() const
{
return hasParentArrayIndex() ? flattenedOffsetInParentArrays : 0;
}
void setParentArrayIndex(int index) { flattenedOffsetInParentArrays = index; }
bool hasParentArrayIndex() const { return flattenedOffsetInParentArrays != -1; }
// Static use means that the variable is accessed somewhere in the shader source. // Static use means that the variable is accessed somewhere in the shader source.
bool staticUse; bool staticUse;
...@@ -136,16 +143,18 @@ struct ShaderVariable ...@@ -136,16 +143,18 @@ struct ShaderVariable
std::vector<ShaderVariable> fields; std::vector<ShaderVariable> fields;
std::string structName; std::string structName;
// Only applies to interface block fields. Kept here for simplicity.
bool isRowMajorLayout;
protected: protected:
bool isSameVariableAtLinkTime(const ShaderVariable &other, bool isSameVariableAtLinkTime(const ShaderVariable &other,
bool matchPrecision, bool matchPrecision,
bool matchName) const; bool matchName) const;
bool operator==(const ShaderVariable &other) const; bool operator==(const ShaderVariable &other) const;
bool operator!=(const ShaderVariable &other) const bool operator!=(const ShaderVariable &other) const { return !operator==(other); }
{
return !operator==(other); int flattenedOffsetInParentArrays;
}
}; };
// A variable with an integer location to pass back to the GL API: either uniform (can have location // A variable with an integer location to pass back to the GL API: either uniform (can have location
...@@ -169,10 +178,7 @@ struct Uniform : public VariableWithLocation ...@@ -169,10 +178,7 @@ struct Uniform : public VariableWithLocation
Uniform(const Uniform &other); Uniform(const Uniform &other);
Uniform &operator=(const Uniform &other); Uniform &operator=(const Uniform &other);
bool operator==(const Uniform &other) const; bool operator==(const Uniform &other) const;
bool operator!=(const Uniform &other) const bool operator!=(const Uniform &other) const { return !operator==(other); }
{
return !operator==(other);
}
int binding; int binding;
int offset; int offset;
...@@ -216,19 +222,13 @@ struct InterfaceBlockField : public ShaderVariable ...@@ -216,19 +222,13 @@ struct InterfaceBlockField : public ShaderVariable
InterfaceBlockField(const InterfaceBlockField &other); InterfaceBlockField(const InterfaceBlockField &other);
InterfaceBlockField &operator=(const InterfaceBlockField &other); InterfaceBlockField &operator=(const InterfaceBlockField &other);
bool operator==(const InterfaceBlockField &other) const; bool operator==(const InterfaceBlockField &other) const;
bool operator!=(const InterfaceBlockField &other) const bool operator!=(const InterfaceBlockField &other) const { return !operator==(other); }
{
return !operator==(other);
}
// Decide whether two InterfaceBlock fields are the same at shader // Decide whether two InterfaceBlock fields are the same at shader
// link time, assuming one from vertex shader and the other from // link time, assuming one from vertex shader and the other from
// fragment shader. // fragment shader.
// See GLSL ES Spec 3.00.3, sec 4.3.7. // See GLSL ES Spec 3.00.3, sec 4.3.7.
bool isSameInterfaceBlockFieldAtLinkTime( bool isSameInterfaceBlockFieldAtLinkTime(const InterfaceBlockField &other) const;
const InterfaceBlockField &other) const;
bool isRowMajorLayout;
}; };
struct Varying : public VariableWithLocation struct Varying : public VariableWithLocation
...@@ -238,10 +238,7 @@ struct Varying : public VariableWithLocation ...@@ -238,10 +238,7 @@ struct Varying : public VariableWithLocation
Varying(const Varying &other); Varying(const Varying &other);
Varying &operator=(const Varying &other); Varying &operator=(const Varying &other);
bool operator==(const Varying &other) const; bool operator==(const Varying &other) const;
bool operator!=(const Varying &other) const bool operator!=(const Varying &other) const { return !operator==(other); }
{
return !operator==(other);
}
// Decide whether two varyings are the same at shader link time, // Decide whether two varyings are the same at shader link time,
// assuming one from vertex shader and the other from fragment shader. // assuming one from vertex shader and the other from fragment shader.
...@@ -299,8 +296,7 @@ struct WorkGroupSize ...@@ -299,8 +296,7 @@ struct WorkGroupSize
WorkGroupSize() = default; WorkGroupSize() = default;
explicit constexpr WorkGroupSize(int initialSize) explicit constexpr WorkGroupSize(int initialSize)
: localSizeQualifiers{initialSize, initialSize, initialSize} : localSizeQualifiers{initialSize, initialSize, initialSize}
{ {}
}
void fill(int fillValue); void fill(int fillValue);
void setLocalSize(int localSizeX, int localSizeY, int localSizeZ); void setLocalSize(int localSizeX, int localSizeY, int localSizeZ);
...@@ -328,4 +324,4 @@ struct WorkGroupSize ...@@ -328,4 +324,4 @@ struct WorkGroupSize
} // namespace sh } // namespace sh
#endif // GLSLANG_SHADERVARS_H_ #endif // GLSLANG_SHADERVARS_H_
...@@ -31,16 +31,18 @@ bool InterpolationTypesMatch(InterpolationType a, InterpolationType b) ...@@ -31,16 +31,18 @@ bool InterpolationTypesMatch(InterpolationType a, InterpolationType b)
return (GetNonAuxiliaryInterpolationType(a) == GetNonAuxiliaryInterpolationType(b)); return (GetNonAuxiliaryInterpolationType(a) == GetNonAuxiliaryInterpolationType(b));
} }
ShaderVariable::ShaderVariable() ShaderVariable::ShaderVariable() : ShaderVariable(GL_NONE) {}
: type(0), precision(0), flattenedOffsetInParentArrays(0), staticUse(false), active(false)
{}
ShaderVariable::ShaderVariable(GLenum typeIn) ShaderVariable::ShaderVariable(GLenum typeIn)
: type(typeIn), precision(0), flattenedOffsetInParentArrays(0), staticUse(false), active(false) : type(typeIn),
precision(0),
staticUse(false),
active(false),
isRowMajorLayout(false),
flattenedOffsetInParentArrays(-1)
{} {}
ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) : ShaderVariable(typeIn)
: type(typeIn), precision(0), flattenedOffsetInParentArrays(0), staticUse(false), active(false)
{ {
ASSERT(arraySizeIn != 0); ASSERT(arraySizeIn != 0);
arraySizes.push_back(arraySizeIn); arraySizes.push_back(arraySizeIn);
...@@ -54,11 +56,12 @@ ShaderVariable::ShaderVariable(const ShaderVariable &other) ...@@ -54,11 +56,12 @@ ShaderVariable::ShaderVariable(const ShaderVariable &other)
name(other.name), name(other.name),
mappedName(other.mappedName), mappedName(other.mappedName),
arraySizes(other.arraySizes), arraySizes(other.arraySizes),
flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays),
staticUse(other.staticUse), staticUse(other.staticUse),
active(other.active), active(other.active),
fields(other.fields), fields(other.fields),
structName(other.structName) structName(other.structName),
isRowMajorLayout(other.isRowMajorLayout),
flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
{} {}
ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other) ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
...@@ -70,9 +73,10 @@ ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other) ...@@ -70,9 +73,10 @@ ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
arraySizes = other.arraySizes; arraySizes = other.arraySizes;
staticUse = other.staticUse; staticUse = other.staticUse;
active = other.active; active = other.active;
flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
fields = other.fields; fields = other.fields;
structName = other.structName; structName = other.structName;
isRowMajorLayout = other.isRowMajorLayout;
flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
return *this; return *this;
} }
...@@ -81,7 +85,8 @@ bool ShaderVariable::operator==(const ShaderVariable &other) const ...@@ -81,7 +85,8 @@ bool ShaderVariable::operator==(const ShaderVariable &other) const
if (type != other.type || precision != other.precision || name != other.name || if (type != other.type || precision != other.precision || name != other.name ||
mappedName != other.mappedName || arraySizes != other.arraySizes || mappedName != other.mappedName || arraySizes != other.arraySizes ||
staticUse != other.staticUse || active != other.active || staticUse != other.staticUse || active != other.active ||
fields.size() != other.fields.size() || structName != other.structName) fields.size() != other.fields.size() || structName != other.structName ||
isRowMajorLayout != other.isRowMajorLayout)
{ {
return false; return false;
} }
...@@ -110,8 +115,7 @@ unsigned int ShaderVariable::getArraySizeProduct() const ...@@ -110,8 +115,7 @@ unsigned int ShaderVariable::getArraySizeProduct() const
void ShaderVariable::indexIntoArray(unsigned int arrayIndex) void ShaderVariable::indexIntoArray(unsigned int arrayIndex)
{ {
ASSERT(isArray()); ASSERT(isArray());
flattenedOffsetInParentArrays = flattenedOffsetInParentArrays = arrayIndex + getOutermostArraySize() * parentArrayIndex();
arrayIndex + getOutermostArraySize() * flattenedOffsetInParentArrays;
arraySizes.pop_back(); arraySizes.pop_back();
} }
...@@ -229,6 +233,8 @@ bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other, ...@@ -229,6 +233,8 @@ bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other,
ASSERT(!matchName || mappedName == other.mappedName); ASSERT(!matchName || mappedName == other.mappedName);
if (arraySizes != other.arraySizes) if (arraySizes != other.arraySizes)
return false; return false;
if (isRowMajorLayout != other.isRowMajorLayout)
return false;
if (fields.size() != other.fields.size()) if (fields.size() != other.fields.size())
return false; return false;
...@@ -347,31 +353,28 @@ bool OutputVariable::operator==(const OutputVariable &other) const ...@@ -347,31 +353,28 @@ bool OutputVariable::operator==(const OutputVariable &other) const
return VariableWithLocation::operator==(other) && index == other.index; return VariableWithLocation::operator==(other) && index == other.index;
} }
InterfaceBlockField::InterfaceBlockField() : isRowMajorLayout(false) {} InterfaceBlockField::InterfaceBlockField() {}
InterfaceBlockField::~InterfaceBlockField() {} InterfaceBlockField::~InterfaceBlockField() {}
InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other) InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other) : ShaderVariable(other)
: ShaderVariable(other), isRowMajorLayout(other.isRowMajorLayout)
{} {}
InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other) InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other)
{ {
ShaderVariable::operator=(other); ShaderVariable::operator=(other);
isRowMajorLayout = other.isRowMajorLayout;
return *this; return *this;
} }
bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const
{ {
return (ShaderVariable::operator==(other) && isRowMajorLayout == other.isRowMajorLayout); return ShaderVariable::operator==(other);
} }
bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime( bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime(
const InterfaceBlockField &other) const const InterfaceBlockField &other) const
{ {
return (ShaderVariable::isSameVariableAtLinkTime(other, true, true) && return (ShaderVariable::isSameVariableAtLinkTime(other, true, true));
isRowMajorLayout == other.isRowMajorLayout);
} }
Varying::Varying() : interpolation(INTERPOLATION_SMOOTH), isInvariant(false) {} Varying::Varying() : interpolation(INTERPOLATION_SMOOTH), isInvariant(false) {}
......
...@@ -85,8 +85,8 @@ class BlockLayoutEncoder ...@@ -85,8 +85,8 @@ class BlockLayoutEncoder
static const size_t BytesPerComponent = 4u; static const size_t BytesPerComponent = 4u;
static const unsigned int ComponentsPerRegister = 4u; static const unsigned int ComponentsPerRegister = 4u;
static size_t getBlockRegister(const BlockMemberInfo &info); static size_t GetBlockRegister(const BlockMemberInfo &info);
static size_t getBlockRegisterElement(const BlockMemberInfo &info); static size_t GetBlockRegisterElement(const BlockMemberInfo &info);
protected: protected:
size_t mCurrentOffset; size_t mCurrentOffset;
...@@ -106,6 +106,34 @@ class BlockLayoutEncoder ...@@ -106,6 +106,34 @@ class BlockLayoutEncoder
int matrixStride) = 0; int matrixStride) = 0;
}; };
// Will return default values for everything.
class DummyBlockEncoder : public BlockLayoutEncoder
{
public:
DummyBlockEncoder() = default;
void enterAggregateType() override {}
void exitAggregateType() override {}
protected:
void getBlockLayoutInfo(GLenum type,
const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int *arrayStrideOut,
int *matrixStrideOut) override
{
*arrayStrideOut = 0;
*matrixStrideOut = 0;
}
void advanceOffset(GLenum type,
const std::vector<unsigned int> &arraySizes,
bool isRowMajorMatrix,
int arrayStride,
int matrixStride) override
{}
};
// Block layout according to the std140 block layout // Block layout according to the std140 block layout
// See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification // See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification
...@@ -148,15 +176,118 @@ using BlockLayoutMap = std::map<std::string, BlockMemberInfo>; ...@@ -148,15 +176,118 @@ using BlockLayoutMap = std::map<std::string, BlockMemberInfo>;
void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields, void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields,
const std::string &prefix, const std::string &prefix,
sh::BlockLayoutEncoder *encoder, BlockLayoutEncoder *encoder,
BlockLayoutMap *blockInfoOut); BlockLayoutMap *blockInfoOut);
// Used for laying out the default uniform block on the Vulkan backend. // Used for laying out the default uniform block on the Vulkan backend.
void GetUniformBlockInfo(const std::vector<Uniform> &uniforms, void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
const std::string &prefix, const std::string &prefix,
sh::BlockLayoutEncoder *encoder, BlockLayoutEncoder *encoder,
BlockLayoutMap *blockInfoOut); BlockLayoutMap *blockInfoOut);
class ShaderVariableVisitor
{
public:
virtual ~ShaderVariableVisitor() {}
virtual void enterStruct(const ShaderVariable &structVar) {}
virtual void exitStruct(const ShaderVariable &structVar) {}
virtual void enterStructAccess(const ShaderVariable &structVar) {}
virtual void exitStructAccess(const ShaderVariable &structVar) {}
virtual void enterArray(const ShaderVariable &arrayVar) {}
virtual void exitArray(const ShaderVariable &arrayVar) {}
virtual void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
virtual void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) {}
virtual void visitSampler(const sh::ShaderVariable &sampler) {}
virtual void visitVariable(const ShaderVariable &variable, bool isRowMajor) = 0;
protected:
ShaderVariableVisitor() {}
};
class VariableNameVisitor : public ShaderVariableVisitor
{
public:
VariableNameVisitor(const std::string &namePrefix, const std::string &mappedNamePrefix);
~VariableNameVisitor();
void enterStruct(const ShaderVariable &structVar) override;
void exitStruct(const ShaderVariable &structVar) override;
void enterStructAccess(const ShaderVariable &structVar) override;
void exitStructAccess(const ShaderVariable &structVar) override;
void enterArray(const ShaderVariable &arrayVar) override;
void exitArray(const ShaderVariable &arrayVar) override;
void enterArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override;
void exitArrayElement(const ShaderVariable &arrayVar, unsigned int arrayElement) override
{
mNameStack.pop_back();
mMappedNameStack.pop_back();
}
protected:
virtual void visitNamedSampler(const sh::ShaderVariable &sampler,
const std::string &name,
const std::string &mappedName)
{}
virtual void visitNamedVariable(const ShaderVariable &variable,
bool isRowMajor,
const std::string &name,
const std::string &mappedName) = 0;
private:
void visitSampler(const sh::ShaderVariable &sampler) final;
void visitVariable(const ShaderVariable &variable, bool isRowMajor) final;
std::string collapseNameStack() const;
std::string collapseMappedNameStack() const;
std::vector<std::string> mNameStack;
std::vector<std::string> mMappedNameStack;
};
class BlockEncoderVisitor : public VariableNameVisitor
{
public:
BlockEncoderVisitor(const std::string &namePrefix,
const std::string &mappedNamePrefix,
BlockLayoutEncoder *encoder);
~BlockEncoderVisitor();
void enterStructAccess(const ShaderVariable &structVar) override;
void exitStructAccess(const ShaderVariable &structVar) override;
void visitNamedVariable(const ShaderVariable &variable,
bool isRowMajor,
const std::string &name,
const std::string &mappedName) override;
virtual void encodeVariable(const ShaderVariable &variable,
const BlockMemberInfo &variableInfo,
const std::string &name,
const std::string &mappedName) = 0;
private:
BlockLayoutEncoder *mEncoder;
};
void TraverseShaderVariable(const ShaderVariable &variable,
bool isRowMajorLayout,
ShaderVariableVisitor *visitor);
template <typename T>
void TraverseShaderVariables(const std::vector<T> &vars,
bool isRowMajorLayout,
ShaderVariableVisitor *visitor)
{
for (const T &var : vars)
{
TraverseShaderVariable(var, isRowMajorLayout, visitor);
}
}
} // namespace sh } // namespace sh
#endif // COMMON_BLOCKLAYOUT_H_ #endif // COMMON_BLOCKLAYOUT_H_
...@@ -144,6 +144,8 @@ class ProgramD3DMetadata final : angle::NonCopyable ...@@ -144,6 +144,8 @@ class ProgramD3DMetadata final : angle::NonCopyable
const gl::ShaderMap<const ShaderD3D *> mAttachedShaders; const gl::ShaderMap<const ShaderD3D *> mAttachedShaders;
}; };
using D3DUniformMap = std::map<std::string, D3DUniform *>;
class ProgramD3D : public ProgramImpl class ProgramD3D : public ProgramImpl
{ {
public: public:
...@@ -385,39 +387,12 @@ class ProgramD3D : public ProgramImpl ...@@ -385,39 +387,12 @@ class ProgramD3D : public ProgramImpl
GLint logicalImageUnit; GLint logicalImageUnit;
}; };
typedef std::map<std::string, D3DUniform *> D3DUniformMap;
void initializeUniformStorage(const gl::ShaderBitSet &availableShaderStages); void initializeUniformStorage(const gl::ShaderBitSet &availableShaderStages);
void defineUniformsAndAssignRegisters(); void defineUniformsAndAssignRegisters();
void defineUniformBase(const gl::Shader *shader, void defineUniformBase(const gl::Shader *shader,
const sh::Uniform &uniform, const sh::Uniform &uniform,
D3DUniformMap *uniformMap); D3DUniformMap *uniformMap);
void defineStructUniformFields(gl::ShaderType shaderType,
const std::vector<sh::ShaderVariable> &fields,
const std::string &namePrefix,
const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap);
void defineArrayOfStructsUniformFields(gl::ShaderType shaderType,
const sh::ShaderVariable &uniform,
unsigned int arrayNestingIndex,
const std::string &prefix,
const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap);
void defineArrayUniformElements(gl::ShaderType shaderType,
const sh::ShaderVariable &uniform,
const std::string &fullName,
const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap);
void defineUniform(gl::ShaderType shaderType,
const sh::ShaderVariable &uniform,
const std::string &fullName,
const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap);
void assignAllSamplerRegisters(); void assignAllSamplerRegisters();
void assignSamplerRegisters(size_t uniformIndex); void assignSamplerRegisters(size_t uniformIndex);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment