Skip to content

Commit

Permalink
Fix KhronosGroup#1843: Handle built-in function output parameters to …
Browse files Browse the repository at this point in the history
…a swizzled arg

In GLSL/HLSL/AST,  v.zyx is an l-value, but not in SPIR-V, which cannot represent it.
So, a temporary is used instead.
  • Loading branch information
johnkslang committed Mar 3, 2020
1 parent 56364b6 commit bbbd9a2
Show file tree
Hide file tree
Showing 4 changed files with 481 additions and 442 deletions.
28 changes: 25 additions & 3 deletions SPIRV/GlslangToSpv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2277,7 +2277,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();

spv::Id result = spv::NoResult;
spv::Id invertedType = spv::NoType; // to use to override the natural type of the node
spv::Id invertedType = spv::NoType; // to use to override the natural type of the node
spv::Builder::AccessChain complexLvalue; // for holding swizzling l-values too complex for SPIR-V, for at out parameter
spv::Id temporaryLvalue = spv::NoResult; // temporary to pass, as proxy for complexLValue

auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); };

// try texturing
Expand Down Expand Up @@ -2727,6 +2730,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt

// Does it need a swizzle inversion? If so, evaluation is inverted;
// operate first on the swizzle base, then apply the swizzle.
// That is, we transform
//
// interpolate(v.zy) -> interpolate(v).zy
//
if (glslangOperands[0]->getAsOperator() &&
glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle)
invertedType = convertGlslangToSpvType(glslangOperands[0]->getAsBinaryNode()->getLeft()->getType());
Expand Down Expand Up @@ -2819,8 +2826,19 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
}
#endif

// for l-values, pass the address, for r-values, pass the value
if (lvalue) {
operands.push_back(builder.accessChainGetLValue());
if (invertedType == spv::NoType && !builder.isSpvLvalue()) {
// SPIR-V cannot represent an l-value containing a swizzle that doesn't
// reduce to a simple access chain. So, we need a temporary vector to
// receive the result, and must later swizzle that into the original
// l-value.
complexLvalue = builder.getAccessChain();
temporaryLvalue = builder.createVariable(spv::StorageClassFunction, builder.accessChainGetInferredType(), "swizzleTemp");
operands.push_back(temporaryLvalue);
} else {
operands.push_back(builder.accessChainGetLValue());
}
lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
lvalueCoherentFlags |= TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType());
} else {
Expand Down Expand Up @@ -2883,8 +2901,12 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
result = createMiscOperation(node->getOp(), precision, resultType(), operands, node->getBasicType());
break;
}
if (invertedType)
if (invertedType != spv::NoResult)
result = createInvertedSwizzle(precision, *glslangOperands[0]->getAsBinaryNode(), result);
else if (temporaryLvalue != spv::NoResult) {
builder.setAccessChain(complexLvalue);
builder.accessChainStore(builder.createLoad(temporaryLvalue));
}
}

if (noReturnValue)
Expand Down
5 changes: 5 additions & 0 deletions SPIRV/SpvBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,11 @@ class Builder {
// use accessChain and swizzle to load an r-value
Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);

// Return whether or not the access chain can be represented in SPIR-V
// as an l-value.
// E.g., a[3].yx cannot be, while a[3].y and a[3].y[x] can be.
bool isSpvLvalue() const { return accessChain.swizzle.size() <= 1; }

// get the direct pointer for an l-value
Id accessChainGetLValue();

Expand Down
Loading

0 comments on commit bbbd9a2

Please sign in to comment.