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
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;
}
......@@ -218,7 +220,6 @@ bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const
{
return false;
}
// TODO(jie.a.chen@intel.com): Add a test case to cover this.
if (offset != other.offset)
{
return false;
......
......@@ -49,6 +49,37 @@ void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
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
{
public:
......@@ -158,7 +189,7 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
LinkedUniform uniform;
LoadShaderVar(&stream, &uniform);
uniform.blockIndex = stream.readInt<int>();
uniform.bufferIndex = stream.readInt<int>();
uniform.blockInfo.offset = stream.readInt<int>();
uniform.blockInfo.arrayStride = stream.readInt<int>();
uniform.blockInfo.matrixStride = stream.readInt<int>();
......@@ -191,21 +222,22 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
stream.readString(&uniformBlock.name);
stream.readBool(&uniformBlock.isArray);
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>();
for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
{
uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
}
LoadShaderVariableBuffer(&stream, &uniformBlock);
state->mUniformBlocks.push_back(uniformBlock);
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>();
......@@ -286,6 +318,10 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
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);
}
......@@ -335,7 +371,7 @@ void MemoryProgramCache::Serialize(const Context *context,
// FIXME: referenced
stream.writeInt(uniform.blockIndex);
stream.writeInt(uniform.bufferIndex);
stream.writeInt(uniform.blockInfo.offset);
stream.writeInt(uniform.blockInfo.arrayStride);
stream.writeInt(uniform.blockInfo.matrixStride);
......@@ -358,17 +394,14 @@ void MemoryProgramCache::Serialize(const Context *context,
stream.writeString(uniformBlock.name);
stream.writeInt(uniformBlock.isArray);
stream.writeInt(uniformBlock.arrayElement);
stream.writeInt(uniformBlock.binding);
stream.writeInt(uniformBlock.dataSize);
stream.writeInt(uniformBlock.vertexStaticUse);
stream.writeInt(uniformBlock.fragmentStaticUse);
WriteShaderVariableBuffer(&stream, uniformBlock);
}
stream.writeInt(uniformBlock.memberUniformIndexes.size());
for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
{
stream.writeInt(memberUniformIndex);
}
stream.writeInt(state.mAtomicCounterBuffers.size());
for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers)
{
WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
}
// Warn the app layer if saving a binary with unsupported transform feedback.
......@@ -437,6 +470,9 @@ void MemoryProgramCache::Serialize(const Context *context,
stream.writeInt(imageBinding.elementCount);
}
stream.writeInt(state.getAtomicCounterUniformRange().low());
stream.writeInt(state.getAtomicCounterUniformRange().high());
program->getImplementation()->save(context, &stream);
ASSERT(binaryOut);
......
......@@ -296,6 +296,8 @@ ProgramState::ProgramState()
mAttachedComputeShader(nullptr),
mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
mSamplerUniformRange(0, 0),
mImageUniformRange(0, 0),
mAtomicCounterUniformRange(0, 0),
mBinaryRetrieveableHint(false)
{
mComputeShaderLocalSize.fill(1);
......@@ -757,10 +759,11 @@ Error Program::link(const gl::Context *context)
gatherTransformFeedbackVaryings(mergedVaryings);
}
setUniformValuesFromBindingQualifiers();
gatherAtomicCounterBuffers();
gatherInterfaceBlockInfo(context);
setUniformValuesFromBindingQualifiers();
// Save to the program cache.
if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
!context->getWorkarounds().disableProgramCachingForTransformFeedback))
......@@ -781,12 +784,14 @@ void Program::unlink()
mState.mUniformLocations.clear();
mState.mUniformBlocks.clear();
mState.mActiveUniformBlockBindings.reset();
mState.mAtomicCounterBuffers.clear();
mState.mOutputVariables.clear();
mState.mOutputLocations.clear();
mState.mOutputVariableTypes.clear();
mState.mActiveOutputVariables.reset();
mState.mComputeShaderLocalSize.fill(1);
mState.mSamplerBindings.clear();
mState.mImageBindings.clear();
mValidated = false;
......@@ -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_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_BLOCK_INDEX: return uniform.blockIndex;
case GL_UNIFORM_BLOCK_INDEX:
return uniform.bufferIndex;
case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
......@@ -1763,6 +1769,11 @@ bool Program::linkUniforms(const Context *context,
linkSamplerAndImageBindings();
if (!linkAtomicCounterBuffers())
{
return false;
}
return true;
}
......@@ -1771,6 +1782,16 @@ void Program::linkSamplerAndImageBindings()
unsigned int high = static_cast<unsigned int>(mState.mUniforms.size());
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();
imageIter != mState.mUniforms.rend() && imageIter->isImage(); ++imageIter)
{
......@@ -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,
const std::string &uniformName,
const sh::InterfaceBlockField &vertexUniform,
......@@ -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)
{
ASSERT(mState.mUniformBlocks.empty());
......@@ -2635,7 +2696,7 @@ void Program::defineUniformBlockMembers(const std::vector<VarT> &fields,
}
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
// locations list.
......@@ -2677,7 +2738,7 @@ void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenu
}
UniformBlock block(interfaceBlock.name, true, arrayElement,
blockBinding + arrayElement);
block.memberUniformIndexes = blockUniformIndexes;
block.memberIndexes = blockUniformIndexes;
switch (shaderType)
{
......@@ -2714,7 +2775,7 @@ void Program::defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenu
return;
}
UniformBlock block(interfaceBlock.name, false, 0, blockBinding);
block.memberUniformIndexes = blockUniformIndexes;
block.memberIndexes = blockUniformIndexes;
switch (shaderType)
{
......
......@@ -246,11 +246,16 @@ class ProgramState final : angle::NonCopyable
const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; }
const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; }
const RangeUI &getImageUniformRange() const { return mImageUniformRange; }
const RangeUI &getAtomicCounterUniformRange() const { return mAtomicCounterUniformRange; }
const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const
{
return mLinkedTransformFeedbackVaryings;
}
const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const
{
return mAtomicCounterBuffers;
}
GLint getUniformLocation(const std::string &name) const;
GLuint getUniformIndexFromName(const std::string &name) const;
......@@ -283,15 +288,19 @@ class ProgramState final : angle::NonCopyable
angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
// Uniforms are sorted in order:
// 1. Non-sampler uniforms
// 1. Non-opaque uniforms
// 2. Sampler uniforms
// 3. Uniform block uniforms
// This makes sampler validation easier, since we don't need a separate list.
// 3. Image uniforms
// 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<VariableLocation> mUniformLocations;
std::vector<UniformBlock> mUniformBlocks;
std::vector<AtomicCounterBuffer> mAtomicCounterBuffers;
RangeUI mSamplerUniformRange;
RangeUI mImageUniformRange;
RangeUI mAtomicCounterUniformRange;
// An array of the samplers that are used by the program
std::vector<gl::SamplerBinding> mSamplerBindings;
......@@ -540,6 +549,7 @@ class Program final : angle::NonCopyable, public LabeledObject
InfoLog &infoLog,
const Bindings &uniformLocationBindings);
void linkSamplerAndImageBindings();
bool linkAtomicCounterBuffers();
bool areMatchingInterfaceBlocks(InfoLog &infoLog,
const sh::InterfaceBlock &vertexInterfaceBlock,
......@@ -565,6 +575,7 @@ class Program final : angle::NonCopyable, public LabeledObject
void setUniformValuesFromBindingQualifiers();
void gatherAtomicCounterBuffers();
void gatherInterfaceBlockInfo(const Context *context);
template <typename VarT>
void defineUniformBlockMembers(const std::vector<VarT> &fields,
......
......@@ -14,7 +14,7 @@ namespace gl
{
LinkedUniform::LinkedUniform()
: blockIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
: bufferIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
{
}
......@@ -23,26 +23,28 @@ LinkedUniform::LinkedUniform(GLenum typeIn,
const std::string &nameIn,
unsigned int arraySizeIn,
const int bindingIn,
const int offsetIn,
const int locationIn,
const int blockIndexIn,
const int bufferIndexIn,
const sh::BlockMemberInfo &blockInfoIn)
: blockIndex(blockIndexIn), blockInfo(blockInfoIn)
: bufferIndex(bufferIndexIn), blockInfo(blockInfoIn)
{
type = typeIn;
precision = precisionIn;
name = nameIn;
arraySize = arraySizeIn;
binding = bindingIn;
offset = offsetIn;
location = locationIn;
}
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)
: 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.
ASSERT(uniform.mLazyData.empty());
......@@ -54,7 +56,7 @@ LinkedUniform &LinkedUniform::operator=(const LinkedUniform &uniform)
ASSERT(uniform.mLazyData.empty());
sh::Uniform::operator=(uniform);
blockIndex = uniform.blockIndex;
bufferIndex = uniform.bufferIndex;
blockInfo = uniform.blockInfo;
return *this;
......@@ -66,7 +68,7 @@ LinkedUniform::~LinkedUniform()
bool LinkedUniform::isInDefaultBlock() const
{
return blockIndex == -1;
return bufferIndex == -1;
}
size_t LinkedUniform::dataSize() const
......@@ -108,6 +110,11 @@ bool LinkedUniform::isImage() const
return IsImageType(type);
}
bool LinkedUniform::isAtomicCounter() const
{
return IsAtomicCounterType(type);
}
bool LinkedUniform::isField() const
{
return name.find('.') != std::string::npos;
......@@ -134,10 +141,8 @@ const uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex) const
return const_cast<LinkedUniform *>(this)->getDataPtrToElement(elementIndex);
}
UniformBlock::UniformBlock()
: isArray(false),
arrayElement(0),
binding(0),
ShaderVariableBuffer::ShaderVariableBuffer()
: binding(0),
dataSize(0),
vertexStaticUse(false),
fragmentStaticUse(false),
......@@ -145,19 +150,21 @@ UniformBlock::UniformBlock()
{
}
ShaderVariableBuffer::~ShaderVariableBuffer()
{
}
UniformBlock::UniformBlock() : isArray(false), arrayElement(0)
{
}
UniformBlock::UniformBlock(const std::string &nameIn,
bool isArrayIn,
unsigned int arrayElementIn,
int bindingIn)
: name(nameIn),
isArray(isArrayIn),
arrayElement(arrayElementIn),
binding(bindingIn),
dataSize(0),
vertexStaticUse(false),
fragmentStaticUse(false),
computeStaticUse(false)
: name(nameIn), isArray(isArrayIn), arrayElement(arrayElementIn)
{
binding = bindingIn;
}
std::string UniformBlock::nameWithArrayIndex() const
......
......@@ -28,8 +28,9 @@ struct LinkedUniform : public sh::Uniform
const std::string &name,
unsigned int arraySize,
const int binding,
const int offset,
const int location,
const int blockIndex,
const int bufferIndex,
const sh::BlockMemberInfo &blockInfo);
LinkedUniform(const sh::Uniform &uniform);
LinkedUniform(const LinkedUniform &uniform);
......@@ -41,6 +42,7 @@ struct LinkedUniform : public sh::Uniform
const uint8_t *data() const;
bool isSampler() const;
bool isImage() const;
bool isAtomicCounter() const;
bool isInDefaultBlock() const;
bool isField() const;
size_t getElementSize() const;
......@@ -48,15 +50,37 @@ struct LinkedUniform : public sh::Uniform
uint8_t *getDataPtrToElement(size_t elementIndex);
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;
private:
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
struct UniformBlock
struct UniformBlock : public ShaderVariableBuffer
{
UniformBlock();
UniformBlock(const std::string &nameIn,
......@@ -71,14 +95,6 @@ struct UniformBlock
std::string name;
bool isArray;
unsigned int arrayElement;
int binding;
unsigned int dataSize;
bool vertexStaticUse;
bool fragmentStaticUse;
bool computeStaticUse;
std::vector<unsigned int> memberUniformIndexes;
};
}
......
......@@ -66,6 +66,11 @@ bool UniformLinker::link(const Context *context,
return false;
}
if (!checkMaxCombinedAtomicCounters(context->getCaps(), infoLog))
{
return false;
}
if (!indexUniforms(infoLog, uniformLocationBindings))
{
return false;
......@@ -140,6 +145,12 @@ bool UniformLinker::linkValidateUniforms(InfoLog &infoLog,
<< " differ between vertex and fragment shaders.";
return false;
}
if (vertexUniform.offset != fragmentUniform.offset)
{
infoLog << "Offset layout qualifiers for " << uniformName
<< " differ between vertex and fragment shaders.";
return false;
}
return true;
}
......@@ -326,17 +337,21 @@ bool UniformLinker::flattenUniformsAndCheckCapsForShader(
GLuint maxUniformComponents,
GLuint maxTextureImageUnits,
GLuint maxImageUnits,
GLuint maxAtomicCounters,
const std::string &componentsErrorMessage,
const std::string &samplerErrorMessage,
const std::string &imageErrorMessage,
const std::string &atomicCounterErrorMessage,
std::vector<LinkedUniform> &samplerUniforms,
std::vector<LinkedUniform> &imageUniforms,
std::vector<LinkedUniform> &atomicCounterUniforms,
InfoLog &infoLog)
{
ShaderUniformCount shaderUniformCount;
for (const sh::Uniform &uniform : shader->getUniforms(context))
{
shaderUniformCount += flattenUniform(uniform, &samplerUniforms, &imageUniforms);
shaderUniformCount +=
flattenUniform(uniform, &samplerUniforms, &imageUniforms, &atomicCounterUniforms);
}
if (shaderUniformCount.vectorCount > maxUniformComponents)
......@@ -357,6 +372,12 @@ bool UniformLinker::flattenUniformsAndCheckCapsForShader(
return false;
}
if (shaderUniformCount.atomicCounterCount > maxAtomicCounters)
{
infoLog << atomicCounterErrorMessage << maxAtomicCounters << ").";
return false;
}
return true;
}
......@@ -364,6 +385,7 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog
{
std::vector<LinkedUniform> samplerUniforms;
std::vector<LinkedUniform> imageUniforms;
std::vector<LinkedUniform> atomicCounterUniforms;
const Caps &caps = context->getCaps();
......@@ -375,10 +397,12 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog
if (!flattenUniformsAndCheckCapsForShader(
context, computeShader, caps.maxComputeUniformComponents / 4,
caps.maxComputeTextureImageUnits, caps.maxComputeImageUniforms,
caps.maxComputeAtomicCounters,
"Compute shader active uniforms exceed MAX_COMPUTE_UNIFORM_COMPONENTS (",
"Compute shader sampler count exceeds MAX_COMPUTE_TEXTURE_IMAGE_UNITS (",
"Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (", samplerUniforms,
imageUniforms, infoLog))
"Compute shader image count exceeds MAX_COMPUTE_IMAGE_UNIFORMS (",
"Compute shader atomic counter count exceeds MAX_COMPUTE_ATOMIC_COUNTERS (",
samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
{
return false;
}
......@@ -390,10 +414,12 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog
if (!flattenUniformsAndCheckCapsForShader(
context, vertexShader, caps.maxVertexUniformVectors,
caps.maxVertexTextureImageUnits, caps.maxVertexImageUniforms,
caps.maxVertexAtomicCounters,
"Vertex shader active uniforms exceed MAX_VERTEX_UNIFORM_VECTORS (",
"Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (",
"Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (", samplerUniforms,
imageUniforms, infoLog))
"Vertex shader image count exceeds MAX_VERTEX_IMAGE_UNIFORMS (",
"Vertex shader atomic counter count exceeds MAX_VERTEX_ATOMIC_COUNTERS (",
samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
{
return false;
}
......@@ -402,11 +428,12 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog
if (!flattenUniformsAndCheckCapsForShader(
context, fragmentShader, caps.maxFragmentUniformVectors, caps.maxTextureImageUnits,
caps.maxFragmentImageUniforms,
caps.maxFragmentImageUniforms, caps.maxFragmentAtomicCounters,
"Fragment shader active uniforms exceed MAX_FRAGMENT_UNIFORM_VECTORS (",
"Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (",
"Fragment shader image count exceeds MAX_FRAGMENT_IMAGE_UNIFORMS (",
samplerUniforms, imageUniforms, infoLog))
"Fragment shader atomic counter count exceeds MAX_FRAGMENT_ATOMIC_COUNTERS (",
samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
{
return false;
}
......@@ -414,18 +441,20 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog
mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
return true;
}
UniformLinker::ShaderUniformCount UniformLinker::flattenUniform(
const sh::Uniform &uniform,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms)
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms)
{
int location = uniform.location;
ShaderUniformCount shaderUniformCount =
flattenUniformImpl(uniform, uniform.name, samplerUniforms, imageUniforms, uniform.staticUse,
uniform.binding, &location);
ShaderUniformCount shaderUniformCount = flattenUniformImpl(
uniform, uniform.name, samplerUniforms, imageUniforms, atomicCounterUniforms,
uniform.staticUse, uniform.binding, uniform.offset, &location);
if (uniform.staticUse)
{
return shaderUniformCount;
......@@ -438,8 +467,10 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
const std::string &fullName,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
bool markStaticUse,
int binding,
int offset,
int *location)
{
ASSERT(location);
......@@ -458,7 +489,7 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
shaderUniformCount +=
flattenUniformImpl(field, fieldFullName, samplerUniforms, imageUniforms,
markStaticUse, -1, location);
atomicCounterUniforms, markStaticUse, -1, -1, location);
}
}
......@@ -468,16 +499,20 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
// 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)
{
// Store sampler uniforms separately, so we'll append them to the end of the list.
uniformList = samplerUniforms;
}
else if (isImage)
{
uniformList = imageUniforms;
}
else if (isAtomicCounter)
{
uniformList = atomicCounterUniforms;
}
LinkedUniform *existingUniform = FindUniform(*uniformList, fullName);
if (existingUniform)
{
......@@ -485,6 +520,10 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
{
existingUniform->binding = binding;
}
if (offset != -1)
{
existingUniform->offset = offset;
}
if (*location != -1)
{
existingUniform->location = *location;
......@@ -497,20 +536,22 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
else
{
LinkedUniform linkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
binding, *location, -1,
binding, -1, *location, -1,
sh::BlockMemberInfo::getDefaultBlockInfo());
linkedUniform.staticUse = markStaticUse;
uniformList->push_back(linkedUniform);
}
unsigned int elementCount = uniform.elementCount();
// Samplers and images aren't "real" uniforms, so they don't count towards register usage.
// Likewise, don't count "real" uniforms towards sampler and image count.
// Likewise, don't count "real" uniforms towards opaque count.
shaderUniformCount.vectorCount =
((isSampler || isImage) ? 0 : (VariableRegisterCount(uniform.type) * elementCount));
(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)
{
......@@ -520,4 +561,23 @@ UniformLinker::ShaderUniformCount UniformLinker::flattenUniformImpl(
return shaderUniformCount;
}
bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
{
unsigned int atomicCounterCount = 0;
for (const auto &uniform : mUniforms)
{
if (IsAtomicCounterType(uniform.type) && uniform.staticUse)
{
atomicCounterCount += uniform.elementCount();
if (atomicCounterCount > caps.maxCombinedAtomicCounters)
{
infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
<< caps.maxCombinedAtomicCounters << ").";
return false;
}
}
}
return true;
}
} // namespace gl
......@@ -32,7 +32,9 @@ class UniformLinker
private:
struct ShaderUniformCount
{
ShaderUniformCount() : vectorCount(0), samplerCount(0), imageCount(0) {}
ShaderUniformCount() : vectorCount(0), samplerCount(0), imageCount(0), atomicCounterCount(0)
{
}
ShaderUniformCount(const ShaderUniformCount &other) = default;
ShaderUniformCount &operator=(const ShaderUniformCount &other) = default;
......@@ -41,12 +43,14 @@ class UniformLinker
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 validateVertexAndFragmentUniforms(const Context *context, InfoLog &infoLog) const;
......@@ -61,18 +65,23 @@ class UniformLinker
GLuint maxUniformComponents,
GLuint maxTextureImageUnits,
GLuint maxImageUnits,
GLuint maxAtomicCounters,
const std::string &componentsErrorMessage,
const std::string &samplerErrorMessage,
const std::string &imageErrorMessage,
const std::string &atomicCounterErrorMessage,
std::vector<LinkedUniform> &samplerUniforms,
std::vector<LinkedUniform> &imageUniforms,
std::vector<LinkedUniform> &atomicCounterUniforms,
InfoLog &infoLog);
bool flattenUniformsAndCheckCaps(const Context *context, 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> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms);
// markStaticUse is given as a separate parameter because it is tracked here at struct
// granularity.
......@@ -80,8 +89,10 @@ class UniformLinker
const std::string &fullName,
std::vector<LinkedUniform> *samplerUniforms,
std::vector<LinkedUniform> *imageUniforms,
std::vector<LinkedUniform> *atomicCounterUniforms,
bool markStaticUse,
int binding,
int offset,
int *location);
bool indexUniforms(InfoLog &infoLog, const Program::Bindings &uniformLocationBindings);
......
......@@ -816,14 +816,14 @@ void QueryActiveUniformBlockiv(const Program *program,
*params = ConvertToGLint(uniformBlock.nameWithArrayIndex().size() + 1);
break;
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
*params = ConvertToGLint(uniformBlock.memberUniformIndexes.size());
*params = ConvertToGLint(uniformBlock.memberIndexes.size());
break;
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
for (size_t blockMemberIndex = 0;
blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
for (size_t blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberIndexes.size();
blockMemberIndex++)
{
params[blockMemberIndex] =
ConvertToGLint(uniformBlock.memberUniformIndexes[blockMemberIndex]);
ConvertToGLint(uniformBlock.memberIndexes[blockMemberIndex]);
}
break;
case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
......
......@@ -518,7 +518,7 @@ bool ValidateGetActiveUniformBlockivBase(Context *context,
{
const UniformBlock &uniformBlock =
programObject->getUniformBlockByIndex(uniformBlockIndex);
*length = static_cast<GLsizei>(uniformBlock.memberUniformIndexes.size());
*length = static_cast<GLsizei>(uniformBlock.memberIndexes.size());
}
else
{
......
......@@ -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,
ES3_OPENGL(),
ES3_OPENGLES(),
ES31_OPENGL(),
ES31_OPENGLES());
ANGLE_INSTANTIATE_TEST(AtomicCounterBufferTest31, ES31_OPENGL(), ES31_OPENGLES());
} // 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