New nonuniform analysis (#2457)

This implements a new nonunifom analysis suggested by @jbolz. This change
generates nonUniform decorations that were previously missing and avoids
generation of incorrect decorations. Most notably, it now generates
decorations for nonuniform functions and out params. It avoids generating
decorations for lvalues which themselves are not nonuniform.
This commit is contained in:
greg-lunarg
2020-11-12 11:10:07 -07:00
committed by GitHub
parent 74e8f05b9f
commit 639f5461e3
6 changed files with 496 additions and 373 deletions

View File

@@ -149,6 +149,7 @@ protected:
spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier);
spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
spv::Decoration TranslateNonUniformDecoration(const glslang::TQualifier& qualifier);
spv::Decoration TranslateNonUniformDecoration(const spv::Builder::AccessChain::CoherentFlags& coherentFlags);
spv::Builder::AccessChain::CoherentFlags TranslateCoherent(const glslang::TType& type);
spv::MemoryAccessMask TranslateMemoryAccess(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
spv::ImageOperandsMask TranslateImageOperands(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
@@ -539,6 +540,20 @@ spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glsl
return spv::DecorationMax;
}
// If lvalue flags contains nonUniform, return SPIR-V NonUniform decoration.
spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(
const spv::Builder::AccessChain::CoherentFlags& coherentFlags)
{
#ifndef GLSLANG_WEB
if (coherentFlags.isNonUniform()) {
builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
builder.addCapability(spv::CapabilityShaderNonUniformEXT);
return spv::DecorationNonUniformEXT;
} else
#endif
return spv::DecorationMax;
}
spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess(
const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
{
@@ -614,6 +629,7 @@ spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCohere
flags.volatil;
flags.isImage = type.getBasicType() == glslang::EbtSampler;
#endif
flags.nonUniform = type.getQualifier().nonUniform;
return flags;
}
@@ -1376,6 +1392,8 @@ void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& pa
if (parent.writeonly)
child.writeonly = true;
#endif
if (parent.nonUniform)
child.nonUniform = true;
}
bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifier& qualifier)
@@ -1881,9 +1899,11 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
spv::Id leftRValue = accessChainLoad(node->getLeft()->getType());
// do the operation
spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());
coherentFlags |= TranslateCoherent(node->getRight()->getType());
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
TranslateNoContractionDecoration(node->getType().getQualifier()),
TranslateNonUniformDecoration(node->getType().getQualifier()) };
TranslateNonUniformDecoration(coherentFlags) };
rValue = createBinaryOperation(node->getOp(), decorations,
convertGlslangToSpvType(node->getType()), leftRValue, rValue,
node->getType().getBasicType());
@@ -1914,13 +1934,16 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
if (! node->getLeft()->getType().isArray() &&
node->getLeft()->getType().isVector() &&
node->getOp() == glslang::EOpIndexDirect) {
// Swizzle is uniform so propagate uniform into access chain
spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());
coherentFlags.nonUniform = 0;
// This is essentially a hard-coded vector swizzle of size 1,
// so short circuit the access-chain stuff with a swizzle.
std::vector<unsigned> swizzle;
swizzle.push_back(glslangIndex);
int dummySize;
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
TranslateCoherent(node->getLeft()->getType()),
coherentFlags,
glslangIntermediate->getBaseAlignmentScalar(
node->getLeft()->getType(), dummySize));
} else {
@@ -1951,9 +1974,14 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
}
}
// Struct reference propagates uniform lvalue
spv::Builder::AccessChain::CoherentFlags coherentFlags =
TranslateCoherent(node->getLeft()->getType());
coherentFlags.nonUniform = 0;
// normal case for indexing array or structure or block
builder.accessChainPush(builder.makeIntConstant(spvIndex),
TranslateCoherent(node->getLeft()->getType()),
coherentFlags,
node->getLeft()->getType().getBufferReferenceAlignment());
// Add capabilities here for accessing PointSize and clip/cull distance.
@@ -1987,15 +2015,20 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
// restore the saved access chain
builder.setAccessChain(partial);
// Only if index is nonUniform should we propagate nonUniform into access chain
spv::Builder::AccessChain::CoherentFlags index_flags = TranslateCoherent(node->getRight()->getType());
spv::Builder::AccessChain::CoherentFlags coherent_flags = TranslateCoherent(node->getLeft()->getType());
coherent_flags.nonUniform = index_flags.nonUniform;
if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) {
int dummySize;
builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()),
TranslateCoherent(node->getLeft()->getType()),
builder.accessChainPushComponent(
index, convertGlslangToSpvType(node->getLeft()->getType()), coherent_flags,
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),
dummySize));
} else
builder.accessChainPush(index, TranslateCoherent(node->getLeft()->getType()),
node->getLeft()->getType().getBufferReferenceAlignment());
builder.accessChainPush(index, coherent_flags,
node->getLeft()->getType().getBufferReferenceAlignment());
}
return false;
case glslang::EOpVectorSwizzle:
@@ -2119,7 +2152,7 @@ spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object)
// handle 32-bit v.xy* -> 64-bit
builder.clearAccessChain();
builder.setAccessChainLValue(object);
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, objectTypeId);
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId);
std::vector<spv::Id> components;
components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 0));
components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 1));
@@ -2135,7 +2168,7 @@ spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object)
// and we insert a transpose after loading the original non-transposed builtins
builder.clearAccessChain();
builder.setAccessChainLValue(object);
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, objectTypeId);
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId);
return builder.createUnaryOp(spv::OpTranspose, desiredTypeId, object);
} else {
@@ -2322,7 +2355,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
// The result of operation is always stored, but conditionally the
// consumed result. The consumed result is always an r-value.
builder.accessChainStore(result,
TranslateNonUniformDecoration(node->getOperand()->getType().getQualifier()));
TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags));
builder.clearAccessChain();
if (node->getOp() == glslang::EOpPreIncrement ||
node->getOp() == glslang::EOpPreDecrement)
@@ -2398,7 +2431,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
spv::Id invertedType = spv::NoType; // to use to override the natural type of the node
std::vector<spv::Builder::AccessChain> complexLvalues; // for holding swizzling l-values too complex for
// SPIR-V, for an out parameter
std::vector<glslang::TQualifier> complexLValueQualifiers;
std::vector<spv::Id> temporaryLvalues; // temporaries to pass, as proxies for complexLValues
auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ?
@@ -3020,7 +3052,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
// receive the result, and must later swizzle that into the original
// l-value.
complexLvalues.push_back(builder.getAccessChain());
complexLValueQualifiers.push_back(glslangOperands[arg]->getAsTyped()->getType().getQualifier());
temporaryLvalues.push_back(builder.createVariable(
spv::NoPrecision, spv::StorageClassFunction,
builder.accessChainGetInferredType(), "swizzleTemp"));
@@ -3125,7 +3156,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
for (unsigned int i = 0; i < temporaryLvalues.size(); ++i) {
builder.setAccessChain(complexLvalues[i]);
builder.accessChainStore(builder.createLoad(temporaryLvalues[i], spv::NoPrecision), TranslateNonUniformDecoration(complexLValueQualifiers[i]));
builder.accessChainStore(builder.createLoad(temporaryLvalues[i], spv::NoPrecision),
TranslateNonUniformDecoration(complexLvalues[i].coherentFlags));
}
}
@@ -4135,6 +4167,7 @@ spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
alignment |= type.getBufferReferenceAlignment();
spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),
TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),
TranslateNonUniformDecoration(type.getQualifier()),
nominalTypeId,
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask),
@@ -4202,7 +4235,7 @@ void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::I
unsigned int alignment = builder.getAccessChain().alignment;
alignment |= type.getBufferReferenceAlignment();
builder.accessChainStore(rvalue, TranslateNonUniformDecoration(type.getQualifier()),
builder.accessChainStore(rvalue, TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) &
~spv::MemoryAccessMakePointerVisibleKHRMask),
TranslateMemoryScope(coherentFlags), alignment);
@@ -4734,8 +4767,10 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate&
}
if (lvalue) {
arguments.push_back(builder.accessChainGetLValue());
spv::Id lvalue_id = builder.accessChainGetLValue();
arguments.push_back(lvalue_id);
lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
builder.addDecoration(lvalue_id, TranslateNonUniformDecoration(lvalueCoherentFlags));
lvalueCoherentFlags |= TranslateCoherent(glslangArguments[i]->getAsTyped()->getType());
} else
#endif
@@ -5415,6 +5450,7 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg
// 3. Make the call.
spv::Id result = builder.createFunctionCall(function, spvArgs);
builder.setPrecision(result, TranslatePrecisionDecoration(node->getType()));
builder.addDecoration(result, TranslateNonUniformDecoration(node->getType().getQualifier()));
// 4. Copy back out an "out" arguments.
lValueCount = 0;
@@ -5424,6 +5460,7 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg
else if (writableParam(qualifiers[a])) {
if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
spv::Id copy = builder.createLoad(spvArgs[a], spv::NoPrecision);
builder.addDecoration(copy, TranslateNonUniformDecoration(argTypes[a]->getQualifier()));
builder.setAccessChain(lValues[lValueCount]);
multiTypeStore(*argTypes[a], copy);
}
@@ -8228,9 +8265,6 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol
builder.addDecoration(id, memory[i]);
}
// nonuniform
builder.addDecoration(id, TranslateNonUniformDecoration(symbol->getType().getQualifier()));
if (builtIn == spv::BuiltInSampleMask) {
spv::Decoration decoration;
// GL_NV_sample_mask_override_coverage extension