Commit eaef1e5e by jchen10

Link atomic counters to buffers

Gather counters from each shader and group them according the layout qualifier 'binding' into each buffer. BUG=angleproject:1729 TEST=angle_end2end_tests:AtomicCounterBufferTest Change-Id: I8d0cd0d2bf65be37c035b0e1540481c8bee0bae4
parent eb7f90fd
...@@ -210,7 +210,9 @@ bool Uniform::operator==(const Uniform &other) const ...@@ -210,7 +210,9 @@ bool Uniform::operator==(const Uniform &other) const
bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const
{ {
if (binding != other.binding) // Enforce a consistent match.
// https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261
if (binding != -1 && other.binding != -1 && binding != other.binding)
{ {
return false; return false;
} }
...@@ -218,7 +220,6 @@ bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const ...@@ -218,7 +220,6 @@ bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const
{ {
return false; return false;
} }
// TODO(jie.a.chen@intel.com): Add a test case to cover this.
if (offset != other.offset) if (offset != other.offset)
{ {
return false; return false;
......
...@@ -49,6 +49,37 @@ void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var) ...@@ -49,6 +49,37 @@ void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
var->structName = stream->readString(); var->structName = stream->readString();
} }
void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var)
{
stream->writeInt(var.binding);
stream->writeInt(var.dataSize);
stream->writeInt(var.vertexStaticUse);
stream->writeInt(var.fragmentStaticUse);
stream->writeInt(var.computeStaticUse);
stream->writeInt(var.memberIndexes.size());
for (unsigned int memberCounterIndex : var.memberIndexes)
{
stream->writeInt(memberCounterIndex);
}
}
void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var)
{
var->binding = stream->readInt<int>();
var->dataSize = stream->readInt<unsigned int>();
var->vertexStaticUse = stream->readBool();
var->fragmentStaticUse = stream->readBool();
var->computeStaticUse = stream->readBool();
unsigned int numMembers = stream->readInt<unsigned int>();
for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
{
var->memberIndexes.push_back(stream->readInt<unsigned int>());
}
}
class HashStream final : angle::NonCopyable class HashStream final : angle::NonCopyable
{ {
public: public:
...@@ -158,7 +189,7 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -158,7 +189,7 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
LinkedUniform uniform; LinkedUniform uniform;
LoadShaderVar(&stream, &uniform); LoadShaderVar(&stream, &uniform);
uniform.blockIndex = stream.readInt<int>(); uniform.bufferIndex = stream.readInt<int>();
uniform.blockInfo.offset = stream.readInt<int>(); uniform.blockInfo.offset = stream.readInt<int>();
uniform.blockInfo.arrayStride = stream.readInt<int>(); uniform.blockInfo.arrayStride = stream.readInt<int>();
uniform.blockInfo.matrixStride = stream.readInt<int>(); uniform.blockInfo.matrixStride = stream.readInt<int>();
...@@ -191,21 +222,22 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -191,21 +222,22 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
stream.readString(&uniformBlock.name); stream.readString(&uniformBlock.name);
stream.readBool(&uniformBlock.isArray); stream.readBool(&uniformBlock.isArray);
stream.readInt(&uniformBlock.arrayElement); stream.readInt(&uniformBlock.arrayElement);
stream.readInt(&uniformBlock.binding);
stream.readInt(&uniformBlock.dataSize);
stream.readBool(&uniformBlock.vertexStaticUse);
stream.readBool(&uniformBlock.fragmentStaticUse);
unsigned int numMembers = stream.readInt<unsigned int>(); LoadShaderVariableBuffer(&stream, &uniformBlock);
for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
{
uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
}
state->mUniformBlocks.push_back(uniformBlock); state->mUniformBlocks.push_back(uniformBlock);
state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0); state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
} }
unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
ASSERT(state->mAtomicCounterBuffers.empty());
for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
{
AtomicCounterBuffer atomicCounterBuffer;
LoadShaderVariableBuffer(&stream, &atomicCounterBuffer);
state->mAtomicCounterBuffers.push_back(atomicCounterBuffer);
}
unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>(); unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
...@@ -286,6 +318,10 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -286,6 +318,10 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
state->mImageBindings.emplace_back(ImageBinding(boundImageUnit, elementCount)); state->mImageBindings.emplace_back(ImageBinding(boundImageUnit, elementCount));
} }
unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
state->mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);
return program->getImplementation()->load(context, infoLog, &stream); return program->getImplementation()->load(context, infoLog, &stream);
} }
...@@ -335,7 +371,7 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -335,7 +371,7 @@ void MemoryProgramCache::Serialize(const Context *context,
// FIXME: referenced // FIXME: referenced
stream.writeInt(uniform.blockIndex); stream.writeInt(uniform.bufferIndex);
stream.writeInt(uniform.blockInfo.offset); stream.writeInt(uniform.blockInfo.offset);
stream.writeInt(uniform.blockInfo.arrayStride); stream.writeInt(uniform.blockInfo.arrayStride);
stream.writeInt(uniform.blockInfo.matrixStride); stream.writeInt(uniform.blockInfo.matrixStride);
...@@ -358,17 +394,14 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -358,17 +394,14 @@ void MemoryProgramCache::Serialize(const Context *context,
stream.writeString(uniformBlock.name); stream.writeString(uniformBlock.name);
stream.writeInt(uniformBlock.isArray); stream.writeInt(uniformBlock.isArray);
stream.writeInt(uniformBlock.arrayElement); stream.writeInt(uniformBlock.arrayElement);
stream.writeInt(uniformBlock.binding);
stream.writeInt(uniformBlock.dataSize);
stream.writeInt(uniformBlock.vertexStaticUse); WriteShaderVariableBuffer(&stream, uniformBlock);
stream.writeInt(uniformBlock.fragmentStaticUse); }
stream.writeInt(uniformBlock.memberUniformIndexes.size()); stream.writeInt(state.mAtomicCounterBuffers.size());
for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes) for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers)
{ {
stream.writeInt(memberUniformIndex); WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
}
} }
// Warn the app layer if saving a binary with unsupported transform feedback. // Warn the app layer if saving a binary with unsupported transform feedback.
...@@ -437,6 +470,9 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -437,6 +470,9 @@ void MemoryProgramCache::Serialize(const Context *context,
stream.writeInt(imageBinding.elementCount); stream.writeInt(imageBinding.elementCount);
} }
stream.writeInt(state.getAtomicCounterUniformRange().low());
stream.writeInt(state.getAtomicCounterUniformRange().high());
program->getImplementation()->save(context, &stream); program->getImplementation()->save(context, &stream);
ASSERT(binaryOut); ASSERT(binaryOut);
......
...@@ -296,6 +296,8 @@ ProgramState::ProgramState() ...@@ -296,6 +296,8 @@ ProgramState::ProgramState()
mAttachedComputeShader(nullptr), mAttachedComputeShader(nullptr),
mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS), mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
mSamplerUniformRange(0, 0), mSamplerUniformRange(0, 0),
mImageUniformRange(0, 0),
mAtomicCounterUniformRange(0, 0),
mBinaryRetrieveableHint(false) mBinaryRetrieveableHint(false)
{ {
mComputeShaderLocalSize.fill(1); mComputeShaderLocalSize.fill(1);
...@@ -757,10 +759,11 @@ Error Program::link(const gl::Context *context) ...@@ -757,10 +759,11 @@ Error Program::link(const gl::Context *context)
gatherTransformFeedbackVaryings(mergedVaryings); gatherTransformFeedbackVaryings(mergedVaryings);
} }
setUniformValuesFromBindingQualifiers(); gatherAtomicCounterBuffers();
gatherInterfaceBlockInfo(context); gatherInterfaceBlockInfo(context);
setUniformValuesFromBindingQualifiers();
// Save to the program cache. // Save to the program cache.
if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() || if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
!context->getWorkarounds().disableProgramCachingForTransformFeedback)) !context->getWorkarounds().disableProgramCachingForTransformFeedback))
...@@ -781,12 +784,14 @@ void Program::unlink() ...@@ -781,12 +784,14 @@ void Program::unlink()
mState.mUniformLocations.clear(); mState.mUniformLocations.clear();
mState.mUniformBlocks.clear(); mState.mUniformBlocks.clear();
mState.mActiveUniformBlockBindings.reset(); mState.mActiveUniformBlockBindings.reset();
mState.mAtomicCounterBuffers.clear();
mState.mOutputVariables.clear(); mState.mOutputVariables.clear();
mState.mOutputLocations.clear(); mState.mOutputLocations.clear();
mState.mOutputVariableTypes.clear(); mState.mOutputVariableTypes.clear();
mState.mActiveOutputVariables.reset(); mState.mActiveOutputVariables.reset();
mState.mComputeShaderLocalSize.fill(1); mState.mComputeShaderLocalSize.fill(1);
mState.mSamplerBindings.clear(); mState.mSamplerBindings.clear();
mState.mImageBindings.clear();
mValidated = false; mValidated = false;
...@@ -1219,7 +1224,8 @@ GLint Program::getActiveUniformi(GLuint index, GLenum pname) const ...@@ -1219,7 +1224,8 @@ GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type); case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount()); case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0)); case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex; case GL_UNIFORM_BLOCK_INDEX:
return uniform.bufferIndex;
case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset; case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride; case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride; case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
...@@ -1763,6 +1769,11 @@ bool Program::linkUniforms(const Context *context, ...@@ -1763,6 +1769,11 @@ bool Program::linkUniforms(const Context *context,
linkSamplerAndImageBindings(); linkSamplerAndImageBindings();
if (!linkAtomicCounterBuffers())
{
return false;
}
return true; return true;
} }
...@@ -1771,6 +1782,16 @@ void Program::linkSamplerAndImageBindings() ...@@ -1771,6 +1782,16 @@ void Program::linkSamplerAndImageBindings()
unsigned int high = static_cast<unsigned int>(mState.mUniforms.size()); unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
unsigned int low = high; unsigned int low = high;
for (auto counterIter = mState.mUniforms.rbegin();
counterIter != mState.mUniforms.rend() && counterIter->isAtomicCounter(); ++counterIter)
{
--low;
}
mState.mAtomicCounterUniformRange = RangeUI(low, high);
high = low;
for (auto imageIter = mState.mUniforms.rbegin(); for (auto imageIter = mState.mUniforms.rbegin();
imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter) imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
{ {
...@@ -1815,6 +1836,39 @@ void Program::linkSamplerAndImageBindings() ...@@ -1815,6 +1836,39 @@ void Program::linkSamplerAndImageBindings()
} }
} }
bool Program::linkAtomicCounterBuffers()
{
for (unsigned int index : mState.mAtomicCounterUniformRange)
{
auto &uniform = mState.mUniforms[index];
bool found = false;
for (unsigned int bufferIndex = 0; bufferIndex < mState.mAtomicCounterBuffers.size();
++bufferIndex)
{
auto &buffer = mState.mAtomicCounterBuffers[bufferIndex];
if (buffer.binding == uniform.binding)
{
buffer.memberIndexes.push_back(index);
uniform.bufferIndex = bufferIndex;
found = true;
break;
}
}
if (!found)
{
AtomicCounterBuffer atomicCounterBuffer;
atomicCounterBuffer.binding = uniform.binding;
atomicCounterBuffer.memberIndexes.push_back(index);
mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
uniform.bufferIndex = static_cast<int>(mState.mAtomicCounterBuffers.size() - 1);
}
}
// TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
// gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers.
return true;
}
bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog,
const std::string &uniformName, const std::string &uniformName,
const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &vertexUniform,
...@@ -2530,6 +2584,13 @@ void Program::setUniformValuesFromBindingQualifiers() ...@@ -2530,6 +2584,13 @@ void Program::setUniformValuesFromBindingQualifiers()
} }
} }
void Program::gatherAtomicCounterBuffers()
{
// TODO(jie.a.chen@intel.com): Get the actual OFFSET and ARRAY_STRIDE from the backend for each
// counter.
// TODO(jie.a.chen@intel.com): Get the actual BUFFER_DATA_SIZE from backend for each buffer.
}
void Program::gatherInterfaceBlockInfo(const Context *context) void Program::gatherInterfaceBlockInfo(const Context *context)
{ {
ASSERT(mState.mUniformBlocks.empty()); ASSERT(mState.mUniformBlocks.empty());
...@@ -2635,7 +2696,7 @@ void Program::defineUniformBlockMembers(const std::vector<VarT> &fields, ...@@ -2635,7 +2696,7 @@ void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
} }
LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1, LinkedUniform newUniform(field.type, field.precision, fullName, field.arraySize, -1, -1,
blockIndex, memberInfo); -1, blockIndex, memberInfo);
// Since block uniforms have no location, we don't need to store them in the uniform // Since block uniforms have no location, we don't need to store them in the uniform
// locations list. // locations list.
...@@ -2677,7 +2738,7 @@ void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenu ...@@ -2677,7 +2738,7 @@ void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenu
} }
UniformBlock block(interfaceBlock.name, true, arrayElement, UniformBlock block(interfaceBlock.name, true, arrayElement,
blockBinding + arrayElement); blockBinding + arrayElement);
block.memberUniformIndexes = blockUniformIndexes; block.memberIndexes = blockUniformIndexes;
switch (shaderType) switch (shaderType)
{ {
...@@ -2714,7 +2775,7 @@ void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenu ...@@ -2714,7 +2775,7 @@ void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenu
return; return;
} }
UniformBlock block(interfaceBlock.name, false, 0, blockBinding); UniformBlock block(interfaceBlock.name, false, 0, blockBinding);
block.memberUniformIndexes = blockUniformIndexes; block.memberIndexes = blockUniformIndexes;
switch (shaderType) switch (shaderType)
{ {
......
...@@ -246,11 +246,16 @@ class ProgramState final : angle::NonCopyable ...@@ -246,11 +246,16 @@ class ProgramState final : angle::NonCopyable
const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; } const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; }
const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; } const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; }
const RangeUI &getImageUniformRange() const { return mImageUniformRange; } const RangeUI &getImageUniformRange() const { return mImageUniformRange; }
const RangeUI &getAtomicCounterUniformRange() const { return mAtomicCounterUniformRange; }
const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const
{ {
return mLinkedTransformFeedbackVaryings; return mLinkedTransformFeedbackVaryings;
} }
const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const
{
return mAtomicCounterBuffers;
}
GLint getUniformLocation(const std::string &name) const; GLint getUniformLocation(const std::string &name) const;
GLuint getUniformIndexFromName(const std::string &name) const; GLuint getUniformIndexFromName(const std::string &name) const;
...@@ -283,15 +288,19 @@ class ProgramState final : angle::NonCopyable ...@@ -283,15 +288,19 @@ class ProgramState final : angle::NonCopyable
angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask; angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
// Uniforms are sorted in order: // Uniforms are sorted in order:
// 1. Non-sampler uniforms // 1. Non-opaque uniforms
// 2. Sampler uniforms // 2. Sampler uniforms
// 3. Uniform block uniforms // 3. Image uniforms
// This makes sampler validation easier, since we don't need a separate list. // 4. Atomic counter uniforms
// 5. Uniform block uniforms
// This makes opaque uniform validation easier, since we don't need a separate list.
std::vector<LinkedUniform> mUniforms; std::vector<LinkedUniform> mUniforms;
std::vector<VariableLocation> mUniformLocations; std::vector<VariableLocation> mUniformLocations;
std::vector<UniformBlock> mUniformBlocks; std::vector<UniformBlock> mUniformBlocks;
std::vector<AtomicCounterBuffer> mAtomicCounterBuffers;
RangeUI mSamplerUniformRange; RangeUI mSamplerUniformRange;
RangeUI mImageUniformRange; RangeUI mImageUniformRange;
RangeUI mAtomicCounterUniformRange;
// An array of the samplers that are used by the program // An array of the samplers that are used by the program
std::vector<gl::SamplerBinding> mSamplerBindings; std::vector<gl::SamplerBinding> mSamplerBindings;
...@@ -540,6 +549,7 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -540,6 +549,7 @@ class Program final : angle::NonCopyable, public LabeledObject
InfoLog &infoLog, InfoLog &infoLog,
const Bindings &uniformLocationBindings); const Bindings &uniformLocationBindings);
void linkSamplerAndImageBindings(); void linkSamplerAndImageBindings();
bool linkAtomicCounterBuffers();
bool areMatchingInterfaceBlocks(InfoLog &infoLog, bool areMatchingInterfaceBlocks(InfoLog &infoLog,
const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &vertexInterfaceBlock,
...@@ -565,6 +575,7 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -565,6 +575,7 @@ class Program final : angle::NonCopyable, public LabeledObject
void setUniformValuesFromBindingQualifiers(); void setUniformValuesFromBindingQualifiers();
void gatherAtomicCounterBuffers();
void gatherInterfaceBlockInfo(const Context *context); void gatherInterfaceBlockInfo(const Context *context);
template <typename VarT> template <typename VarT>
void defineUniformBlockMembers(const std::vector<VarT> &fields, void defineUniformBlockMembers(const std::vector<VarT> &fields,
......
...@@ -14,7 +14,7 @@ namespace gl ...@@ -14,7 +14,7 @@ namespace gl
{ {
LinkedUniform::LinkedUniform() LinkedUniform::LinkedUniform()
: blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) : bufferIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
{ {
} }
...@@ -23,26 +23,28 @@ LinkedUniform::LinkedUniform(GLenum typeIn, ...@@ -23,26 +23,28 @@ LinkedUniform::LinkedUniform(GLenum typeIn,
const std::string &nameIn, const std::string &nameIn,
unsigned int arraySizeIn, unsigned int arraySizeIn,
const int bindingIn, const int bindingIn,
const int offsetIn,
const int locationIn, const int locationIn,
const int blockIndexIn, const int bufferIndexIn,
const sh::BlockMemberInfo &blockInfoIn) const sh::BlockMemberInfo &blockInfoIn)
: blockIndex(blockIndexIn), blockInfo(blockInfoIn) : bufferIndex(bufferIndexIn), blockInfo(blockInfoIn)
{ {
type = typeIn; type = typeIn;
precision = precisionIn; precision = precisionIn;
name = nameIn; name = nameIn;
arraySize = arraySizeIn; arraySize = arraySizeIn;
binding = bindingIn; binding = bindingIn;
offset = offsetIn;
location = locationIn; location = locationIn;
} }
LinkedUniform::LinkedUniform(const sh::Uniform &uniform) LinkedUniform::LinkedUniform(const sh::Uniform &uniform)
: sh::Uniform(uniform), blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) : sh::Uniform(uniform), bufferIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
{ {
} }
LinkedUniform::LinkedUniform(const LinkedUniform &uniform) LinkedUniform::LinkedUniform(const LinkedUniform &uniform)
: sh::Uniform(uniform), blockIndex(uniform.blockIndex), blockInfo(uniform.blockInfo) : sh::Uniform(uniform), bufferIndex(uniform.bufferIndex), blockInfo(uniform.blockInfo)
{ {
// This function is not intended to be called during runtime. // This function is not intended to be called during runtime.
ASSERT(uniform.mLazyData.empty()); ASSERT(uniform.mLazyData.empty());
...@@ -54,7 +56,7 @@ LinkedUniform &LinkedUniform::operator=(const LinkedUniform &uniform) ...@@ -54,7 +56,7 @@ LinkedUniform &LinkedUniform::operator=(const LinkedUniform &uniform)
ASSERT(uniform.mLazyData.empty()); ASSERT(uniform.mLazyData.empty());
sh::Uniform::operator=(uniform); sh::Uniform::operator=(uniform);
blockIndex = uniform.blockIndex; bufferIndex = uniform.bufferIndex;
blockInfo = uniform.blockInfo; blockInfo = uniform.blockInfo;
return *this; return *this;
...@@ -66,7 +68,7 @@ LinkedUniform::~LinkedUniform() ...@@ -66,7 +68,7 @@ LinkedUniform::~LinkedUniform()
bool LinkedUniform::isInDefaultBlock() const bool LinkedUniform::isInDefaultBlock() const
{ {
return blockIndex == -1; return bufferIndex == -1;
} }
size_t LinkedUniform::dataSize() const size_t LinkedUniform::dataSize() const
...@@ -108,6 +110,11 @@ bool LinkedUniform::isImage() const ...@@ -108,6 +110,11 @@ bool LinkedUniform::isImage() const
return IsImageType(type); return IsImageType(type);
} }
bool LinkedUniform::isAtomicCounter() const
{
return IsAtomicCounterType(type);
}
bool LinkedUniform::isField() const bool LinkedUniform::isField() const
{ {
return name.find('.') != std::string::npos; return name.find('.') != std::string::npos;
...@@ -134,10 +141,8 @@ const uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex) const ...@@ -134,10 +141,8 @@ const uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex) const
return const_cast<LinkedUniform *>(this)->getDataPtrToElement(elementIndex); return const_cast<LinkedUniform *>(this)->getDataPtrToElement(elementIndex);
} }
UniformBlock::UniformBlock() ShaderVariableBuffer::ShaderVariableBuffer()
: isArray(false), : binding(0),
arrayElement(0),
binding(0),
dataSize(0), dataSize(0),
vertexStaticUse(false), vertexStaticUse(false),
fragmentStaticUse(false), fragmentStaticUse(false),
...@@ -145,19 +150,21 @@ UniformBlock::UniformBlock() ...@@ -145,19 +150,21 @@ UniformBlock::UniformBlock()
{ {
} }
ShaderVariableBuffer::~ShaderVariableBuffer()
{
}
UniformBlock::UniformBlock() : isArray(false), arrayElement(0)
{
}
UniformBlock::UniformBlock(const std::string &nameIn, UniformBlock::UniformBlock(const std::string &nameIn,
bool isArrayIn, bool isArrayIn,
unsigned int arrayElementIn, unsigned int arrayElementIn,
int bindingIn) int bindingIn)
: name(nameIn), : name(nameIn), isArray(isArrayIn), arrayElement(arrayElementIn)
isArray(isArrayIn),
arrayElement(arrayElementIn),
binding(bindingIn),
dataSize(0),
vertexStaticUse(false),
fragmentStaticUse(false),
computeStaticUse(false)
{ {
binding = bindingIn;
} }
std::string UniformBlock::nameWithArrayIndex() const std::string UniformBlock::nameWithArrayIndex() const
......
...@@ -28,8 +28,9 @@ struct LinkedUniform : public sh::Uniform ...@@ -28,8 +28,9 @@ struct LinkedUniform : public sh::Uniform
const std::string &name, const std::string &name,
unsigned int arraySize, unsigned int arraySize,
const int binding, const int binding,
const int offset,
const int location, const int location,
const int blockIndex, const int bufferIndex,
const sh::BlockMemberInfo &blockInfo); const sh::BlockMemberInfo &blockInfo);
LinkedUniform(const sh::Uniform &uniform); LinkedUniform(const sh::Uniform &uniform);
LinkedUniform(const LinkedUniform &uniform); LinkedUniform(const LinkedUniform &uniform);
...@@ -41,6 +42,7 @@ struct LinkedUniform : public sh::Uniform ...@@ -41,6 +42,7 @@ struct LinkedUniform : public sh::Uniform
const uint8_t *data() const; const uint8_t *data() const;
bool isSampler() const; bool isSampler() const;
bool isImage() const; bool isImage() const;
bool isAtomicCounter() const;
bool isInDefaultBlock() const; bool isInDefaultBlock() const;
bool isField() const; bool isField() const;
size_t getElementSize() const; size_t getElementSize() const;
...@@ -48,15 +50,37 @@ struct LinkedUniform : public sh::Uniform ...@@ -48,15 +50,37 @@ struct LinkedUniform : public sh::Uniform
uint8_t *getDataPtrToElement(size_t elementIndex); uint8_t *getDataPtrToElement(size_t elementIndex);
const uint8_t *getDataPtrToElement(size_t elementIndex) const; const uint8_t *getDataPtrToElement(size_t elementIndex) const;
int blockIndex; // Identifies the containing buffer backed resource -- interface block or atomic counter buffer.
int bufferIndex;
sh::BlockMemberInfo blockInfo; sh::BlockMemberInfo blockInfo;
private: private:
mutable angle::MemoryBuffer mLazyData; mutable angle::MemoryBuffer mLazyData;
}; };
// Parent struct for atomic counter, uniform block, and shader storage block buffer, which all
// contain a group of shader variables, and have a GL buffer backed.
struct ShaderVariableBuffer
{
ShaderVariableBuffer();
virtual ~ShaderVariableBuffer();
ShaderVariableBuffer(const ShaderVariableBuffer &other) = default;
ShaderVariableBuffer &operator=(const ShaderVariableBuffer &other) = default;
int numActiveVariables() const { return static_cast<int>(memberIndexes.size()); }
int binding;
unsigned int dataSize;
std::vector<unsigned int> memberIndexes;
bool vertexStaticUse;
bool fragmentStaticUse;
bool computeStaticUse;
};
using AtomicCounterBuffer = ShaderVariableBuffer;
// Helper struct representing a single shader uniform block // Helper struct representing a single shader uniform block
struct UniformBlock struct UniformBlock : public ShaderVariableBuffer
{ {
UniformBlock(); UniformBlock();
UniformBlock(const std::string &nameIn, UniformBlock(const std::string &nameIn,
...@@ -71,14 +95,6 @@ struct UniformBlock ...@@ -71,14 +95,6 @@ struct UniformBlock
std::string name; std::string name;
bool isArray; bool isArray;
unsigned int arrayElement; unsigned int arrayElement;
int binding;
unsigned int dataSize;
bool vertexStaticUse;
bool fragmentStaticUse;
bool computeStaticUse;
std::vector<unsigned int> memberUniformIndexes;
}; };
} }
......
...@@ -32,7 +32,9 @@ class UniformLinker ...@@ -32,7 +32,9 @@ class UniformLinker
private: private:
struct ShaderUniformCount struct ShaderUniformCount
{ {
ShaderUniformCount() : vectorCount(0), samplerCount(0), imageCount(0) {} ShaderUniformCount() : vectorCount(0), samplerCount(0), imageCount(0), atomicCounterCount(0)
{
}
ShaderUniformCount(const ShaderUniformCount &other) = default; ShaderUniformCount(const ShaderUniformCount &other) = default;
ShaderUniformCount &operator=(const ShaderUniformCount &other) = default; ShaderUniformCount &operator=(const ShaderUniformCount &other) = default;
...@@ -41,12 +43,14 @@ class UniformLinker ...@@ -41,12 +43,14 @@ class UniformLinker
vectorCount += other.vectorCount; vectorCount += other.vectorCount;
samplerCount += other.samplerCount; samplerCount += other.samplerCount;
imageCount += other.imageCount; imageCount += other.imageCount;
atomicCounterCount += other.atomicCounterCount;
return *this; return *this;
} }
unsigned int vectorCount; unsigned int vectorCount;
unsigned int samplerCount; unsigned int samplerCount;
unsigned int imageCount; unsigned int imageCount;
unsigned int atomicCounterCount;
}; };
bool validateVertexAndFragmentUniforms(const Context *context, InfoLog &infoLog) const; bool validateVertexAndFragmentUniforms(const Context *context, InfoLog &infoLog) const;
...@@ -61,18 +65,23 @@ class UniformLinker ...@@ -61,18 +65,23 @@ class UniformLinker
GLuint maxUniformComponents, GLuint maxUniformComponents,
GLuint maxTextureImageUnits, GLuint maxTextureImageUnits,
GLuint maxImageUnits, GLuint maxImageUnits,
GLuint maxAtomicCounters,
const std::string &componentsErrorMessage, const std::string &componentsErrorMessage,
const std::string &samplerErrorMessage, const std::string &samplerErrorMessage,
const std::string &imageErrorMessage, const std::string &imageErrorMessage,
const std::string &atomicCounterErrorMessage,
std::vector<LinkedUniform> &samplerUniforms, std::vector<LinkedUniform> &samplerUniforms,
std::vector<LinkedUniform> &imageUniforms, std::vector<LinkedUniform> &imageUniforms,
std::vector<LinkedUniform> &atomicCounterUniforms,
InfoLog &infoLog); InfoLog &infoLog);
bool flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog); bool flattenUniformsAndCheckCaps(const Context *context, InfoLog &infoLog);
bool checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog);
ShaderUniformCount flattenUniform(const sh::Uniform &uniform, ShaderUniformCount flattenUniform(const sh::Uniform &uniform,
std::vector<LinkedUniform> *samplerUniforms, std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms); std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms);
// markStaticUse is given as a separate parameter because it is tracked here at struct // markStaticUse is given as a separate parameter because it is tracked here at struct
// granularity. // granularity.
...@@ -80,8 +89,10 @@ class UniformLinker ...@@ -80,8 +89,10 @@ class UniformLinker
const std::string &fullName, const std::string &fullName,
std::vector<LinkedUniform> *samplerUniforms, std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms, std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
bool markStaticUse, bool markStaticUse,
int binding, int binding,
int offset,
int *location); int *location);
bool indexUniforms(InfoLog &infoLog, const Program::Bindings &uniformLocationBindings); bool indexUniforms(InfoLog &infoLog, const Program::Bindings &uniformLocationBindings);
......
...@@ -816,14 +816,14 @@ void QueryActiveUniformBlockiv(const Program *program, ...@@ -816,14 +816,14 @@ void QueryActiveUniformBlockiv(const Program *program,
*params = ConvertToGLint(uniformBlock.nameWithArrayIndex().size() + 1); *params = ConvertToGLint(uniformBlock.nameWithArrayIndex().size() + 1);
break; break;
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
*params = ConvertToGLint(uniformBlock.memberUniformIndexes.size()); *params = ConvertToGLint(uniformBlock.memberIndexes.size());
break; break;
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
for (size_t blockMemberIndex = 0; for (size_t blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberIndexes.size();
blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) blockMemberIndex++)
{ {
params[blockMemberIndex] = params[blockMemberIndex] =
ConvertToGLint(uniformBlock.memberUniformIndexes[blockMemberIndex]); ConvertToGLint(uniformBlock.memberIndexes[blockMemberIndex]);
} }
break; break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
......
...@@ -518,7 +518,7 @@ bool ValidateGetActiveUniformBlockivBase(Context *context, ...@@ -518,7 +518,7 @@ bool ValidateGetActiveUniformBlockivBase(Context *context,
{ {
const UniformBlock &uniformBlock = const UniformBlock &uniformBlock =
programObject->getUniformBlockByIndex(uniformBlockIndex); programObject->getUniformBlockByIndex(uniformBlockIndex);
*length = static_cast<GLsizei>(uniformBlock.memberUniformIndexes.size()); *length = static_cast<GLsizei>(uniformBlock.memberIndexes.size());
} }
else else
{ {
......
...@@ -45,10 +45,79 @@ TEST_P(AtomicCounterBufferTest, AtomicCounterBufferBindings) ...@@ -45,10 +45,79 @@ TEST_P(AtomicCounterBufferTest, AtomicCounterBufferBindings)
} }
} }
class AtomicCounterBufferTest31 : public AtomicCounterBufferTest
{
};
// Linking should fail if counters in vertex shader exceed gl_MaxVertexAtomicCounters.
TEST_P(AtomicCounterBufferTest31, ExceedMaxVertexAtomicCounters)
{
const std::string &vertexShaderSource =
"#version 310 es\n"
"layout(binding = 2) uniform atomic_uint foo[gl_MaxVertexAtomicCounters + 1];\n"
"void main()\n"
"{\n"
" atomicCounterIncrement(foo[0]);\n"
"}\n";
const std::string &fragmentShaderSource =
"#version 310 es\n"
"void main()\n"
"{\n"
"}\n";
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_EQ(0u, program);
}
// Counters matching across shader stages should fail if offsets aren't all specified.
// GLSL ES Spec 3.10.4, section 9.2.1.
TEST_P(AtomicCounterBufferTest31, OffsetNotAllSpecified)
{
const std::string &vertexShaderSource =
"#version 310 es\n"
"layout(binding = 2, offset = 4) uniform atomic_uint foo;\n"
"void main()\n"
"{\n"
" atomicCounterIncrement(foo);\n"
"}\n";
const std::string &fragmentShaderSource =
"#version 310 es\n"
"layout(binding = 2) uniform atomic_uint foo;\n"
"void main()\n"
"{\n"
"}\n";
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_EQ(0u, program);
}
// Counters matching across shader stages should fail if offsets aren't all specified with same
// value.
TEST_P(AtomicCounterBufferTest31, OffsetNotAllSpecifiedWithSameValue)
{
const std::string &vertexShaderSource =
"#version 310 es\n"
"layout(binding = 2, offset = 4) uniform atomic_uint foo;\n"
"void main()\n"
"{\n"
" atomicCounterIncrement(foo);\n"
"}\n";
const std::string &fragmentShaderSource =
"#version 310 es\n"
"layout(binding = 2, offset = 8) uniform atomic_uint foo;\n"
"void main()\n"
"{\n"
"}\n";
GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
EXPECT_EQ(0u, program);
}
ANGLE_INSTANTIATE_TEST(AtomicCounterBufferTest, ANGLE_INSTANTIATE_TEST(AtomicCounterBufferTest,
ES3_OPENGL(), ES3_OPENGL(),
ES3_OPENGLES(), ES3_OPENGLES(),
ES31_OPENGL(), ES31_OPENGL(),
ES31_OPENGLES()); ES31_OPENGLES());
ANGLE_INSTANTIATE_TEST(AtomicCounterBufferTest31, ES31_OPENGL(), ES31_OPENGLES());
} // namespace } // namespace
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