Fix integer cube map sample HLSL calculation
This patch fixes two issues in the HLSL generated to sample an integer cube map.
The first issue was that an inappropriate major axis was selected when sampling
from corners of the cube map. In particular, the added test case demonstrates a
situation where a major axis of length 0 was selected, which lead to an infinite
LOD being calculated. The fix was to adjust inequalities such that always
exactly one of xMajor, yMajor and zMajor is true.
The second issue was that the derivative functions ddx and ddy were being used
on values that depended on the choice of major axis, which is not continuous at
the corners of a cube map. This lead to a finite but incorrect LOD being
calculated. The fix was to make sure major axis choice is not included when
estimating the scaling factor.
Bug: angleproject:3442
Change-Id: Ia3eb8c89f47d1bfdadc18aec989e8cbebc088ec0
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1601515
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index f57be09..e747bf8 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -1231,6 +1231,38 @@
GLint mTextureCubeUniformLocation;
};
+class TextureCubeIntegerEdgeTestES3 : public TextureCubeIntegerTestES3
+{
+ protected:
+ TextureCubeIntegerEdgeTestES3() : TextureCubeIntegerTestES3() {}
+
+ const char *getVertexShaderSource() override
+ {
+ return "#version 300 es\n"
+ "out vec2 texcoord;\n"
+ "in vec4 position;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
+ " texcoord = position.xy;\n"
+ "}\n";
+ }
+
+ const char *getFragmentShaderSource() override
+ {
+ return "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp usamplerCube;\n"
+ "uniform usamplerCube texCube;\n"
+ "in vec2 texcoord;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = vec4(texture(texCube, vec3(texcoord, 0)))/255.0;\n"
+ "}\n";
+ }
+};
+
TEST_P(Texture2DTest, NegativeAPISubImage)
{
glBindTexture(GL_TEXTURE_2D, mTexture2D);
@@ -4581,6 +4613,46 @@
EXPECT_PIXEL_COLOR_EQ(width - 1, height - 1, color);
}
+// This test sets up a cube map with four distincly colored MIP levels.
+// The size of the texture and the geometry is chosen such that levels 1 or 2 should be chosen at
+// the corners of the screen.
+TEST_P(TextureCubeIntegerEdgeTestES3, IntegerCubeTextureCorner)
+{
+ glActiveTexture(GL_TEXTURE0);
+
+ glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
+ int width = getWindowWidth();
+ int height = getWindowHeight();
+ ASSERT_EQ(width, height);
+ GLColor color[4] = {GLColor::white, GLColor::green, GLColor::blue, GLColor::red};
+ for (GLint level = 0; level < 4; level++)
+ {
+ for (GLenum faceIndex = 0; faceIndex < 6; faceIndex++)
+ {
+ int levelWidth = (2 * width) >> level;
+ int levelHeight = (2 * height) >> level;
+ std::vector<GLColor> pixels(levelWidth * levelHeight, color[level]);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, GL_RGBA8UI, levelWidth,
+ levelHeight, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, pixels.data());
+ EXPECT_GL_NO_ERROR();
+ }
+ }
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 3);
+
+ glUseProgram(mProgram);
+ glUniform1i(mTextureCubeUniformLocation, 0);
+ drawQuad(mProgram, "position", 0.5f);
+
+ ASSERT_GL_NO_ERROR();
+ // Check that we do not read from levels 0 or 3. Levels 1 and 2 are both acceptable.
+ EXPECT_EQ(ReadColor(0, 0).R, 0);
+ EXPECT_EQ(ReadColor(width - 1, 0).R, 0);
+ EXPECT_EQ(ReadColor(0, height - 1).R, 0);
+ EXPECT_EQ(ReadColor(width - 1, height - 1).R, 0);
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(Texture2DTest,
@@ -4682,5 +4754,6 @@
ANGLE_INSTANTIATE_TEST(TextureCubeTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(Texture2DIntegerTestES3, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(TextureCubeIntegerTestES3, ES3_D3D11(), ES3_OPENGL());
+ANGLE_INSTANTIATE_TEST(TextureCubeIntegerEdgeTestES3, ES3_D3D11(), ES3_OPENGL());
} // anonymous namespace