HLSL: Allow stream output Append() method after entry point.
Append() method is special: unlike most outputs, it does not copy some temporary data to a symbol in the entry point epilogue, but rather uses an emit builtin after each write to the output stream. This had been handled by remembering the special output symbol for the stream as it was declared in the shader entry point before symbol sanitization. However the prior code was too simple and only handled cases where the Append() method happened after the entry point, so that the output symbol had been seen. This PR adds a patching step so that the Append()s may appear in any order WRT the entry point. They are patched in an epilogue, whereupon it is guaranteed in a well formed shader that we have seen the appropriate declaration. Fixes #1217.
This commit is contained in:
@@ -4487,23 +4487,18 @@ void HlslParseContext::decomposeGeometryMethods(const TSourceLoc& loc, TIntermTy
|
||||
emit->setLoc(loc);
|
||||
emit->setType(TType(EbtVoid));
|
||||
|
||||
// find the matching output
|
||||
if (gsStreamOutput == nullptr) {
|
||||
error(loc, "unable to find output symbol for Append()", "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
sequence = intermediate.growAggregate(sequence,
|
||||
handleAssign(loc, EOpAssign,
|
||||
intermediate.addSymbol(*gsStreamOutput, loc),
|
||||
argAggregate->getSequence()[1]->getAsTyped()),
|
||||
loc);
|
||||
TIntermTyped* data = argAggregate->getSequence()[1]->getAsTyped();
|
||||
|
||||
// This will be patched in finalization during finalizeAppendMethods()
|
||||
sequence = intermediate.growAggregate(sequence, data, loc);
|
||||
sequence = intermediate.growAggregate(sequence, emit);
|
||||
|
||||
sequence->setOperator(EOpSequence);
|
||||
sequence->setLoc(loc);
|
||||
sequence->setType(TType(EbtVoid));
|
||||
|
||||
gsAppends.push_back({sequence, loc});
|
||||
|
||||
node = sequence;
|
||||
}
|
||||
break;
|
||||
@@ -9919,6 +9914,31 @@ void HlslParseContext::fixTextureShadowModes()
|
||||
}
|
||||
}
|
||||
|
||||
// Finalization step: patch append methods to use proper stream output, which isn't known until
|
||||
// main is parsed, which could happen after the append method is parsed.
|
||||
void HlslParseContext::finalizeAppendMethods()
|
||||
{
|
||||
TSourceLoc loc;
|
||||
loc.init();
|
||||
|
||||
// Nothing to do: bypass test for valid stream output.
|
||||
if (gsAppends.empty())
|
||||
return;
|
||||
|
||||
if (gsStreamOutput == nullptr) {
|
||||
error(loc, "unable to find output symbol for Append()", "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
// Patch append sequences, now that we know the stream output symbol.
|
||||
for (auto append = gsAppends.begin(); append != gsAppends.end(); ++append) {
|
||||
append->node->getSequence()[0] =
|
||||
handleAssign(append->loc, EOpAssign,
|
||||
intermediate.addSymbol(*gsStreamOutput, append->loc),
|
||||
append->node->getSequence()[0]->getAsTyped());
|
||||
}
|
||||
}
|
||||
|
||||
// post-processing
|
||||
void HlslParseContext::finish()
|
||||
{
|
||||
@@ -9931,6 +9951,7 @@ void HlslParseContext::finish()
|
||||
removeUnusedStructBufferCounters();
|
||||
addPatchConstantInvocation();
|
||||
fixTextureShadowModes();
|
||||
finalizeAppendMethods();
|
||||
|
||||
// Communicate out (esp. for command line) that we formed AST that will make
|
||||
// illegal AST SPIR-V and it needs transforms to legalize it.
|
||||
|
||||
@@ -266,6 +266,7 @@ protected:
|
||||
TVariable* getSplitNonIoVar(int id) const;
|
||||
void addPatchConstantInvocation();
|
||||
void fixTextureShadowModes();
|
||||
void finalizeAppendMethods();
|
||||
TIntermTyped* makeIntegerIndex(TIntermTyped*);
|
||||
|
||||
void fixBuiltInIoType(TType&);
|
||||
@@ -460,6 +461,17 @@ protected:
|
||||
|
||||
TVector<tMipsOperatorData> mipsOperatorMipArg;
|
||||
|
||||
// The geometry output stream is not copied out from the entry point as a typical output variable
|
||||
// is. It's written via EmitVertex (hlsl=Append), which may happen in arbitrary control flow.
|
||||
// For this we need the real output symbol. Since it may not be known at the time and Append()
|
||||
// method is parsed, the sequence will be patched during finalization.
|
||||
struct tGsAppendData {
|
||||
TIntermAggregate* node;
|
||||
TSourceLoc loc;
|
||||
};
|
||||
|
||||
TVector<tGsAppendData> gsAppends;
|
||||
|
||||
// A texture object may be used with shadow and non-shadow samplers, but both may not be
|
||||
// alive post-DCE in the same shader. We do not know at compilation time which are alive: that's
|
||||
// only known post-DCE. If a texture is used both ways, we create two textures, and
|
||||
|
||||
Reference in New Issue
Block a user