Fix TextureUpgradeAndSamplerRemovalTransform when used with qualifiers
authorArseny Kapoulkine <arseny.kapoulkine@gmail.com>
Mon, 21 May 2018 22:27:07 +0000 (15:27 -0700)
committerArseny Kapoulkine <arseny.kapoulkine@gmail.com>
Mon, 21 May 2018 22:27:07 +0000 (15:27 -0700)
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.

glslang/MachineIndependent/Intermediate.cpp

index 0333e5d01f87c5265d5bc640c9b49e4d57b89d29..de722179c7a2d337fdc5a3db78af1525d1eb03c8 100644 (file)
@@ -3769,23 +3769,39 @@ struct TextureUpgradeAndSamplerRemovalTransform : public TIntermTraverser {
     bool visitAggregate(TVisit, TIntermAggregate* ag) override {
         using namespace std;
         TIntermSequence& seq = ag->getSequence();
-        // remove pure sampler variables
-        TIntermSequence::iterator newEnd = remove_if(seq.begin(), seq.end(), [](TIntermNode* node) {
-            TIntermSymbol* symbol = node->getAsSymbolNode();
-            if (!symbol)
-                return false;
+        TQualifierList& qual = ag->getQualifierList();
+
+        // 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());
+
+        size_t write = 0;
+        for (size_t i = 0; i < seq.size(); ++i) {
+            TIntermSymbol* symbol = seq[i]->getAsSymbolNode();
+            if (symbol && symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isPureSampler()) {
+                // remove pure sampler variables
+                continue;
+            }
+
+            TIntermNode* result = seq[i];
 
-            return (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isPureSampler());
-        });
-        seq.erase(newEnd, seq.end());
-        // replace constructors with sampler/textures
-        for_each(seq.begin(), seq.end(), [](TIntermNode*& node) {
-            TIntermAggregate *constructor = node->getAsAggregate();
+            // replace constructors with sampler/textures
+            TIntermAggregate *constructor = seq[i]->getAsAggregate();
             if (constructor && constructor->getOp() == EOpConstructTextureSampler) {
                 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;
     }
 };