Fix TextureUpgradeAndSamplerRemovalTransform when used with qualifiers

The transform removes sampler arguments from functions and function
calls; this causes function arguments to change their indices. When some
function arguments have an output qualifier, this qualifier can get lost
because of the removal which can lead to incorrect results (e.g. out
qualifier not having effect).

To fix this we iterate through both seq & qual arrays in lock-step and
manually remove/replace entries as appropriate.
This commit is contained in:
Arseny Kapoulkine 2018-05-21 15:27:07 -07:00
parent 2fb966aad2
commit b239d22f7b

View File

@ -3769,23 +3769,39 @@ struct TextureUpgradeAndSamplerRemovalTransform : public TIntermTraverser {
bool visitAggregate(TVisit, TIntermAggregate* ag) override { bool visitAggregate(TVisit, TIntermAggregate* ag) override {
using namespace std; using namespace std;
TIntermSequence& seq = ag->getSequence(); TIntermSequence& seq = ag->getSequence();
// remove pure sampler variables TQualifierList& qual = ag->getQualifierList();
TIntermSequence::iterator newEnd = remove_if(seq.begin(), seq.end(), [](TIntermNode* node) {
TIntermSymbol* symbol = node->getAsSymbolNode();
if (!symbol)
return false;
return (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isPureSampler()); // qual and seq are indexed using the same indices, so we have to modify both in lock-step
}); assert(seq.size() == qual.size() || qual.empty());
seq.erase(newEnd, seq.end());
// replace constructors with sampler/textures size_t write = 0;
for_each(seq.begin(), seq.end(), [](TIntermNode*& node) { for (size_t i = 0; i < seq.size(); ++i) {
TIntermAggregate *constructor = node->getAsAggregate(); TIntermSymbol* symbol = seq[i]->getAsSymbolNode();
if (symbol && symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isPureSampler()) {
// remove pure sampler variables
continue;
}
TIntermNode* result = seq[i];
// replace constructors with sampler/textures
TIntermAggregate *constructor = seq[i]->getAsAggregate();
if (constructor && constructor->getOp() == EOpConstructTextureSampler) { if (constructor && constructor->getOp() == EOpConstructTextureSampler) {
if (!constructor->getSequence().empty()) if (!constructor->getSequence().empty())
node = constructor->getSequence()[0]; result = constructor->getSequence()[0];
} }
});
// write new node & qualifier
seq[write] = result;
if (!qual.empty())
qual[write] = qual[i];
write++;
}
seq.resize(write);
if (!qual.empty())
qual.resize(write);
return true; return true;
} }
}; };