Determine D3D texture storage size with correct base level
The size of the texture storage is now determined by extrapolating
the level zero texture dimensions from the base level dimensions.
This fixes crashing when images for levels below the base level are
not defined, and also fixes texture storage dimensions being
calculated wrong in case the levels outside the used level range have
dimensions that are inconsistent with the dimensions inside the used
level range.
Checking texture level completeness in TextureD3D is now done based on
the dimensions of the base level, and levels that are outside the base
level to max level range are not taken into account. Textures are
marked incomplete in case their base level is greater than their max
level.
Changing the base level can also affect the size of the storage
required for the texture. Old storage is now discarded when the base
level is changed and the new base level calls for different storage
dimensions.
Code in TextureD3D is refactored so that "base level" actually means
the base level of the texture specified through the GLES API, and
"level zero" is used where TextureD3D would sometimes previously use
"base level".
Changing either the base level or max level can also affect texture
completeness, so invalidate the cached completeness in Texture if
they are changed.
Some of the added tests are still failing on Intel and NVIDIA OpenGL
drivers because of driver bugs. Tests also fail on OSX.
BUG=angleproject:596
TEST=angle_end2end_tests,
dEQP-GLES3.functional.texture.* (no regressions),
dEQP-GLES3.functional.shaders.texture_functions.* (no regressions),
dEQP-GLES3.functional.state_query.texture.* (no regressions)
Change-Id: Icd73d6e29f84a341ed5ff36d5ec5cb2f469cb4e8
Reviewed-on: https://chromium-review.googlesource.com/333352
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 22dfac3..40f2162 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -268,7 +268,7 @@
int testImageChannels = std::min(sourceImageChannels, destImageChannels);
- EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
if (testImageChannels > 1)
{
EXPECT_PIXEL_EQ(getWindowHeight() - 1, 0, 0, 255, 0, 255);
@@ -780,6 +780,60 @@
GLint mTexture1Location;
};
+class Texture3DTestES3 : public TexCoordDrawTest
+{
+ protected:
+ Texture3DTestES3() : TexCoordDrawTest(), mTexture3D(0), mTexture3DUniformLocation(-1) {}
+
+ std::string getVertexShaderSource() override
+ {
+ return std::string(
+ "#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 * 0.5) + 0.5;\n"
+ "}\n");
+ }
+
+ std::string getFragmentShaderSource() override
+ {
+ return std::string(
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "uniform highp sampler3D tex3D;\n"
+ "in vec2 texcoord;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = texture(tex3D, vec3(texcoord, 0.0));\n"
+ "}\n");
+ }
+
+ void SetUp() override
+ {
+ TexCoordDrawTest::SetUp();
+
+ glGenTextures(1, &mTexture3D);
+
+ setUpProgram();
+
+ mTexture3DUniformLocation = glGetUniformLocation(mProgram, "tex3D");
+ ASSERT_NE(-1, mTexture3DUniformLocation);
+ }
+
+ void TearDown() override
+ {
+ glDeleteTextures(1, &mTexture3D);
+ TexCoordDrawTest::TearDown();
+ }
+
+ GLuint mTexture3D;
+ GLint mTexture3DUniformLocation;
+};
+
class ShadowSamplerPlusSampler3DTestES3 : public TexCoordDrawTest
{
protected:
@@ -990,11 +1044,10 @@
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
- GLubyte texDataGreen[1u * 1u * 4u];
- FillWithRGBA<GLubyte>(1u * 1u, 0u, 255u, 0u, 255u, texDataGreen);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataGreen);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ &GLColor::green);
drawQuad(mProgram, "position", 0.5f);
- EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
};
@@ -1232,11 +1285,9 @@
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
- // Fill with red
- std::vector<GLubyte> pixels(4 * 16 * 16);
- FillWithRGBA<GLubyte>(16u * 16u, 255u, 0u, 0u, 255u, pixels.data());
+ std::vector<GLColor> pixelsRed(16u * 16u, GLColor::red);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelsRed.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
@@ -1246,24 +1297,24 @@
glUniform2f(mDrawScaleUniformLocation, 0.0625f, 0.0625f);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
- EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
- // Fill with blue
- FillWithRGBA<GLubyte>(16u * 16u, 0u, 0u, 255u, 255u, pixels.data());
+ std::vector<GLColor> pixelsBlue(16u * 16u, GLColor::blue);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsBlue.data());
glGenerateMipmap(GL_TEXTURE_2D);
- // Fill with green
- FillWithRGBA<GLubyte>(16u * 16u, 0u, 255u, 0u, 255u, pixels.data());
+ std::vector<GLColor> pixelsGreen(16u * 16u, GLColor::green);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsGreen.data());
glGenerateMipmap(GL_TEXTURE_2D);
drawQuad(mProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
- EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
}
// Test creating a FBO with a cube map render target, to test an ANGLE bug
@@ -1598,13 +1649,14 @@
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mTexture2D);
- GLubyte texDataRed[4u * 4u * 4u];
- FillWithRGBA<GLubyte>(4u * 4u, 255u, 0u, 0u, 255u, texDataRed);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed);
- GLubyte texDataGreen[2u * 2u * 4u];
- FillWithRGBA<GLubyte>(2u * 2u, 0u, 255u, 0u, 255u, texDataGreen);
- glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataGreen);
- glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataGreen);
+
+ std::vector<GLColor> texDataRed(4u * 4u, GLColor::red);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed.data());
+ std::vector<GLColor> texDataGreen(2u * 2u, GLColor::green);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+ glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
@@ -1613,7 +1665,527 @@
drawQuad(mProgram, "position", 0.5f);
- EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range do not
+// have images defined.
+TEST_P(Texture2DTestES3, DrawWithLevelsOutsideRangeUndefined)
+{
+ if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ // Observed crashing on AMD. Oddly the crash only happens with 2D textures, not 3D or array.
+ std::cout << "Test skipped on AMD OpenGL." << std::endl;
+ return;
+ }
+ if (IsOSX())
+ {
+ // Observed incorrect rendering on OSX.
+ std::cout << "Test skipped on OSX." << std::endl;
+ return;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+ std::vector<GLColor> texDataGreen(2u * 2u, GLColor::green);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range have
+// dimensions that don't fit the images inside the range.
+// GLES 3.0.4 section 3.8.13 Texture completeness
+TEST_P(Texture2DTestES3, DrawWithLevelsOutsideRangeWithInconsistentDimensions)
+{
+ if (IsOSX())
+ {
+ // Observed incorrect rendering on OSX.
+ std::cout << "Test skipped on OSX." << std::endl;
+ return;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+ std::vector<GLColor> texDataRed(8u * 8u, GLColor::red);
+ std::vector<GLColor> texDataGreen(2u * 2u, GLColor::green);
+ std::vector<GLColor> texDataCyan(2u * 2u, GLColor::cyan);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+ // Two levels that are initially unused.
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDataRed.data());
+ glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataCyan.data());
+
+ // One level that is used - only this level should affect completeness.
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+
+ if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ // Intel was observed drawing color 0,0,0,0 instead of the texture color after the base
+ // level was changed.
+ std::cout << "Test partially skipped on Intel OpenGL." << std::endl;
+ return;
+ }
+
+ // Switch the level that is being used to the cyan level 2.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
+}
+
+// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range do not
+// have images defined.
+TEST_P(Texture3DTestES3, DrawWithLevelsOutsideRangeUndefined)
+{
+ if (IsOSX())
+ {
+ // Observed incorrect rendering on OSX.
+ std::cout << "Test skipped on OSX." << std::endl;
+ return;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_3D, mTexture3D);
+ std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
+ glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 1);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range have
+// dimensions that don't fit the images inside the range.
+// GLES 3.0.4 section 3.8.13 Texture completeness
+TEST_P(Texture3DTestES3, DrawWithLevelsOutsideRangeWithInconsistentDimensions)
+{
+ if (IsOSX())
+ {
+ // Observed incorrect rendering on OSX.
+ std::cout << "Test skipped on OSX." << std::endl;
+ return;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_3D, mTexture3D);
+ std::vector<GLColor> texDataRed(8u * 8u * 8u, GLColor::red);
+ std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
+ std::vector<GLColor> texDataCyan(2u * 2u * 2u, GLColor::cyan);
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+ // Two levels that are initially unused.
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataRed.data());
+ glTexImage3D(GL_TEXTURE_3D, 2, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataCyan.data());
+
+ // One level that is used - only this level should affect completeness.
+ glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 1);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+
+ if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ // Intel was observed drawing color 0,0,0,0 instead of the texture color after the base
+ // level was changed.
+ std::cout << "Test partially skipped on Intel OpenGL." << std::endl;
+ return;
+ }
+
+ // Switch the level that is being used to the cyan level 2.
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 2);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 2);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
+}
+
+// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range do not
+// have images defined.
+TEST_P(Texture2DArrayTestES3, DrawWithLevelsOutsideRangeUndefined)
+{
+ if (IsOSX())
+ {
+ // Observed incorrect rendering on OSX.
+ std::cout << "Test skipped on OSX." << std::endl;
+ return;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+ std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 1);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test that drawing works correctly when levels outside the BASE_LEVEL/MAX_LEVEL range have
+// dimensions that don't fit the images inside the range.
+// GLES 3.0.4 section 3.8.13 Texture completeness
+TEST_P(Texture2DArrayTestES3, DrawWithLevelsOutsideRangeWithInconsistentDimensions)
+{
+ if (IsOSX())
+ {
+ // Observed incorrect rendering on OSX.
+ std::cout << "Test skipped on OSX." << std::endl;
+ return;
+ }
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_3D, m2DArrayTexture);
+ std::vector<GLColor> texDataRed(8u * 8u * 8u, GLColor::red);
+ std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
+ std::vector<GLColor> texDataCyan(2u * 2u * 2u, GLColor::cyan);
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+ // Two levels that are initially unused.
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataRed.data());
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 2, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataCyan.data());
+
+ // One level that is used - only this level should affect completeness.
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 1);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+
+ if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ // Intel was observed drawing color 0,0,0,0 instead of the texture color after the base
+ // level was changed.
+ std::cout << "Test partially skipped on Intel OpenGL." << std::endl;
+ return;
+ }
+ if (IsNVIDIA() && (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE ||
+ getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE))
+ {
+ // NVIDIA was observed drawing color 0,0,0,0 instead of the texture color after the base
+ // level was changed.
+ std::cout << "Test partially skipped on NVIDIA OpenGL." << std::endl;
+ return;
+ }
+
+ // Switch the level that is being used to the cyan level 2.
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 2);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 2);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
+}
+
+// Test that texture completeness is updated if texture max level changes.
+// GLES 3.0.4 section 3.8.13 Texture completeness
+TEST_P(Texture2DTestES3, TextureCompletenessChangesWithMaxLevel)
+{
+ if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ // Intel was observed having wrong behavior after the texture is made incomplete by changing
+ // the base level.
+ std::cout << "Test skipped on Intel OpenGL." << std::endl;
+ return;
+ }
+ if (IsOSX())
+ {
+ // Observed incorrect rendering on OSX.
+ std::cout << "Test skipped on OSX." << std::endl;
+ return;
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+ std::vector<GLColor> texDataGreen(8u * 8u, GLColor::green);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+ // A level that is initially unused.
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+
+ // One level that is initially used - only this level should affect completeness.
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+
+ // Switch the max level to level 1. The levels within the used range now have inconsistent
+ // dimensions and the texture should be incomplete.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
+}
+
+// Test that 3D texture completeness is updated if texture max level changes.
+// GLES 3.0.4 section 3.8.13 Texture completeness
+TEST_P(Texture3DTestES3, Texture3DCompletenessChangesWithMaxLevel)
+{
+ if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ // Intel was observed having wrong behavior after the texture is made incomplete by changing
+ // the base level.
+ std::cout << "Test skipped on Intel OpenGL." << std::endl;
+ return;
+ }
+ if (IsOSX())
+ {
+ // Observed incorrect rendering on OSX.
+ std::cout << "Test skipped on OSX." << std::endl;
+ return;
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_3D, mTexture3D);
+ std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+ // A level that is initially unused.
+ glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+
+ // One level that is initially used - only this level should affect completeness.
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+
+ // Switch the max level to level 1. The levels within the used range now have inconsistent
+ // dimensions and the texture should be incomplete.
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 1);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
+}
+
+// Test that texture completeness is updated if texture base level changes.
+// GLES 3.0.4 section 3.8.13 Texture completeness
+TEST_P(Texture2DTestES3, TextureCompletenessChangesWithBaseLevel)
+{
+ if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ // Intel was observed having wrong behavior after the texture is made incomplete by changing
+ // the base level.
+ std::cout << "Test skipped on Intel OpenGL." << std::endl;
+ return;
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+ std::vector<GLColor> texDataGreen(8u * 8u, GLColor::green);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+ // Two levels that are initially unused.
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+
+ // One level that is initially used - only this level should affect completeness.
+ glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+
+ // Switch the base level to level 1. The levels within the used range now have inconsistent
+ // dimensions and the texture should be incomplete.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
+}
+
+// Test that texture is not complete if base level is greater than max level.
+// GLES 3.0.4 section 3.8.13 Texture completeness
+TEST_P(Texture2DTestES3, TextureBaseLevelGreaterThanMaxLevel)
+{
+ if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ // Intel Windows OpenGL driver crashes if the base level of a non-immutable texture is out
+ // of range.
+ std::cout << "Test skipped on Intel OpenGL." << std::endl;
+ return;
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 10000);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ // Texture should be incomplete.
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
+}
+
+// Test that immutable texture base level and max level are clamped.
+// GLES 3.0.4 section 3.8.10 subsection Mipmapping
+TEST_P(Texture2DTestES3, ImmutableTextureBaseLevelOutOfRange)
+{
+ if (IsOSX())
+ {
+ // Observed incorrect rendering on OSX.
+ std::cout << "Test skipped on OSX." << std::endl;
+ return;
+ }
+ if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ // Observed incorrect rendering on AMD OpenGL.
+ std::cout << "Test skipped on AMD OpenGL." << std::endl;
+ return;
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
+
+ // For immutable-format textures, base level should be clamped to [0, levels - 1], and max level
+ // should be clamped to [base_level, levels - 1].
+ // GLES 3.0.4 section 3.8.10 subsection Mipmapping
+ // In the case of this test, those rules make the effective base level and max level 0.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 10000);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 10000);
+
+ EXPECT_GL_NO_ERROR();
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ // Texture should be complete.
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test that setting a texture image works when base level is out of range.
+TEST_P(Texture2DTestES3, SetImageWhenBaseLevelOutOfRange)
+{
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 10000);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 10000);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
+
+ EXPECT_GL_NO_ERROR();
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+
+ drawQuad(mProgram, "position", 0.5f);
+
+ // Texture should be complete.
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// In the D3D11 renderer, we need to initialize some texture formats, to fill empty channels. EG RBA->RGBA8, with 1.0
@@ -1641,12 +2213,12 @@
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
drawQuad(mProgram, "position", 1.0f);
- EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
// The dimension of the respecification must match the original exactly to trigger the bug.
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 4, 4, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixelData[0]);
drawQuad(mProgram, "position", 1.0f);
- EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
ASSERT_GL_NO_ERROR();
}
@@ -2538,6 +3110,7 @@
ES2_OPENGL(),
ES2_OPENGLES());
ANGLE_INSTANTIATE_TEST(Texture2DTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
+ANGLE_INSTANTIATE_TEST(Texture3DTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(Texture2DIntegerAlpha1TestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(Texture2DUnsignedIntegerAlpha1TestES3,
ES3_D3D11(),