From b239d22f7be2ca73230b50d660969ebe8b43dd2a Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Mon, 21 May 2018 15:27:07 -0700
Subject: [PATCH] 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.
---
 glslang/MachineIndependent/Intermediate.cpp | 42 ++++++++++++++-------
 1 file changed, 29 insertions(+), 13 deletions(-)

diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 0333e5d01..de722179c 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -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;
     }
 };
-- 
GitLab