Resubmit: Use ImmutableString for HLSL texture references

This fixes an issue in the original revision of this patch by adding
a operator<< to TInfoSinkBase that takes ImmutableString as a
parameter.

This also adds ImmutableStringBuilder class, which can be used to
build ImmutableStrings in place without extra allocations if the
maximum length is known in advance.

BUG=angleproject:2267
TEST=angle_unittests

Change-Id: I52e984657a3aba3e6fe67a82b401c6b8de557d18
Reviewed-on: https://chromium-review.googlesource.com/890522
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/TextureFunctionHLSL.cpp b/src/compiler/translator/TextureFunctionHLSL.cpp
index d2b65a6..36898ff 100644
--- a/src/compiler/translator/TextureFunctionHLSL.cpp
+++ b/src/compiler/translator/TextureFunctionHLSL.cpp
@@ -11,6 +11,7 @@
 
 #include "compiler/translator/TextureFunctionHLSL.h"
 
+#include "compiler/translator/ImmutableStringBuilder.h"
 #include "compiler/translator/UtilsHLSL.h"
 
 namespace sh
@@ -104,8 +105,8 @@
 
 void OutputHLSL4SampleFunctionPrefix(TInfoSinkBase &out,
                                      const TextureFunctionHLSL::TextureFunction &textureFunction,
-                                     const TString &textureReference,
-                                     const TString &samplerReference)
+                                     const ImmutableString &textureReference,
+                                     const ImmutableString &samplerReference)
 {
     out << textureReference;
     if (IsIntegerSampler(textureFunction.sampler) ||
@@ -450,37 +451,56 @@
 void GetTextureReference(TInfoSinkBase &out,
                          const TextureFunctionHLSL::TextureFunction &textureFunction,
                          const ShShaderOutput outputType,
-                         TString *textureReference,
-                         TString *samplerReference)
+                         ImmutableString *textureReference,
+                         ImmutableString *samplerReference)
 {
     if (outputType == SH_HLSL_4_1_OUTPUT)
     {
-        TString suffix = TextureGroupSuffix(textureFunction.sampler);
+        static const ImmutableString kTexturesStr("textures");
+        static const ImmutableString kSamplersStr("samplers");
+        static const ImmutableString kSamplerIndexStr("[samplerIndex]");
+        static const ImmutableString kTextureIndexStr("[textureIndex]");
+        static const ImmutableString kSamplerArrayIndexStr("[samplerArrayIndex]");
+        ImmutableString suffix(TextureGroupSuffix(textureFunction.sampler));
+
         if (TextureGroup(textureFunction.sampler) == HLSL_TEXTURE_2D)
         {
-            *textureReference = TString("textures") + suffix + "[samplerIndex]";
-            *samplerReference = TString("samplers") + suffix + "[samplerIndex]";
+            ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
+                                                     kSamplerIndexStr.length());
+            textureRefBuilder << kTexturesStr << suffix << kSamplerIndexStr;
+            *textureReference = textureRefBuilder;
+            ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
+                                                     kSamplerIndexStr.length());
+            samplerRefBuilder << kSamplersStr << suffix << kSamplerIndexStr;
+            *samplerReference = samplerRefBuilder;
         }
         else
         {
-            out << "    const uint textureIndex = samplerIndex - textureIndexOffset" << suffix
-                << ";\n";
-            *textureReference = TString("textures") + suffix + "[textureIndex]";
-            out << "    const uint samplerArrayIndex = samplerIndex - samplerIndexOffset" << suffix
-                << ";\n";
-            *samplerReference = TString("samplers") + suffix + "[samplerArrayIndex]";
+            out << "    const uint textureIndex = samplerIndex - textureIndexOffset"
+                << suffix.data() << ";\n";
+            ImmutableStringBuilder textureRefBuilder(kTexturesStr.length() + suffix.length() +
+                                                     kTextureIndexStr.length());
+            textureRefBuilder << kTexturesStr << suffix << kTextureIndexStr;
+            *textureReference = textureRefBuilder;
+
+            out << "    const uint samplerArrayIndex = samplerIndex - samplerIndexOffset"
+                << suffix.data() << ";\n";
+            ImmutableStringBuilder samplerRefBuilder(kSamplersStr.length() + suffix.length() +
+                                                     kSamplerArrayIndexStr.length());
+            samplerRefBuilder << kSamplersStr << suffix << kSamplerArrayIndexStr;
+            *samplerReference = samplerRefBuilder;
         }
     }
     else
     {
-        *textureReference = "x";
-        *samplerReference = "s";
+        *textureReference = ImmutableString("x");
+        *samplerReference = ImmutableString("s");
     }
 }
 
 void OutputTextureSizeFunctionBody(TInfoSinkBase &out,
                                    const TextureFunctionHLSL::TextureFunction &textureFunction,
-                                   const TString &textureReference,
+                                   const ImmutableString &textureReference,
                                    bool getDimensionsIgnoresBaseLevel)
 {
     if (IsSampler2DMS(textureFunction.sampler))
@@ -565,7 +585,7 @@
     TInfoSinkBase &out,
     const TextureFunctionHLSL::TextureFunction &textureFunction,
     const ShShaderOutput outputType,
-    const TString &textureReference,
+    const ImmutableString &textureReference,
     TString *texCoordX,
     TString *texCoordY,
     TString *texCoordZ)
@@ -811,8 +831,8 @@
     TInfoSinkBase &out,
     const TextureFunctionHLSL::TextureFunction &textureFunction,
     const ShShaderOutput outputType,
-    const TString &textureReference,
-    const TString &samplerReference,
+    const ImmutableString &textureReference,
+    const ImmutableString &samplerReference,
     const TString &texCoordX,
     const TString &texCoordY,
     const TString &texCoordZ)
@@ -1291,8 +1311,8 @@
         // sampling we need to call the function directly on references to the texture and sampler
         // arrays. The bug was found using dEQP-GLES3.functional.shaders.discard*loop_texture*
         // tests.
-        TString textureReference;
-        TString samplerReference;
+        ImmutableString textureReference("");
+        ImmutableString samplerReference("");
         GetTextureReference(out, textureFunction, outputType, &textureReference, &samplerReference);
 
         if (textureFunction.method == TextureFunction::SIZE)