Merge master branch from upstream
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index baa6dea..fe3134f 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -88,6 +88,10 @@
spv::Id createSpvVariable(const glslang::TIntermSymbol*);
spv::Id getSampledType(const glslang::TSampler&);
spv::Id convertGlslangToSpvType(const glslang::TType& type);
+ spv::Id convertGlslangToSpvType(const glslang::TType& type, bool explicitLayout);
+ bool requiresExplicitLayout(const glslang::TType& type) const;
+ int getArrayStride(const glslang::TType& arrayType);
+ int getMatrixStride(const glslang::TType& matrixType);
void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset);
bool isShaderEntrypoint(const glslang::TIntermAggregate* node);
@@ -578,12 +582,12 @@
// evaluate the right
builder.clearAccessChain();
node->getRight()->traverse(this);
- spv::Id rValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+ spv::Id rValue = builder.accessChainLoad(convertGlslangToSpvType(node->getRight()->getType()));
if (node->getOp() != glslang::EOpAssign) {
// the left is also an r-value
builder.setAccessChain(lValue);
- spv::Id leftRValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));
+ spv::Id leftRValue = builder.accessChainLoad(convertGlslangToSpvType(node->getLeft()->getType()));
// do the operation
rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()),
@@ -635,10 +639,10 @@
// so short circuit the access-chain stuff with a swizzle.
std::vector<unsigned> swizzle;
swizzle.push_back(node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst());
- builder.accessChainPushSwizzle(swizzle);
+ builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
} else {
// normal case for indexing array or structure or block
- builder.accessChainPush(builder.makeIntConstant(index), convertGlslangToSpvType(node->getType()));
+ builder.accessChainPush(builder.makeIntConstant(index));
}
}
return false;
@@ -659,15 +663,15 @@
// compute the next index in the chain
builder.clearAccessChain();
node->getRight()->traverse(this);
- spv::Id index = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+ spv::Id index = builder.accessChainLoad(convertGlslangToSpvType(node->getRight()->getType()));
// restore the saved access chain
builder.setAccessChain(partial);
if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
- builder.accessChainPushComponent(index);
+ builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()));
else
- builder.accessChainPush(index, convertGlslangToSpvType(node->getType()));
+ builder.accessChainPush(index);
}
return false;
case glslang::EOpVectorSwizzle:
@@ -677,7 +681,7 @@
std::vector<unsigned> swizzle;
for (int i = 0; i < (int)swizzleSequence.size(); ++i)
swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
- builder.accessChainPushSwizzle(swizzle);
+ builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
}
return false;
default:
@@ -689,11 +693,11 @@
// Get the operands
builder.clearAccessChain();
node->getLeft()->traverse(this);
- spv::Id left = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));
+ spv::Id left = builder.accessChainLoad(convertGlslangToSpvType(node->getLeft()->getType()));
builder.clearAccessChain();
node->getRight()->traverse(this);
- spv::Id right = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
+ spv::Id right = builder.accessChainLoad(convertGlslangToSpvType(node->getRight()->getType()));
spv::Id result;
spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
@@ -728,10 +732,29 @@
}
// Non-texturing.
+
+ if (node->getOp() == glslang::EOpArrayLength) {
+ // Quite special; won't want to evaluate the operand.
+
+ // Normal .length() would have been constant folded by the front-end.
+ // So, this has to be block.lastMember.length().
+ // SPV wants "block" as the operand, go get it.
+ assert(node->getOperand()->getType().isRuntimeSizedArray());
+ glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft();
+ block->traverse(this);
+ spv::Id length = builder.createUnaryOp(spv::OpArrayLength, builder.makeIntType(32), builder.accessChainGetLValue());
+
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(length);
+
+ return false;
+ }
+
// Start by evaluating the operand
builder.clearAccessChain();
node->getOperand()->traverse(this);
+
spv::Id operand = spv::NoResult;
if (node->getOp() == glslang::EOpAtomicCounterIncrement ||
@@ -739,7 +762,7 @@
node->getOp() == glslang::EOpAtomicCounter)
operand = builder.accessChainGetLValue(); // Special case l-value operands
else
- operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));
+ operand = builder.accessChainLoad(convertGlslangToSpvType(node->getOperand()->getType()));
spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
@@ -1027,17 +1050,6 @@
// which can be emitted by the one in createBinaryOperation()
binOp = glslang::EOpMod;
break;
- case glslang::EOpArrayLength:
- {
- glslang::TIntermTyped* typedNode = node->getSequence()[0]->getAsTyped();
- assert(typedNode);
- spv::Id length = builder.makeIntConstant(typedNode->getType().getOuterArraySize());
-
- builder.clearAccessChain();
- builder.setAccessChainRValue(length);
-
- return false;
- }
case glslang::EOpEmitVertex:
case glslang::EOpEndPrimitive:
case glslang::EOpBarrier:
@@ -1091,11 +1103,11 @@
builder.clearAccessChain();
left->traverse(this);
- spv::Id leftId = builder.accessChainLoad(TranslatePrecisionDecoration(left->getType()));
+ spv::Id leftId = builder.accessChainLoad(convertGlslangToSpvType(left->getType()));
builder.clearAccessChain();
right->traverse(this);
- spv::Id rightId = builder.accessChainLoad(TranslatePrecisionDecoration(right->getType()));
+ spv::Id rightId = builder.accessChainLoad(convertGlslangToSpvType(right->getType()));
result = createBinaryOperation(binOp, precision,
convertGlslangToSpvType(node->getType()), leftId, rightId,
@@ -1148,7 +1160,7 @@
if (lvalue)
operands.push_back(builder.accessChainGetLValue());
else
- operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));
+ operands.push_back(builder.accessChainLoad(convertGlslangToSpvType(glslangOperands[arg]->getAsTyped()->getType())));
}
if (atomic) {
@@ -1198,13 +1210,13 @@
node->getCondition()->traverse(this);
// make an "if" based on the value created by the condition
- spv::Builder::If ifBuilder(builder.accessChainLoad(spv::NoPrecision), builder);
+ spv::Builder::If ifBuilder(builder.accessChainLoad(convertGlslangToSpvType(node->getCondition()->getType())), builder);
if (node->getTrueBlock()) {
// emit the "then" statement
node->getTrueBlock()->traverse(this);
if (result)
- builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getTrueBlock()->getAsTyped()->getType())), result);
+ builder.createStore(builder.accessChainLoad(convertGlslangToSpvType(node->getTrueBlock()->getAsTyped()->getType())), result);
}
if (node->getFalseBlock()) {
@@ -1212,7 +1224,7 @@
// emit the "else" statement
node->getFalseBlock()->traverse(this);
if (result)
- builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getFalseBlock()->getAsTyped()->getType())), result);
+ builder.createStore(builder.accessChainLoad(convertGlslangToSpvType(node->getFalseBlock()->getAsTyped()->getType())), result);
}
ifBuilder.makeEndIf();
@@ -1233,7 +1245,7 @@
{
// emit and get the condition before doing anything with switch
node->getCondition()->traverse(this);
- spv::Id selector = builder.accessChainLoad(TranslatePrecisionDecoration(node->getCondition()->getAsTyped()->getType()));
+ spv::Id selector = builder.accessChainLoad(convertGlslangToSpvType(node->getCondition()->getAsTyped()->getType()));
// browse the children to sort out code segments
int defaultSegment = -1;
@@ -1297,7 +1309,7 @@
if (node->getTest()) {
node->getTest()->traverse(this);
// the AST only contained the test computation, not the branch, we have to add it
- spv::Id condition = builder.accessChainLoad(TranslatePrecisionDecoration(node->getTest()->getType()));
+ spv::Id condition = builder.accessChainLoad(convertGlslangToSpvType(node->getTest()->getType()));
builder.createLoopTestBranch(condition);
} else {
builder.createBranchToBody();
@@ -1343,7 +1355,7 @@
if (inMain)
builder.makeMainReturn();
else if (node->getExpression())
- builder.makeReturn(false, builder.accessChainLoad(TranslatePrecisionDecoration(node->getExpression()->getType())));
+ builder.makeReturn(false, builder.accessChainLoad(convertGlslangToSpvType(node->getExpression()->getType())));
else
builder.makeReturn();
@@ -1391,9 +1403,17 @@
}
}
-// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
+// Convert from a glslang type to an SPV type, by calling into
+// recursive version of this function.
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
{
+ return convertGlslangToSpvType(type, requiresExplicitLayout(type));
+}
+
+// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
+// explicitLayout can be kept the same throughout the heirarchical recursive walk.
+spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, bool explicitLayout)
+{
spv::Id spvType = 0;
switch (type.getBasicType()) {
@@ -1456,7 +1476,7 @@
} else {
if (type.getBasicType() == glslang::EbtBlock)
memberRemapper[glslangStruct][i] = i - memberDelta;
- structFields.push_back(convertGlslangToSpvType(glslangType));
+ structFields.push_back(convertGlslangToSpvType(glslangType, explicitLayout));
}
}
@@ -1484,15 +1504,19 @@
builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);
if (glslangType.getQualifier().hasXfbOffset())
builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);
- else {
+ else if (explicitLayout) {
// figure out what to do with offset, which is accumulating
int nextOffset;
updateMemberOffset(type, glslangType, offset, nextOffset);
if (offset >= 0)
- builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutOffset);
+ builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset);
offset = nextOffset;
}
+ if (glslangType.isMatrix() && explicitLayout) {
+ builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangType));
+ }
+
// built-in variable decorations
spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);
if (builtIn != spv::BadValue)
@@ -1527,18 +1551,56 @@
}
if (type.isArray()) {
- unsigned arraySize;
- if (! type.isExplicitlySizedArray()) {
- spv::MissingFunctionality("Unsized array");
- arraySize = 8;
- } else
- arraySize = type.getOuterArraySize();
- spvType = builder.makeArrayType(spvType, arraySize);
+ // Do all but the outer dimension
+ for (int dim = type.getArraySizes()->getNumDims() - 1; dim > 0; --dim) {
+ assert(type.getArraySizes()->getDimSize(dim) > 0);
+ spvType = builder.makeArrayType(spvType, type.getArraySizes()->getDimSize(dim));
+ }
+
+ // Do the outer dimension, which might not be known for a runtime-sized array
+ if (type.isRuntimeSizedArray()) {
+ spvType = builder.makeRuntimeArray(spvType);
+ } else {
+ assert(type.getOuterArraySize() > 0);
+ spvType = builder.makeArrayType(spvType, type.getOuterArraySize());
+ }
+
+ // TODO: 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)
+ builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type));
}
return spvType;
}
+bool TGlslangToSpvTraverser::requiresExplicitLayout(const glslang::TType& type) const
+{
+ return type.getBasicType() == glslang::EbtBlock &&
+ type.getQualifier().layoutPacking != glslang::ElpShared &&
+ type.getQualifier().layoutPacking != glslang::ElpPacked &&
+ (type.getQualifier().storage == glslang::EvqUniform ||
+ type.getQualifier().storage == glslang::EvqBuffer);
+}
+
+// Given an array type, returns the integer stride required for that array
+int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType)
+{
+ glslang::TType derefType(arrayType, 0);
+ int size;
+ glslangIntermediate->getBaseAlignment(derefType, size, true);
+ return size;
+}
+
+// Given a matrix type, returns the integer stride required for that matrix
+// when used as a member of an interface block
+int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType)
+{
+ int size;
+ return glslangIntermediate->getBaseAlignment(matrixType, size, true);
+}
+
// Given a member type of a struct, realign the current offset for it, and compute
// the next (not yet aligned) offset for the next member, which will get aligned
// on the next call.
@@ -1700,9 +1762,8 @@
if (lvalue) {
arguments.push_back(builder.accessChainGetLValue());
- }
- else {
- arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));
+ } else {
+ arguments.push_back(builder.accessChainLoad(convertGlslangToSpvType(glslangArguments[i]->getAsTyped()->getType())));
}
}
}
@@ -1711,7 +1772,7 @@
{
builder.clearAccessChain();
node.getOperand()->traverse(this);
- arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(node.getAsTyped()->getType())));
+ arguments.push_back(builder.accessChainLoad(convertGlslangToSpvType(node.getOperand()->getType())));
}
spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)
@@ -1792,8 +1853,6 @@
}
// Check for texture functions other than queries
- if (cracked.fetch)
- spv::MissingFunctionality("texel fetch");
if (cracked.gather)
spv::MissingFunctionality("texture gather");
@@ -1849,7 +1908,7 @@
++extraArgs;
}
- return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), cracked.proj, params);
+ return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), cracked.fetch, cracked.proj, params);
}
spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
@@ -1873,17 +1932,19 @@
// 1. Evaluate the arguments
std::vector<spv::Builder::AccessChain> lValues;
std::vector<spv::Id> rValues;
+ std::vector<spv::Id> argTypes;
for (int a = 0; a < (int)glslangArgs.size(); ++a) {
// build l-value
builder.clearAccessChain();
glslangArgs[a]->traverse(this);
+ argTypes.push_back(convertGlslangToSpvType(glslangArgs[a]->getAsTyped()->getType()));
// keep outputs as l-values, evaluate input-only as r-values
if (qualifiers[a] != glslang::EvqConstReadOnly) {
// save l-value
lValues.push_back(builder.getAccessChain());
} else {
// process r-value
- rValues.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArgs[a]->getAsTyped()->getType())));
+ rValues.push_back(builder.accessChainLoad(argTypes.back()));
}
}
@@ -1903,7 +1964,7 @@
if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
// need to copy the input into output space
builder.setAccessChain(lValues[lValueCount]);
- spv::Id copy = builder.accessChainLoad(spv::NoPrecision); // TODO: get precision
+ spv::Id copy = builder.accessChainLoad(argTypes[a]);
builder.createStore(copy, arg);
}
++lValueCount;