Commit 55bc905f by Olli Etuaho Committed by Commit Bot

Always consider type arrayness for atomic counters

Atomic counter arrays may be declared with various different syntax - the array size may be declared as a part of the type or as a part of the declarator. Take this into account when determining whether atomic counter offsets overlap. BUG=angleproject:1729 TEST=angle_unittests Change-Id: I7435ded9401c4c1caab22c22d83fd2ad301df768 Reviewed-on: https://chromium-review.googlesource.com/738140Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 87c35883
...@@ -2248,30 +2248,35 @@ void TParseContext::checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &m ...@@ -2248,30 +2248,35 @@ void TParseContext::checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &m
// Make sure there is no offset overlapping, and store the newly assigned offset to "type" in // Make sure there is no offset overlapping, and store the newly assigned offset to "type" in
// intermediate tree. // intermediate tree.
void TParseContext::checkAtomicCounterOffsetIsNotOverlapped(TPublicType &publicType, void TParseContext::checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend,
size_t size, const TSourceLoc &loc,
bool forceAppend, TType *type)
const TSourceLoc &loc,
TType &type)
{ {
auto &bindingState = mAtomicCounterBindingStates[publicType.layoutQualifier.binding]; if (!IsAtomicCounter(type->getBasicType()))
{
return;
}
const size_t size = type->isArray() ? kAtomicCounterArrayStride * type->getArraySizeProduct()
: kAtomicCounterSize;
TLayoutQualifier layoutQualifier = type->getLayoutQualifier();
auto &bindingState = mAtomicCounterBindingStates[layoutQualifier.binding];
int offset; int offset;
if (publicType.layoutQualifier.offset == -1 || forceAppend) if (layoutQualifier.offset == -1 || forceAppend)
{ {
offset = bindingState.appendSpan(size); offset = bindingState.appendSpan(size);
} }
else else
{ {
offset = bindingState.insertSpan(publicType.layoutQualifier.offset, size); offset = bindingState.insertSpan(layoutQualifier.offset, size);
} }
if (offset == -1) if (offset == -1)
{ {
error(loc, "Offset overlapping", "atomic counter"); error(loc, "Offset overlapping", "atomic counter");
return; return;
} }
TLayoutQualifier qualifier = type.getLayoutQualifier(); layoutQualifier.offset = offset;
qualifier.offset = offset; type->setLayoutQualifier(layoutQualifier);
type.setLayoutQualifier(qualifier);
} }
void TParseContext::checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location, void TParseContext::checkGeometryShaderInputAndSetArraySize(const TSourceLoc &location,
...@@ -2373,12 +2378,7 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration( ...@@ -2373,12 +2378,7 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration(
checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, &type); checkCanBeDeclaredWithoutInitializer(identifierOrTypeLocation, identifier, &type);
if (IsAtomicCounter(publicType.getBasicType())) checkAtomicCounterOffsetDoesNotOverlap(false, identifierOrTypeLocation, &type);
{
checkAtomicCounterOffsetIsNotOverlapped(publicType, kAtomicCounterSize, false,
identifierOrTypeLocation, type);
}
TVariable *variable = nullptr; TVariable *variable = nullptr;
declareVariable(identifierOrTypeLocation, identifier, type, &variable); declareVariable(identifierOrTypeLocation, identifier, type, &variable);
...@@ -2421,12 +2421,7 @@ TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &elem ...@@ -2421,12 +2421,7 @@ TIntermDeclaration *TParseContext::parseSingleArrayDeclaration(TPublicType &elem
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &arrayType); checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &arrayType);
if (IsAtomicCounter(elementType.getBasicType())) checkAtomicCounterOffsetDoesNotOverlap(false, identifierLocation, &arrayType);
{
checkAtomicCounterOffsetIsNotOverlapped(
elementType, kAtomicCounterArrayStride * arrayType.getArraySizeProduct(), false,
identifierLocation, arrayType);
}
TVariable *variable = nullptr; TVariable *variable = nullptr;
declareVariable(identifierLocation, identifier, arrayType, &variable); declareVariable(identifierLocation, identifier, arrayType, &variable);
...@@ -2587,11 +2582,8 @@ void TParseContext::parseDeclarator(TPublicType &publicType, ...@@ -2587,11 +2582,8 @@ void TParseContext::parseDeclarator(TPublicType &publicType,
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &type); checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &type);
if (IsAtomicCounter(publicType.getBasicType())) checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, &type);
{
checkAtomicCounterOffsetIsNotOverlapped(publicType, kAtomicCounterSize, true,
identifierLocation, type);
}
declareVariable(identifierLocation, identifier, type, &variable); declareVariable(identifierLocation, identifier, type, &variable);
if (variable) if (variable)
...@@ -2628,12 +2620,7 @@ void TParseContext::parseArrayDeclarator(TPublicType &elementType, ...@@ -2628,12 +2620,7 @@ void TParseContext::parseArrayDeclarator(TPublicType &elementType,
checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &arrayType); checkCanBeDeclaredWithoutInitializer(identifierLocation, identifier, &arrayType);
if (IsAtomicCounter(elementType.getBasicType())) checkAtomicCounterOffsetDoesNotOverlap(true, identifierLocation, &arrayType);
{
checkAtomicCounterOffsetIsNotOverlapped(
elementType, kAtomicCounterArrayStride * arrayType.getArraySizeProduct(), true,
identifierLocation, arrayType);
}
TVariable *variable = nullptr; TVariable *variable = nullptr;
declareVariable(identifierLocation, identifier, arrayType, &variable); declareVariable(identifierLocation, identifier, arrayType, &variable);
......
...@@ -441,6 +441,7 @@ class TParseContext : angle::NonCopyable ...@@ -441,6 +441,7 @@ class TParseContext : angle::NonCopyable
// we treat it as always 4 in favour of the original interpretation in // we treat it as always 4 in favour of the original interpretation in
// "ARB_shader_atomic_counters". // "ARB_shader_atomic_counters".
// TODO(jie.a.chen@intel.com): Double check this once the spec vagueness is resolved. // TODO(jie.a.chen@intel.com): Double check this once the spec vagueness is resolved.
// Note that there may be tests in AtomicCounter_test that will need to be updated as well.
constexpr static size_t kAtomicCounterArrayStride = 4; constexpr static size_t kAtomicCounterArrayStride = 4;
// Returns a clamped index. If it prints out an error message, the token is "[]". // Returns a clamped index. If it prints out an error message, the token is "[]".
...@@ -480,11 +481,9 @@ class TParseContext : angle::NonCopyable ...@@ -480,11 +481,9 @@ class TParseContext : angle::NonCopyable
TLayoutImageInternalFormat internalFormat); TLayoutImageInternalFormat internalFormat);
void checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier, void checkMemoryQualifierIsNotSpecified(const TMemoryQualifier &memoryQualifier,
const TSourceLoc &location); const TSourceLoc &location);
void checkAtomicCounterOffsetIsNotOverlapped(TPublicType &publicType, void checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend,
size_t size, const TSourceLoc &loc,
bool forceAppend, TType *type);
const TSourceLoc &loc,
TType &type);
void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type); void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type);
void checkBindingIsNotSpecified(const TSourceLoc &location, int binding); void checkBindingIsNotSpecified(const TSourceLoc &location, int binding);
void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset); void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset);
......
...@@ -211,3 +211,20 @@ TEST_F(AtomicCounterTest, OffsetMustNotSpecifiedForGlobalLayoutQualifier) ...@@ -211,3 +211,20 @@ TEST_F(AtomicCounterTest, OffsetMustNotSpecifiedForGlobalLayoutQualifier)
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
} }
} }
// Test that offset overlapping leads to compile-time error (ESSL 3.10 section 4.4.6).
// Note that there is some vagueness in the spec when it comes to this test.
TEST_F(AtomicCounterTest, BindingOffsetOverlappingForArrays)
{
const std::string &source =
"#version 310 es\n"
"layout(binding = 2, offset = 4) uniform atomic_uint[2] a;\n"
"layout(binding = 2, offset = 8) uniform atomic_uint b;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(source))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
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