Merge pull request #2625 from amdrexu/feature
Implement the extension GL_EXT_spirv_intrinsics
This commit is contained in:
commit
71612a7e5d
40 changed files with 7337 additions and 3967 deletions
|
|
@ -1092,12 +1092,31 @@ TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunct
|
|||
TSymbol* symbol = symbolTable.find(function.getMangledName(), &builtIn);
|
||||
if (symbol && symbol->getAsFunction() && builtIn)
|
||||
requireProfile(loc, ~EEsProfile, "redefinition of built-in function");
|
||||
#ifndef GLSLANG_WEB
|
||||
// Check the validity of using spirv_literal qualifier
|
||||
for (int i = 0; i < function.getParamCount(); ++i) {
|
||||
if (function[i].type->getQualifier().isSpirvLiteral() && function.getBuiltInOp() != EOpSpirvInst)
|
||||
error(loc, "'spirv_literal' can only be used on functions defined with 'spirv_instruction' for argument",
|
||||
function.getName().c_str(), "%d", i + 1);
|
||||
}
|
||||
|
||||
// For function declaration with SPIR-V instruction qualifier, always ignore the built-in function and
|
||||
// respect this redeclared one.
|
||||
if (symbol && builtIn && function.getBuiltInOp() == EOpSpirvInst)
|
||||
symbol = nullptr;
|
||||
#endif
|
||||
const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0;
|
||||
if (prevDec) {
|
||||
if (prevDec->isPrototyped() && prototype)
|
||||
profileRequires(loc, EEsProfile, 300, nullptr, "multiple prototypes for same function");
|
||||
if (prevDec->getType() != function.getType())
|
||||
error(loc, "overloaded functions must have the same return type", function.getName().c_str(), "");
|
||||
#ifndef GLSLANG_WEB
|
||||
if (prevDec->getSpirvInstruction() != function.getSpirvInstruction()) {
|
||||
error(loc, "overloaded functions must have the same qualifiers", function.getName().c_str(),
|
||||
"spirv_instruction");
|
||||
}
|
||||
#endif
|
||||
for (int i = 0; i < prevDec->getParamCount(); ++i) {
|
||||
if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage)
|
||||
error(loc, "overloaded functions must have the same parameter storage qualifiers for argument", function[i].type->getStorageQualifierString(), "%d", i+1);
|
||||
|
|
@ -1299,6 +1318,15 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction
|
|||
if (lValueErrorCheck(arguments->getLoc(), "assign", arg->getAsTyped()))
|
||||
error(arguments->getLoc(), "Non-L-value cannot be passed for 'out' or 'inout' parameters.", "out", "");
|
||||
}
|
||||
#ifndef GLSLANG_WEB
|
||||
if (formalQualifier.isSpirvLiteral()) {
|
||||
if (!arg->getAsTyped()->getQualifier().isFrontEndConstant()) {
|
||||
error(arguments->getLoc(),
|
||||
"Non front-end constant expressions cannot be passed for 'spirv_literal' parameters.",
|
||||
"spirv_literal", "");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
const TType& argType = arg->getAsTyped()->getType();
|
||||
const TQualifier& argQualifier = argType.getQualifier();
|
||||
if (argQualifier.isMemory() && (argType.containsOpaque() || argType.isReference())) {
|
||||
|
|
@ -1353,6 +1381,11 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction
|
|||
if (builtIn && fnCandidate->getBuiltInOp() != EOpNull) {
|
||||
// A function call mapped to a built-in operation.
|
||||
result = handleBuiltInFunctionCall(loc, arguments, *fnCandidate);
|
||||
#ifndef GLSLANG_WEB
|
||||
} else if (fnCandidate->getBuiltInOp() == EOpSpirvInst) {
|
||||
// When SPIR-V instruction qualifier is specified, the function call is still mapped to a built-in operation.
|
||||
result = handleBuiltInFunctionCall(loc, arguments, *fnCandidate);
|
||||
#endif
|
||||
} else {
|
||||
// This is a function call not mapped to built-in operator.
|
||||
// It could still be a built-in function, but only if PureOperatorBuiltins == false.
|
||||
|
|
@ -1430,6 +1463,35 @@ TIntermTyped* TParseContext::handleBuiltInFunctionCall(TSourceLoc loc, TIntermNo
|
|||
} else if (result->getAsOperator())
|
||||
builtInOpCheck(loc, function, *result->getAsOperator());
|
||||
|
||||
#ifndef GLSLANG_WEB
|
||||
// Special handling for function call with SPIR-V instruction qualifier specified
|
||||
if (function.getBuiltInOp() == EOpSpirvInst) {
|
||||
if (auto agg = result->getAsAggregate()) {
|
||||
// Propogate spirv_by_reference/spirv_literal from parameters to arguments
|
||||
auto& sequence = agg->getSequence();
|
||||
for (unsigned i = 0; i < sequence.size(); ++i) {
|
||||
if (function[i].type->getQualifier().isSpirvByReference())
|
||||
sequence[i]->getAsTyped()->getQualifier().setSpirvByReference();
|
||||
if (function[i].type->getQualifier().isSpirvLiteral())
|
||||
sequence[i]->getAsTyped()->getQualifier().setSpirvLiteral();
|
||||
}
|
||||
|
||||
// Attach the function call to SPIR-V intruction
|
||||
agg->setSpirvInstruction(function.getSpirvInstruction());
|
||||
} else if (auto unaryNode = result->getAsUnaryNode()) {
|
||||
// Propogate spirv_by_reference/spirv_literal from parameters to arguments
|
||||
if (function[0].type->getQualifier().isSpirvByReference())
|
||||
unaryNode->getOperand()->getQualifier().setSpirvByReference();
|
||||
if (function[0].type->getQualifier().isSpirvLiteral())
|
||||
unaryNode->getOperand()->getQualifier().setSpirvLiteral();
|
||||
|
||||
// Attach the function call to SPIR-V intruction
|
||||
unaryNode->setSpirvInstruction(function.getSpirvInstruction());
|
||||
} else
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -2931,7 +2993,8 @@ void TParseContext::reservedErrorCheck(const TSourceLoc& loc, const TString& ide
|
|||
// "Identifiers starting with "gl_" are reserved for use by OpenGL, and may not be
|
||||
// declared in a shader; this results in a compile-time error."
|
||||
if (! symbolTable.atBuiltInLevel()) {
|
||||
if (builtInName(identifier))
|
||||
if (builtInName(identifier) && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics))
|
||||
// The extension GL_EXT_spirv_intrinsics allows us to declare identifiers starting with "gl_".
|
||||
error(loc, "identifiers starting with \"gl_\" are reserved", identifier.c_str(), "");
|
||||
|
||||
// "__" are not supposed to be an error. ES 300 (and desktop) added the clarification:
|
||||
|
|
@ -2939,7 +3002,8 @@ void TParseContext::reservedErrorCheck(const TSourceLoc& loc, const TString& ide
|
|||
// reserved; using such a name does not itself result in an error, but may result
|
||||
// in undefined behavior."
|
||||
// however, before that, ES tests required an error.
|
||||
if (identifier.find("__") != TString::npos) {
|
||||
if (identifier.find("__") != TString::npos && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) {
|
||||
// The extension GL_EXT_spirv_intrinsics allows us to declare identifiers starting with "__".
|
||||
if (isEsProfile() && version < 300)
|
||||
error(loc, "identifiers containing consecutive underscores (\"__\") are reserved, and an error if version < 300", identifier.c_str(), "");
|
||||
else
|
||||
|
|
@ -2960,14 +3024,16 @@ void TParseContext::reservedPpErrorCheck(const TSourceLoc& loc, const char* iden
|
|||
// single underscore) are also reserved, and defining such a name results in a
|
||||
// compile-time error."
|
||||
// however, before that, ES tests required an error.
|
||||
if (strncmp(identifier, "GL_", 3) == 0)
|
||||
if (strncmp(identifier, "GL_", 3) == 0 && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics))
|
||||
// The extension GL_EXT_spirv_intrinsics allows us to declare macros prefixed with "GL_".
|
||||
ppError(loc, "names beginning with \"GL_\" can't be (un)defined:", op, identifier);
|
||||
else if (strncmp(identifier, "defined", 8) == 0)
|
||||
if (relaxedErrors())
|
||||
ppWarn(loc, "\"defined\" is (un)defined:", op, identifier);
|
||||
else
|
||||
ppError(loc, "\"defined\" can't be (un)defined:", op, identifier);
|
||||
else if (strstr(identifier, "__") != 0) {
|
||||
else if (strstr(identifier, "__") != 0 && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) {
|
||||
// The extension GL_EXT_spirv_intrinsics allows us to declare macros prefixed with "__".
|
||||
if (isEsProfile() && version >= 300 &&
|
||||
(strcmp(identifier, "__LINE__") == 0 ||
|
||||
strcmp(identifier, "__FILE__") == 0 ||
|
||||
|
|
@ -3594,6 +3660,14 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q
|
|||
if (!nonuniformOkay && qualifier.isNonUniform())
|
||||
error(loc, "for non-parameter, can only apply to 'in' or no storage qualifier", "nonuniformEXT", "");
|
||||
|
||||
#ifndef GLSLANG_WEB
|
||||
if (qualifier.isSpirvByReference())
|
||||
error(loc, "can only apply to parameter", "spirv_by_reference", "");
|
||||
|
||||
if (qualifier.isSpirvLiteral())
|
||||
error(loc, "can only apply to parameter", "spirv_literal", "");
|
||||
#endif
|
||||
|
||||
// Storage qualifier isn't ready for memberQualifierCheck, we should skip invariantCheck for it.
|
||||
if (!isMemberCheck || structNestingLevel > 0)
|
||||
invariantCheck(loc, qualifier);
|
||||
|
|
@ -3855,6 +3929,41 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons
|
|||
MERGE_SINGLETON(nonUniform);
|
||||
#endif
|
||||
|
||||
#ifndef GLSLANG_WEB
|
||||
// SPIR-V storage class qualifier (GL_EXT_spirv_intrinsics)
|
||||
dst.spirvStorageClass = src.spirvStorageClass;
|
||||
|
||||
// SPIR-V decorate qualifiers (GL_EXT_spirv_intrinsics)
|
||||
if (src.hasSprivDecorate()) {
|
||||
if (dst.hasSprivDecorate()) {
|
||||
const TSpirvDecorate& srcSpirvDecorate = src.getSpirvDecorate();
|
||||
TSpirvDecorate& dstSpirvDecorate = dst.getSpirvDecorate();
|
||||
for (auto& decorate : srcSpirvDecorate.decorates) {
|
||||
if (dstSpirvDecorate.decorates.find(decorate.first) != dstSpirvDecorate.decorates.end())
|
||||
error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate", "(decoration=%u)", decorate.first);
|
||||
else
|
||||
dstSpirvDecorate.decorates.insert(decorate);
|
||||
}
|
||||
|
||||
for (auto& decorateId : srcSpirvDecorate.decorateIds) {
|
||||
if (dstSpirvDecorate.decorateIds.find(decorateId.first) != dstSpirvDecorate.decorateIds.end())
|
||||
error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate_id", "(decoration=%u)", decorateId.first);
|
||||
else
|
||||
dstSpirvDecorate.decorateIds.insert(decorateId);
|
||||
}
|
||||
|
||||
for (auto& decorateString : srcSpirvDecorate.decorateStrings) {
|
||||
if (dstSpirvDecorate.decorates.find(decorateString.first) != dstSpirvDecorate.decorates.end())
|
||||
error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate_string", "(decoration=%u)", decorateString.first);
|
||||
else
|
||||
dstSpirvDecorate.decorates.insert(decorateString);
|
||||
}
|
||||
} else {
|
||||
dst.spirvDecorate = src.spirvDecorate;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (repeated)
|
||||
error(loc, "replicated qualifiers", "", "");
|
||||
}
|
||||
|
|
@ -4818,6 +4927,17 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali
|
|||
}
|
||||
if (qualifier.isNonUniform())
|
||||
type.getQualifier().nonUniform = qualifier.nonUniform;
|
||||
#ifndef GLSLANG_WEB
|
||||
if (qualifier.isSpirvByReference())
|
||||
type.getQualifier().setSpirvByReference();
|
||||
if (qualifier.isSpirvLiteral()) {
|
||||
if (type.getBasicType() == EbtFloat || type.getBasicType() == EbtInt || type.getBasicType() == EbtUint ||
|
||||
type.getBasicType() == EbtBool)
|
||||
type.getQualifier().setSpirvLiteral();
|
||||
else
|
||||
error(loc, "cannot use spirv_literal qualifier", type.getBasicTypeString().c_str(), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
paramCheckFixStorage(loc, qualifier.storage, type);
|
||||
}
|
||||
|
|
@ -5885,6 +6005,9 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb
|
|||
case EvqVaryingIn:
|
||||
case EvqVaryingOut:
|
||||
if (!type.getQualifier().isTaskMemory() &&
|
||||
#ifndef GLSLANG_WEB
|
||||
!type.getQualifier().hasSprivDecorate() &&
|
||||
#endif
|
||||
(type.getBasicType() != EbtBlock ||
|
||||
(!(*type.getStruct())[0].type->getQualifier().hasLocation() &&
|
||||
(*type.getStruct())[0].type->getQualifier().builtIn == EbvNone)))
|
||||
|
|
@ -5946,6 +6069,11 @@ void TParseContext::layoutMemberLocationArrayCheck(const TSourceLoc& loc, bool m
|
|||
// Do layout error checking with respect to a type.
|
||||
void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
||||
{
|
||||
#ifndef GLSLANG_WEB
|
||||
if (extensionTurnedOn(E_GL_EXT_spirv_intrinsics))
|
||||
return; // Skip any check if GL_EXT_spirv_intrinsics is turned on
|
||||
#endif
|
||||
|
||||
const TQualifier& qualifier = type.getQualifier();
|
||||
|
||||
// first, intra-layout qualifier-only error checking
|
||||
|
|
@ -7952,6 +8080,10 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|||
memberQualifier.perViewNV = currentBlockQualifier.perViewNV;
|
||||
if (currentBlockQualifier.perTaskNV)
|
||||
memberQualifier.perTaskNV = currentBlockQualifier.perTaskNV;
|
||||
if (memberQualifier.storage == EvqSpirvStorageClass)
|
||||
error(memberLoc, "member cannot have a spirv_storage_class qualifier", memberType.getFieldName().c_str(), "");
|
||||
if (memberQualifier.hasSprivDecorate() && !memberQualifier.getSpirvDecorate().decorateIds.empty())
|
||||
error(memberLoc, "member cannot have a spirv_decorate_id qualifier", memberType.getFieldName().c_str(), "");
|
||||
#endif
|
||||
if ((currentBlockQualifier.storage == EvqUniform || currentBlockQualifier.storage == EvqBuffer) && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary()))
|
||||
error(memberLoc, "member of uniform or buffer block cannot have an auxiliary or interpolation qualifier", memberType.getFieldName().c_str(), "");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue