Commit 977abce7 by Jamie Madill Committed by Commit Bot

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: 's avatarYuly Novikov <ynovikov@chromium.org>
parent bd3cd506
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 184 #define ANGLE_SH_VERSION 185
enum ShShaderSpec enum ShShaderSpec
{ {
......
...@@ -233,6 +233,9 @@ struct InterfaceBlock ...@@ -233,6 +233,9 @@ struct InterfaceBlock
bool isBuiltIn() const { return name.compare(0, 3, "gl_") == 0; } bool isBuiltIn() const { return name.compare(0, 3, "gl_") == 0; }
bool isArray() const { return arraySize > 0; }
unsigned int elementCount() const { return std::max(1u, arraySize); }
std::string name; std::string name;
std::string mappedName; std::string mappedName;
std::string instanceName; std::string instanceName;
......
...@@ -646,18 +646,9 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -646,18 +646,9 @@ class Program final : angle::NonCopyable, public LabeledObject
void setUniformValuesFromBindingQualifiers(); void setUniformValuesFromBindingQualifiers();
void gatherAtomicCounterBuffers(); void gatherAtomicCounterBuffers();
void gatherComputeBlockInfo(const std::vector<sh::InterfaceBlock> &computeBlocks); void gatherUniformBlockInfo(const gl::Context *context);
void gatherVertexAndFragmentBlockInfo( void gatherShaderStorageBlockInfo(const gl::Context *context);
const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks,
const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks);
void gatherInterfaceBlockInfo(const 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" // Both these function update the cached uniform values and return a modified "count"
// so that the uniform update doesn't overflow the uniform. // so that the uniform update doesn't overflow the uniform.
......
...@@ -466,7 +466,7 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniform( ...@@ -466,7 +466,7 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
std::vector<LinkedUniform> *atomicCounterUniforms, std::vector<LinkedUniform> *atomicCounterUniforms,
GLenum shaderType) GLenum shaderType)
{ {
int location = uniform.location; int location = uniform.location;
ShaderUniformCount shaderUniformCount = ShaderUniformCount shaderUniformCount =
flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms, flattenUniformImpl(uniform, uniform.name, uniform.mappedName, samplerUniforms,
imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse, imageUniforms, atomicCounterUniforms, shaderType, uniform.staticUse,
...@@ -588,7 +588,7 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl( ...@@ -588,7 +588,7 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
shaderUniformCount.vectorCount = shaderUniformCount.vectorCount =
(IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount)); (IsOpaqueType(uniform.type) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
shaderUniformCount.samplerCount = (isSampler ? elementCount : 0); shaderUniformCount.samplerCount = (isSampler ? elementCount : 0);
shaderUniformCount.imageCount = (isImage ? elementCount : 0); shaderUniformCount.imageCount = (isImage ? elementCount : 0);
shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0); shaderUniformCount.atomicCounterCount = (isAtomicCounter ? elementCount : 0);
if (*location != -1) if (*location != -1)
...@@ -618,4 +618,220 @@ bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &in ...@@ -618,4 +618,220 @@ bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &in
return true; 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 } // namespace gl
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "libANGLE/Program.h" #include "libANGLE/Program.h"
#include "libANGLE/Uniform.h" #include "libANGLE/Uniform.h"
#include <functional>
namespace gl namespace gl
{ {
...@@ -111,6 +113,87 @@ class UniformLinker ...@@ -111,6 +113,87 @@ class UniformLinker
std::vector<VariableLocation> mUniformLocations; 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 } // namespace gl
#endif // LIBANGLE_UNIFORMLINKER_H_ #endif // LIBANGLE_UNIFORMLINKER_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment