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;
};
}
......
......@@ -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