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: Yuly Novikov <ynovikov@chromium.org>
This commit is contained in:
Jamie Madill 2018-12-16 19:14:58 -05:00 коммит произвёл Commit Bot
Родитель e321940cb0
Коммит 8c78ce4bd3
9 изменённых файлов: 1005 добавлений и 1002 удалений

Просмотреть файл

@ -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) {}

Просмотреть файл

@ -17,91 +17,27 @@ namespace sh
namespace
{
bool IsRowMajorLayout(const InterfaceBlockField &var)
class BlockLayoutMapVisitor : public BlockEncoderVisitor
{
return var.isRowMajorLayout;
}
public:
BlockLayoutMapVisitor(BlockLayoutMap *blockInfoOut,
const std::string &instanceName,
BlockLayoutEncoder *encoder)
: BlockEncoderVisitor(instanceName, instanceName, encoder), mInfoOut(blockInfoOut)
{}
bool IsRowMajorLayout(const ShaderVariable &var)
{
return false;
}
template <typename VarT>
void GetInterfaceBlockInfo(const std::vector<VarT> &fields,
const std::string &prefix,
sh::BlockLayoutEncoder *encoder,
bool inRowMajorLayout,
BlockLayoutMap *blockInfoOut);
template <typename VarT>
void GetInterfaceBlockStructMemberInfo(const std::vector<VarT> &fields,
const std::string &fieldName,
sh::BlockLayoutEncoder *encoder,
bool inRowMajorLayout,
BlockLayoutMap *blockInfoOut)
{
// TODO(jiajia.qin@intel.com):we need to set the right structure base alignment before
// enterAggregateType for std430 layout just like GetShaderStorageBlockFieldMemberInfo did in
// ShaderStorageBlockOutputHLSL.cpp. http://anglebug.com/1920
encoder->enterAggregateType();
GetInterfaceBlockInfo(fields, fieldName, encoder, inRowMajorLayout, blockInfoOut);
encoder->exitAggregateType();
}
template <typename VarT>
void GetInterfaceBlockStructArrayMemberInfo(const VarT &field,
unsigned int arrayNestingIndex,
const std::string &arrayName,
sh::BlockLayoutEncoder *encoder,
bool inRowMajorLayout,
BlockLayoutMap *blockInfoOut)
{
// Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
// innermost.
const unsigned int currentArraySize = field.getNestedArraySize(arrayNestingIndex);
for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
void encodeVariable(const ShaderVariable &variable,
const BlockMemberInfo &variableInfo,
const std::string &name,
const std::string &mappedName) override
{
const std::string elementName = arrayName + ArrayString(arrayElement);
if (arrayNestingIndex + 1u < field.arraySizes.size())
{
GetInterfaceBlockStructArrayMemberInfo(field, arrayNestingIndex + 1u, elementName,
encoder, inRowMajorLayout, blockInfoOut);
}
else
{
GetInterfaceBlockStructMemberInfo(field.fields, elementName, encoder, inRowMajorLayout,
blockInfoOut);
}
ASSERT(!gl::IsSamplerType(variable.type));
(*mInfoOut)[name] = variableInfo;
}
}
template <typename VarT>
void GetInterfaceBlockArrayOfArraysMemberInfo(const VarT &field,
unsigned int arrayNestingIndex,
const std::string &arrayName,
sh::BlockLayoutEncoder *encoder,
bool isRowMajorMatrix,
BlockLayoutMap *blockInfoOut)
{
const unsigned int currentArraySize = field.getNestedArraySize(arrayNestingIndex);
for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
{
const std::string elementName = arrayName + ArrayString(arrayElement);
if (arrayNestingIndex + 2u < field.arraySizes.size())
{
GetInterfaceBlockArrayOfArraysMemberInfo(field, arrayNestingIndex + 1u, elementName,
encoder, isRowMajorMatrix, blockInfoOut);
}
else
{
std::vector<unsigned int> innermostArraySize(
1u, field.getNestedArraySize(arrayNestingIndex + 1u));
(*blockInfoOut)[elementName] =
encoder->encodeType(field.type, innermostArraySize, isRowMajorMatrix);
}
}
}
private:
BlockLayoutMap *mInfoOut;
};
template <typename VarT>
void GetInterfaceBlockInfo(const std::vector<VarT> &fields,
@ -110,46 +46,105 @@ void GetInterfaceBlockInfo(const std::vector<VarT> &fields,
bool inRowMajorLayout,
BlockLayoutMap *blockInfoOut)
{
for (const VarT &field : fields)
// TODO(jiajia.qin@intel.com):we need to set the right structure base alignment before
// enterAggregateType for std430 layout just like GetShaderStorageBlockFieldMemberInfo did in
// ShaderStorageBlockOutputHLSL.cpp. http://anglebug.com/1920
BlockLayoutMapVisitor visitor(blockInfoOut, prefix, encoder);
TraverseShaderVariables(fields, inRowMajorLayout, &visitor);
}
void TraverseStructVariable(const ShaderVariable &variable,
bool isRowMajorLayout,
ShaderVariableVisitor *visitor)
{
const std::vector<ShaderVariable> &fields = variable.fields;
visitor->enterStructAccess(variable);
TraverseShaderVariables(fields, isRowMajorLayout, visitor);
visitor->exitStructAccess(variable);
}
void TraverseStructArrayVariable(const ShaderVariable &variable,
unsigned int arrayNestingIndex,
bool inRowMajorLayout,
ShaderVariableVisitor *visitor)
{
visitor->enterArray(variable);
// Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
// innermost. We make a special case for unsized arrays.
const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex);
unsigned int count = std::max(currentArraySize, 1u);
for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement)
{
// Skip samplers. On Vulkan we use this for the default uniform block, so samplers may be
// included.
if (gl::IsSamplerType(field.type))
{
continue;
}
visitor->enterArrayElement(variable, arrayElement);
const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
ShaderVariable elementVar = variable;
elementVar.indexIntoArray(arrayElement);
bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
if (field.isStruct())
if (arrayNestingIndex + 1u < variable.arraySizes.size())
{
if (field.isArray())
{
GetInterfaceBlockStructArrayMemberInfo(field, 0u, fieldName, encoder,
rowMajorLayout, blockInfoOut);
}
else
{
GetInterfaceBlockStructMemberInfo(field.fields, fieldName, encoder, rowMajorLayout,
blockInfoOut);
}
}
else if (field.isArrayOfArrays())
{
GetInterfaceBlockArrayOfArraysMemberInfo(field, 0u, fieldName, encoder,
rowMajorLayout && gl::IsMatrixType(field.type),
blockInfoOut);
TraverseStructArrayVariable(elementVar, arrayNestingIndex, inRowMajorLayout, visitor);
}
else
{
(*blockInfoOut)[fieldName] = encoder->encodeType(
field.type, field.arraySizes, rowMajorLayout && gl::IsMatrixType(field.type));
TraverseStructVariable(elementVar, inRowMajorLayout, visitor);
}
visitor->exitArrayElement(variable, arrayElement);
}
visitor->exitArray(variable);
}
void TraverseArrayOfArraysVariable(const ShaderVariable &variable,
unsigned int arrayNestingIndex,
bool isRowMajorMatrix,
ShaderVariableVisitor *visitor)
{
visitor->enterArray(variable);
const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex);
unsigned int count = std::max(currentArraySize, 1u);
for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement)
{
visitor->enterArrayElement(variable, arrayElement);
ShaderVariable elementVar = variable;
elementVar.indexIntoArray(arrayElement);
if (arrayNestingIndex + 2u < variable.arraySizes.size())
{
TraverseArrayOfArraysVariable(elementVar, arrayNestingIndex, isRowMajorMatrix, visitor);
}
else
{
if (gl::IsSamplerType(variable.type))
{
visitor->visitSampler(elementVar);
}
else
{
visitor->visitVariable(elementVar, isRowMajorMatrix);
}
}
visitor->exitArrayElement(variable, arrayElement);
}
visitor->exitArray(variable);
}
std::string CollapseNameStack(const std::vector<std::string> &nameStack)
{
std::stringstream strstr;
for (const std::string &part : nameStack)
{
strstr << part;
}
return strstr.str();
}
} // anonymous namespace
BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0), mStructureBaseAlignment(0) {}
@ -184,13 +179,13 @@ void BlockLayoutEncoder::setStructureBaseAlignment(size_t baseAlignment)
}
// static
size_t BlockLayoutEncoder::getBlockRegister(const BlockMemberInfo &info)
size_t BlockLayoutEncoder::GetBlockRegister(const BlockMemberInfo &info)
{
return (info.offset / BytesPerComponent) / ComponentsPerRegister;
}
// static
size_t BlockLayoutEncoder::getBlockRegisterElement(const BlockMemberInfo &info)
size_t BlockLayoutEncoder::GetBlockRegisterElement(const BlockMemberInfo &info)
{
return (info.offset / BytesPerComponent) % ComponentsPerRegister;
}
@ -342,4 +337,193 @@ void GetUniformBlockInfo(const std::vector<Uniform> &uniforms,
GetInterfaceBlockInfo(uniforms, prefix, encoder, false, blockInfoOut);
}
// VariableNameVisitor implementation.
VariableNameVisitor::VariableNameVisitor(const std::string &namePrefix,
const std::string &mappedNamePrefix)
{
if (!namePrefix.empty())
{
mNameStack.push_back(namePrefix + ".");
}
if (!mappedNamePrefix.empty())
{
mMappedNameStack.push_back(mappedNamePrefix + ".");
}
}
VariableNameVisitor::~VariableNameVisitor() = default;
void VariableNameVisitor::enterStruct(const ShaderVariable &structVar)
{
mNameStack.push_back(structVar.name);
mMappedNameStack.push_back(structVar.mappedName);
}
void VariableNameVisitor::exitStruct(const ShaderVariable &structVar)
{
mNameStack.pop_back();
mMappedNameStack.pop_back();
}
void VariableNameVisitor::enterStructAccess(const ShaderVariable &structVar)
{
mNameStack.push_back(".");
mMappedNameStack.push_back(".");
}
void VariableNameVisitor::exitStructAccess(const ShaderVariable &structVar)
{
mNameStack.pop_back();
mMappedNameStack.pop_back();
}
void VariableNameVisitor::enterArray(const ShaderVariable &arrayVar)
{
if (!arrayVar.hasParentArrayIndex())
{
mNameStack.push_back(arrayVar.name);
mMappedNameStack.push_back(arrayVar.mappedName);
}
}
void VariableNameVisitor::exitArray(const ShaderVariable &arrayVar)
{
if (!arrayVar.hasParentArrayIndex())
{
mNameStack.pop_back();
mMappedNameStack.pop_back();
}
}
void VariableNameVisitor::enterArrayElement(const ShaderVariable &arrayVar,
unsigned int arrayElement)
{
std::stringstream strstr;
strstr << "[" << arrayElement << "]";
std::string elementString = strstr.str();
mNameStack.push_back(elementString);
mMappedNameStack.push_back(elementString);
}
std::string VariableNameVisitor::collapseNameStack() const
{
return CollapseNameStack(mNameStack);
}
std::string VariableNameVisitor::collapseMappedNameStack() const
{
return CollapseNameStack(mMappedNameStack);
}
void VariableNameVisitor::visitSampler(const sh::ShaderVariable &sampler)
{
if (!sampler.hasParentArrayIndex())
{
mNameStack.push_back(sampler.name);
mMappedNameStack.push_back(sampler.mappedName);
}
std::string name = collapseNameStack();
std::string mappedName = collapseMappedNameStack();
if (!sampler.hasParentArrayIndex())
{
mNameStack.pop_back();
mMappedNameStack.pop_back();
}
visitNamedSampler(sampler, name, mappedName);
}
void VariableNameVisitor::visitVariable(const ShaderVariable &variable, bool isRowMajor)
{
if (!variable.hasParentArrayIndex())
{
mNameStack.push_back(variable.name);
mMappedNameStack.push_back(variable.mappedName);
}
std::string name = collapseNameStack();
std::string mappedName = collapseMappedNameStack();
if (!variable.hasParentArrayIndex())
{
mNameStack.pop_back();
mMappedNameStack.pop_back();
}
visitNamedVariable(variable, isRowMajor, name, mappedName);
}
// BlockEncoderVisitor implementation.
BlockEncoderVisitor::BlockEncoderVisitor(const std::string &namePrefix,
const std::string &mappedNamePrefix,
BlockLayoutEncoder *encoder)
: VariableNameVisitor(namePrefix, mappedNamePrefix), mEncoder(encoder)
{}
BlockEncoderVisitor::~BlockEncoderVisitor() = default;
void BlockEncoderVisitor::enterStructAccess(const ShaderVariable &structVar)
{
VariableNameVisitor::enterStructAccess(structVar);
mEncoder->enterAggregateType();
}
void BlockEncoderVisitor::exitStructAccess(const ShaderVariable &structVar)
{
mEncoder->exitAggregateType();
VariableNameVisitor::exitStructAccess(structVar);
}
void BlockEncoderVisitor::visitNamedVariable(const ShaderVariable &variable,
bool isRowMajor,
const std::string &name,
const std::string &mappedName)
{
std::vector<unsigned int> innermostArraySize;
if (variable.isArray())
{
innermostArraySize.push_back(variable.getNestedArraySize(0));
}
BlockMemberInfo variableInfo =
mEncoder->encodeType(variable.type, innermostArraySize, isRowMajor);
encodeVariable(variable, variableInfo, name, mappedName);
}
void TraverseShaderVariable(const ShaderVariable &variable,
bool isRowMajorLayout,
ShaderVariableVisitor *visitor)
{
bool rowMajorLayout = (isRowMajorLayout || variable.isRowMajorLayout);
bool isRowMajor = rowMajorLayout && gl::IsMatrixType(variable.type);
if (variable.isStruct())
{
if (variable.isArray())
{
TraverseStructArrayVariable(variable, 0u, rowMajorLayout, visitor);
}
else
{
visitor->enterStruct(variable);
TraverseStructVariable(variable, rowMajorLayout, visitor);
visitor->exitStruct(variable);
}
}
else if (variable.isArrayOfArrays())
{
TraverseArrayOfArraysVariable(variable, 0u, isRowMajor, visitor);
}
else if (gl::IsSamplerType(variable.type))
{
visitor->visitSampler(variable);
}
else
{
visitor->visitVariable(variable, isRowMajor);
}
}
} // namespace sh

Просмотреть файл

@ -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_

Просмотреть файл

@ -19,10 +19,8 @@
namespace gl
{
namespace
{
LinkedUniform *FindUniform(std::vector<LinkedUniform> &list, const std::string &name)
{
for (LinkedUniform &uniform : list)
@ -243,6 +241,359 @@ void LogUniformsExceedLimit(ShaderType shaderType,
<< GetUniformResourceLimitName(shaderType, uniformType) << "(" << limit << ")";
}
// The purpose of this visitor is to capture the uniforms in a uniform block. Each new uniform is
// added to "uniformsOut".
class UniformBlockEncodingVisitor : public sh::VariableNameVisitor
{
public:
UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
std::vector<LinkedUniform> *uniformsOut,
ShaderType shaderType,
int blockIndex)
: sh::VariableNameVisitor(namePrefix, mappedNamePrefix),
mGetMemberInfo(getMemberInfo),
mUniformsOut(uniformsOut),
mShaderType(shaderType),
mBlockIndex(blockIndex)
{}
void visitNamedVariable(const sh::ShaderVariable &variable,
bool isRowMajor,
const std::string &name,
const std::string &mappedName) override
{
// If getBlockMemberInfo returns false, the variable is optimized out.
sh::BlockMemberInfo variableInfo;
if (!mGetMemberInfo(name, mappedName, &variableInfo))
return;
std::string nameWithArrayIndex = name;
std::string mappedNameWithArrayIndex = mappedName;
if (variable.isArray())
{
nameWithArrayIndex += "[0]";
mappedNameWithArrayIndex += "[0]";
}
if (mBlockIndex == -1)
{
SetActive(mUniformsOut, nameWithArrayIndex, mShaderType, variable.active);
return;
}
LinkedUniform newUniform(variable.type, variable.precision, nameWithArrayIndex,
variable.arraySizes, -1, -1, -1, mBlockIndex, variableInfo);
newUniform.mappedName = mappedNameWithArrayIndex;
newUniform.setActive(mShaderType, variable.active);
// Since block uniforms have no location, we don't need to store them in the uniform
// locations list.
mUniformsOut->push_back(newUniform);
}
private:
const GetBlockMemberInfoFunc &mGetMemberInfo;
std::vector<LinkedUniform> *mUniformsOut;
const ShaderType mShaderType;
const int mBlockIndex;
};
// The purpose of this visitor is to capture the buffer variables in a shader storage block. Each
// new buffer variable is stored in "bufferVariablesOut".
class ShaderStorageBlockVisitor : public sh::VariableNameVisitor
{
public:
ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
std::vector<BufferVariable> *bufferVariablesOut,
ShaderType shaderType,
int blockIndex)
: sh::VariableNameVisitor(namePrefix, mappedNamePrefix),
mGetMemberInfo(getMemberInfo),
mBufferVariablesOut(bufferVariablesOut),
mShaderType(shaderType),
mBlockIndex(blockIndex)
{}
void enterArrayElement(const sh::ShaderVariable &arrayVar, unsigned int arrayElement) override
{
if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
{
// From the ES 3.1 spec "7.3.1.1 Naming Active Resources":
// For an active shader storage block member declared as an array of an aggregate type,
// an entry will be generated only for the first array element, regardless of its type.
// Such block members are referred to as top-level arrays. If the block member is an
// aggregate type, the enumeration rules are then applied recursively.
if (arrayElement == 0)
{
mTopLevelArraySize = arrayVar.getOutermostArraySize();
}
else
{
mSkipEnabled = true;
}
}
sh::VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
}
void exitArrayElement(const sh::ShaderVariable &arrayVar, unsigned int arrayElement) override
{
if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
{
mTopLevelArraySize = 1;
mSkipEnabled = false;
}
sh::VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
}
void enterStructAccess(const sh::ShaderVariable &structVar) override
{
mStructStackSize++;
sh::VariableNameVisitor::enterStructAccess(structVar);
}
void exitStructAccess(const sh::ShaderVariable &structVar) override
{
mStructStackSize--;
sh::VariableNameVisitor::exitStructAccess(structVar);
}
void visitNamedVariable(const sh::ShaderVariable &variable,
bool isRowMajor,
const std::string &name,
const std::string &mappedName) override
{
if (mSkipEnabled)
return;
// If getBlockMemberInfo returns false, the variable is optimized out.
sh::BlockMemberInfo variableInfo;
if (!mGetMemberInfo(name, mappedName, &variableInfo))
return;
std::string nameWithArrayIndex = name;
std::string mappedNameWithArrayIndex = mappedName;
if (variable.isArray())
{
nameWithArrayIndex += "[0]";
mappedNameWithArrayIndex += "[0]";
}
if (mBlockIndex == -1)
{
SetActive(mBufferVariablesOut, nameWithArrayIndex, mShaderType, variable.active);
return;
}
BufferVariable newBufferVariable(variable.type, variable.precision, nameWithArrayIndex,
variable.arraySizes, mBlockIndex, variableInfo);
newBufferVariable.mappedName = mappedNameWithArrayIndex;
newBufferVariable.setActive(mShaderType, variable.active);
newBufferVariable.topLevelArraySize = mTopLevelArraySize;
mBufferVariablesOut->push_back(newBufferVariable);
}
private:
const GetBlockMemberInfoFunc &mGetMemberInfo;
std::vector<BufferVariable> *mBufferVariablesOut;
const ShaderType mShaderType;
const int mBlockIndex;
unsigned int mStructStackSize = 0;
int mTopLevelArraySize = 1;
bool mSkipEnabled = false;
};
struct ShaderUniformCount
{
unsigned int vectorCount = 0;
unsigned int samplerCount = 0;
unsigned int imageCount = 0;
unsigned int atomicCounterCount = 0;
};
ShaderUniformCount &operator+=(ShaderUniformCount &lhs, const ShaderUniformCount &rhs)
{
lhs.vectorCount += rhs.vectorCount;
lhs.samplerCount += rhs.samplerCount;
lhs.imageCount += rhs.imageCount;
lhs.atomicCounterCount += rhs.atomicCounterCount;
return lhs;
}
// The purpose of this visitor is to flatten struct and array uniforms into a list of singleton
// uniforms. They are stored in separate lists by uniform type so they can be sorted in order.
// Counts for each uniform category are stored and can be queried with "getCounts".
class FlattenUniformVisitor : public sh::VariableNameVisitor
{
public:
FlattenUniformVisitor(ShaderType shaderType,
const sh::Uniform &uniform,
std::vector<LinkedUniform> *uniforms,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms)
: sh::VariableNameVisitor("", ""),
mShaderType(shaderType),
mMarkActive(uniform.active),
mMarkStaticUse(uniform.staticUse),
mBinding(uniform.binding),
mOffset(uniform.offset),
mLocation(uniform.location),
mUniforms(uniforms),
mSamplerUniforms(samplerUniforms),
mImageUniforms(imageUniforms),
mAtomicCounterUniforms(atomicCounterUniforms),
mUnusedUniforms(unusedUniforms)
{}
void visitNamedSampler(const sh::ShaderVariable &sampler,
const std::string &name,
const std::string &mappedName) override
{
visitNamedVariable(sampler, false, name, mappedName);
}
void visitNamedVariable(const sh::ShaderVariable &variable,
bool isRowMajor,
const std::string &name,
const std::string &mappedName) override
{
bool isSampler = IsSamplerType(variable.type);
bool isImage = IsImageType(variable.type);
bool isAtomicCounter = IsAtomicCounterType(variable.type);
std::vector<gl::LinkedUniform> *uniformList = mUniforms;
if (isSampler)
{
uniformList = mSamplerUniforms;
}
else if (isImage)
{
uniformList = mImageUniforms;
}
else if (isAtomicCounter)
{
uniformList = mAtomicCounterUniforms;
}
std::string fullNameWithArrayIndex(name);
std::string fullMappedNameWithArrayIndex(mappedName);
if (variable.isArray())
{
// We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
// Resources and including [0] at the end of array variable names.
fullNameWithArrayIndex += "[0]";
fullMappedNameWithArrayIndex += "[0]";
}
LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
if (existingUniform)
{
if (getBinding() != -1)
{
existingUniform->binding = getBinding();
}
if (getOffset() != -1)
{
existingUniform->offset = getOffset();
}
if (mLocation != -1)
{
existingUniform->location = mLocation;
}
if (mMarkActive)
{
existingUniform->active = true;
existingUniform->setActive(mShaderType, true);
}
if (mMarkStaticUse)
{
existingUniform->staticUse = true;
}
}
else
{
LinkedUniform linkedUniform(variable.type, variable.precision, fullNameWithArrayIndex,
variable.arraySizes, getBinding(), getOffset(), mLocation,
-1, sh::BlockMemberInfo::getDefaultBlockInfo());
linkedUniform.mappedName = fullMappedNameWithArrayIndex;
linkedUniform.active = mMarkActive;
linkedUniform.staticUse = mMarkStaticUse;
linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
if (mMarkActive)
{
linkedUniform.setActive(mShaderType, true);
}
else
{
mUnusedUniforms->emplace_back(linkedUniform.name, linkedUniform.isSampler());
}
uniformList->push_back(linkedUniform);
}
unsigned int elementCount = variable.getBasicTypeElementCount();
// Samplers and images aren't "real" uniforms, so they don't count towards register usage.
// Likewise, don't count "real" uniforms towards opaque count.
if (!IsOpaqueType(variable.type))
{
mUniformCount.vectorCount += VariableRegisterCount(variable.type) * elementCount;
}
mUniformCount.samplerCount += (isSampler ? elementCount : 0);
mUniformCount.imageCount += (isImage ? elementCount : 0);
mUniformCount.atomicCounterCount += (isAtomicCounter ? elementCount : 0);
if (mLocation != -1)
{
mLocation += elementCount;
}
}
void enterStructAccess(const sh::ShaderVariable &structVar) override
{
mStructStackSize++;
sh::VariableNameVisitor::enterStructAccess(structVar);
}
void exitStructAccess(const sh::ShaderVariable &structVar) override
{
mStructStackSize--;
sh::VariableNameVisitor::exitStructAccess(structVar);
}
ShaderUniformCount getCounts() const { return mUniformCount; }
private:
int getBinding() const { return mStructStackSize == 0 ? mBinding : -1; }
int getOffset() const { return mStructStackSize == 0 ? mOffset : -1; }
ShaderType mShaderType;
// Active and StaticUse are given separately because they are tracked at struct granularity.
bool mMarkActive;
bool mMarkStaticUse;
int mBinding;
int mOffset;
int mLocation;
std::vector<LinkedUniform> *mUniforms;
std::vector<LinkedUniform> *mSamplerUniforms;
std::vector<LinkedUniform> *mImageUniforms;
std::vector<LinkedUniform> *mAtomicCounterUniforms;
std::vector<UnusedUniform> *mUnusedUniforms;
ShaderUniformCount mUniformCount;
unsigned int mStructStackSize = 0;
};
} // anonymous namespace
UniformLinker::UniformLinker(const ProgramState &state) : mState(state) {}
@ -519,9 +870,18 @@ bool UniformLinker::flattenUniformsAndCheckCapsForShader(
ShaderUniformCount shaderUniformCount;
for (const sh::Uniform &uniform : shader->getUniforms())
{
shaderUniformCount +=
flattenUniform(uniform, &samplerUniforms, &imageUniforms, &atomicCounterUniforms,
&unusedUniforms, shader->getType());
FlattenUniformVisitor flattener(shader->getType(), uniform, &mUniforms, &samplerUniforms,
&imageUniforms, &atomicCounterUniforms, &unusedUniforms);
sh::TraverseShaderVariable(uniform, false, &flattener);
if (uniform.active)
{
shaderUniformCount += flattener.getCounts();
}
else
{
unusedUniforms.emplace_back(uniform.name, IsSamplerType(uniform.type));
}
}
ShaderType shaderType = shader->getType();
@ -599,276 +959,6 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoL
return true;
}
UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
const sh::Uniform &uniform,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms,
ShaderType shaderType)
{
int location = uniform.location;
ShaderUniformCount shaderUniformCount = flattenUniformImpl(
uniform, uniform.name, uniform.mappedName, samplerUniforms, imageUniforms,
atomicCounterUniforms, unusedUniforms, shaderType, uniform.active, uniform.staticUse,
uniform.binding, uniform.offset, &location);
if (uniform.active)
{
return shaderUniformCount;
}
else
{
unusedUniforms->emplace_back(uniform.name, IsSamplerType(uniform.type));
}
return ShaderUniformCount();
}
UniformLinker::ShaderUniformCount UniformLinker::flattenArrayOfStructsUniform(
const sh::ShaderVariable &uniform,
unsigned int arrayNestingIndex,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms,
ShaderType shaderType,
bool markActive,
bool markStaticUse,
int binding,
int offset,
int *location)
{
// Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
// innermost.
ShaderUniformCount shaderUniformCount;
const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
{
const std::string elementName = namePrefix + ArrayString(arrayElement);
const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
if (arrayNestingIndex + 1u < uniform.arraySizes.size())
{
shaderUniformCount += flattenArrayOfStructsUniform(
uniform, arrayNestingIndex + 1u, elementName, elementMappedName, samplerUniforms,
imageUniforms, atomicCounterUniforms, unusedUniforms, shaderType, markActive,
markStaticUse, binding, offset, location);
}
else
{
shaderUniformCount += flattenStructUniform(
uniform.fields, elementName, elementMappedName, samplerUniforms, imageUniforms,
atomicCounterUniforms, unusedUniforms, shaderType, markActive, markStaticUse,
binding, offset, location);
}
}
return shaderUniformCount;
}
UniformLinker::ShaderUniformCount UniformLinker::flattenStructUniform(
const std::vector<sh::ShaderVariable> &fields,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms,
ShaderType shaderType,
bool markActive,
bool markStaticUse,
int binding,
int offset,
int *location)
{
ShaderUniformCount shaderUniformCount;
for (const sh::ShaderVariable &field : fields)
{
const std::string &fieldName = namePrefix + "." + field.name;
const std::string &fieldMappedName = mappedNamePrefix + "." + field.mappedName;
shaderUniformCount +=
flattenUniformImpl(field, fieldName, fieldMappedName, samplerUniforms, imageUniforms,
atomicCounterUniforms, unusedUniforms, shaderType, markActive,
markStaticUse, -1, -1, location);
}
return shaderUniformCount;
}
UniformLinker::ShaderUniformCount UniformLinker::flattenArrayUniform(
const sh::ShaderVariable &uniform,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms,
ShaderType shaderType,
bool markActive,
bool markStaticUse,
int binding,
int offset,
int *location)
{
ShaderUniformCount shaderUniformCount;
ASSERT(uniform.isArray());
for (unsigned int arrayElement = 0u; arrayElement < uniform.getOutermostArraySize();
++arrayElement)
{
sh::ShaderVariable uniformElement = uniform;
uniformElement.indexIntoArray(arrayElement);
const std::string elementName = namePrefix + ArrayString(arrayElement);
const std::string elementMappedName = mappedNamePrefix + ArrayString(arrayElement);
shaderUniformCount +=
flattenUniformImpl(uniformElement, elementName, elementMappedName, samplerUniforms,
imageUniforms, atomicCounterUniforms, unusedUniforms, shaderType,
markActive, markStaticUse, binding, offset, location);
}
return shaderUniformCount;
}
UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
const sh::ShaderVariable &uniform,
const std::string &fullName,
const std::string &fullMappedName,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms,
ShaderType shaderType,
bool markActive,
bool markStaticUse,
int binding,
int offset,
int *location)
{
ASSERT(location);
ShaderUniformCount shaderUniformCount;
if (uniform.isStruct())
{
if (uniform.isArray())
{
shaderUniformCount += flattenArrayOfStructsUniform(
uniform, 0u, fullName, fullMappedName, samplerUniforms, imageUniforms,
atomicCounterUniforms, unusedUniforms, shaderType, markActive, markStaticUse,
binding, offset, location);
}
else
{
shaderUniformCount += flattenStructUniform(
uniform.fields, fullName, fullMappedName, samplerUniforms, imageUniforms,
atomicCounterUniforms, unusedUniforms, shaderType, markActive, markStaticUse,
binding, offset, location);
}
return shaderUniformCount;
}
if (uniform.isArrayOfArrays())
{
// GLES 3.1 November 2016 section 7.3.1 page 77:
// "For an active variable declared as an array of an aggregate data type (structures or
// arrays), a separate entry will be generated for each active array element"
return flattenArrayUniform(uniform, fullName, fullMappedName, samplerUniforms,
imageUniforms, atomicCounterUniforms, unusedUniforms, shaderType,
markActive, markStaticUse, binding, offset, location);
}
// Not a struct
bool isSampler = IsSamplerType(uniform.type);
bool isImage = IsImageType(uniform.type);
bool isAtomicCounter = IsAtomicCounterType(uniform.type);
std::vector<gl::LinkedUniform> *uniformList = &mUniforms;
if (isSampler)
{
uniformList = samplerUniforms;
}
else if (isImage)
{
uniformList = imageUniforms;
}
else if (isAtomicCounter)
{
uniformList = atomicCounterUniforms;
}
std::string fullNameWithArrayIndex(fullName);
std::string fullMappedNameWithArrayIndex(fullMappedName);
if (uniform.isArray())
{
// We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active Resources
// and including [0] at the end of array variable names.
fullNameWithArrayIndex += "[0]";
fullMappedNameWithArrayIndex += "[0]";
}
LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
if (existingUniform)
{
if (binding != -1)
{
existingUniform->binding = binding;
}
if (offset != -1)
{
existingUniform->offset = offset;
}
if (*location != -1)
{
existingUniform->location = *location;
}
if (markActive)
{
existingUniform->active = true;
existingUniform->setActive(shaderType, true);
}
if (markStaticUse)
{
existingUniform->staticUse = true;
}
}
else
{
ASSERT(uniform.arraySizes.size() <= 1u);
LinkedUniform linkedUniform(uniform.type, uniform.precision, fullNameWithArrayIndex,
uniform.arraySizes, binding, offset, *location, -1,
sh::BlockMemberInfo::getDefaultBlockInfo());
linkedUniform.mappedName = fullMappedNameWithArrayIndex;
linkedUniform.active = markActive;
linkedUniform.staticUse = markStaticUse;
linkedUniform.flattenedOffsetInParentArrays = uniform.flattenedOffsetInParentArrays;
if (markActive)
{
linkedUniform.setActive(shaderType, true);
}
else
{
unusedUniforms->emplace_back(linkedUniform.name, linkedUniform.isSampler());
}
uniformList->push_back(linkedUniform);
}
// Struct and array of arrays uniforms get flattened so we can use getBasicTypeElementCount().
unsigned int elementCount = uniform.getBasicTypeElementCount();
// Samplers and images aren't "real" uniforms, so they don't count towards register usage.
// Likewise, don't count "real" uniforms towards opaque count.
shaderUniformCount.vectorCount =
(IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
shaderUniformCount.imageCount = (isImage ? elementCount : 0);
shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
if (*location != -1)
{
*location += elementCount;
}
return shaderUniformCount;
}
bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
{
unsigned int atomicCounterCount = 0;
@ -901,8 +991,8 @@ void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
mShaderBlocks[shaderType] = blocks;
}
void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
const GetBlockMemberInfo &getMemberInfo) const
void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize,
const GetBlockMemberInfoFunc &getMemberInfo) const
{
ASSERT(mBlocksOut->empty());
@ -915,182 +1005,40 @@ void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
continue;
}
for (const auto &block : *mShaderBlocks[shaderType])
for (const sh::InterfaceBlock &block : *mShaderBlocks[shaderType])
{
if (!IsActiveInterfaceBlock(block))
continue;
if (visitedList.count(block.name) > 0)
{
if (block.active)
{
for (InterfaceBlock &priorBlock : *mBlocksOut)
{
if (block.name == priorBlock.name)
{
priorBlock.setActive(shaderType, true);
// Update the block members static use.
defineBlockMembers(nullptr, block.fields, block.fieldPrefix(),
block.fieldMappedPrefix(), -1,
block.blockType == sh::BlockType::BLOCK_BUFFER, 1,
shaderType);
}
}
}
}
else
if (visitedList.count(block.name) == 0)
{
defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
visitedList.insert(block.name);
continue;
}
if (!block.active)
continue;
for (InterfaceBlock &priorBlock : *mBlocksOut)
{
if (block.name == priorBlock.name)
{
priorBlock.setActive(shaderType, true);
std::unique_ptr<sh::ShaderVariableVisitor> visitor(
getVisitor(getMemberInfo, block.fieldPrefix(), block.fieldMappedPrefix(),
shaderType, -1));
sh::TraverseShaderVariables(block.fields, false, visitor.get());
}
}
}
}
}
template <typename VarT>
void InterfaceBlockLinker::defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
const VarT &field,
unsigned int arrayNestingIndex,
const std::string &prefix,
const std::string &mappedPrefix,
int blockIndex,
bool singleEntryForTopLevelArray,
int topLevelArraySize,
ShaderType shaderType) const
{
// Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
// innermost.
unsigned int entryGenerationArraySize = field.getNestedArraySize(arrayNestingIndex);
if (singleEntryForTopLevelArray)
{
entryGenerationArraySize = 1;
}
for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize; ++arrayElement)
{
const std::string elementName = prefix + ArrayString(arrayElement);
const std::string elementMappedName = mappedPrefix + ArrayString(arrayElement);
if (arrayNestingIndex + 1u < field.arraySizes.size())
{
defineArrayOfStructsBlockMembers(getMemberInfo, field, arrayNestingIndex + 1u,
elementName, elementMappedName, blockIndex, false,
topLevelArraySize, shaderType);
}
else
{
defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
blockIndex, false, topLevelArraySize, shaderType);
}
}
}
template <typename VarT>
void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
const std::vector<VarT> &fields,
const std::string &prefix,
const std::string &mappedPrefix,
int blockIndex,
bool singleEntryForTopLevelArray,
int topLevelArraySize,
ShaderType shaderType) const
{
for (const VarT &field : fields)
{
std::string fullName = (prefix.empty() ? field.name : prefix + "." + field.name);
std::string fullMappedName =
(mappedPrefix.empty() ? field.mappedName : mappedPrefix + "." + field.mappedName);
defineBlockMember(getMemberInfo, field, fullName, fullMappedName, blockIndex,
singleEntryForTopLevelArray, topLevelArraySize, shaderType);
}
}
template <typename VarT>
void InterfaceBlockLinker::defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
const VarT &field,
const std::string &fullName,
const std::string &fullMappedName,
int blockIndex,
bool singleEntryForTopLevelArray,
int topLevelArraySize,
ShaderType shaderType) const
{
int nextArraySize = topLevelArraySize;
if (((field.isArray() && field.isStruct()) || field.isArrayOfArrays()) &&
singleEntryForTopLevelArray)
{
// In OpenGL ES 3.10 spec, session 7.3.1.1 'For an active shader storage block
// member declared as an array of an aggregate type, an entry will be generated only
// for the first array element, regardless of its type.'
nextArraySize = field.getOutermostArraySize();
}
if (field.isStruct())
{
if (field.isArray())
{
defineArrayOfStructsBlockMembers(getMemberInfo, field, 0u, fullName, fullMappedName,
blockIndex, singleEntryForTopLevelArray, nextArraySize,
shaderType);
}
else
{
ASSERT(nextArraySize == topLevelArraySize);
defineBlockMembers(getMemberInfo, field.fields, fullName, fullMappedName, blockIndex,
false, nextArraySize, shaderType);
}
return;
}
if (field.isArrayOfArrays())
{
unsigned int entryGenerationArraySize = field.getOutermostArraySize();
if (singleEntryForTopLevelArray)
{
entryGenerationArraySize = 1u;
}
for (unsigned int arrayElement = 0u; arrayElement < entryGenerationArraySize;
++arrayElement)
{
VarT fieldElement = field;
fieldElement.indexIntoArray(arrayElement);
const std::string elementName = fullName + ArrayString(arrayElement);
const std::string elementMappedName = fullMappedName + ArrayString(arrayElement);
defineBlockMember(getMemberInfo, fieldElement, elementName, elementMappedName,
blockIndex, false, nextArraySize, shaderType);
}
return;
}
std::string fullNameWithArrayIndex = fullName;
std::string fullMappedNameWithArrayIndex = fullMappedName;
if (field.isArray())
{
fullNameWithArrayIndex += "[0]";
fullMappedNameWithArrayIndex += "[0]";
}
if (blockIndex == -1)
{
updateBlockMemberActiveImpl(fullNameWithArrayIndex, shaderType, field.active);
}
else
{
// If getBlockMemberInfo returns false, the variable is optimized out.
sh::BlockMemberInfo memberInfo;
if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
{
return;
}
ASSERT(nextArraySize == topLevelArraySize);
defineBlockMemberImpl(field, fullNameWithArrayIndex, fullMappedNameWithArrayIndex,
blockIndex, memberInfo, nextArraySize, shaderType);
}
}
void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
const GetBlockMemberInfo &getMemberInfo,
void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
const GetBlockMemberInfoFunc &getMemberInfo,
const sh::InterfaceBlock &interfaceBlock,
ShaderType shaderType) const
{
@ -1101,9 +1049,12 @@ void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize
// Track the first and last block member index to determine the range of active block members in
// the block.
size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
interfaceBlock.fieldMappedPrefix(), blockIndex,
interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER, 1, shaderType);
std::unique_ptr<sh::ShaderVariableVisitor> visitor(
getVisitor(getMemberInfo, interfaceBlock.fieldPrefix(), interfaceBlock.fieldMappedPrefix(),
shaderType, blockIndex));
sh::TraverseShaderVariables(interfaceBlock.fields, false, visitor.get());
size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
@ -1155,34 +1106,20 @@ UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
UniformBlockLinker::~UniformBlockLinker() {}
void UniformBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
const std::string &fullName,
const std::string &fullMappedName,
int blockIndex,
const sh::BlockMemberInfo &memberInfo,
int /*topLevelArraySize*/,
ShaderType shaderType) const
{
LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySizes, -1, -1, -1,
blockIndex, memberInfo);
newUniform.mappedName = fullMappedName;
newUniform.setActive(shaderType, field.active);
// Since block uniforms have no location, we don't need to store them in the uniform locations
// list.
mUniformsOut->push_back(newUniform);
}
size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
{
return mUniformsOut->size();
}
void UniformBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
ShaderType shaderType,
bool active) const
sh::ShaderVariableVisitor *UniformBlockLinker::getVisitor(
const GetBlockMemberInfoFunc &getMemberInfo,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
ShaderType shaderType,
int blockIndex) const
{
SetActive(mUniformsOut, fullName, shaderType, active);
return new UniformBlockEncodingVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
mUniformsOut, shaderType, blockIndex);
}
// ShaderStorageBlockLinker implementation.
@ -1193,34 +1130,20 @@ ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *
ShaderStorageBlockLinker::~ShaderStorageBlockLinker() {}
void ShaderStorageBlockLinker::defineBlockMemberImpl(const sh::ShaderVariable &field,
const std::string &fullName,
const std::string &fullMappedName,
int blockIndex,
const sh::BlockMemberInfo &memberInfo,
int topLevelArraySize,
ShaderType shaderType) const
{
BufferVariable newBufferVariable(field.type, field.precision, fullName, field.arraySizes,
blockIndex, memberInfo);
newBufferVariable.mappedName = fullMappedName;
newBufferVariable.setActive(shaderType, field.active);
newBufferVariable.topLevelArraySize = topLevelArraySize;
mBufferVariablesOut->push_back(newBufferVariable);
}
size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
{
return mBufferVariablesOut->size();
}
void ShaderStorageBlockLinker::updateBlockMemberActiveImpl(const std::string &fullName,
ShaderType shaderType,
bool active) const
sh::ShaderVariableVisitor *ShaderStorageBlockLinker::getVisitor(
const GetBlockMemberInfoFunc &getMemberInfo,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
ShaderType shaderType,
int blockIndex) const
{
SetActive(mBufferVariablesOut, fullName, shaderType, active);
return new ShaderStorageBlockVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
mBufferVariablesOut, shaderType, blockIndex);
}
// AtomicCounterBufferLinker implementation.

Просмотреть файл

@ -23,6 +23,7 @@ namespace sh
struct BlockMemberInfo;
struct InterfaceBlock;
struct ShaderVariable;
class ShaderVariableVisitor;
struct Uniform;
} // namespace sh
@ -57,28 +58,6 @@ class UniformLinker final : angle::NonCopyable
std::vector<VariableLocation> *uniformLocations);
private:
struct ShaderUniformCount
{
ShaderUniformCount() : vectorCount(0), samplerCount(0), imageCount(0), atomicCounterCount(0)
{}
ShaderUniformCount(const ShaderUniformCount &other) = default;
ShaderUniformCount &operator=(const ShaderUniformCount &other) = default;
ShaderUniformCount &operator+=(const ShaderUniformCount &other)
{
vectorCount += other.vectorCount;
samplerCount += other.samplerCount;
imageCount += other.imageCount;
atomicCounterCount += other.atomicCounterCount;
return *this;
}
unsigned int vectorCount;
unsigned int samplerCount;
unsigned int imageCount;
unsigned int atomicCounterCount;
};
bool validateGraphicsUniforms(InfoLog &infoLog) const;
bool flattenUniformsAndCheckCapsForShader(Shader *shader,
@ -92,73 +71,6 @@ class UniformLinker final : angle::NonCopyable
bool flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog);
bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog);
ShaderUniformCount flattenUniform(const sh::Uniform &uniform,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms,
ShaderType shaderType);
ShaderUniformCount flattenArrayOfStructsUniform(
const sh::ShaderVariable &uniform,
unsigned int arrayNestingIndex,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms,
ShaderType shaderType,
bool markActive,
bool markStaticUse,
int binding,
int offset,
int *location);
ShaderUniformCount flattenStructUniform(const std::vector<sh::ShaderVariable> &fields,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms,
ShaderType shaderType,
bool markActive,
bool markStaticUse,
int binding,
int offset,
int *location);
ShaderUniformCount flattenArrayUniform(const sh::ShaderVariable &uniform,
const std::string &fullName,
const std::string &fullMappedName,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms,
ShaderType shaderType,
bool markActive,
bool markStaticUse,
int binding,
int offset,
int *location);
// markActive and markStaticUse are given as separate parameters because they are tracked here
// at struct granularity.
ShaderUniformCount flattenUniformImpl(const sh::ShaderVariable &uniform,
const std::string &fullName,
const std::string &fullMappedName,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
std::vector<UnusedUniform> *unusedUniforms,
ShaderType shaderType,
bool markActive,
bool markStaticUse,
int binding,
int offset,
int *location);
bool indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings);
bool gatherUniformLocationsAndCheckConflicts(InfoLog &infoLog,
const ProgramBindings &uniformLocationBindings,
@ -172,6 +84,11 @@ class UniformLinker final : angle::NonCopyable
std::vector<VariableLocation> mUniformLocations;
};
using GetBlockSizeFunc = std::function<
bool(const std::string &blockName, const std::string &blockMappedName, size_t *sizeOut)>;
using GetBlockMemberInfoFunc = std::function<
bool(const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut)>;
// This class is intended to be used during the link step to store interface block information.
// It is called by the Impl class during ProgramImpl::link so that it has access to the
// real block size and layout.
@ -180,72 +97,32 @@ class InterfaceBlockLinker : angle::NonCopyable
public:
virtual ~InterfaceBlockLinker();
using GetBlockSize = std::function<
bool(const std::string &blockName, const std::string &blockMappedName, size_t *sizeOut)>;
using GetBlockMemberInfo = std::function<
bool(const std::string &name, const std::string &mappedName, sh::BlockMemberInfo *infoOut)>;
// This is called once per shader stage. It stores a pointer to the block vector, so it's
// important that this class does not persist longer than the duration of Program::link.
void addShaderBlocks(ShaderType shader, const std::vector<sh::InterfaceBlock> *blocks);
// This is called once during a link operation, after all shader blocks are added.
void linkBlocks(const GetBlockSize &getBlockSize,
const GetBlockMemberInfo &getMemberInfo) const;
void linkBlocks(const GetBlockSizeFunc &getBlockSize,
const GetBlockMemberInfoFunc &getMemberInfo) const;
protected:
InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut);
void defineInterfaceBlock(const GetBlockSize &getBlockSize,
const GetBlockMemberInfo &getMemberInfo,
void defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
const GetBlockMemberInfoFunc &getMemberInfo,
const sh::InterfaceBlock &interfaceBlock,
ShaderType shaderType) const;
template <typename VarT>
void defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
const std::vector<VarT> &fields,
const std::string &prefix,
const std::string &mappedPrefix,
int blockIndex,
bool singleEntryForTopLevelArray,
int topLevelArraySize,
ShaderType shaderType) const;
template <typename VarT>
void defineBlockMember(const GetBlockMemberInfo &getMemberInfo,
const VarT &field,
const std::string &fullName,
const std::string &fullMappedName,
int blockIndex,
bool singleEntryForTopLevelArray,
int topLevelArraySize,
ShaderType shaderType) const;
virtual void defineBlockMemberImpl(const sh::ShaderVariable &field,
const std::string &fullName,
const std::string &fullMappedName,
int blockIndex,
const sh::BlockMemberInfo &memberInfo,
int topLevelArraySize,
ShaderType shaderType) const = 0;
virtual size_t getCurrentBlockMemberIndex() const = 0;
virtual void updateBlockMemberActiveImpl(const std::string &fullName,
ShaderType shaderType,
bool active) const = 0;
virtual size_t getCurrentBlockMemberIndex() const = 0;
ShaderMap<const std::vector<sh::InterfaceBlock> *> mShaderBlocks;
std::vector<InterfaceBlock> *mBlocksOut;
private:
template <typename VarT>
void defineArrayOfStructsBlockMembers(const GetBlockMemberInfo &getMemberInfo,
const VarT &field,
unsigned int arrayNestingIndex,
const std::string &prefix,
const std::string &mappedPrefix,
int blockIndex,
bool singleEntryForTopLevelArray,
int topLevelArraySize,
ShaderType shaderType) const;
virtual sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
ShaderType shaderType,
int blockIndex) const = 0;
};
class UniformBlockLinker final : public InterfaceBlockLinker
@ -256,17 +133,14 @@ class UniformBlockLinker final : public InterfaceBlockLinker
~UniformBlockLinker() override;
private:
void defineBlockMemberImpl(const sh::ShaderVariable &field,
const std::string &fullName,
const std::string &fullMappedName,
int blockIndex,
const sh::BlockMemberInfo &memberInfo,
int topLevelArraySize,
ShaderType shaderType) const override;
size_t getCurrentBlockMemberIndex() const override;
void updateBlockMemberActiveImpl(const std::string &fullName,
ShaderType shaderType,
bool active) const override;
sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
ShaderType shaderType,
int blockIndex) const override;
std::vector<LinkedUniform> *mUniformsOut;
};
@ -278,17 +152,14 @@ class ShaderStorageBlockLinker final : public InterfaceBlockLinker
~ShaderStorageBlockLinker() override;
private:
void defineBlockMemberImpl(const sh::ShaderVariable &field,
const std::string &fullName,
const std::string &fullMappedName,
int blockIndex,
const sh::BlockMemberInfo &memberInfo,
int topLevelArraySize,
ShaderType shaderType) const override;
size_t getCurrentBlockMemberIndex() const override;
void updateBlockMemberActiveImpl(const std::string &fullName,
ShaderType shaderType,
bool active) const override;
sh::ShaderVariableVisitor *getVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
const std::string &namePrefix,
const std::string &mappedNamePrefix,
ShaderType shaderType,
int blockIndex) const override;
std::vector<BufferVariable> *mBufferVariablesOut;
};

Просмотреть файл

@ -245,6 +245,66 @@ bool InterfaceBlockInfo::getBlockMemberInfo(const std::string &name,
*infoOut = infoIter->second;
return true;
};
// Helper class that gathers uniform info from the default uniform block.
class UniformEncodingVisitorD3D : public sh::BlockEncoderVisitor
{
public:
UniformEncodingVisitorD3D(gl::ShaderType shaderType,
HLSLRegisterType registerType,
sh::BlockLayoutEncoder *encoder,
D3DUniformMap *uniformMapOut)
: sh::BlockEncoderVisitor("", "", encoder),
mShaderType(shaderType),
mRegisterType(registerType),
mUniformMapOut(uniformMapOut)
{}
void visitNamedSampler(const sh::ShaderVariable &sampler,
const std::string &name,
const std::string &mappedName) override
{
auto uniformMapEntry = mUniformMapOut->find(name);
if (uniformMapEntry == mUniformMapOut->end())
{
(*mUniformMapOut)[name] =
new D3DUniform(sampler.type, mRegisterType, name, sampler.arraySizes, true);
}
}
void encodeVariable(const sh::ShaderVariable &variable,
const sh::BlockMemberInfo &variableInfo,
const std::string &name,
const std::string &mappedName) override
{
auto uniformMapEntry = mUniformMapOut->find(name);
D3DUniform *d3dUniform = nullptr;
if (uniformMapEntry != mUniformMapOut->end())
{
d3dUniform = uniformMapEntry->second;
}
else
{
d3dUniform =
new D3DUniform(variable.type, mRegisterType, name, variable.arraySizes, true);
(*mUniformMapOut)[name] = d3dUniform;
}
d3dUniform->registerElement = static_cast<unsigned int>(
sh::BlockLayoutEncoder::GetBlockRegisterElement(variableInfo));
unsigned int reg =
static_cast<unsigned int>(sh::BlockLayoutEncoder::GetBlockRegister(variableInfo));
ASSERT(mShaderType != gl::ShaderType::InvalidEnum);
d3dUniform->mShaderRegisterIndexes[mShaderType] = reg;
}
private:
gl::ShaderType mShaderType;
HLSLRegisterType mRegisterType;
D3DUniformMap *mUniformMapOut;
};
} // anonymous namespace
// D3DUniform Implementation
@ -2130,33 +2190,42 @@ void ProgramD3D::defineUniformBase(const gl::Shader *shader,
const sh::Uniform &uniform,
D3DUniformMap *uniformMap)
{
sh::DummyBlockEncoder dummyEncoder;
// Samplers get their registers assigned in assignAllSamplerRegisters, and images get their
// registers assigned in assignAllImageRegisters.
if (gl::IsSamplerType(uniform.type))
{
defineUniform(shader->getType(), uniform, uniform.name, HLSLRegisterType::Texture, nullptr,
uniformMap);
UniformEncodingVisitorD3D visitor(shader->getType(), HLSLRegisterType::Texture,
&dummyEncoder, uniformMap);
sh::TraverseShaderVariable(uniform, false, &visitor);
return;
}
else if (gl::IsImageType(uniform.type))
if (gl::IsImageType(uniform.type))
{
if (uniform.readonly)
{
defineUniform(shader->getType(), uniform, uniform.name, HLSLRegisterType::Texture,
nullptr, uniformMap);
UniformEncodingVisitorD3D visitor(shader->getType(), HLSLRegisterType::Texture,
&dummyEncoder, uniformMap);
sh::TraverseShaderVariable(uniform, false, &visitor);
}
else
{
defineUniform(shader->getType(), uniform, uniform.name,
HLSLRegisterType::UnorderedAccessView, nullptr, uniformMap);
UniformEncodingVisitorD3D visitor(shader->getType(),
HLSLRegisterType::UnorderedAccessView, &dummyEncoder,
uniformMap);
sh::TraverseShaderVariable(uniform, false, &visitor);
}
mImageBindingMap[uniform.name] = uniform.binding;
return;
}
else if (uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn())
if (uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn())
{
defineUniform(shader->getType(), uniform, uniform.name, HLSLRegisterType::None, nullptr,
uniformMap);
UniformEncodingVisitorD3D visitor(shader->getType(), HLSLRegisterType::None, &dummyEncoder,
uniformMap);
sh::TraverseShaderVariable(uniform, false, &visitor);
return;
}
@ -2166,8 +2235,9 @@ void ProgramD3D::defineUniformBase(const gl::Shader *shader,
sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType), true);
encoder.skipRegisters(startRegister);
defineUniform(shader->getType(), uniform, uniform.name, HLSLRegisterType::None, &encoder,
uniformMap);
UniformEncodingVisitorD3D visitor(shader->getType(), HLSLRegisterType::None, &encoder,
uniformMap);
sh::TraverseShaderVariable(uniform, false, &visitor);
}
D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name)
@ -2183,156 +2253,6 @@ D3DUniform *ProgramD3D::getD3DUniformByName(const std::string &name)
return nullptr;
}
void ProgramD3D::defineStructUniformFields(gl::ShaderType shaderType,
const std::vector<sh::ShaderVariable> &fields,
const std::string &namePrefix,
const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap)
{
if (encoder)
encoder->enterAggregateType();
for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
{
const sh::ShaderVariable &field = fields[fieldIndex];
const std::string &fieldFullName = (namePrefix + "." + field.name);
// Samplers get their registers assigned in assignAllSamplerRegisters.
// Also they couldn't use the same encoder as the rest of the struct, since they are
// extracted out of the struct by the shader translator.
if (gl::IsSamplerType(field.type))
{
defineUniform(shaderType, field, fieldFullName, regType, nullptr, uniformMap);
}
else
{
defineUniform(shaderType, field, fieldFullName, regType, encoder, uniformMap);
}
}
if (encoder)
encoder->exitAggregateType();
}
void ProgramD3D::defineArrayOfStructsUniformFields(gl::ShaderType shaderType,
const sh::ShaderVariable &uniform,
unsigned int arrayNestingIndex,
const std::string &prefix,
const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap)
{
// Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
// innermost.
const unsigned int currentArraySize = uniform.getNestedArraySize(arrayNestingIndex);
for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
{
const std::string &elementString = prefix + ArrayString(arrayElement);
if (arrayNestingIndex + 1u < uniform.arraySizes.size())
{
defineArrayOfStructsUniformFields(shaderType, uniform, arrayNestingIndex + 1u,
elementString, regType, encoder, uniformMap);
}
else
{
defineStructUniformFields(shaderType, uniform.fields, elementString, regType, encoder,
uniformMap);
}
}
}
void ProgramD3D::defineArrayUniformElements(gl::ShaderType shaderType,
const sh::ShaderVariable &uniform,
const std::string &fullName,
const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap)
{
if (encoder)
encoder->enterAggregateType();
sh::ShaderVariable uniformElement = uniform;
uniformElement.arraySizes.pop_back();
for (unsigned int arrayIndex = 0u; arrayIndex < uniform.getOutermostArraySize(); ++arrayIndex)
{
std::string elementFullName = fullName + ArrayString(arrayIndex);
defineUniform(shaderType, uniformElement, elementFullName, regType, encoder, uniformMap);
}
if (encoder)
encoder->exitAggregateType();
}
void ProgramD3D::defineUniform(gl::ShaderType shaderType,
const sh::ShaderVariable &uniform,
const std::string &fullName,
const HLSLRegisterType regType,
sh::HLSLBlockEncoder *encoder,
D3DUniformMap *uniformMap)
{
if (uniform.isStruct())
{
if (uniform.isArray())
{
defineArrayOfStructsUniformFields(shaderType, uniform, 0u, fullName, regType, encoder,
uniformMap);
}
else
{
defineStructUniformFields(shaderType, uniform.fields, fullName, regType, encoder,
uniformMap);
}
return;
}
if (uniform.isArrayOfArrays())
{
defineArrayUniformElements(shaderType, uniform, fullName, regType, encoder, uniformMap);
return;
}
// Not a struct. Arrays are treated as aggregate types.
if (uniform.isArray() && encoder)
{
encoder->enterAggregateType();
}
// Advance the uniform offset, to track registers allocation for structs
sh::BlockMemberInfo blockInfo =
encoder ? encoder->encodeType(uniform.type, uniform.arraySizes, false)
: sh::BlockMemberInfo::getDefaultBlockInfo();
auto uniformMapEntry = uniformMap->find(fullName);
D3DUniform *d3dUniform = nullptr;
if (uniformMapEntry != uniformMap->end())
{
d3dUniform = uniformMapEntry->second;
}
else
{
d3dUniform = new D3DUniform(uniform.type, regType, fullName, uniform.arraySizes, true);
(*uniformMap)[fullName] = d3dUniform;
}
if (encoder)
{
d3dUniform->registerElement =
static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo));
unsigned int reg =
static_cast<unsigned int>(sh::HLSLBlockEncoder::getBlockRegister(blockInfo));
ASSERT(shaderType != gl::ShaderType::InvalidEnum);
d3dUniform->mShaderRegisterIndexes[shaderType] = reg;
// Arrays are treated as aggregate types
if (uniform.isArray())
{
encoder->exitAggregateType();
}
}
}
// Assume count is already clamped.
template <typename T>
void ProgramD3D::setUniformImpl(const gl::VariableLocation &locationInfo,
@ -2450,9 +2370,9 @@ void ProgramD3D::assignSamplerRegisters(size_t uniformIndex)
// mD3DUniforms. However, the sampler register info is stored in the shader only for the
// outermost array.
std::vector<unsigned int> subscripts;
const std::string baseName = gl::ParseResourceName(d3dUniform->name, &subscripts);
unsigned int registerOffset = mState.getUniforms()[uniformIndex].flattenedOffsetInParentArrays *
d3dUniform->getArraySizeProduct();
const std::string baseName = gl::ParseResourceName(d3dUniform->name, &subscripts);
unsigned int registerOffset =
mState.getUniforms()[uniformIndex].parentArrayIndex() * d3dUniform->getArraySizeProduct();
bool hasUniform = false;
for (gl::ShaderType shaderType : gl::AllShaderTypes())
@ -2525,9 +2445,9 @@ void ProgramD3D::assignImageRegisters(size_t uniformIndex)
// mD3DUniforms. However, the image register info is stored in the shader only for the
// outermost array.
std::vector<unsigned int> subscripts;
const std::string baseName = gl::ParseResourceName(d3dUniform->name, &subscripts);
unsigned int registerOffset = mState.getUniforms()[uniformIndex].flattenedOffsetInParentArrays *
d3dUniform->getArraySizeProduct();
const std::string baseName = gl::ParseResourceName(d3dUniform->name, &subscripts);
unsigned int registerOffset =
mState.getUniforms()[uniformIndex].parentArrayIndex() * d3dUniform->getArraySizeProduct();
const gl::Shader *computeShader = mState.getAttachedShader(gl::ShaderType::Compute);
if (computeShader)

Просмотреть файл

@ -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);