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 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 202
#define ANGLE_SH_VERSION 203
enum ShShaderSpec
{
......
......@@ -106,7 +106,7 @@ struct ShaderVariable
// If no match is found, return false.
bool findInfoByMappedName(const std::string &mappedFullName,
const ShaderVariable **leafVar,
std::string* originalFullName) const;
std::string *originalFullName) const;
bool isBuiltIn() const;
bool isEmulatedBuiltIn() const;
......@@ -125,7 +125,14 @@ struct ShaderVariable
// int a[3][4];
// then the flattenedOffsetInParentArrays of a[2] would be 2.
// 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.
bool staticUse;
......@@ -136,16 +143,18 @@ struct ShaderVariable
std::vector<ShaderVariable> fields;
std::string structName;
// Only applies to interface block fields. Kept here for simplicity.
bool isRowMajorLayout;
protected:
bool isSameVariableAtLinkTime(const ShaderVariable &other,
bool matchPrecision,
bool matchName) const;
bool operator==(const ShaderVariable &other) const;
bool operator!=(const ShaderVariable &other) const
{
return !operator==(other);
}
bool operator!=(const ShaderVariable &other) const { return !operator==(other); }
int flattenedOffsetInParentArrays;
};
// 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
Uniform(const Uniform &other);
Uniform &operator=(const Uniform &other);
bool operator==(const Uniform &other) const;
bool operator!=(const Uniform &other) const
{
return !operator==(other);
}
bool operator!=(const Uniform &other) const { return !operator==(other); }
int binding;
int offset;
......@@ -216,19 +222,13 @@ struct InterfaceBlockField : public ShaderVariable
InterfaceBlockField(const InterfaceBlockField &other);
InterfaceBlockField &operator=(const InterfaceBlockField &other);
bool operator==(const InterfaceBlockField &other) const;
bool operator!=(const InterfaceBlockField &other) const
{
return !operator==(other);
}
bool operator!=(const InterfaceBlockField &other) const { return !operator==(other); }
// Decide whether two InterfaceBlock fields are the same at shader
// link time, assuming one from vertex shader and the other from
// fragment shader.
// See GLSL ES Spec 3.00.3, sec 4.3.7.
bool isSameInterfaceBlockFieldAtLinkTime(
const InterfaceBlockField &other) const;
bool isRowMajorLayout;
bool isSameInterfaceBlockFieldAtLinkTime(const InterfaceBlockField &other) const;
};
struct Varying : public VariableWithLocation
......@@ -238,10 +238,7 @@ struct Varying : public VariableWithLocation
Varying(const Varying &other);
Varying &operator=(const Varying &other);
bool operator==(const Varying &other) const;
bool operator!=(const Varying &other) const
{
return !operator==(other);
}
bool operator!=(const Varying &other) const { return !operator==(other); }
// Decide whether two varyings are the same at shader link time,
// assuming one from vertex shader and the other from fragment shader.
......@@ -299,8 +296,7 @@ struct WorkGroupSize
WorkGroupSize() = default;
explicit constexpr WorkGroupSize(int initialSize)
: localSizeQualifiers{initialSize, initialSize, initialSize}
{
}
{}
void fill(int fillValue);
void setLocalSize(int localSizeX, int localSizeY, int localSizeZ);
......@@ -328,4 +324,4 @@ struct WorkGroupSize
} // namespace sh
#endif // GLSLANG_SHADERVARS_H_
#endif // GLSLANG_SHADERVARS_H_
......@@ -31,16 +31,18 @@ bool InterpolationTypesMatch(InterpolationType a, InterpolationType b)
return (GetNonAuxiliaryInterpolationType(a) == GetNonAuxiliaryInterpolationType(b));
}
ShaderVariable::ShaderVariable()
: type(0), precision(0), flattenedOffsetInParentArrays(0), staticUse(false), active(false)
{}
ShaderVariable::ShaderVariable() : ShaderVariable(GL_NONE) {}
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)
: type(typeIn), precision(0), flattenedOffsetInParentArrays(0), staticUse(false), active(false)
ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) : ShaderVariable(typeIn)
{
ASSERT(arraySizeIn != 0);
arraySizes.push_back(arraySizeIn);
......@@ -54,11 +56,12 @@ ShaderVariable::ShaderVariable(const ShaderVariable &other)
name(other.name),
mappedName(other.mappedName),
arraySizes(other.arraySizes),
flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays),
staticUse(other.staticUse),
active(other.active),
fields(other.fields),
structName(other.structName)
structName(other.structName),
isRowMajorLayout(other.isRowMajorLayout),
flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
{}
ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
......@@ -70,9 +73,10 @@ ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
arraySizes = other.arraySizes;
staticUse = other.staticUse;
active = other.active;
flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
fields = other.fields;
structName = other.structName;
isRowMajorLayout = other.isRowMajorLayout;
flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
return *this;
}
......@@ -81,7 +85,8 @@ bool ShaderVariable::operator==(const ShaderVariable &other) const
if (type != other.type || precision != other.precision || name != other.name ||
mappedName != other.mappedName || arraySizes != other.arraySizes ||
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;
}
......@@ -110,8 +115,7 @@ unsigned int ShaderVariable::getArraySizeProduct() const
void ShaderVariable::indexIntoArray(unsigned int arrayIndex)
{
ASSERT(isArray());
flattenedOffsetInParentArrays =
arrayIndex + getOutermostArraySize() * flattenedOffsetInParentArrays;
flattenedOffsetInParentArrays = arrayIndex + getOutermostArraySize() * parentArrayIndex();
arraySizes.pop_back();
}
......@@ -229,6 +233,8 @@ bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other,
ASSERT(!matchName || mappedName == other.mappedName);
if (arraySizes != other.arraySizes)
return false;
if (isRowMajorLayout != other.isRowMajorLayout)
return false;
if (fields.size() != other.fields.size())
return false;
......@@ -347,31 +353,28 @@ bool OutputVariable::operator==(const OutputVariable &other) const
return VariableWithLocation::operator==(other) && index == other.index;
}
InterfaceBlockField::InterfaceBlockField() : isRowMajorLayout(false) {}
InterfaceBlockField::InterfaceBlockField() {}
InterfaceBlockField::~InterfaceBlockField() {}
InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other)
: ShaderVariable(other), isRowMajorLayout(other.isRowMajorLayout)
InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other) : ShaderVariable(other)
{}
InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other)
{
ShaderVariable::operator=(other);
isRowMajorLayout = other.isRowMajorLayout;
return *this;
}
bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const
{
return (ShaderVariable::operator==(other) && isRowMajorLayout == other.isRowMajorLayout);
return ShaderVariable::operator==(other);
}
bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime(
const InterfaceBlockField &other) const
{
return (ShaderVariable::isSameVariableAtLinkTime(other, true, true) &&
isRowMajorLayout == other.isRowMajorLayout);
return (ShaderVariable::isSameVariableAtLinkTime(other, true, true));
}
Varying::Varying() : interpolation(INTERPOLATION_SMOOTH), isInvariant(false) {}
......
......@@ -85,8 +85,8 @@ class BlockLayoutEncoder
static const size_t BytesPerComponent = 4u;
static const unsigned int ComponentsPerRegister = 4u;
static size_t getBlockRegister(const BlockMemberInfo &info);
static size_t getBlockRegisterElement(const BlockMemberInfo &info);
static size_t GetBlockRegister(const BlockMemberInfo &info);
static size_t GetBlockRegisterElement(const BlockMemberInfo &info);
protected:
size_t mCurrentOffset;
......@@ -106,6 +106,34 @@ class BlockLayoutEncoder
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
// 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>;
void GetInterfaceBlockInfo(const std::vector<InterfaceBlockField> &fields,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
BlockLayoutEncoder *encoder,
BlockLayoutMap *blockInfoOut);
// Used for laying out the default uniform block on the Vulkan backend.
void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
BlockLayoutEncoder *encoder,
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
#endif // COMMON_BLOCKLAYOUT_H_
......@@ -144,6 +144,8 @@ class ProgramD3DMetadata final : angle::NonCopyable
const gl::ShaderMap<const ShaderD3D *> mAttachedShaders;
};
using D3DUniformMap = std::map<std::string, D3DUniform *>;
class ProgramD3D : public ProgramImpl
{
public:
......@@ -385,39 +387,12 @@ class ProgramD3D : public ProgramImpl
GLint logicalImageUnit;
};
typedef std::map<std::string, D3DUniform *> D3DUniformMap;
void initializeUniformStorage(const gl::ShaderBitSet &availableShaderStages);
void defineUniformsAndAssignRegisters();
void defineUniformBase(const gl::Shader *shader,
const sh::Uniform &uniform,
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 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