Implement textureSize.

TRAC #23485
Signed-off-by: Jamie Madill
Signed-off-by: Shannon Woods
Author: Nicolas Capens
diff --git a/src/compiler/Initialize.cpp b/src/compiler/Initialize.cpp
index 3b524e7..345ecac 100644
--- a/src/compiler/Initialize.cpp
+++ b/src/compiler/Initialize.cpp
@@ -22,6 +22,7 @@
     TType *float3 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 3);
     TType *float4 = new TType(EbtFloat, EbpUndefined, EvqGlobal, 4);
 
+    TType *int1 = new TType(EbtInt, EbpUndefined, EvqGlobal, 1);
     TType *int2 = new TType(EbtInt, EbpUndefined, EvqGlobal, 2);
     TType *int3 = new TType(EbtInt, EbpUndefined, EvqGlobal, 3);
     TType *int4 = new TType(EbtInt, EbpUndefined, EvqGlobal, 4);
@@ -459,6 +460,19 @@
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, uint4, "textureProj", usampler3D, "sampler", float4, "coord", float1, "bias");
     }
 
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", sampler2D, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", isampler2D, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", usampler2D, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", sampler3D, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", isampler3D, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", usampler3D, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerCube, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", isamplerCube, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", usamplerCube, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", sampler2DArray, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", isampler2DArray, "sampler", int1, "lod");
+    symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", usampler2DArray, "sampler", int1, "lod");
+
     if(type == SH_FRAGMENT_SHADER)
     {
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "dFdx", float1, "p");
diff --git a/src/compiler/OutputHLSL.cpp b/src/compiler/OutputHLSL.cpp
index 0938d02..dfcc268 100644
--- a/src/compiler/OutputHLSL.cpp
+++ b/src/compiler/OutputHLSL.cpp
@@ -53,12 +53,13 @@
         name += "Proj";
     }
 
-    switch(mipmap)
+    switch(method)
     {
       case IMPLICIT:                 break;
       case BIAS:                     break;
       case LOD:      name += "Lod";  break;
       case LOD0:     name += "Lod0"; break;
+      case SIZE:     name += "Size"; break;
       default: UNREACHABLE();
     }
 
@@ -70,7 +71,7 @@
     if (sampler < rhs.sampler) return true;
     if (coords < rhs.coords)   return true;
     if (!proj && rhs.proj)     return true;
-    if (mipmap < rhs.mipmap)   return true;
+    if (method < rhs.method)   return true;
 
     return false;
 }
@@ -883,21 +884,43 @@
     for (TextureFunctionSet::const_iterator textureFunction = mUsesTexture.begin(); textureFunction != mUsesTexture.end(); textureFunction++)
     {
         // Return type
-        switch(textureFunction->sampler)
+        if (textureFunction->method == TextureFunction::SIZE)
         {
-          case EbtSampler2D:       out << "float4 "; break;
-          case EbtSampler3D:       out << "float4 "; break;
-          case EbtSamplerCube:     out << "float4 "; break;
-          case EbtSampler2DArray:  out << "float4 "; break;
-          case EbtISampler2D:      out << "int4 ";   break;
-          case EbtISampler3D:      out << "int4 ";   break;
-          case EbtISamplerCube:    out << "int4 ";   break;
-          case EbtISampler2DArray: out << "int4 ";   break;
-          case EbtUSampler2D:      out << "uint4 ";  break;
-          case EbtUSampler3D:      out << "uint4 ";  break;
-          case EbtUSamplerCube:    out << "uint4 ";  break;
-          case EbtUSampler2DArray: out << "uint4 ";  break;
-          default: UNREACHABLE();
+            switch(textureFunction->sampler)
+            {
+              case EbtSampler2D:       out << "int2 "; break;
+              case EbtSampler3D:       out << "int3 "; break;
+              case EbtSamplerCube:     out << "int2 "; break;
+              case EbtSampler2DArray:  out << "int3 "; break;
+              case EbtISampler2D:      out << "int2 "; break;
+              case EbtISampler3D:      out << "int3 "; break;
+              case EbtISamplerCube:    out << "int2 "; break;
+              case EbtISampler2DArray: out << "int3 "; break;
+              case EbtUSampler2D:      out << "int2 "; break;
+              case EbtUSampler3D:      out << "int3 "; break;
+              case EbtUSamplerCube:    out << "int2 "; break;
+              case EbtUSampler2DArray: out << "int3 "; break;
+              default: UNREACHABLE();
+            }
+        }
+        else   // Sampling function
+        {
+            switch(textureFunction->sampler)
+            {
+              case EbtSampler2D:       out << "float4 "; break;
+              case EbtSampler3D:       out << "float4 "; break;
+              case EbtSamplerCube:     out << "float4 "; break;
+              case EbtSampler2DArray:  out << "float4 "; break;
+              case EbtISampler2D:      out << "int4 ";   break;
+              case EbtISampler3D:      out << "int4 ";   break;
+              case EbtISamplerCube:    out << "int4 ";   break;
+              case EbtISampler2DArray: out << "int4 ";   break;
+              case EbtUSampler2D:      out << "uint4 ";  break;
+              case EbtUSampler3D:      out << "uint4 ";  break;
+              case EbtUSamplerCube:    out << "uint4 ";  break;
+              case EbtUSampler2DArray: out << "uint4 ";  break;
+              default: UNREACHABLE();
+            }
         }
 
         // Function name
@@ -915,7 +938,7 @@
               default: UNREACHABLE();
             }
 
-            switch(textureFunction->mipmap)
+            switch(textureFunction->method)
             {
               case TextureFunction::IMPLICIT:                 break;
               case TextureFunction::BIAS:     hlslCoords = 4; break;
@@ -947,25 +970,66 @@
 
         switch(textureFunction->coords)
         {
+          case 1: out << ", int lod";  break;
           case 2: out << ", float2 t"; break;
           case 3: out << ", float3 t"; break;
           case 4: out << ", float4 t"; break;
           default: UNREACHABLE();
         }
 
-        switch(textureFunction->mipmap)
+        switch(textureFunction->method)
         {
           case TextureFunction::IMPLICIT:                        break;
           case TextureFunction::BIAS:     out << ", float bias"; break;
           case TextureFunction::LOD:      out << ", float lod";  break;
           case TextureFunction::LOD0:                            break;
+          case TextureFunction::SIZE:                            break;
           default: UNREACHABLE();
         }
 
         out << ")\n"
                "{\n";
 
-        if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
+        if (textureFunction->method == TextureFunction::SIZE)
+        {
+            if (IsSampler2D(textureFunction->sampler) || IsSamplerCube(textureFunction->sampler))
+            {
+                if (IsSamplerArray(textureFunction->sampler))
+                {
+                    out << "    uint width; uint height; uint layers; uint numberOfLevels;\n"
+                           "    x.GetDimensions(lod, width, height, layers, numberOfLevels);\n";
+                }
+                else
+                {
+                    out << "    uint width; uint height; uint numberOfLevels;\n"
+                           "    x.GetDimensions(lod, width, height, numberOfLevels);\n";
+                }
+            }
+            else if (IsSampler3D(textureFunction->sampler))
+            {
+                out << "    uint width; uint height; uint depth; uint numberOfLevels;\n"
+                       "    x.GetDimensions(lod, width, height, depth, numberOfLevels);\n";
+            }
+            else UNREACHABLE();
+
+            switch(textureFunction->sampler)
+            {
+              case EbtSampler2D:       out << "    return int2(width, height);";         break;
+              case EbtSampler3D:       out << "    return int3(width, height, depth);";  break;
+              case EbtSamplerCube:     out << "    return int2(width, height);";         break;
+              case EbtSampler2DArray:  out << "    return int3(width, height, layers);"; break;
+              case EbtISampler2D:      out << "    return int2(width, height);";         break;
+              case EbtISampler3D:      out << "    return int3(width, height, depth);";  break;
+              case EbtISamplerCube:    out << "    return int2(width, height);";         break;
+              case EbtISampler2DArray: out << "    return int3(width, height, layers);"; break;
+              case EbtUSampler2D:      out << "    return int2(width, height);";         break;
+              case EbtUSampler3D:      out << "    return int3(width, height, depth);";  break;
+              case EbtUSamplerCube:    out << "    return int2(width, height);";         break;
+              case EbtUSampler2DArray: out << "    return int3(width, height, layers);"; break;
+              default: UNREACHABLE();
+            }
+        }
+        else if (IsIntegerSampler(textureFunction->sampler) && IsSamplerCube(textureFunction->sampler))
         {
             // Currently unsupported because TextureCube does not support Load
             // This will require emulation using a Texture2DArray with 6 faces
@@ -1016,7 +1080,7 @@
                   default: UNREACHABLE();
                 }
 
-                switch(textureFunction->mipmap)
+                switch(textureFunction->method)
                 {
                   case TextureFunction::IMPLICIT: out << "(s, ";     break;
                   case TextureFunction::BIAS:     out << "bias(s, "; break;
@@ -1033,7 +1097,7 @@
                 }
                 else
                 {
-                    switch(textureFunction->mipmap)
+                    switch(textureFunction->method)
                     {
                       case TextureFunction::IMPLICIT: out << "x.Sample(s, ";      break;
                       case TextureFunction::BIAS:     out << "x.SampleBias(s, ";  break;
@@ -1115,7 +1179,7 @@
 
                 if (hlslCoords == 4)
                 {
-                    switch(textureFunction->mipmap)
+                    switch(textureFunction->method)
                     {
                       case TextureFunction::BIAS: out << ", bias"; break;
                       case TextureFunction::LOD:  out << ", lod";  break;
@@ -1135,7 +1199,7 @@
 
                 if (!IsIntegerSampler(textureFunction->sampler))
                 {
-                    switch(textureFunction->mipmap)
+                    switch(textureFunction->method)
                     {
                       case TextureFunction::IMPLICIT: out << "));";       break;
                       case TextureFunction::BIAS:     out << "), bias);"; break;
@@ -2264,39 +2328,43 @@
                 TextureFunction textureFunction;
                 textureFunction.sampler = samplerType;
                 textureFunction.coords = arguments[1]->getAsTyped()->getNominalSize();
-                textureFunction.mipmap = TextureFunction::IMPLICIT;
+                textureFunction.method = TextureFunction::IMPLICIT;
+                textureFunction.proj = false;
 
                 if (name == "texture2D" || name == "textureCube" || name == "texture")
                 {
-                    textureFunction.mipmap = TextureFunction::IMPLICIT;
-                    textureFunction.proj = false;
+                    textureFunction.method = TextureFunction::IMPLICIT;
                 }
                 else if (name == "texture2DProj" || name == "textureProj")
                 {
-                    textureFunction.mipmap = TextureFunction::IMPLICIT;
+                    textureFunction.method = TextureFunction::IMPLICIT;
                     textureFunction.proj = true;
                 }
                 else if (name == "texture2DLod" || name == "textureCubeLod" || name == "textureLod")
                 {
-                    textureFunction.mipmap = TextureFunction::LOD;
-                    textureFunction.proj = false;
+                    textureFunction.method = TextureFunction::LOD;
                 }
                 else if (name == "texture2DProjLod" || name == "textureProjLod")
                 {
-                    textureFunction.mipmap = TextureFunction::LOD;
+                    textureFunction.method = TextureFunction::LOD;
                     textureFunction.proj = true;
                 }
+                else if (name == "textureSize")
+                {
+                    textureFunction.method = TextureFunction::SIZE;
+                }
                 else UNREACHABLE();
 
-                if (textureFunction.mipmap != TextureFunction::LOD)
+                if (textureFunction.method != TextureFunction::LOD &&
+                    textureFunction.method != TextureFunction::SIZE)
                 {
                     if (lod0 || mContext.shaderType == SH_VERTEX_SHADER)
                     {
-                        textureFunction.mipmap = TextureFunction::LOD0;
+                        textureFunction.method = TextureFunction::LOD0;
                     }
                     else if (arguments.size() == 3)
                     {
-                        textureFunction.mipmap = TextureFunction::BIAS;
+                        textureFunction.method = TextureFunction::BIAS;
                     }
                 }
 
diff --git a/src/compiler/OutputHLSL.h b/src/compiler/OutputHLSL.h
index b4f68dc..2a3736c 100644
--- a/src/compiler/OutputHLSL.h
+++ b/src/compiler/OutputHLSL.h
@@ -96,18 +96,19 @@
 
     struct TextureFunction
     {
-        enum Mipmap
+        enum Method
         {
-            IMPLICIT,
+            IMPLICIT,   // Mipmap LOD determined implicitly (standard lookup)
             BIAS,
             LOD,
-            LOD0
+            LOD0,
+            SIZE   // textureSize()
         };
 
         TBasicType sampler;
         int coords;
         bool proj;
-        Mipmap mipmap;
+        Method method;
 
         TString name() const;