Implementing gl_InstanceID in the HLSL compiler.

Fixes:
dEQP-GLES3.functional.instanced.draw_arrays_instanced.instance_id
dEQP-GLES3.functional.instanced.draw_arrays_instanced.mixed
dEQP-GLES3.functional.instanced.draw_elements_instanced.instance_id
dEQP-GLES3.functional.instanced.draw_elements_instanced.mixed

BUG=angle:601

Change-Id: I6e120eebc90d00e025fc58f096064e6ed1da826b
Reviewed-on: https://chromium-review.googlesource.com/246911
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Gregoire Payen de La Garanderie <Gregory.Payen@imgtec.com>
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
diff --git a/src/compiler/translator/BaseTypes.h b/src/compiler/translator/BaseTypes.h
index 0872df5..fd09d7d 100644
--- a/src/compiler/translator/BaseTypes.h
+++ b/src/compiler/translator/BaseTypes.h
@@ -298,6 +298,9 @@
     EvqInOut,
     EvqConstReadOnly,
 
+    // built-ins read by vertex shader
+    EvqInstanceID,
+
     // built-ins written by vertex shader
     EvqPosition,
     EvqPointSize,
@@ -392,6 +395,7 @@
     case EvqIn:             return "in";             break;
     case EvqOut:            return "out";            break;
     case EvqInOut:          return "inout";          break;
+    case EvqInstanceID:     return "InstanceID";     break;
     case EvqPosition:       return "Position";       break;
     case EvqPointSize:      return "PointSize";      break;
     case EvqFragCoord:      return "FragCoord";      break;
diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp
index 9f94cb9..59b617c 100644
--- a/src/compiler/translator/Initialize.cpp
+++ b/src/compiler/translator/Initialize.cpp
@@ -745,6 +745,7 @@
     case GL_VERTEX_SHADER:
         symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition,    4)));
         symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize,   1)));
+        symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_InstanceID"), TType(EbtInt, EbpHigh, EvqInstanceID,   1)));
         break;
 
     default: assert(false && "Language not supported");
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 065719b..44d348a 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -110,6 +110,7 @@
     mUsesPointCoord = false;
     mUsesFrontFacing = false;
     mUsesPointSize = false;
+    mUsesInstanceID = false;
     mUsesFragDepth = false;
     mUsesXor = false;
     mUsesDiscardRewriting = false;
@@ -498,6 +499,11 @@
             out << "static float gl_PointSize = float(1);\n";
         }
 
+        if (mUsesInstanceID)
+        {
+            out << "static int gl_InstanceID;";
+        }
+
         out << "\n"
                "// Varyings\n";
         out <<  varyings;
@@ -1305,6 +1311,11 @@
             mUsesPointSize = true;
             out << name;
         }
+        else if (qualifier == EvqInstanceID)
+        {
+            mUsesInstanceID = true;
+            out << name;
+        }
         else if (name == "gl_FragDepthEXT")
         {
             mUsesFragDepth = true;
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index b6e9db6..dec421c 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -132,6 +132,7 @@
     bool mUsesPointCoord;
     bool mUsesFrontFacing;
     bool mUsesPointSize;
+    bool mUsesInstanceID;
     bool mUsesFragDepth;
     bool mUsesXor;
     bool mUsesDiscardRewriting;
diff --git a/src/compiler/translator/VariableInfo.cpp b/src/compiler/translator/VariableInfo.cpp
index 67b7c8c..b9cf3a4 100644
--- a/src/compiler/translator/VariableInfo.cpp
+++ b/src/compiler/translator/VariableInfo.cpp
@@ -142,6 +142,7 @@
       mPointCoordAdded(false),
       mFrontFacingAdded(false),
       mFragCoordAdded(false),
+      mInstanceIDAdded(false),
       mPositionAdded(false),
       mPointSizeAdded(false),
       mLastFragDataAdded(false),
@@ -250,6 +251,22 @@
                 mPointCoordAdded = true;
             }
             return;
+          case EvqInstanceID:
+            if (!mInstanceIDAdded)
+            {
+                Attribute info;
+                const char kName[] = "gl_InstanceID";
+                info.name = kName;
+                info.mappedName = kName;
+                info.type = GL_INT;
+                info.arraySize = 0;
+                info.precision = GL_HIGH_INT;  // Defined by spec.
+                info.staticUse = true;
+                info.location = -1;
+                mAttribs->push_back(info);
+                mInstanceIDAdded = true;
+            }
+            return;
           case EvqPosition:
             if (!mPositionAdded)
             {
diff --git a/src/compiler/translator/VariableInfo.h b/src/compiler/translator/VariableInfo.h
index b0e0455..bb1328a 100644
--- a/src/compiler/translator/VariableInfo.h
+++ b/src/compiler/translator/VariableInfo.h
@@ -51,6 +51,7 @@
     bool mFrontFacingAdded;
     bool mFragCoordAdded;
 
+    bool mInstanceIDAdded;
     bool mPositionAdded;
     bool mPointSizeAdded;
     bool mLastFragDataAdded;
diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
index afe3eab..5f75902 100644
--- a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -392,11 +392,31 @@
             else
             {
                 GLenum componentType = mRenderer->getVertexComponentType(vertexFormat);
-                structHLSL += "    " + HLSLComponentTypeString(componentType, VariableComponentCount(shaderAttribute.type));
+
+                if (shaderAttribute.name == "gl_InstanceID")
+                {
+                    // The input type of the instance ID in HLSL (uint) differs from the one in ESSL (int).
+                    structHLSL += " uint";
+                }
+                else
+                {
+                    structHLSL += "    " + HLSLComponentTypeString(componentType, VariableComponentCount(shaderAttribute.type));
+                }
             }
 
-            structHLSL += " " + decorateVariable(shaderAttribute.name) + " : TEXCOORD" + Str(semanticIndex) + ";\n";
-            semanticIndex += VariableRegisterCount(shaderAttribute.type);
+            structHLSL += " " + decorateVariable(shaderAttribute.name) + " : ";
+
+            if (shaderAttribute.name == "gl_InstanceID")
+            {
+                structHLSL += "SV_InstanceID";
+            }
+            else
+            {
+                structHLSL += "TEXCOORD" + Str(semanticIndex);
+                semanticIndex += VariableRegisterCount(shaderAttribute.type);
+            }
+
+            structHLSL += ";\n";
 
             // HLSL code for initialization
             initHLSL += "    " + decorateVariable(shaderAttribute.name) + " = ";
diff --git a/tests/angle_tests/GLSLTest.cpp b/tests/angle_tests/GLSLTest.cpp
index 1277576..9178e1b 100644
--- a/tests/angle_tests/GLSLTest.cpp
+++ b/tests/angle_tests/GLSLTest.cpp
@@ -258,6 +258,14 @@
     std::string mSimpleVSSource;
 };
 
+// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
+ANGLE_TYPED_TEST_CASE(GLSLTest_ES3, ES3_D3D11);
+
+template<typename T>
+class GLSLTest_ES3 : public GLSLTest<T>
+{
+};
+
 TYPED_TEST(GLSLTest, NamelessScopedStructs)
 {
     const std::string fragmentShaderSource = SHADER_SOURCE
@@ -905,3 +913,61 @@
     ASSERT_GL_NO_ERROR();
     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
 }
+
+// Tests that using a global static initialized from gl_InstanceID works as expected.
+TYPED_TEST(GLSLTest_ES3, GlobalStaticAndInstanceID)
+{
+    const std::string &vertexShaderSource =
+        "#version 300 es\n"
+        "precision highp float;\n"
+        "in vec4 a_position;\n"
+        "out vec4 vColour;"
+        "int x = gl_InstanceID;"
+        "int global_v = x;"
+        "void main() {\n"
+        "  gl_Position = a_position;\n"
+        "  vColour = vec4(float(global_v)/255., 0.0, 0.0, 1.0);\n"
+        "}\n";
+
+    const std::string &fragmentShaderSource =
+        "#version 300 es\n"
+        "precision highp float;\n"
+        "in vec4 vColour;"
+        "out vec4 colour;"
+        "void main() {\n"
+        "  colour = vColour;\n"
+        "}\n";
+
+    GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+    ASSERT_NE(0u, program);
+
+    GLint positionLocation = glGetAttribLocation(program, "a_position");
+
+    glUseProgram(program);
+
+    const GLfloat vertices[] =
+    {
+        -1.0f,  1.0f, 0.5f,
+        -1.0f, -1.0f, 0.5f,
+         1.0f, -1.0f, 0.5f,
+
+        -1.0f,  1.0f, 0.5f,
+         1.0f, -1.0f, 0.5f,
+         1.0f,  1.0f, 0.5f,
+    };
+
+    glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, vertices);
+    glEnableVertexAttribArray(positionLocation);
+
+    glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 7);
+
+    glDisableVertexAttribArray(positionLocation);
+    glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
+
+    glUseProgram(0);
+
+    swapBuffers();
+
+    ASSERT_GL_NO_ERROR();
+    EXPECT_PIXEL_EQ(0, 0, 6, 0, 0, 255);
+}