D3D11: Work around compiler nested sampling bug.

We can potentially work around a bug in the HLSL compiler by
omitting the const qualifier from some sampling operations.

BUG=angleproject:1923

Change-Id: I8a5d119707721e9c19f06be4ad808f87bfcdbee5
Reviewed-on: https://chromium-review.googlesource.com/454938
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index ea52305..ccb01aa 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -2670,6 +2670,106 @@
     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
 }
 
+// This test covers a bug (and associated workaround) with nested sampling operations in the HLSL
+// compiler DLL.
+TEST_P(GLSLTest_ES3, NestedSamplingOperation)
+{
+    // This seems to be bugged on some version of Android. Might not affect the newest versions.
+    // TODO(jmadill): Lift suppression when Chromium bots are upgraded.
+    if (IsAndroid() && IsOpenGLES())
+    {
+        std::cout << "Test skipped on Android because of bug with Nexus 5X." << std::endl;
+        return;
+    }
+
+    const std::string &vertexShader =
+        "#version 300 es\n"
+        "out vec2 texCoord;\n"
+        "in vec2 position;\n"
+        "void main()\n"
+        "{\n"
+        "    gl_Position = vec4(position, 0, 1);\n"
+        "    texCoord = position * 0.5 + vec2(0.5);\n"
+        "}\n";
+
+    const std::string &simpleFragmentShader =
+        "#version 300 es\n"
+        "in mediump vec2 texCoord;\n"
+        "out mediump vec4 fragColor;\n"
+        "void main()\n"
+        "{\n"
+        "    fragColor = vec4(texCoord, 0, 1);\n"
+        "}\n";
+
+    const std::string &nestedFragmentShader =
+        "#version 300 es\n"
+        "uniform mediump sampler2D samplerA;\n"
+        "uniform mediump sampler2D samplerB;\n"
+        "in mediump vec2 texCoord;\n"
+        "out mediump vec4 fragColor;\n"
+        "void main ()\n"
+        "{\n"
+        "    fragColor = texture(samplerB, texture(samplerA, texCoord).xy);\n"
+        "}\n";
+
+    ANGLE_GL_PROGRAM(initProg, vertexShader, simpleFragmentShader);
+    ANGLE_GL_PROGRAM(nestedProg, vertexShader, nestedFragmentShader);
+
+    // Initialize a first texture with default texCoord data.
+    GLTexture texA;
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, texA);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
+                 GL_UNSIGNED_BYTE, nullptr);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+    GLFramebuffer fbo;
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texA, 0);
+
+    drawQuad(initProg, "position", 0.5f);
+    ASSERT_GL_NO_ERROR();
+
+    // Initialize a second texture with a simple color pattern.
+    GLTexture texB;
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, texB);
+
+    std::array<GLColor, 4> simpleColors = {
+        {GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                 simpleColors.data());
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+    // Draw with the nested program, using the first texture to index the second.
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    glUseProgram(nestedProg);
+    GLint samplerALoc = glGetUniformLocation(nestedProg, "samplerA");
+    ASSERT_NE(-1, samplerALoc);
+    glUniform1i(samplerALoc, 0);
+    GLint samplerBLoc = glGetUniformLocation(nestedProg, "samplerB");
+    ASSERT_NE(-1, samplerBLoc);
+    glUniform1i(samplerBLoc, 1);
+
+    drawQuad(nestedProg, "position", 0.5f);
+    ASSERT_GL_NO_ERROR();
+
+    // Compute four texel centers.
+    Vector2 windowSize(getWindowWidth(), getWindowHeight());
+    Vector2 quarterWindowSize = windowSize / 4;
+    Vector2 ul                = quarterWindowSize;
+    Vector2 ur(windowSize.x() - quarterWindowSize.x(), quarterWindowSize.y());
+    Vector2 ll(quarterWindowSize.x(), windowSize.y() - quarterWindowSize.y());
+    Vector2 lr = windowSize - quarterWindowSize;
+
+    EXPECT_PIXEL_COLOR_EQ_VEC2(ul, simpleColors[0]);
+    EXPECT_PIXEL_COLOR_EQ_VEC2(ur, simpleColors[1]);
+    EXPECT_PIXEL_COLOR_EQ_VEC2(ll, simpleColors[2]);
+    EXPECT_PIXEL_COLOR_EQ_VEC2(lr, simpleColors[3]);
+}
+
 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
 ANGLE_INSTANTIATE_TEST(GLSLTest,
                        ES2_D3D9(),