Refactor interface block linking.
This moves the logic for interface block linking. The new design is
intended to be flexible enough to be passed into a back-end call to
ProgramImpl::link. Then, the Impl object can be responsible for both
filtering out unreferenced interface blocks as well as having access
to the linked interface block information.
A future change will pass the InterfaceBlockLinker objects (or objects
when dealing with ES 3.1 and Shader Storage Blocks) to the Impl. This
will help fix a D3D11 back-end bug where we would need acess to the
Shader objects to finish a deferred uniform block link.
This should also potentially make it easier for the back-ends to
determine Shader Storage Block size and properties without defining
new Impl methods.
BUG=angleproject:2208
Change-Id: Ic5244a808dba44ba1a8c08d9ee701952034d2b18
Reviewed-on: https://chromium-review.googlesource.com/746203
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 286aedc..de9724c 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -2826,71 +2826,76 @@
// TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer.
}
-void Program::gatherComputeBlockInfo(const std::vector<sh::InterfaceBlock> &computeBlocks)
+void Program::gatherUniformBlockInfo(const gl::Context *context)
{
- for (const sh::InterfaceBlock &computeBlock : computeBlocks)
+ UniformBlockLinker blockLinker(&mState.mUniformBlocks, &mState.mUniforms);
+
+ if (mState.mAttachedVertexShader)
{
-
- // Only 'packed' blocks are allowed to be considered inactive.
- if (!computeBlock.staticUse && computeBlock.layout == sh::BLOCKLAYOUT_PACKED)
- continue;
-
- defineInterfaceBlock(computeBlock, GL_COMPUTE_SHADER);
+ blockLinker.addShaderBlocks(GL_VERTEX_SHADER,
+ &mState.mAttachedVertexShader->getUniformBlocks(context));
}
+
+ if (mState.mAttachedFragmentShader)
+ {
+ blockLinker.addShaderBlocks(GL_FRAGMENT_SHADER,
+ &mState.mAttachedFragmentShader->getUniformBlocks(context));
+ }
+
+ if (mState.mAttachedComputeShader)
+ {
+ blockLinker.addShaderBlocks(GL_COMPUTE_SHADER,
+ &mState.mAttachedComputeShader->getUniformBlocks(context));
+ }
+
+ auto getImplBlockSize = [this](const std::string &name, const std::string &mappedName,
+ size_t *sizeOut) {
+ return this->mProgram->getUniformBlockSize(name, mappedName, sizeOut);
+ };
+
+ auto getImplMemberInfo = [this](const std::string &name, const std::string &mappedName,
+ sh::BlockMemberInfo *infoOut) {
+ return this->mProgram->getUniformBlockMemberInfo(name, mappedName, infoOut);
+ };
+
+ blockLinker.linkBlocks(getImplBlockSize, getImplMemberInfo);
}
-void Program::gatherVertexAndFragmentBlockInfo(
- const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
- const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks)
+void Program::gatherShaderStorageBlockInfo(const gl::Context *context)
{
- std::set<std::string> visitedList;
+ ShaderStorageBlockLinker blockLinker(&mState.mShaderStorageBlocks);
- for (const sh::InterfaceBlock &vertexBlock : vertexInterfaceBlocks)
+ if (mState.mAttachedVertexShader)
{
- // Only 'packed' blocks are allowed to be considered inactive.
- if (!vertexBlock.staticUse && vertexBlock.layout == sh::BLOCKLAYOUT_PACKED)
- continue;
-
- defineInterfaceBlock(vertexBlock, GL_VERTEX_SHADER);
- visitedList.insert(vertexBlock.name);
+ blockLinker.addShaderBlocks(GL_VERTEX_SHADER,
+ &mState.mAttachedVertexShader->getShaderStorageBlocks(context));
}
- for (const sh::InterfaceBlock &fragmentBlock : fragmentInterfaceBlocks)
+ if (mState.mAttachedFragmentShader)
{
- // Only 'packed' blocks are allowed to be considered inactive.
- if (!fragmentBlock.staticUse && fragmentBlock.layout == sh::BLOCKLAYOUT_PACKED)
- continue;
-
- if (visitedList.count(fragmentBlock.name) > 0)
- {
- if (fragmentBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
- {
- for (InterfaceBlock &block : mState.mUniformBlocks)
- {
- if (block.name == fragmentBlock.name)
- {
- block.fragmentStaticUse = fragmentBlock.staticUse;
- }
- }
- }
- else
- {
- ASSERT(fragmentBlock.blockType == sh::BlockType::BLOCK_BUFFER);
- for (InterfaceBlock &block : mState.mShaderStorageBlocks)
- {
- if (block.name == fragmentBlock.name)
- {
- block.fragmentStaticUse = fragmentBlock.staticUse;
- }
- }
- }
-
- continue;
- }
-
- defineInterfaceBlock(fragmentBlock, GL_FRAGMENT_SHADER);
- visitedList.insert(fragmentBlock.name);
+ blockLinker.addShaderBlocks(
+ GL_FRAGMENT_SHADER, &mState.mAttachedFragmentShader->getShaderStorageBlocks(context));
}
+
+ if (mState.mAttachedComputeShader)
+ {
+ blockLinker.addShaderBlocks(
+ GL_COMPUTE_SHADER, &mState.mAttachedComputeShader->getShaderStorageBlocks(context));
+ }
+
+ // We don't have a way of determining block info for shader storage blocks yet.
+ // TODO(jiajia.qin@intel.com): Determine correct block size and layout.
+ auto getImplBlockSize = [this](const std::string &name, const std::string &mappedName,
+ size_t *sizeOut) {
+ return this->mProgram->getUniformBlockSize(name, mappedName, sizeOut);
+ };
+
+ auto getImplMemberInfo = [this](const std::string &name, const std::string &mappedName,
+ sh::BlockMemberInfo *infoOut) {
+ return this->mProgram->getUniformBlockMemberInfo(name, mappedName, infoOut);
+ };
+
+ blockLinker.linkBlocks(getImplBlockSize, getImplMemberInfo);
}
void Program::gatherInterfaceBlockInfo(const Context *context)
@@ -2898,24 +2903,10 @@
ASSERT(mState.mUniformBlocks.empty());
ASSERT(mState.mShaderStorageBlocks.empty());
- if (mState.mAttachedComputeShader)
- {
- Shader *computeShader = mState.getAttachedComputeShader();
-
- gatherComputeBlockInfo(computeShader->getUniformBlocks(context));
- gatherComputeBlockInfo(computeShader->getShaderStorageBlocks(context));
- return;
- }
-
- Shader *vertexShader = mState.getAttachedVertexShader();
- Shader *fragmentShader = mState.getAttachedFragmentShader();
-
- gatherVertexAndFragmentBlockInfo(vertexShader->getUniformBlocks(context),
- fragmentShader->getUniformBlocks(context));
+ gatherUniformBlockInfo(context);
if (context->getClientVersion() >= Version(3, 1))
{
- gatherVertexAndFragmentBlockInfo(vertexShader->getShaderStorageBlocks(context),
- fragmentShader->getShaderStorageBlocks(context));
+ gatherShaderStorageBlockInfo(context);
}
// Set initial bindings from shader.
@@ -2926,154 +2917,6 @@
}
}
-template <typename VarT>
-void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
- const std::string &prefix,
- const std::string &mappedPrefix,
- int blockIndex)
-{
- 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);
-
- if (field.isStruct())
- {
- for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
- {
- const std::string uniformElementName =
- fullName + (field.isArray() ? ArrayString(arrayElement) : "");
- const std::string uniformElementMappedName =
- fullMappedName + (field.isArray() ? ArrayString(arrayElement) : "");
- defineUniformBlockMembers(field.fields, uniformElementName,
- uniformElementMappedName, blockIndex);
- }
- }
- else
- {
- // If getBlockMemberInfo returns false, the uniform is optimized out.
- sh::BlockMemberInfo memberInfo;
- if (!mProgram->getUniformBlockMemberInfo(fullName, fullMappedName, &memberInfo))
- {
- continue;
- }
-
- if (field.isArray())
- {
- fullName += "[0]";
- fullMappedName += "[0]";
- }
-
- LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1,
- -1, blockIndex, memberInfo);
- newUniform.mappedName = fullMappedName;
-
- // Since block uniforms have no location, we don't need to store them in the uniform
- // locations list.
- mState.mUniforms.push_back(newUniform);
- }
- }
-}
-
-void Program::defineInterfaceBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType)
-{
- size_t blockSize = 0;
- std::vector<unsigned int> blockIndexes;
-
- if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
- {
- int blockIndex = static_cast<int>(mState.mUniformBlocks.size());
- // Track the first and last uniform index to determine the range of active uniforms in the
- // block.
- size_t firstBlockUniformIndex = mState.mUniforms.size();
- defineUniformBlockMembers(interfaceBlock.fields, interfaceBlock.fieldPrefix(),
- interfaceBlock.fieldMappedPrefix(), blockIndex);
- size_t lastBlockUniformIndex = mState.mUniforms.size();
-
- for (size_t blockUniformIndex = firstBlockUniformIndex;
- blockUniformIndex < lastBlockUniformIndex; ++blockUniformIndex)
- {
- blockIndexes.push_back(static_cast<unsigned int>(blockUniformIndex));
- }
- }
- else
- {
- // TODO(jiajia.qin@intel.com) : Add buffer variables support and calculate the block index.
- ASSERT(interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER);
- }
- // ESSL 3.10 section 4.4.4 page 58:
- // Any uniform or shader storage block declared without a binding qualifier is initially
- // assigned to block binding point zero.
- int blockBinding = (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding);
- if (interfaceBlock.arraySize > 0)
- {
- for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.arraySize; ++arrayElement)
- {
- // TODO(jiajia.qin@intel.com) : use GetProgramResourceiv to calculate BUFFER_DATA_SIZE
- // of UniformBlock and ShaderStorageBlock.
- if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
- {
- // Don't define this block at all if it's not active in the implementation.
- if (!mProgram->getUniformBlockSize(
- interfaceBlock.name + ArrayString(arrayElement),
- interfaceBlock.mappedName + ArrayString(arrayElement), &blockSize))
- {
- continue;
- }
- }
-
- InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName, true, arrayElement,
- blockBinding + arrayElement);
- block.memberIndexes = blockIndexes;
- block.setStaticUse(shaderType, interfaceBlock.staticUse);
-
- // Since all block elements in an array share the same active interface blocks, they
- // will all be active once any block member is used. So, since interfaceBlock.name[0]
- // was active, here we will add every block element in the array.
- block.dataSize = static_cast<unsigned int>(blockSize);
- if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
- {
- mState.mUniformBlocks.push_back(block);
- }
- else
- {
- ASSERT(interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER);
- mState.mShaderStorageBlocks.push_back(block);
- }
- }
- }
- else
- {
- // TODO(jiajia.qin@intel.com) : use GetProgramResourceiv to calculate BUFFER_DATA_SIZE
- // of UniformBlock and ShaderStorageBlock.
- if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
- {
- if (!mProgram->getUniformBlockSize(interfaceBlock.name, interfaceBlock.mappedName,
- &blockSize))
- {
- return;
- }
- }
-
- InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName, false, 0,
- blockBinding);
- block.memberIndexes = blockIndexes;
- block.setStaticUse(shaderType, interfaceBlock.staticUse);
- block.dataSize = static_cast<unsigned int>(blockSize);
- if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
- {
- mState.mUniformBlocks.push_back(block);
- }
- else
- {
- ASSERT(interfaceBlock.blockType == sh::BlockType::BLOCK_BUFFER);
- mState.mShaderStorageBlocks.push_back(block);
- }
- }
-}
-
void Program::updateSamplerUniform(const VariableLocation &locationInfo,
GLsizei clampedCount,
const GLint *v)
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
index 50364ea..99f3959 100644
--- a/src/libANGLE/Program.h
+++ b/src/libANGLE/Program.h
@@ -646,18 +646,9 @@
void setUniformValuesFromBindingQualifiers();
void gatherAtomicCounterBuffers();
- void gatherComputeBlockInfo(const std::vector<sh::InterfaceBlock> &computeBlocks);
- void gatherVertexAndFragmentBlockInfo(
- const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
- const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks);
+ void gatherUniformBlockInfo(const gl::Context *context);
+ void gatherShaderStorageBlockInfo(const gl::Context *context);
void gatherInterfaceBlockInfo(const Context *context);
- template <typename VarT>
- void defineUniformBlockMembers(const std::vector<VarT> &fields,
- const std::string &prefix,
- const std::string &mappedPrefix,
- int blockIndex);
-
- void defineInterfaceBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType);
// Both these function update the cached uniform values and return a modified "count"
// so that the uniform update doesn't overflow the uniform.
diff --git a/src/libANGLE/UniformLinker.cpp b/src/libANGLE/UniformLinker.cpp
index a14ac53..37e7036 100644
--- a/src/libANGLE/UniformLinker.cpp
+++ b/src/libANGLE/UniformLinker.cpp
@@ -466,7 +466,7 @@
std::vector<LinkedUniform> *atomicCounterUniforms,
GLenum shaderType)
{
- int location = uniform.location;
+ int location = uniform.location;
ShaderUniformCount shaderUniformCount =
flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse,
@@ -588,7 +588,7 @@
shaderUniformCount.vectorCount =
(IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
- shaderUniformCount.imageCount = (isImage ? elementCount : 0);
+ shaderUniformCount.imageCount = (isImage ? elementCount : 0);
shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
if (*location != -1)
@@ -618,4 +618,220 @@
return true;
}
+// InterfaceBlockLinker implementation.
+InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut)
+ : mBlocksOut(blocksOut)
+{
+}
+
+InterfaceBlockLinker::~InterfaceBlockLinker()
+{
+}
+
+void InterfaceBlockLinker::addShaderBlocks(GLenum shader,
+ const std::vector<sh::InterfaceBlock> *blocks)
+{
+ mShaderBlocks.push_back(std::make_pair(shader, blocks));
+}
+
+void InterfaceBlockLinker::linkBlocks(const GetBlockSize &getBlockSize,
+ const GetBlockMemberInfo &getMemberInfo) const
+{
+ std::set<std::string> visitedList;
+
+ for (const auto &shaderBlocks : mShaderBlocks)
+ {
+ const GLenum shaderType = shaderBlocks.first;
+
+ for (const auto &block : *shaderBlocks.second)
+ {
+ // Only 'packed' blocks are allowed to be considered inactive.
+ if (!block.staticUse && block.layout == sh::BLOCKLAYOUT_PACKED)
+ continue;
+
+ if (visitedList.count(block.name) > 0)
+ {
+ if (block.staticUse)
+ {
+ for (InterfaceBlock &priorBlock : *mBlocksOut)
+ {
+ if (block.name == priorBlock.name)
+ {
+ priorBlock.setStaticUse(shaderType, true);
+ }
+ }
+ }
+ }
+ else
+ {
+ defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
+ visitedList.insert(block.name);
+ }
+ }
+ }
+}
+
+template <typename VarT>
+void InterfaceBlockLinker::defineBlockMembers(const GetBlockMemberInfo &getMemberInfo,
+ const std::vector<VarT> &fields,
+ const std::string &prefix,
+ const std::string &mappedPrefix,
+ int blockIndex) 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);
+
+ if (field.isStruct())
+ {
+ for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
+ {
+ const std::string elementName =
+ fullName + (field.isArray() ? ArrayString(arrayElement) : "");
+ const std::string elementMappedName =
+ fullMappedName + (field.isArray() ? ArrayString(arrayElement) : "");
+ defineBlockMembers(getMemberInfo, field.fields, elementName, elementMappedName,
+ blockIndex);
+ }
+ }
+ else
+ {
+ // If getBlockMemberInfo returns false, the variable is optimized out.
+ sh::BlockMemberInfo memberInfo;
+ if (!getMemberInfo(fullName, fullMappedName, &memberInfo))
+ {
+ continue;
+ }
+
+ if (field.isArray())
+ {
+ fullName += "[0]";
+ fullMappedName += "[0]";
+ }
+
+ defineBlockMember(field, fullName, fullMappedName, blockIndex, memberInfo);
+ }
+ }
+}
+
+void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSize &getBlockSize,
+ const GetBlockMemberInfo &getMemberInfo,
+ const sh::InterfaceBlock &interfaceBlock,
+ GLenum shaderType) const
+{
+ size_t blockSize = 0;
+ std::vector<unsigned int> blockIndexes;
+
+ int blockIndex = static_cast<int>(mBlocksOut->size());
+ // Track the first and last uniform index to determine the range of active uniforms in the
+ // block.
+ size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
+ defineBlockMembers(getMemberInfo, interfaceBlock.fields, interfaceBlock.fieldPrefix(),
+ interfaceBlock.fieldMappedPrefix(), blockIndex);
+ size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
+
+ for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
+ ++blockMemberIndex)
+ {
+ blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
+ }
+
+ // ESSL 3.10 section 4.4.4 page 58:
+ // Any uniform or shader storage block declared without a binding qualifier is initially
+ // assigned to block binding point zero.
+ int blockBinding = (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding);
+ for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
+ ++arrayElement)
+ {
+ // We don't currently have the getBlockSize implemented for SSBOs.
+ // TODO(jiajia.qin@intel.com): Remove the if when we have getBlockSize for SSBOs.
+ if (interfaceBlock.blockType == sh::BlockType::BLOCK_UNIFORM)
+ {
+ std::string blockArrayName = interfaceBlock.name;
+ std::string blockMappedArrayName = interfaceBlock.mappedName;
+ if (interfaceBlock.isArray())
+ {
+ blockArrayName += ArrayString(arrayElement);
+ blockMappedArrayName += ArrayString(arrayElement);
+ }
+
+ // Don't define this block at all if it's not active in the implementation.
+ if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
+ {
+ continue;
+ }
+ }
+
+ InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
+ interfaceBlock.isArray(), arrayElement, blockBinding + arrayElement);
+ block.memberIndexes = blockIndexes;
+ block.setStaticUse(shaderType, interfaceBlock.staticUse);
+
+ // Since all block elements in an array share the same active interface blocks, they
+ // will all be active once any block member is used. So, since interfaceBlock.name[0]
+ // was active, here we will add every block element in the array.
+ block.dataSize = static_cast<unsigned int>(blockSize);
+ mBlocksOut->push_back(block);
+ }
+}
+
+// UniformBlockLinker implementation.
+UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
+ std::vector<LinkedUniform> *uniformsOut)
+ : InterfaceBlockLinker(blocksOut), mUniformsOut(uniformsOut)
+{
+}
+
+UniformBlockLinker::~UniformBlockLinker()
+{
+}
+
+void UniformBlockLinker::defineBlockMember(const sh::ShaderVariable &field,
+ const std::string &fullName,
+ const std::string &fullMappedName,
+ int blockIndex,
+ const sh::BlockMemberInfo &memberInfo) const
+{
+ LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1, -1,
+ blockIndex, memberInfo);
+ newUniform.mappedName = fullMappedName;
+
+ // 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();
+}
+
+// ShaderStorageBlockLinker implementation.
+ShaderStorageBlockLinker::ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut)
+ : InterfaceBlockLinker(blocksOut)
+{
+}
+
+ShaderStorageBlockLinker::~ShaderStorageBlockLinker()
+{
+}
+
+void ShaderStorageBlockLinker::defineBlockMember(const sh::ShaderVariable &field,
+ const std::string &fullName,
+ const std::string &fullMappedName,
+ int blockIndex,
+ const sh::BlockMemberInfo &memberInfo) const
+{
+ // TODO(jiajia.qin@intel.com): Add buffer variables support.
+}
+
+size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
+{
+ // TODO(jiajia.qin@intel.com): Add buffer variables support.
+ return 0;
+}
+
} // namespace gl
diff --git a/src/libANGLE/UniformLinker.h b/src/libANGLE/UniformLinker.h
index 3c827c8..3aac690 100644
--- a/src/libANGLE/UniformLinker.h
+++ b/src/libANGLE/UniformLinker.h
@@ -14,6 +14,8 @@
#include "libANGLE/Program.h"
#include "libANGLE/Uniform.h"
+#include <functional>
+
namespace gl
{
@@ -111,6 +113,87 @@
std::vector<VariableLocation> mUniformLocations;
};
+// 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.
+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(GLenum 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;
+
+ protected:
+ InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut);
+ void defineInterfaceBlock(const GetBlockSize &getBlockSize,
+ const GetBlockMemberInfo &getMemberInfo,
+ const sh::InterfaceBlock &interfaceBlock,
+ GLenum 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) const;
+
+ virtual void defineBlockMember(const sh::ShaderVariable &field,
+ const std::string &fullName,
+ const std::string &fullMappedName,
+ int blockIndex,
+ const sh::BlockMemberInfo &memberInfo) const = 0;
+ virtual size_t getCurrentBlockMemberIndex() const = 0;
+
+ using ShaderBlocks = std::pair<GLenum, const std::vector<sh::InterfaceBlock> *>;
+ std::vector<ShaderBlocks> mShaderBlocks;
+
+ std::vector<InterfaceBlock> *mBlocksOut;
+};
+
+class UniformBlockLinker final : public InterfaceBlockLinker
+{
+ public:
+ UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
+ std::vector<LinkedUniform> *uniformsOut);
+ virtual ~UniformBlockLinker();
+
+ private:
+ void defineBlockMember(const sh::ShaderVariable &field,
+ const std::string &fullName,
+ const std::string &fullMappedName,
+ int blockIndex,
+ const sh::BlockMemberInfo &memberInfo) const override;
+ size_t getCurrentBlockMemberIndex() const override;
+ std::vector<LinkedUniform> *mUniformsOut;
+};
+
+// TODO(jiajia.qin@intel.com): Add buffer variables support.
+class ShaderStorageBlockLinker final : public InterfaceBlockLinker
+{
+ public:
+ ShaderStorageBlockLinker(std::vector<InterfaceBlock> *blocksOut);
+ virtual ~ShaderStorageBlockLinker();
+
+ private:
+ void defineBlockMember(const sh::ShaderVariable &field,
+ const std::string &fullName,
+ const std::string &fullMappedName,
+ int blockIndex,
+ const sh::BlockMemberInfo &memberInfo) const override;
+ size_t getCurrentBlockMemberIndex() const override;
+};
+
} // namespace gl
#endif // LIBANGLE_UNIFORMLINKER_H_