SPIR-V: Move from Version .99 Rev 31 to Version 1.0, Rev 2.
This commit is contained in:
parent
1c77f3a8d2
commit
55e7d11ce8
117 changed files with 6740 additions and 5997 deletions
|
|
@ -60,7 +60,10 @@ namespace spv {
|
|||
|
||||
namespace {
|
||||
|
||||
const int GlslangMagic = 0x51a;
|
||||
// For low-order part of the generator's magic number. Bump up
|
||||
// when there is a change in the style (e.g., if SSA form changes,
|
||||
// or a different instruction sequence to do something gets used).
|
||||
const int GeneratorVersion = 1;
|
||||
|
||||
//
|
||||
// The main holder of information for translating glslang to SPIR-V.
|
||||
|
|
@ -113,13 +116,16 @@ protected:
|
|||
spv::Id createNoArgOperation(glslang::TOperator op);
|
||||
spv::Id getSymbolId(const glslang::TIntermSymbol* node);
|
||||
void addDecoration(spv::Id id, spv::Decoration dec);
|
||||
void addDecoration(spv::Id id, spv::Decoration dec, unsigned value);
|
||||
void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
|
||||
spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);
|
||||
spv::Id createSpvSpecConstant(const glslang::TIntermTyped&);
|
||||
spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
|
||||
bool isTrivialLeaf(const glslang::TIntermTyped* node);
|
||||
bool isTrivial(const glslang::TIntermTyped* node);
|
||||
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
|
||||
|
||||
spv::Function* shaderEntry;
|
||||
spv::Instruction* entryPoint;
|
||||
int sequenceDepth;
|
||||
|
||||
// There is a 1:1 mapping between a spv builder and a module; this is thread safe
|
||||
|
|
@ -169,7 +175,7 @@ spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)
|
|||
case EShLangFragment: return spv::ExecutionModelFragment;
|
||||
case EShLangCompute: return spv::ExecutionModelGLCompute;
|
||||
default:
|
||||
spv::MissingFunctionality("GLSL stage");
|
||||
assert(0);
|
||||
return spv::ExecutionModelFragment;
|
||||
}
|
||||
}
|
||||
|
|
@ -191,12 +197,12 @@ spv::StorageClass TranslateStorageClass(const glslang::TType& type)
|
|||
// TODO: how are we distuingishing between default and non-default non-writable uniforms? Do default uniforms even exist?
|
||||
} else {
|
||||
switch (type.getQualifier().storage) {
|
||||
case glslang::EvqShared: return spv::StorageClassWorkgroupLocal; break;
|
||||
case glslang::EvqGlobal: return spv::StorageClassPrivateGlobal;
|
||||
case glslang::EvqShared: return spv::StorageClassWorkgroup; break;
|
||||
case glslang::EvqGlobal: return spv::StorageClassPrivate;
|
||||
case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
|
||||
case glslang::EvqTemporary: return spv::StorageClassFunction;
|
||||
default:
|
||||
spv::MissingFunctionality("unknown glslang storage class");
|
||||
assert(0);
|
||||
return spv::StorageClassFunction;
|
||||
}
|
||||
}
|
||||
|
|
@ -206,14 +212,14 @@ spv::StorageClass TranslateStorageClass(const glslang::TType& type)
|
|||
spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
|
||||
{
|
||||
switch (sampler.dim) {
|
||||
case glslang::Esd1D: return spv::Dim1D;
|
||||
case glslang::Esd2D: return spv::Dim2D;
|
||||
case glslang::Esd3D: return spv::Dim3D;
|
||||
case glslang::EsdCube: return spv::DimCube;
|
||||
case glslang::EsdRect: return spv::DimRect;
|
||||
case glslang::EsdBuffer: return spv::DimBuffer;
|
||||
case glslang::Esd1D: return spv::Dim1D;
|
||||
case glslang::Esd2D: return spv::Dim2D;
|
||||
case glslang::Esd3D: return spv::Dim3D;
|
||||
case glslang::EsdCube: return spv::DimCube;
|
||||
case glslang::EsdRect: return spv::DimRect;
|
||||
case glslang::EsdBuffer: return spv::DimBuffer;
|
||||
default:
|
||||
spv::MissingFunctionality("unknown sampler dimension");
|
||||
assert(0);
|
||||
return spv::Dim2D;
|
||||
}
|
||||
}
|
||||
|
|
@ -240,7 +246,7 @@ spv::Decoration TranslateBlockDecoration(const glslang::TType& type)
|
|||
case glslang::EvqVaryingIn: return spv::DecorationBlock;
|
||||
case glslang::EvqVaryingOut: return spv::DecorationBlock;
|
||||
default:
|
||||
spv::MissingFunctionality("kind of block");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -275,11 +281,10 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)
|
|||
}
|
||||
case glslang::EvqVaryingIn:
|
||||
case glslang::EvqVaryingOut:
|
||||
if (type.getQualifier().layoutPacking != glslang::ElpNone)
|
||||
spv::MissingFunctionality("in/out block layout");
|
||||
assert(type.getQualifier().layoutPacking == glslang::ElpNone);
|
||||
return (spv::Decoration)spv::BadValue;
|
||||
default:
|
||||
spv::MissingFunctionality("block storage qualification");
|
||||
assert(0);
|
||||
return (spv::Decoration)spv::BadValue;
|
||||
}
|
||||
}
|
||||
|
|
@ -287,12 +292,16 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)
|
|||
}
|
||||
|
||||
// Translate glslang type to SPIR-V interpolation decorations.
|
||||
// Returns spv::Decoration(spv::BadValue) when no decoration
|
||||
// should be applied.
|
||||
spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)
|
||||
{
|
||||
if (type.getQualifier().smooth)
|
||||
return spv::DecorationSmooth;
|
||||
if (type.getQualifier().smooth) {
|
||||
// Smooth decoration doesn't exist in SPIR-V 1.0
|
||||
return (spv::Decoration)spv::BadValue;
|
||||
}
|
||||
if (type.getQualifier().nopersp)
|
||||
return spv::DecorationNoperspective;
|
||||
return spv::DecorationNoPerspective;
|
||||
else if (type.getQualifier().patch)
|
||||
return spv::DecorationPatch;
|
||||
else if (type.getQualifier().flat)
|
||||
|
|
@ -344,8 +353,6 @@ spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)
|
|||
case glslang::EbvSampleId: return spv::BuiltInSampleId;
|
||||
case glslang::EbvSamplePosition: return spv::BuiltInSamplePosition;
|
||||
case glslang::EbvSampleMask: return spv::BuiltInSampleMask;
|
||||
case glslang::EbvFragColor: return spv::BuiltInFragColor;
|
||||
case glslang::EbvFragData: return spv::BuiltInFragColor;
|
||||
case glslang::EbvFragDepth: return spv::BuiltInFragDepth;
|
||||
case glslang::EbvHelperInvocation: return spv::BuiltInHelperInvocation;
|
||||
case glslang::EbvNumWorkGroups: return spv::BuiltInNumWorkgroups;
|
||||
|
|
@ -414,7 +421,7 @@ spv::ImageFormat TranslateImageFormat(const glslang::TType& type)
|
|||
|
||||
TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)
|
||||
: TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),
|
||||
builder(GlslangMagic),
|
||||
builder((glslang::GetKhronosToolId() << 16) | GeneratorVersion),
|
||||
inMain(false), mainTerminated(false), linkageOnly(false),
|
||||
glslangIntermediate(glslangIntermediate)
|
||||
{
|
||||
|
|
@ -425,7 +432,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
|
|||
stdBuiltins = builder.import("GLSL.std.450");
|
||||
builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
|
||||
shaderEntry = builder.makeMain();
|
||||
builder.addEntryPoint(executionModel, shaderEntry, "main");
|
||||
entryPoint = builder.addEntryPoint(executionModel, shaderEntry, "main");
|
||||
|
||||
// Add the source extensions
|
||||
const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
|
||||
|
|
@ -451,9 +458,9 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
|
|||
case EShLangTessEvaluation:
|
||||
builder.addCapability(spv::CapabilityTessellation);
|
||||
switch (glslangIntermediate->getInputPrimitive()) {
|
||||
case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;
|
||||
case glslang::ElgQuads: mode = spv::ExecutionModeInputQuads; break;
|
||||
case glslang::ElgIsolines: mode = spv::ExecutionModeInputIsolines; break;
|
||||
case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break;
|
||||
case glslang::ElgQuads: mode = spv::ExecutionModeQuads; break;
|
||||
case glslang::ElgIsolines: mode = spv::ExecutionModeIsolines; break;
|
||||
default: mode = spv::BadValue; break;
|
||||
}
|
||||
if (mode != spv::BadValue)
|
||||
|
|
@ -486,7 +493,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
|
|||
case glslang::ElgPoints: mode = spv::ExecutionModeInputPoints; break;
|
||||
case glslang::ElgLines: mode = spv::ExecutionModeInputLines; break;
|
||||
case glslang::ElgLinesAdjacency: mode = spv::ExecutionModeInputLinesAdjacency; break;
|
||||
case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;
|
||||
case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break;
|
||||
case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
|
||||
default: mode = spv::BadValue; break;
|
||||
}
|
||||
|
|
@ -520,7 +527,6 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
|
|||
builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests);
|
||||
|
||||
switch(glslangIntermediate->getDepth()) {
|
||||
case glslang::EldAny: mode = spv::ExecutionModeDepthAny; break;
|
||||
case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break;
|
||||
case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break;
|
||||
default: mode = spv::BadValue; break;
|
||||
|
|
@ -591,6 +597,11 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
|
|||
builder.setAccessChainRValue(id);
|
||||
else
|
||||
builder.setAccessChainLValue(id);
|
||||
} else {
|
||||
// finish off the entry-point SPV instruction by adding the Input/Output <id>
|
||||
spv::StorageClass sc = builder.getStorageClass(id);
|
||||
if (sc == spv::StorageClassInput || sc == spv::StorageClassOutput)
|
||||
entryPoint->addIdOperand(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -639,8 +650,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
|||
node->getType().getBasicType());
|
||||
|
||||
// these all need their counterparts in createBinaryOperation()
|
||||
if (rValue == 0)
|
||||
spv::MissingFunctionality("createBinaryOperation");
|
||||
assert(rValue != spv::NoResult);
|
||||
}
|
||||
|
||||
// store the result
|
||||
|
|
@ -660,20 +670,13 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
|||
|
||||
// Add the next element in the chain
|
||||
|
||||
int index = 0;
|
||||
if (node->getRight()->getAsConstantUnion() == 0)
|
||||
spv::MissingFunctionality("direct index without a constant node");
|
||||
else
|
||||
index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
|
||||
int index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {
|
||||
// This may be, e.g., an anonymous block-member selection, which generally need
|
||||
// index remapping due to hidden members in anonymous blocks.
|
||||
std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];
|
||||
if (remapper.size() == 0)
|
||||
spv::MissingFunctionality("block without member remapping");
|
||||
else
|
||||
index = remapper[index];
|
||||
assert(remapper.size() > 0);
|
||||
index = remapper[index];
|
||||
}
|
||||
|
||||
if (! node->getLeft()->getType().isArray() &&
|
||||
|
|
@ -766,7 +769,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
|||
node->getLeft()->getType().getBasicType());
|
||||
|
||||
if (! result) {
|
||||
spv::MissingFunctionality("glslang binary operation");
|
||||
spv::MissingFunctionality("unknown glslang binary operation");
|
||||
} else {
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainRValue(result);
|
||||
|
|
@ -832,7 +835,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
|||
|
||||
// if not, then possibly an operation
|
||||
if (! result)
|
||||
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType());
|
||||
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType());
|
||||
|
||||
if (result) {
|
||||
builder.clearAccessChain();
|
||||
|
|
@ -862,8 +865,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
|||
spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()),
|
||||
convertGlslangToSpvType(node->getType()), operand, one,
|
||||
node->getType().getBasicType());
|
||||
if (result == 0)
|
||||
spv::MissingFunctionality("createBinaryOperation for unary");
|
||||
assert(result != spv::NoResult);
|
||||
|
||||
// The result of operation is always stored, but conditionally the
|
||||
// consumed result. The consumed result is always an r-value.
|
||||
|
|
@ -886,7 +888,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
|||
return false;
|
||||
|
||||
default:
|
||||
spv::MissingFunctionality("glslang unary");
|
||||
spv::MissingFunctionality("unknown glslang unary");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -990,13 +992,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
|||
{
|
||||
if (node->isUserDefined())
|
||||
result = handleUserFunctionCall(node);
|
||||
|
||||
if (! result) {
|
||||
spv::MissingFunctionality("glslang function call");
|
||||
glslang::TConstUnionArray emptyConsts;
|
||||
int nextConst = 0;
|
||||
result = createSpvConstant(node->getType(), emptyConsts, nextConst);
|
||||
}
|
||||
assert(result);
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainRValue(result);
|
||||
|
||||
|
|
@ -1053,12 +1049,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
|||
for (int c = 0; c < (int)arguments.size(); ++c)
|
||||
constituents.push_back(arguments[c]);
|
||||
constructed = builder.createCompositeConstruct(resultTypeId, constituents);
|
||||
} else {
|
||||
if (isMatrix)
|
||||
constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
|
||||
else
|
||||
constructed = builder.createConstructor(precision, arguments, resultTypeId);
|
||||
}
|
||||
} else if (isMatrix)
|
||||
constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
|
||||
else
|
||||
constructed = builder.createConstructor(precision, arguments, resultTypeId);
|
||||
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainRValue(constructed);
|
||||
|
|
@ -1131,21 +1125,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
|||
atomic = true;
|
||||
break;
|
||||
|
||||
case glslang::EOpAddCarry:
|
||||
case glslang::EOpSubBorrow:
|
||||
case glslang::EOpUMulExtended:
|
||||
case glslang::EOpIMulExtended:
|
||||
case glslang::EOpBitfieldExtract:
|
||||
case glslang::EOpBitfieldInsert:
|
||||
spv::MissingFunctionality("integer aggregate");
|
||||
break;
|
||||
|
||||
case glslang::EOpFma:
|
||||
case glslang::EOpFrexp:
|
||||
case glslang::EOpLdexp:
|
||||
spv::MissingFunctionality("fma/frexp/ldexp aggregate");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1171,9 +1150,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
|||
left->getType().getBasicType(), reduceComparison);
|
||||
|
||||
// code above should only make binOp that exists in createBinaryOperation
|
||||
if (result == 0)
|
||||
spv::MissingFunctionality("createBinaryOperation for aggregate");
|
||||
|
||||
assert(result != spv::NoResult);
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainRValue(result);
|
||||
|
||||
|
|
@ -1192,7 +1169,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
|||
// special case l-value operands; there are just a few
|
||||
bool lvalue = false;
|
||||
switch (node->getOp()) {
|
||||
//case glslang::EOpFrexp:
|
||||
case glslang::EOpFrexp:
|
||||
case glslang::EOpModf:
|
||||
if (arg == 1)
|
||||
lvalue = true;
|
||||
|
|
@ -1208,9 +1185,16 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
|||
if (arg == 0)
|
||||
lvalue = true;
|
||||
break;
|
||||
//case glslang::EOpUAddCarry:
|
||||
//case glslang::EOpUSubBorrow:
|
||||
//case glslang::EOpUMulExtended:
|
||||
case glslang::EOpAddCarry:
|
||||
case glslang::EOpSubBorrow:
|
||||
if (arg == 2)
|
||||
lvalue = true;
|
||||
break;
|
||||
case glslang::EOpUMulExtended:
|
||||
case glslang::EOpIMulExtended:
|
||||
if (arg >= 2)
|
||||
lvalue = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1230,7 +1214,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
|||
result = createNoArgOperation(node->getOp());
|
||||
break;
|
||||
case 1:
|
||||
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType());
|
||||
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), glslangOperands[0]->getAsTyped()->getBasicType());
|
||||
break;
|
||||
default:
|
||||
result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
|
||||
|
|
@ -1242,7 +1226,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
|||
return false;
|
||||
|
||||
if (! result) {
|
||||
spv::MissingFunctionality("glslang aggregate");
|
||||
spv::MissingFunctionality("unknown glslang aggregate");
|
||||
return true;
|
||||
} else {
|
||||
builder.clearAccessChain();
|
||||
|
|
@ -1350,7 +1334,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
|
|||
void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
|
||||
{
|
||||
int nextConst = 0;
|
||||
spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);
|
||||
spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst, false);
|
||||
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainRValue(constant);
|
||||
|
|
@ -1418,7 +1402,7 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T
|
|||
break;
|
||||
|
||||
default:
|
||||
spv::MissingFunctionality("branch type");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1429,9 +1413,9 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol*
|
|||
{
|
||||
// First, steer off constants, which are not SPIR-V variables, but
|
||||
// can still have a mapping to a SPIR-V Id.
|
||||
// This includes specialization constants.
|
||||
if (node->getQualifier().storage == glslang::EvqConst) {
|
||||
int nextConst = 0;
|
||||
return createSpvConstant(node->getType(), node->getConstArray(), nextConst);
|
||||
return createSpvSpecConstant(*node);
|
||||
}
|
||||
|
||||
// Now, handle actual variables
|
||||
|
|
@ -1453,7 +1437,7 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
|
|||
case glslang::EbtInt: return builder.makeIntType(32);
|
||||
case glslang::EbtUint: return builder.makeUintType(32);
|
||||
default:
|
||||
spv::MissingFunctionality("sampled type");
|
||||
assert(0);
|
||||
return builder.makeFloatType(32);
|
||||
}
|
||||
}
|
||||
|
|
@ -1474,8 +1458,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
|||
switch (type.getBasicType()) {
|
||||
case glslang::EbtVoid:
|
||||
spvType = builder.makeVoidType();
|
||||
if (type.isArray())
|
||||
spv::MissingFunctionality("array of void");
|
||||
assert (! type.isArray());
|
||||
break;
|
||||
case glslang::EbtFloat:
|
||||
spvType = builder.makeFloatType(32);
|
||||
|
|
@ -1499,12 +1482,13 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
|||
case glslang::EbtSampler:
|
||||
{
|
||||
const glslang::TSampler& sampler = type.getSampler();
|
||||
spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
|
||||
sampler.image ? 2 : 1, TranslateImageFormat(type));
|
||||
// OpenGL "textures" need to be combined with a sampler
|
||||
if (! sampler.image)
|
||||
spvType = builder.makeSampledImageType(spvType);
|
||||
}
|
||||
// an image is present, make its type
|
||||
spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
|
||||
sampler.image ? 2 : 1, TranslateImageFormat(type));
|
||||
if (! sampler.image) {
|
||||
spvType = builder.makeSampledImageType(spvType);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case glslang::EbtStruct:
|
||||
case glslang::EbtBlock:
|
||||
|
|
@ -1593,7 +1577,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
|||
}
|
||||
break;
|
||||
default:
|
||||
spv::MissingFunctionality("basic type");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1620,10 +1604,14 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
|||
spvType = builder.makeArrayType(spvType, type.getOuterArraySize());
|
||||
}
|
||||
|
||||
// TODO: layout still needs to be done hierarchically for arrays of arrays, which
|
||||
// TODO: explicit layout still needs to be done hierarchically for arrays of arrays, which
|
||||
// may still require additional "link time" support from the front-end
|
||||
// for arrays of arrays
|
||||
if (explicitLayout)
|
||||
|
||||
// We need to decorate array strides for types needing explicit layout,
|
||||
// except for the very top if it is an array of blocks; that array is
|
||||
// not laid out in memory in a way needing a stride.
|
||||
if (explicitLayout && type.getBasicType() != glslang::EbtBlock)
|
||||
builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type));
|
||||
}
|
||||
|
||||
|
|
@ -1883,8 +1871,11 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
|||
operands.push_back(*(opIt++));
|
||||
if (node->getOp() == glslang::EOpImageStore)
|
||||
operands.push_back(*(opIt++));
|
||||
// TODO: add 'sample' operand
|
||||
if (node->getOp() == glslang::EOpImageLoad) {
|
||||
if (sampler.ms) {
|
||||
operands.push_back(spv::ImageOperandsSampleMask);
|
||||
operands.push_back(*(opIt++));
|
||||
}
|
||||
return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands);
|
||||
} else if (node->getOp() == glslang::EOpImageStore) {
|
||||
builder.createNoResultOp(spv::OpImageWrite, operands);
|
||||
|
|
@ -1909,8 +1900,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
|||
}
|
||||
|
||||
// Check for texture functions other than queries
|
||||
if (cracked.gather)
|
||||
spv::MissingFunctionality("texture gather");
|
||||
|
||||
// check for bias argument
|
||||
bool bias = false;
|
||||
|
|
@ -1925,14 +1914,18 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
|||
bias = true;
|
||||
}
|
||||
|
||||
bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
|
||||
|
||||
// set the rest of the arguments
|
||||
|
||||
params.coords = arguments[1];
|
||||
int extraArgs = 0;
|
||||
if (cubeCompare)
|
||||
|
||||
// sort out where Dref is coming from
|
||||
if (sampler.shadow && sampler.dim == glslang::EsdCube && sampler.arrayed)
|
||||
params.Dref = arguments[2];
|
||||
else if (sampler.shadow) {
|
||||
else if (sampler.shadow && cracked.gather) {
|
||||
params.Dref = arguments[2];
|
||||
++extraArgs;
|
||||
} else if (sampler.shadow) {
|
||||
std::vector<spv::Id> indexes;
|
||||
int comp;
|
||||
if (cracked.proj)
|
||||
|
|
@ -1954,20 +1947,28 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
|||
params.gradY = arguments[3 + extraArgs];
|
||||
extraArgs += 2;
|
||||
}
|
||||
//if (gather && compare) {
|
||||
// params.compare = arguments[2 + extraArgs];
|
||||
// ++extraArgs;
|
||||
//}
|
||||
if (cracked.offset || cracked.offsets) {
|
||||
if (cracked.offset) {
|
||||
params.offset = arguments[2 + extraArgs];
|
||||
++extraArgs;
|
||||
} else if (cracked.offsets) {
|
||||
params.offsets = arguments[2 + extraArgs];
|
||||
++extraArgs;
|
||||
}
|
||||
if (bias) {
|
||||
params.bias = arguments[2 + extraArgs];
|
||||
++extraArgs;
|
||||
}
|
||||
if (cracked.gather && ! sampler.shadow) {
|
||||
// default component is 0, if missing, otherwise an argument
|
||||
if (2 + extraArgs < (int)arguments.size()) {
|
||||
params.comp = arguments[2 + extraArgs];
|
||||
++extraArgs;
|
||||
} else {
|
||||
params.comp = builder.makeIntConstant(0);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), cracked.fetch, cracked.proj, params);
|
||||
return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), cracked.fetch, cracked.proj, cracked.gather, params);
|
||||
}
|
||||
|
||||
spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
|
||||
|
|
@ -2308,6 +2309,7 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
|
|||
{
|
||||
spv::Op unaryOp = spv::OpNop;
|
||||
int libCall = -1;
|
||||
bool isUnsigned = typeProxy == glslang::EbtUint;
|
||||
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
|
||||
|
||||
switch (op) {
|
||||
|
|
@ -2538,11 +2540,13 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
|
|||
unaryOp = spv::OpBitCount;
|
||||
break;
|
||||
case glslang::EOpFindLSB:
|
||||
libCall = spv::GLSLstd450FindILSB;
|
||||
libCall = spv::GLSLstd450FindILsb;
|
||||
break;
|
||||
case glslang::EOpFindMSB:
|
||||
spv::MissingFunctionality("signed vs. unsigned FindMSB");
|
||||
libCall = spv::GLSLstd450FindSMSB;
|
||||
if (isUnsigned)
|
||||
libCall = spv::GLSLstd450FindUMsb;
|
||||
else
|
||||
libCall = spv::GLSLstd450FindSMsb;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -2717,7 +2721,7 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
|
|||
opCode = spv::OpAtomicLoad;
|
||||
break;
|
||||
default:
|
||||
spv::MissingFunctionality("missing nested atomic");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2754,6 +2758,11 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
|||
|
||||
spv::Op opCode = spv::OpNop;
|
||||
int libCall = -1;
|
||||
int consumedOperands = operands.size();
|
||||
spv::Id typeId0 = 0;
|
||||
if (consumedOperands > 0)
|
||||
typeId0 = builder.getTypeId(operands[0]);
|
||||
spv::Id frexpIntType = 0;
|
||||
|
||||
switch (op) {
|
||||
case glslang::EOpMin:
|
||||
|
|
@ -2794,7 +2803,10 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
|||
libCall = spv::GLSLstd450SClamp;
|
||||
break;
|
||||
case glslang::EOpMix:
|
||||
libCall = spv::GLSLstd450Mix;
|
||||
if (isFloat)
|
||||
libCall = spv::GLSLstd450FMix;
|
||||
else
|
||||
libCall = spv::GLSLstd450IMix;
|
||||
break;
|
||||
case glslang::EOpStep:
|
||||
libCall = spv::GLSLstd450Step;
|
||||
|
|
@ -2819,6 +2831,52 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
|||
libCall = spv::GLSLstd450Refract;
|
||||
break;
|
||||
|
||||
case glslang::EOpAddCarry:
|
||||
opCode = spv::OpIAddCarry;
|
||||
typeId = builder.makeStructResultType(typeId0, typeId0);
|
||||
consumedOperands = 2;
|
||||
break;
|
||||
case glslang::EOpSubBorrow:
|
||||
opCode = spv::OpISubBorrow;
|
||||
typeId = builder.makeStructResultType(typeId0, typeId0);
|
||||
consumedOperands = 2;
|
||||
break;
|
||||
case glslang::EOpUMulExtended:
|
||||
opCode = spv::OpUMulExtended;
|
||||
typeId = builder.makeStructResultType(typeId0, typeId0);
|
||||
consumedOperands = 2;
|
||||
break;
|
||||
case glslang::EOpIMulExtended:
|
||||
opCode = spv::OpSMulExtended;
|
||||
typeId = builder.makeStructResultType(typeId0, typeId0);
|
||||
consumedOperands = 2;
|
||||
break;
|
||||
case glslang::EOpBitfieldExtract:
|
||||
if (isUnsigned)
|
||||
opCode = spv::OpBitFieldUExtract;
|
||||
else
|
||||
opCode = spv::OpBitFieldSExtract;
|
||||
break;
|
||||
case glslang::EOpBitfieldInsert:
|
||||
opCode = spv::OpBitFieldInsert;
|
||||
break;
|
||||
|
||||
case glslang::EOpFma:
|
||||
libCall = spv::GLSLstd450Fma;
|
||||
break;
|
||||
case glslang::EOpFrexp:
|
||||
libCall = spv::GLSLstd450FrexpStruct;
|
||||
if (builder.getNumComponents(operands[0]) == 1)
|
||||
frexpIntType = builder.makeIntegerType(32, true);
|
||||
else
|
||||
frexpIntType = builder.makeVectorType(builder.makeIntegerType(32, true), builder.getNumComponents(operands[0]));
|
||||
typeId = builder.makeStructResultType(typeId0, frexpIntType);
|
||||
consumedOperands = 1;
|
||||
break;
|
||||
case glslang::EOpLdexp:
|
||||
libCall = spv::GLSLstd450Ldexp;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2827,7 +2885,7 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
|||
if (libCall >= 0)
|
||||
id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);
|
||||
else {
|
||||
switch (operands.size()) {
|
||||
switch (consumedOperands) {
|
||||
case 0:
|
||||
// should all be handled by visitAggregate and createNoArgOperation
|
||||
assert(0);
|
||||
|
|
@ -2839,16 +2897,34 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
|||
case 2:
|
||||
id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
|
||||
break;
|
||||
case 3:
|
||||
id = builder.createTriOp(opCode, typeId, operands[0], operands[1], operands[2]);
|
||||
break;
|
||||
default:
|
||||
// These do not exist yet
|
||||
assert(0 && "operation with more than 3 operands");
|
||||
// anything 3 or over doesn't have l-value operands, so all should be consumed
|
||||
assert(consumedOperands == operands.size());
|
||||
id = builder.createOp(opCode, typeId, operands);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the return types that were structures
|
||||
switch (op) {
|
||||
case glslang::EOpAddCarry:
|
||||
case glslang::EOpSubBorrow:
|
||||
builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
|
||||
id = builder.createCompositeExtract(id, typeId0, 0);
|
||||
break;
|
||||
case glslang::EOpUMulExtended:
|
||||
case glslang::EOpIMulExtended:
|
||||
builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]);
|
||||
builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
|
||||
break;
|
||||
case glslang::EOpFrexp:
|
||||
builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]);
|
||||
id = builder.createCompositeExtract(id, typeId0, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
builder.setPrecision(id, precision);
|
||||
|
||||
return id;
|
||||
|
|
@ -2883,13 +2959,13 @@ spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
|
|||
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsImageMemoryMask);
|
||||
return 0;
|
||||
case glslang::EOpMemoryBarrierShared:
|
||||
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);
|
||||
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupMemoryMask);
|
||||
return 0;
|
||||
case glslang::EOpGroupMemoryBarrier:
|
||||
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);
|
||||
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsCrossWorkgroupMemoryMask);
|
||||
return 0;
|
||||
default:
|
||||
spv::MissingFunctionality("operation with no arguments");
|
||||
spv::MissingFunctionality("unknown operation with no arguments");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -2945,31 +3021,57 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol
|
|||
if (builtIn != spv::BadValue)
|
||||
builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
|
||||
|
||||
if (linkageOnly)
|
||||
builder.addDecoration(id, spv::DecorationNoStaticUse);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// If 'dec' is valid, add no-operand decoration to an object
|
||||
void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)
|
||||
{
|
||||
if (dec != spv::BadValue)
|
||||
builder.addDecoration(id, dec);
|
||||
}
|
||||
|
||||
// If 'dec' is valid, add a one-operand decoration to an object
|
||||
void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec, unsigned value)
|
||||
{
|
||||
if (dec != spv::BadValue)
|
||||
builder.addDecoration(id, dec, value);
|
||||
}
|
||||
|
||||
// If 'dec' is valid, add a no-operand decoration to a struct member
|
||||
void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)
|
||||
{
|
||||
if (dec != spv::BadValue)
|
||||
builder.addMemberDecoration(id, (unsigned)member, dec);
|
||||
}
|
||||
|
||||
// Make a full tree of instructions to build a SPIR-V specialization constant,
|
||||
// or regularly constant if possible.
|
||||
//
|
||||
// TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though
|
||||
//
|
||||
// Recursively walk the nodes. The nodes form a tree whose leaves are
|
||||
// regular constants, which themselves are trees that createSpvConstant()
|
||||
// recursively walks. So, this function walks the "top" of the tree:
|
||||
// - emit specialization constant-building instructions for specConstant
|
||||
// - when running into a non-spec-constant, switch to createSpvConstant()
|
||||
spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node)
|
||||
{
|
||||
assert(node.getQualifier().storage == glslang::EvqConst);
|
||||
|
||||
// hand off to the non-spec-constant path
|
||||
assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
|
||||
int nextConst = 0;
|
||||
return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), nextConst, false);
|
||||
}
|
||||
|
||||
// Use 'consts' as the flattened glslang source of scalar constants to recursively
|
||||
// build the aggregate SPIR-V constant.
|
||||
//
|
||||
// If there are not enough elements present in 'consts', 0 will be substituted;
|
||||
// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
|
||||
//
|
||||
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)
|
||||
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
|
||||
{
|
||||
// vector of constants for SPIR-V
|
||||
std::vector<spv::Id> spvConsts;
|
||||
|
|
@ -2980,15 +3082,15 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
|
|||
if (glslangType.isArray()) {
|
||||
glslang::TType elementType(glslangType, 0);
|
||||
for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
|
||||
spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));
|
||||
spvConsts.push_back(createSpvConstant(elementType, consts, nextConst, false));
|
||||
} else if (glslangType.isMatrix()) {
|
||||
glslang::TType vectorType(glslangType, 0);
|
||||
for (int col = 0; col < glslangType.getMatrixCols(); ++col)
|
||||
spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));
|
||||
spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst, false));
|
||||
} else if (glslangType.getStruct()) {
|
||||
glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
|
||||
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
|
||||
spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));
|
||||
spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst, false));
|
||||
} else if (glslangType.isVector()) {
|
||||
for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
|
||||
bool zero = nextConst >= consts.size();
|
||||
|
|
@ -3009,7 +3111,7 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
|
|||
spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
|
||||
break;
|
||||
default:
|
||||
spv::MissingFunctionality("constant vector type");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
++nextConst;
|
||||
|
|
@ -3020,22 +3122,22 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
|
|||
spv::Id scalar = 0;
|
||||
switch (glslangType.getBasicType()) {
|
||||
case glslang::EbtInt:
|
||||
scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());
|
||||
scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant);
|
||||
break;
|
||||
case glslang::EbtUint:
|
||||
scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());
|
||||
scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant);
|
||||
break;
|
||||
case glslang::EbtFloat:
|
||||
scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());
|
||||
scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
|
||||
break;
|
||||
case glslang::EbtDouble:
|
||||
scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());
|
||||
scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);
|
||||
break;
|
||||
case glslang::EbtBool:
|
||||
scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());
|
||||
scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);
|
||||
break;
|
||||
default:
|
||||
spv::MissingFunctionality("constant scalar type");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
++nextConst;
|
||||
|
|
@ -3180,7 +3282,7 @@ void GetSpirvVersion(std::string& version)
|
|||
{
|
||||
const int bufSize = 100;
|
||||
char buf[bufSize];
|
||||
snprintf(buf, bufSize, "%d, Revision %d", spv::Version, spv::Revision);
|
||||
snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision);
|
||||
version = buf;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue