Commit 186fe990 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Redo RewriteAtomicCounters

With MonomorphizeUnsupportedFunctionsInVulkanGLSL and RewriteArrayOfArrayOfOpaqueUniforms transformations run, it is no longer possible to encounter array of array of atomic counters, or have any passed to functions. As a result, RewriteAtomicCounters is greatly simplified. Additionally, it is no longer necessary to pass binding/offset information for atomic counters around and they can use constants. This change removes dependency on the shaderStorageBufferArrayDynamicIndexing Vulkan feature. Bug: angleproject:3726 Bug: angleproject:3881 Change-Id: Ia43092a668f60d009eccbbceeed5deaf105a5895 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2633687Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 64c89120
...@@ -20,7 +20,6 @@ namespace sh ...@@ -20,7 +20,6 @@ namespace sh
{ {
namespace namespace
{ {
constexpr ImmutableString kAtomicCounterTypeName = ImmutableString("ANGLE_atomic_uint");
constexpr ImmutableString kAtomicCountersVarName = ImmutableString("atomicCounters"); constexpr ImmutableString kAtomicCountersVarName = ImmutableString("atomicCounters");
constexpr ImmutableString kAtomicCounterFieldName = ImmutableString("counters"); constexpr ImmutableString kAtomicCounterFieldName = ImmutableString("counters");
...@@ -50,32 +49,32 @@ const TVariable *DeclareAtomicCountersBuffers(TIntermBlock *root, TSymbolTable * ...@@ -50,32 +49,32 @@ const TVariable *DeclareAtomicCountersBuffers(TIntermBlock *root, TSymbolTable *
ImmutableString(vk::kAtomicCountersBlockName), kAtomicCountersVarName); ImmutableString(vk::kAtomicCountersBlockName), kAtomicCountersVarName);
} }
TIntermConstantUnion *CreateUIntConstant(uint32_t value) TIntermTyped *CreateUniformBufferOffset(const TIntermTyped *uniformBufferOffsets, int binding)
{ {
TType *constantType = new TType(*StaticType::GetBasic<EbtUInt, 1>()); // Each uint in the |acbBufferOffsets| uniform contains offsets for 4 bindings. Therefore, the
constantType->setQualifier(EvqConst); // expression to get the uniform offset for the binding is:
//
TConstantUnion *constantValue = new TConstantUnion; // acbBufferOffsets[binding / 4] >> ((binding % 4) * 8) & 0xFF
constantValue->setUConst(value);
return new TIntermConstantUnion(constantValue, *constantType);
}
TIntermTyped *CreateAtomicCounterConstant(TType *atomicCounterType, // acbBufferOffsets[binding / 4]
uint32_t binding, TIntermBinary *uniformBufferOffsetUint = new TIntermBinary(
uint32_t offset) EOpIndexDirect, uniformBufferOffsets->deepCopy(), CreateIndexNode(binding / 4));
{
ASSERT(atomicCounterType->getBasicType() == EbtStruct);
TIntermSequence *arguments = new TIntermSequence(); // acbBufferOffsets[binding / 4] >> ((binding % 4) * 8)
arguments->push_back(CreateUIntConstant(binding)); TIntermBinary *uniformBufferOffsetShifted = uniformBufferOffsetUint;
arguments->push_back(CreateUIntConstant(offset)); if (binding % 4 != 0)
{
uniformBufferOffsetShifted = new TIntermBinary(EOpBitShiftRight, uniformBufferOffsetUint,
CreateUIntNode((binding % 4) * 8));
}
return TIntermAggregate::CreateConstructor(*atomicCounterType, arguments); // acbBufferOffsets[binding / 4] >> ((binding % 4) * 8) & 0xFF
return new TIntermBinary(EOpBitwiseAnd, uniformBufferOffsetShifted, CreateUIntNode(0xFF));
} }
TIntermBinary *CreateAtomicCounterRef(const TVariable *atomicCounters, TIntermBinary *CreateAtomicCounterRef(TIntermTyped *atomicCounterExpression,
const TIntermTyped *bindingOffset, const TVariable *atomicCounters,
const TIntermTyped *bufferOffsets) const TIntermTyped *uniformBufferOffsets)
{ {
// The atomic counters storage buffer declaration looks as such: // The atomic counters storage buffer declaration looks as such:
// //
...@@ -86,79 +85,109 @@ TIntermBinary *CreateAtomicCounterRef(const TVariable *atomicCounters, ...@@ -86,79 +85,109 @@ TIntermBinary *CreateAtomicCounterRef(const TVariable *atomicCounters,
// //
// Where N is large enough to accommodate atomic counter buffer bindings used in the shader. // Where N is large enough to accommodate atomic counter buffer bindings used in the shader.
// //
// Given an ANGLEAtomicCounter variable (which is a struct of {binding, offset}), we need to // This function takes an expression that uses an atomic counter, which can either be:
// return: //
// - ac
// - acArray[index]
//
// Note that RewriteArrayOfArrayOfOpaqueUniforms has already flattened array of array of atomic
// counters.
//
// For the first case (ac), the following code is generated:
// //
// atomicCounters[binding].counters[offset] // atomicCounters[binding].counters[offset]
// //
// The offset itself is the provided one plus an offset given through uniforms. // For the second case (acArray[index]), the following code is generated:
//
// atomicCounters[binding].counters[offset + index]
//
// In either case, an offset given through uniforms is also added to |offset|. The binding is
// necessarily a constant thanks to MonomorphizeUnsupportedFunctionsInVulkanGLSL.
TIntermSymbol *atomicCountersRef = new TIntermSymbol(atomicCounters); // First determine if there's an index, and extract the atomic counter symbol out of the
// expression.
TIntermSymbol *atomicCounterSymbol = atomicCounterExpression->getAsSymbolNode();
TIntermTyped *atomicCounterIndex = nullptr;
int atomicCounterConstIndex = 0;
TIntermBinary *asBinary = atomicCounterExpression->getAsBinaryNode();
if (asBinary != nullptr)
{
atomicCounterSymbol = asBinary->getLeft()->getAsSymbolNode();
switch (asBinary->getOp())
{
case EOpIndexDirect:
atomicCounterConstIndex = asBinary->getRight()->getAsConstantUnion()->getIConst(0);
break;
case EOpIndexIndirect:
atomicCounterIndex = asBinary->getRight();
break;
default:
UNREACHABLE();
}
}
// Extract binding and offset information out of the atomic counter symbol.
ASSERT(atomicCounterSymbol);
const TVariable *atomicCounterVar = &atomicCounterSymbol->variable();
const TType &atomicCounterType = atomicCounterVar->getType();
const int binding = atomicCounterType.getLayoutQualifier().binding;
int offset = atomicCounterType.getLayoutQualifier().offset / 4;
// Create the expression:
//
// offset + arrayIndex + uniformOffset
//
// If arrayIndex is a constant, it's added with offset right here.
offset += atomicCounterConstIndex;
TIntermTyped *index = CreateUniformBufferOffset(uniformBufferOffsets, binding);
if (atomicCounterIndex != nullptr)
{
index = new TIntermBinary(EOpAdd, index, atomicCounterIndex);
}
if (offset != 0)
{
index = new TIntermBinary(EOpAdd, index, CreateIndexNode(offset));
}
TIntermConstantUnion *bindingFieldRef = CreateIndexNode(0); // Finally, create the complete expression:
TIntermConstantUnion *offsetFieldRef = CreateIndexNode(1); //
TIntermConstantUnion *countersFieldRef = CreateIndexNode(0); // atomicCounters[binding].counters[index]
// Create references to bindingOffset.binding and bindingOffset.offset. TIntermSymbol *atomicCountersRef = new TIntermSymbol(atomicCounters);
TIntermBinary *binding =
new TIntermBinary(EOpIndexDirectStruct, bindingOffset->deepCopy(), bindingFieldRef);
TIntermBinary *offset =
new TIntermBinary(EOpIndexDirectStruct, bindingOffset->deepCopy(), offsetFieldRef);
// Create reference to atomicCounters[bindingOffset.binding] // atomicCounters[binding]
TIntermBinary *countersBlock = new TIntermBinary(EOpIndexDirect, atomicCountersRef, binding); TIntermBinary *countersBlock =
new TIntermBinary(EOpIndexDirect, atomicCountersRef, CreateIndexNode(binding));
// Create reference to atomicCounters[bindingOffset.binding].counters // atomicCounters[binding].counters
TIntermBinary *counters = TIntermBinary *counters =
new TIntermBinary(EOpIndexDirectInterfaceBlock, countersBlock, countersFieldRef); new TIntermBinary(EOpIndexDirectInterfaceBlock, countersBlock, CreateIndexNode(0));
// Create bufferOffsets[binding / 4]. Each uint in bufferOffsets contains offsets for 4 return new TIntermBinary(EOpIndexIndirect, counters, index);
// bindings.
TIntermBinary *bindingDivFour =
new TIntermBinary(EOpDiv, binding->deepCopy(), CreateUIntConstant(4));
TIntermBinary *bufferOffsetUint =
new TIntermBinary(EOpIndexDirect, bufferOffsets->deepCopy(), bindingDivFour);
// Create (binding % 4) * 8
TIntermBinary *bindingModFour =
new TIntermBinary(EOpIMod, binding->deepCopy(), CreateUIntConstant(4));
TIntermBinary *bufferOffsetShift =
new TIntermBinary(EOpMul, bindingModFour, CreateUIntConstant(8));
// Create bufferOffsets[binding / 4] >> ((binding % 4) * 8) & 0xFF
TIntermBinary *bufferOffsetShifted =
new TIntermBinary(EOpBitShiftRight, bufferOffsetUint, bufferOffsetShift);
TIntermBinary *bufferOffset =
new TIntermBinary(EOpBitwiseAnd, bufferOffsetShifted, CreateUIntConstant(0xFF));
// return atomicCounters[bindingOffset.binding].counters[bindingOffset.offset + bufferOffset]
offset = new TIntermBinary(EOpAdd, offset, bufferOffset);
return new TIntermBinary(EOpIndexDirect, counters, offset);
} }
// Traverser that: // Traverser that:
// //
// 1. Converts the |atomic_uint| types to |{uint,uint}| for binding and offset. // 1. Removes the |uniform atomic_uint| declarations and remembers the binding and offset.
// 2. Substitutes the |uniform atomic_uint| declarations with a global declaration that holds the // 2. Substitutes |atomicVar[n]| with |buffer[binding].counters[offset + n]|.
// binding and offset.
// 3. Substitutes |atomicVar[n]| with |buffer[binding].counters[offset + n]|.
class RewriteAtomicCountersTraverser : public TIntermTraverser class RewriteAtomicCountersTraverser : public TIntermTraverser
{ {
public: public:
RewriteAtomicCountersTraverser(TSymbolTable *symbolTable, RewriteAtomicCountersTraverser(TSymbolTable *symbolTable,
const TVariable *atomicCounters, const TVariable *atomicCounters,
const TIntermTyped *acbBufferOffsets) const TIntermTyped *acbBufferOffsets)
: TIntermTraverser(true, true, true, symbolTable), : TIntermTraverser(true, false, false, symbolTable),
mAtomicCounters(atomicCounters), mAtomicCounters(atomicCounters),
mAcbBufferOffsets(acbBufferOffsets), mAcbBufferOffsets(acbBufferOffsets)
mAtomicCounterType(nullptr),
mAtomicCounterTypeConst(nullptr),
mAtomicCounterTypeDeclaration(nullptr)
{} {}
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
{ {
if (visit != PreVisit) if (!mInGlobalScope)
{ {
return true; return true;
} }
...@@ -167,411 +196,50 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser ...@@ -167,411 +196,50 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser
TIntermTyped *variable = sequence.front()->getAsTyped(); TIntermTyped *variable = sequence.front()->getAsTyped();
const TType &type = variable->getType(); const TType &type = variable->getType();
bool isAtomicCounter = type.getQualifier() == EvqUniform && type.isAtomicCounter(); bool isAtomicCounter = type.isAtomicCounter();
if (isAtomicCounter) if (isAtomicCounter)
{ {
// Atomic counters cannot have initializers, so the declaration must necessarily be a ASSERT(type.getQualifier() == EvqUniform);
// symbol. TIntermSequence emptySequence;
TIntermSymbol *samplerVariable = variable->getAsSymbolNode(); mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node, emptySequence);
ASSERT(samplerVariable != nullptr);
declareAtomicCounter(&samplerVariable->variable(), node);
return false; return false;
} }
return true; return true;
} }
void visitFunctionPrototype(TIntermFunctionPrototype *node) override
{
const TFunction *function = node->getFunction();
// Go over the parameters and replace the atomic arguments with a uint type.
mRetyper.visitFunctionPrototype();
for (size_t paramIndex = 0; paramIndex < function->getParamCount(); ++paramIndex)
{
const TVariable *param = function->getParam(paramIndex);
TVariable *replacement = convertFunctionParameter(node, param);
if (replacement)
{
mRetyper.replaceFunctionParam(param, replacement);
}
}
TIntermFunctionPrototype *replacementPrototype =
mRetyper.convertFunctionPrototype(mSymbolTable, function);
if (replacementPrototype)
{
queueReplacement(replacementPrototype, OriginalNode::IS_DROPPED);
}
}
bool visitAggregate(Visit visit, TIntermAggregate *node) override bool visitAggregate(Visit visit, TIntermAggregate *node) override
{ {
if (visit == PreVisit)
{
mRetyper.preVisitAggregate();
}
if (visit != PostVisit)
{
return true;
}
if (node->getOp() == EOpCallBuiltInFunction) if (node->getOp() == EOpCallBuiltInFunction)
{ {
convertBuiltinFunction(node); bool converted = convertBuiltinFunction(node);
} return !converted;
else if (node->getOp() == EOpCallFunctionInAST)
{
TIntermAggregate *substituteCall = mRetyper.convertASTFunction(node);
if (substituteCall)
{
queueReplacement(substituteCall, OriginalNode::IS_DROPPED);
} }
}
mRetyper.postVisitAggregate();
// AST functions don't require modification as atomic counter function parameters are
// removed by MonomorphizeUnsupportedFunctionsInVulkanGLSL.
return true; return true;
} }
void visitSymbol(TIntermSymbol *symbol) override void visitSymbol(TIntermSymbol *symbol) override
{ {
const TVariable *symbolVariable = &symbol->variable(); // Connot encounter the atomic counter symbol directly. It can only be used with functions,
// and therefore it's handled by visitAggregate.
if (!symbol->getType().isAtomicCounter()) ASSERT(!symbol->getType().isAtomicCounter());
{
return;
} }
// The symbol is either referencing a global atomic counter, or is a function parameter. In bool visitBinary(Visit visit, TIntermBinary *node) override
// either case, it could be an array. The are the following possibilities:
//
// layout(..) uniform atomic_uint ac;
// layout(..) uniform atomic_uint acArray[N];
//
// void func(inout atomic_uint c)
// {
// otherFunc(c);
// }
//
// void funcArray(inout atomic_uint cArray[N])
// {
// otherFuncArray(cArray);
// otherFunc(cArray[n]);
// }
//
// void funcGlobal()
// {
// func(ac);
// func(acArray[n]);
// funcArray(acArray);
// atomicIncrement(ac);
// atomicIncrement(acArray[n]);
// }
//
// This should translate to:
//
// buffer ANGLEAtomicCounters
// {
// uint counters[];
// } atomicCounters;
//
// struct ANGLEAtomicCounter
// {
// uint binding;
// uint offset;
// };
// const ANGLEAtomicCounter ac = {<binding>, <offset>};
// const ANGLEAtomicCounter acArray = {<binding>, <offset>};
//
// void func(inout ANGLEAtomicCounter c)
// {
// otherFunc(c);
// }
//
// void funcArray(inout uint cArray)
// {
// otherFuncArray(cArray);
// otherFunc({cArray.binding, cArray.offset + n});
// }
//
// void funcGlobal()
// {
// func(ac);
// func(acArray+n);
// funcArray(acArray);
// atomicAdd(atomicCounters[ac.binding]counters[ac.offset]);
// atomicAdd(atomicCounters[ac.binding]counters[ac.offset+n]);
// }
//
// In all cases, the argument transformation is stored in mRetyper. In the function call's
// PostVisit, if it's a builtin, the look up in |atomicCounters.counters| is done as well as
// the builtin function change. Otherwise, the transformed argument is passed on as is.
//
TIntermTyped *bindingOffset =
new TIntermSymbol(mRetyper.getVariableReplacement(symbolVariable));
ASSERT(bindingOffset != nullptr);
TIntermNode *argument = convertFunctionArgument(symbol, &bindingOffset);
if (mRetyper.isInAggregate())
{
mRetyper.replaceFunctionCallArg(argument, bindingOffset);
}
else
{
// If there's a stray ac[i] lying around, just delete it. This can happen if the shader
// uses ac[i].length(), which in RemoveArrayLengthMethod() will result in an ineffective
// statement that's just ac[i]; (similarly for a stray ac;, it doesn't have to be
// subscripted). Note that the subscript could have side effects, but the
// convertFunctionArgument above has already generated code that includes the subscript
// (and therefore its side-effect).
TIntermBlock *block = nullptr;
for (uint32_t ancestorIndex = 0; block == nullptr; ++ancestorIndex)
{ {
block = getAncestorNode(ancestorIndex)->getAsBlock(); // Connot encounter an atomic counter expression directly. It can only be used with
} // functions, and therefore it's handled by visitAggregate.
ASSERT(!node->getType().isAtomicCounter());
TIntermSequence emptySequence; return true;
mMultiReplacements.emplace_back(block, argument, emptySequence);
}
} }
TIntermDeclaration *getAtomicCounterTypeDeclaration() { return mAtomicCounterTypeDeclaration; }
private: private:
void declareAtomicCounter(const TVariable *atomicCounterVar, TIntermDeclaration *node) bool convertBuiltinFunction(TIntermAggregate *node)
{
// Create a global variable that contains the binding and offset of this atomic counter
// declaration.
if (mAtomicCounterType == nullptr)
{
declareAtomicCounterType();
}
ASSERT(mAtomicCounterTypeConst);
TVariable *bindingOffset = new TVariable(mSymbolTable, atomicCounterVar->name(),
mAtomicCounterTypeConst, SymbolType::UserDefined);
const TType &atomicCounterType = atomicCounterVar->getType();
uint32_t offset = atomicCounterType.getLayoutQualifier().offset;
uint32_t binding = atomicCounterType.getLayoutQualifier().binding;
ASSERT(offset % 4 == 0);
TIntermTyped *bindingOffsetInitValue =
CreateAtomicCounterConstant(mAtomicCounterTypeConst, binding, offset / 4);
TIntermSymbol *bindingOffsetSymbol = new TIntermSymbol(bindingOffset);
TIntermBinary *bindingOffsetInit =
new TIntermBinary(EOpInitialize, bindingOffsetSymbol, bindingOffsetInitValue);
TIntermDeclaration *bindingOffsetDeclaration = new TIntermDeclaration();
bindingOffsetDeclaration->appendDeclarator(bindingOffsetInit);
// Replace the atomic_uint declaration with the binding/offset declaration.
TIntermSequence replacement;
replacement.push_back(bindingOffsetDeclaration);
mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node, replacement);
// Remember the binding/offset variable.
mRetyper.replaceGlobalVariable(atomicCounterVar, bindingOffset);
}
void declareAtomicCounterType()
{
ASSERT(mAtomicCounterType == nullptr);
TFieldList *fields = new TFieldList();
fields->push_back(new TField(new TType(EbtUInt, EbpUndefined, EvqGlobal, 1, 1),
ImmutableString("binding"), TSourceLoc(),
SymbolType::AngleInternal));
fields->push_back(new TField(new TType(EbtUInt, EbpUndefined, EvqGlobal, 1, 1),
ImmutableString("arrayIndex"), TSourceLoc(),
SymbolType::AngleInternal));
TStructure *atomicCounterTypeStruct =
new TStructure(mSymbolTable, kAtomicCounterTypeName, fields, SymbolType::AngleInternal);
mAtomicCounterType = new TType(atomicCounterTypeStruct, false);
mAtomicCounterTypeDeclaration = new TIntermDeclaration;
TVariable *emptyVariable = new TVariable(mSymbolTable, kEmptyImmutableString,
mAtomicCounterType, SymbolType::Empty);
mAtomicCounterTypeDeclaration->appendDeclarator(new TIntermSymbol(emptyVariable));
// Keep a const variant around as well.
mAtomicCounterTypeConst = new TType(*mAtomicCounterType);
mAtomicCounterTypeConst->setQualifier(EvqConst);
}
TVariable *convertFunctionParameter(TIntermNode *parent, const TVariable *param)
{
if (!param->getType().isAtomicCounter())
{
return nullptr;
}
if (mAtomicCounterType == nullptr)
{
declareAtomicCounterType();
}
const TType *paramType = &param->getType();
TType *newType =
paramType->getQualifier() == EvqConst ? mAtomicCounterTypeConst : mAtomicCounterType;
TVariable *replacementVar =
new TVariable(mSymbolTable, param->name(), newType, SymbolType::UserDefined);
return replacementVar;
}
TIntermTyped *convertFunctionArgumentHelper(
const TVector<unsigned int> &runningArraySizeProducts,
TIntermTyped *flattenedSubscript,
uint32_t depth,
uint32_t *subscriptCountOut)
{
std::string prefix(depth, ' ');
TIntermNode *parent = getAncestorNode(depth);
ASSERT(parent);
TIntermBinary *arrayExpression = parent->getAsBinaryNode();
if (!arrayExpression)
{
// If the parent is not an array subscript operation, we have reached the end of the
// subscript chain. Note the depth that's traversed so the corresponding node can be
// taken as the function argument.
*subscriptCountOut = depth;
return flattenedSubscript;
}
ASSERT(arrayExpression->getOp() == EOpIndexDirect ||
arrayExpression->getOp() == EOpIndexIndirect);
// Assume i = n - depth. Get Pi. See comment in convertFunctionArgument.
ASSERT(depth < runningArraySizeProducts.size());
uint32_t thisDimensionSize =
runningArraySizeProducts[runningArraySizeProducts.size() - 1 - depth];
// Get Ii.
TIntermTyped *thisDimensionOffset = arrayExpression->getRight();
TIntermConstantUnion *subscriptAsConstant = thisDimensionOffset->getAsConstantUnion();
const bool subscriptIsZero = subscriptAsConstant && subscriptAsConstant->isZero(0);
// If Ii is zero, don't need to add Ii*Pi; that's zero.
if (!subscriptIsZero)
{
thisDimensionOffset = thisDimensionOffset->deepCopy();
// If Pi is 1, don't multiply. Just accumulate Ii.
if (thisDimensionSize != 1)
{
thisDimensionOffset = new TIntermBinary(EOpMul, thisDimensionOffset,
CreateUIntConstant(thisDimensionSize));
}
// Accumulate with the previous running offset, if any.
if (flattenedSubscript)
{
flattenedSubscript =
new TIntermBinary(EOpAdd, flattenedSubscript, thisDimensionOffset);
}
else
{
flattenedSubscript = thisDimensionOffset;
}
}
// Note: GLSL only allows 2 nested levels of arrays, so this recursion is bounded.
return convertFunctionArgumentHelper(runningArraySizeProducts, flattenedSubscript,
depth + 1, subscriptCountOut);
}
TIntermNode *convertFunctionArgument(TIntermNode *symbol, TIntermTyped **bindingOffset)
{
// Assume a general case of array declaration with N dimensions:
//
// atomic_uint ac[Dn]..[D2][D1];
//
// Let's define
//
// Pn = D(n-1)*...*D2*D1
//
// In that case, we have:
//
// ac[In] = ac + In*Pn
// ac[In][I(n-1)] = ac + In*Pn + I(n-1)*P(n-1)
// ac[In]...[Ii] = ac + In*Pn + ... + Ii*Pi
//
// We have just visited a symbol; ac. Walking the parent chain, we will visit the
// expressions in the above order (ac, ac[In], ac[In][I(n-1)], ...). We therefore can
// simply walk the parent chain and accumulate Ii*Pi to obtain the offset from the base of
// ac.
TIntermSymbol *argumentAsSymbol = symbol->getAsSymbolNode();
ASSERT(argumentAsSymbol);
const TSpan<const unsigned int> &arraySizes = argumentAsSymbol->getType().getArraySizes();
// Calculate Pi
TVector<unsigned int> runningArraySizeProducts;
if (!arraySizes.empty())
{
runningArraySizeProducts.resize(arraySizes.size());
uint32_t runningProduct = 1;
for (size_t dimension = 0; dimension < arraySizes.size(); ++dimension)
{
runningArraySizeProducts[dimension] = runningProduct;
runningProduct *= arraySizes[dimension];
}
}
// Walk the parent chain and accumulate Ii*Pi
uint32_t subscriptCount = 0;
TIntermTyped *flattenedSubscript =
convertFunctionArgumentHelper(runningArraySizeProducts, nullptr, 0, &subscriptCount);
// Find the function argument, which is either in the form of ac (i.e. there are no
// subscripts, in which case that's the function argument), or ac[In]...[Ii] (in which case
// the function argument is the (n-i)th ancestor of ac.
//
// Note that this is the case because no other operation is allowed on ac other than
// subscript.
TIntermNode *argument = subscriptCount == 0 ? symbol : getAncestorNode(subscriptCount - 1);
ASSERT(argument != nullptr);
// If not subscripted, keep the argument as-is.
if (flattenedSubscript == nullptr)
{
return argument;
}
// Copy the atomic counter binding/offset constant and modify it by adding the array
// subscript to its offset field.
TVariable *modified = CreateTempVariable(mSymbolTable, mAtomicCounterType);
TIntermDeclaration *modifiedDecl = CreateTempInitDeclarationNode(modified, *bindingOffset);
TIntermSymbol *modifiedSymbol = new TIntermSymbol(modified);
TConstantUnion *offsetFieldIndex = new TConstantUnion;
offsetFieldIndex->setIConst(1);
TIntermConstantUnion *offsetFieldRef =
new TIntermConstantUnion(offsetFieldIndex, *StaticType::GetBasic<EbtUInt>());
TIntermBinary *offsetField =
new TIntermBinary(EOpIndexDirectStruct, modifiedSymbol, offsetFieldRef);
TIntermBinary *modifiedOffset =
new TIntermBinary(EOpAddAssign, offsetField, flattenedSubscript);
TIntermSequence *modifySequence = new TIntermSequence({modifiedDecl, modifiedOffset});
insertStatementsInParentBlock(*modifySequence);
*bindingOffset = modifiedSymbol->deepCopy();
return argument;
}
void convertBuiltinFunction(TIntermAggregate *node)
{ {
// If the function is |memoryBarrierAtomicCounter|, simply replace it with // If the function is |memoryBarrierAtomicCounter|, simply replace it with
// |memoryBarrierBuffer|. // |memoryBarrierBuffer|.
...@@ -580,17 +248,16 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser ...@@ -580,17 +248,16 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser
TIntermTyped *substituteCall = CreateBuiltInFunctionCallNode( TIntermTyped *substituteCall = CreateBuiltInFunctionCallNode(
"memoryBarrierBuffer", new TIntermSequence, *mSymbolTable, 310); "memoryBarrierBuffer", new TIntermSequence, *mSymbolTable, 310);
queueReplacement(substituteCall, OriginalNode::IS_DROPPED); queueReplacement(substituteCall, OriginalNode::IS_DROPPED);
return; return true;
} }
// If it's an |atomicCounter*| function, replace the function with an |atomic*| equivalent. // If it's an |atomicCounter*| function, replace the function with an |atomic*| equivalent.
if (!node->getFunction()->isAtomicCounterFunction()) if (!node->getFunction()->isAtomicCounterFunction())
{ {
return; return false;
} }
const ImmutableString &functionName = node->getFunction()->name(); const ImmutableString &functionName = node->getFunction()->name();
TIntermSequence *arguments = node->getSequence();
// Note: atomicAdd(0) is used for atomic reads. // Note: atomicAdd(0) is used for atomic reads.
uint32_t valueChange = 0; uint32_t valueChange = 0;
...@@ -615,14 +282,12 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser ...@@ -615,14 +282,12 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser
ASSERT(functionName == "atomicCounter"); ASSERT(functionName == "atomicCounter");
} }
const TIntermNode *param = (*arguments)[0]; TIntermTyped *param = (*node->getSequence())[0]->getAsTyped();
TIntermTyped *bindingOffset = mRetyper.getFunctionCallArgReplacement(param);
TIntermSequence *substituteArguments = new TIntermSequence; TIntermSequence *substituteArguments = new TIntermSequence;
substituteArguments->push_back( substituteArguments->push_back(
CreateAtomicCounterRef(mAtomicCounters, bindingOffset, mAcbBufferOffsets)); CreateAtomicCounterRef(param, mAtomicCounters, mAcbBufferOffsets));
substituteArguments->push_back(CreateUIntConstant(valueChange)); substituteArguments->push_back(CreateUIntNode(valueChange));
TIntermTyped *substituteCall = CreateBuiltInFunctionCallNode( TIntermTyped *substituteCall = CreateBuiltInFunctionCallNode(
kAtomicAddFunction, substituteArguments, *mSymbolTable, 310); kAtomicAddFunction, substituteArguments, *mSymbolTable, 310);
...@@ -631,22 +296,15 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser ...@@ -631,22 +296,15 @@ class RewriteAtomicCountersTraverser : public TIntermTraverser
// unlike atomicAdd. So we need to do a -1 on the result as well. // unlike atomicAdd. So we need to do a -1 on the result as well.
if (isDecrement) if (isDecrement)
{ {
substituteCall = new TIntermBinary(EOpSub, substituteCall, CreateUIntConstant(1)); substituteCall = new TIntermBinary(EOpSub, substituteCall, CreateUIntNode(1));
} }
queueReplacement(substituteCall, OriginalNode::IS_DROPPED); queueReplacement(substituteCall, OriginalNode::IS_DROPPED);
return true;
} }
const TVariable *mAtomicCounters; const TVariable *mAtomicCounters;
const TIntermTyped *mAcbBufferOffsets; const TIntermTyped *mAcbBufferOffsets;
RetypeOpaqueVariablesHelper mRetyper;
TType *mAtomicCounterType;
TType *mAtomicCounterTypeConst;
// Stored to be put at the top of the shader after the pass.
TIntermDeclaration *mAtomicCounterTypeDeclaration;
}; };
} // anonymous namespace } // anonymous namespace
...@@ -660,17 +318,6 @@ bool RewriteAtomicCounters(TCompiler *compiler, ...@@ -660,17 +318,6 @@ bool RewriteAtomicCounters(TCompiler *compiler,
RewriteAtomicCountersTraverser traverser(symbolTable, atomicCounters, acbBufferOffsets); RewriteAtomicCountersTraverser traverser(symbolTable, atomicCounters, acbBufferOffsets);
root->traverse(&traverser); root->traverse(&traverser);
if (!traverser.updateTree(compiler, root)) return traverser.updateTree(compiler, root);
{
return false;
}
TIntermDeclaration *atomicCounterTypeDeclaration = traverser.getAtomicCounterTypeDeclaration();
if (atomicCounterTypeDeclaration)
{
root->getSequence()->insert(root->getSequence()->begin(), atomicCounterTypeDeclaration);
}
return compiler->validateAST(root);
} }
} // namespace sh } // namespace sh
...@@ -1379,9 +1379,6 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1379,9 +1379,6 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
mPhysicalDeviceFeatures.shaderUniformBufferArrayDynamicIndexing; mPhysicalDeviceFeatures.shaderUniformBufferArrayDynamicIndexing;
enabledFeatures.features.shaderSampledImageArrayDynamicIndexing = enabledFeatures.features.shaderSampledImageArrayDynamicIndexing =
mPhysicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing; mPhysicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing;
// Used to support atomic counter emulation:
enabledFeatures.features.shaderStorageBufferArrayDynamicIndexing =
mPhysicalDeviceFeatures.shaderStorageBufferArrayDynamicIndexing;
// Used to support APPLE_clip_distance // Used to support APPLE_clip_distance
enabledFeatures.features.shaderClipDistance = mPhysicalDeviceFeatures.shaderClipDistance; enabledFeatures.features.shaderClipDistance = mPhysicalDeviceFeatures.shaderClipDistance;
// Used to support OES_sample_shading // Used to support OES_sample_shading
......
...@@ -1016,12 +1016,8 @@ bool CanSupportGPUShader5EXT(const VkPhysicalDeviceFeatures &features) ...@@ -1016,12 +1016,8 @@ bool CanSupportGPUShader5EXT(const VkPhysicalDeviceFeatures &features)
// textureGatherOffsets family of functions. // textureGatherOffsets family of functions.
// - shaderSampledImageArrayDynamicIndexing and shaderUniformBufferArrayDynamicIndexing: // - shaderSampledImageArrayDynamicIndexing and shaderUniformBufferArrayDynamicIndexing:
// dynamically uniform indices for samplers and uniform buffers. // dynamically uniform indices for samplers and uniform buffers.
// - shaderStorageBufferArrayDynamicIndexing: While EXT_gpu_shader5 doesn't require dynamically
// uniform indices on storage buffers, we need it as we emulate atomic counter buffers with
// storage buffers (and atomic counter buffers *can* be indexed in that way).
return features.shaderImageGatherExtended && features.shaderSampledImageArrayDynamicIndexing && return features.shaderImageGatherExtended && features.shaderSampledImageArrayDynamicIndexing &&
features.shaderUniformBufferArrayDynamicIndexing && features.shaderUniformBufferArrayDynamicIndexing;
features.shaderStorageBufferArrayDynamicIndexing;
} }
} // namespace vk } // namespace vk
......
...@@ -46,7 +46,7 @@ the name. Examples: ...@@ -46,7 +46,7 @@ the name. Examples:
1442 OPENGL : dEQP-GLES31.functional.separate_shader.* = SKIP 1442 OPENGL : dEQP-GLES31.functional.separate_shader.* = SKIP
1442 D3D11 : dEQP-GLES31.functional.separate_shader.* = SKIP 1442 D3D11 : dEQP-GLES31.functional.separate_shader.* = SKIP
// Bug in older drivers: // Unsupported feature:
3726 VULKAN ANDROID : dEQP-GLES31.functional.synchronization.inter_call.without_memory_barrier.*atomic_counter* = FAIL 3726 VULKAN ANDROID : dEQP-GLES31.functional.synchronization.inter_call.without_memory_barrier.*atomic_counter* = FAIL
// Failing test in Nvidia's OpenGL implementation on windows: // Failing test in Nvidia's OpenGL implementation on windows:
......
...@@ -217,26 +217,9 @@ ...@@ -217,26 +217,9 @@
4110 ANDROID VULKAN : dEQP-GLES31.functional.shaders.helper_invocation.value.points_8_samples = FAIL 4110 ANDROID VULKAN : dEQP-GLES31.functional.shaders.helper_invocation.value.points_8_samples = FAIL
4110 ANDROID VULKAN : dEQP-GLES31.functional.shaders.helper_invocation.value.triangles_max_samples = FAIL 4110 ANDROID VULKAN : dEQP-GLES31.functional.shaders.helper_invocation.value.triangles_max_samples = FAIL
// Passing on recent drivers:
3726 VULKAN ANDROID : dEQP-GLES31.functional.ssbo.layout.* = FAIL
3726 VULKAN ANDROID : dEQP-GLES31.functional.synchronization.inter_call.without_memory_barrier.*atomic_counter* = FAIL
3726 VULKAN ANDROID : dEQP-GLES31.functional.compute.basic.atomic_counter* = FAIL
// Seem to trigger LowMemoryKiller when run in a certain sequence // Seem to trigger LowMemoryKiller when run in a certain sequence
5185 VULKAN ANDROID : dEQP-GLES31.functional.atomic_counter.* = SKIP 5185 VULKAN ANDROID : dEQP-GLES31.functional.atomic_counter.* = SKIP
// Arrays of atomic counters not supported on Android (lacking Vulkan feature)
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_literal_vertex = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_literal_fragment = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_literal_compute = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_expression_vertex = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_expression_fragment = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_expression_compute = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.*uniform_vertex = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.*uniform_fragment = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.*uniform_compute = FAIL
// SSBO synchronization: // SSBO synchronization:
4097 VULKAN PIXEL2ORXL : dEQP-GLES31.functional.synchronization.in_invocation.ssbo_alias_overwrite = FAIL 4097 VULKAN PIXEL2ORXL : dEQP-GLES31.functional.synchronization.in_invocation.ssbo_alias_overwrite = FAIL
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_texture_buffer_range = SKIP 3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_texture_buffer_range = SKIP
// Dispatch indirect: // Dispatch indirect:
3726 VULKAN PIXEL2ORXL : KHR-GLES31.core.compute_shader.pipeline-compute-chain = FAIL
4194 VULKAN PIXEL2ORXL : KHR-GLES31.core.compute_shader.resource-ubo = FAIL 4194 VULKAN PIXEL2ORXL : KHR-GLES31.core.compute_shader.resource-ubo = FAIL
4194 VULKAN PIXEL2ORXL : KHR-GLES31.core.compute_shader.built-in-variables = FAIL 4194 VULKAN PIXEL2ORXL : KHR-GLES31.core.compute_shader.built-in-variables = FAIL
...@@ -88,10 +87,6 @@ ...@@ -88,10 +87,6 @@
// Crashes on Android // Crashes on Android
4107 VULKAN ANDROID : KHR-GLES31.core.shader_storage_buffer_object.advanced-unsizedArrayLength* = SKIP 4107 VULKAN ANDROID : KHR-GLES31.core.shader_storage_buffer_object.advanced-unsizedArrayLength* = SKIP
// Passing on recent drivers:
3726 VULKAN ANDROID : KHR-GLES31.core.shader_atomic_counters.* = FAIL
3726 VULKAN ANDROID : KHR-GLES31.core.shader_atomic_counters.advanced-usage-* = SKIP
// Explicit uniform locations: // Explicit uniform locations:
4219 VULKAN PIXEL2ORXL : KHR-GLES31.core.explicit_uniform_location.uniform-loc-mix-with-implicit-max = FAIL 4219 VULKAN PIXEL2ORXL : KHR-GLES31.core.explicit_uniform_location.uniform-loc-mix-with-implicit-max = FAIL
4219 VULKAN PIXEL2ORXL : KHR-GLES31.core.explicit_uniform_location.uniform-loc-mix-with-implicit-max-array = FAIL 4219 VULKAN PIXEL2ORXL : KHR-GLES31.core.explicit_uniform_location.uniform-loc-mix-with-implicit-max-array = FAIL
......
...@@ -55,7 +55,6 @@ ...@@ -55,7 +55,6 @@
// Android failures // Android failures
// Dynamic indexing features not supported on Qualcomm // Dynamic indexing features not supported on Qualcomm
5435 VULKAN ANDROID : KHR-GLES32.core.gpu_shader5.atomic_counters_array_indexing = FAIL
5435 VULKAN ANDROID : KHR-GLES32.core.gpu_shader5.images_array_indexing = FAIL 5435 VULKAN ANDROID : KHR-GLES32.core.gpu_shader5.images_array_indexing = FAIL
// Texture buffer failures // Texture buffer failures
......
...@@ -115,10 +115,6 @@ TEST_P(AtomicCounterBufferTest31, OffsetNotAllSpecifiedWithSameValue) ...@@ -115,10 +115,6 @@ TEST_P(AtomicCounterBufferTest31, OffsetNotAllSpecifiedWithSameValue)
// Tests atomic counter reads using compute shaders. Used as a confidence check for the translator. // Tests atomic counter reads using compute shaders. Used as a confidence check for the translator.
TEST_P(AtomicCounterBufferTest31, AtomicCounterReadCompute) TEST_P(AtomicCounterBufferTest31, AtomicCounterReadCompute)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Skipping due to a bug on the Adreno OpenGLES Android driver. // Skipping due to a bug on the Adreno OpenGLES Android driver.
// http://anglebug.com/2925 // http://anglebug.com/2925
ANGLE_SKIP_TEST_IF(IsAndroid() && IsAdreno() && IsOpenGLES()); ANGLE_SKIP_TEST_IF(IsAndroid() && IsAdreno() && IsOpenGLES());
...@@ -148,10 +144,6 @@ void main() ...@@ -148,10 +144,6 @@ void main()
// Test atomic counter read. // Test atomic counter read.
TEST_P(AtomicCounterBufferTest31, AtomicCounterRead) TEST_P(AtomicCounterBufferTest31, AtomicCounterRead)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer. // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
// http://anglebug.com/1729 // http://anglebug.com/1729
ANGLE_SKIP_TEST_IF(IsD3D11()); ANGLE_SKIP_TEST_IF(IsD3D11());
...@@ -191,11 +183,7 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRangeRead) ...@@ -191,11 +183,7 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRangeRead)
{ {
// Skipping due to a bug on the Qualcomm driver. // Skipping due to a bug on the Qualcomm driver.
// http://anglebug.com/3726 // http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsNexus5X()); ANGLE_SKIP_TEST_IF(IsNexus5X() && IsOpenGLES());
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer. // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
// http://anglebug.com/1729 // http://anglebug.com/1729
...@@ -245,10 +233,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRangeRead) ...@@ -245,10 +233,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRangeRead)
// there are bugs in how we count valid bindings. // there are bugs in how we count valid bindings.
TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRepeatedBindUnbind) TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRepeatedBindUnbind)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer. // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
// http://anglebug.com/1729 // http://anglebug.com/1729
ANGLE_SKIP_TEST_IF(IsD3D11()); ANGLE_SKIP_TEST_IF(IsD3D11());
...@@ -319,10 +303,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRepeatedBindUnbind) ...@@ -319,10 +303,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRepeatedBindUnbind)
// Test atomic counter increment and decrement. // Test atomic counter increment and decrement.
TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement) TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr char kCS[] = constexpr char kCS[] =
"#version 310 es\n" "#version 310 es\n"
"layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n" "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
...@@ -364,10 +344,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement) ...@@ -364,10 +344,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement)
// Tests multiple atomic counter buffers. // Tests multiple atomic counter buffers.
TEST_P(AtomicCounterBufferTest31, AtomicCounterMultipleBuffers) TEST_P(AtomicCounterBufferTest31, AtomicCounterMultipleBuffers)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
GLint maxAtomicCounterBuffers = 0; GLint maxAtomicCounterBuffers = 0;
glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &maxAtomicCounterBuffers); glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &maxAtomicCounterBuffers);
constexpr unsigned int kBufferCount = 3; constexpr unsigned int kBufferCount = 3;
...@@ -430,10 +406,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterArrayOfArray) ...@@ -430,10 +406,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterArrayOfArray)
// Intel's Windows OpenGL driver crashes in this test. http://anglebug.com/3791 // Intel's Windows OpenGL driver crashes in this test. http://anglebug.com/3791
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows()); ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr char kCS[] = R"(#version 310 es constexpr char kCS[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(binding = 0) uniform atomic_uint ac[7][5][3]; layout(binding = 0) uniform atomic_uint ac[7][5][3];
......
...@@ -401,10 +401,6 @@ TEST_P(ComputeShaderTest, BufferImageBuffer) ...@@ -401,10 +401,6 @@ TEST_P(ComputeShaderTest, BufferImageBuffer)
// See http://anglebug.com/3536 // See http://anglebug.com/3536
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows()); ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr char kCS0[] = R"(#version 310 es constexpr char kCS0[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(binding = 0, offset = 4) uniform atomic_uint ac[2]; layout(binding = 0, offset = 4) uniform atomic_uint ac[2];
...@@ -476,10 +472,6 @@ TEST_P(ComputeShaderTest, ImageAtomicCounterBuffer) ...@@ -476,10 +472,6 @@ TEST_P(ComputeShaderTest, ImageAtomicCounterBuffer)
// Flaky hang. http://anglebug.com/3636 // Flaky hang. http://anglebug.com/3636
ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsDesktopOpenGL()); ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsDesktopOpenGL());
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr char kCS0[] = R"(#version 310 es constexpr char kCS0[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2]; layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];
...@@ -3934,10 +3926,6 @@ TEST_P(ComputeShaderTest, DispatchConvertVertexDispatch) ...@@ -3934,10 +3926,6 @@ TEST_P(ComputeShaderTest, DispatchConvertVertexDispatch)
{ {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_vertex_type_10_10_10_2")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_vertex_type_10_10_10_2"));
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr uint32_t kVertexCount = 6; constexpr uint32_t kVertexCount = 6;
constexpr char kCS[] = R"(#version 310 es constexpr char kCS[] = R"(#version 310 es
......
...@@ -3265,10 +3265,6 @@ TEST_P(GLSLTest_ES31, AtomicCounterArrayLength) ...@@ -3265,10 +3265,6 @@ TEST_P(GLSLTest_ES31, AtomicCounterArrayLength)
// http://anglebug.com/3782 // http://anglebug.com/3782
ANGLE_SKIP_TEST_IF(IsOpenGL()); ANGLE_SKIP_TEST_IF(IsOpenGL());
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr char kCS[] = R"(#version 310 es constexpr char kCS[] = R"(#version 310 es
precision mediump float; precision mediump float;
layout(local_size_x=1) in; layout(local_size_x=1) in;
......
...@@ -890,8 +890,6 @@ TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader) ...@@ -890,8 +890,6 @@ TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
// Tests that saving and loading a program attached with computer shader. // Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test, ProgramBinaryWithAtomicCounterComputeShader) TEST_P(ProgramBinaryES31Test, ProgramBinaryWithAtomicCounterComputeShader)
{ {
// http://anglebug.com/4092
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// We can't run the test if no program binary formats are supported. // We can't run the test if no program binary formats are supported.
GLint binaryFormatCount = 0; GLint binaryFormatCount = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount); glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
......
...@@ -58,10 +58,6 @@ class VulkanDescriptorSetTest : public ANGLETest ...@@ -58,10 +58,6 @@ class VulkanDescriptorSetTest : public ANGLETest
// Test atomic counter read. // Test atomic counter read.
TEST_P(VulkanDescriptorSetTest, AtomicCounterReadLimitedDescriptorPool) TEST_P(VulkanDescriptorSetTest, AtomicCounterReadLimitedDescriptorPool)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer. // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
// http://anglebug.com/1729 // http://anglebug.com/1729
ANGLE_SKIP_TEST_IF(IsD3D11()); ANGLE_SKIP_TEST_IF(IsD3D11());
......
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