Add tests for ES3 TexSubImage format-types Validation errors for TexSubImage calls are similar to TexImage, although with the current texture's internal format replacing the explicit internal format arg. One of the validation conditions is a valid combination of the internal format, format, and type args as per the respective spec, which has been fixed by CL:8008914. This change adds some related test cases. * Added tests to Texture2DTestES3 for texture init and update with various format combinations. Bug: chromium:516824665 Change-Id: I8c71db595a9ba3c898ce8b699d17d86a8d486cd6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/7891751 Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Amirali Abdolrashidi <abdolrashidi@google.com> Reviewed-by: Charlie Lao <cclao@google.com>
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt index 4a82d26..a1f595a 100644 --- a/src/tests/angle_end2end_tests_expectations.txt +++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -303,6 +303,8 @@ 42262474 NVIDIA OPENGL : GLSLTest_ES31.TernaryOnMatricesInDifferentBlockStorages/* = SKIP 42262474 NVIDIA GLES : GLSLTest_ES31.TernaryOnStructsInDifferentBlockStorages/* = SKIP 42262474 NVIDIA GLES : GLSLTest_ES31.TernaryOnMatricesInDifferentBlockStorages/* = SKIP +516824665 WIN NVIDIA GLES : Texture2DTestES3.InvalidFormatTypeCombosShouldFail/* = SKIP +516824665 WIN NVIDIA GLES : Texture2DTestES3.FormatRGB10A2REVToRGB5A1/* = SKIP // Nvidia does not ignore gl_Layer for non-layered framebuffers 374790899 NVIDIA OPENGL : GeometryShaderTest.GLLayerIneffectiveWithoutLayeredFramebuffer/* = SKIP 374790899 NVIDIA GLES : GeometryShaderTest.GLLayerIneffectiveWithoutLayeredFramebuffer/* = SKIP @@ -738,6 +740,8 @@ 519218481 PIXEL4ORXL GLES : MSRTTES3Test.CubeMap/* = SKIP 522247737 PIXEL4ORXL GLES : MSRTTES3Test.DrawDisabled/* = SKIP 522247737 PIXEL4ORXL GLES : MSRTTES3Test.DrawThenDrawDisabled/* = SKIP +516824665 PIXEL4ORXL GLES : Texture2DTestES3.InvalidFormatTypeCombosShouldFail/* = SKIP +516824665 PIXEL4ORXL GLES : Texture2DTestES3.FormatRGB10A2REVToRGB5A1/* = SKIP 526518127 PIXEL4ORXL GLES : ImageTestES3.MipLevelsNonZeroBaseLevel/* = SKIP 526518127 PIXEL4ORXL GLES : ImageTestES3.NonZeroLevel*/* = SKIP @@ -1270,6 +1274,8 @@ 523128541 PIXEL10 GLES : UniformBlockWithOneLargeArrayMemberTest.TwoUniformBlocksInSameProgram/* = SKIP 523128541 PIXEL10 GLES : UniformBufferTest.SameBufferDifferentMetalSize/* = SKIP 526503288 PIXEL10 GLES : BaseInstanceOverflowTest.BaseInstanceOverflow2/ES3_OpenGLES_AlwaysEnableEmulatedMultidrawExtensions = SKIP +516824665 PIXEL10 GLES : Texture2DTestES3.InvalidFormatTypeCombosShouldFail/* = SKIP +516824665 PIXEL10 GLES : Texture2DTestES3.FormatRGB10A2REVToRGB5A1/* = SKIP 525786155 PIXEL10 GLES : PbufferTestES3.ImportImageThenBindTexImageShouldOrphan/* = SKIP 525786155 PIXEL10 GLES : PbufferTestES3.ImportImageThenBindTexImageSourceShouldOrphan/* = SKIP 525786155 PIXEL10 GLES : PbufferTestES3.BindRedefinesAllMips/* = SKIP @@ -2855,6 +2861,8 @@ // Fails test on Metal 499091328 MAC AMD METAL : Texture2DArrayTestES3.ReformatStagedBufferUpdatesLayerCountOOB_2DArray/* = SKIP 512995370 MAC AMD METAL : Texture2DArrayTestES3.ReformatStagedBufferUpdatesLayerCountOOB_3D/* = SKIP +516824665 MAC METAL : Texture2DTestES3.InvalidFormatTypeCombosShouldFail/* = SKIP +516824665 MAC METAL : Texture2DTestES3.FormatRGB10A2REVToRGB5A1/* = SKIP // Timeout on Intel 509829264 VULKAN WIN INTEL : SimpleStateChangeTestES31.TransformFeedbackThenReadWithCompute/* = SKIP
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp index f6a5b2f..7c9df88 100644 --- a/src/tests/gl_tests/TextureTest.cpp +++ b/src/tests/gl_tests/TextureTest.cpp
@@ -3101,6 +3101,247 @@ EXPECT_EQ(expected, actual); } +// Tests updating textures with various internal formats with incompatible format/type combinations, +// which should fail. +TEST_P(Texture2DTestES3, InvalidFormatTypeCombosShouldFail) +{ + glBindTexture(GL_TEXTURE_2D, mTexture2D); + + constexpr size_t kMaxPixelSize = 32; + constexpr size_t kWidth = 4; + constexpr size_t kHeight = 4; + std::vector<uint8_t> data(kMaxPixelSize * kWidth * kHeight, 0xAA); + + const std::vector<GLenum> testFormats = { + GL_RED, + GL_RGBA, + GL_RGB, + GL_ALPHA, + GL_LUMINANCE, + GL_LUMINANCE_ALPHA, + GL_DEPTH_COMPONENT, + GL_DEPTH_STENCIL, + }; + const std::vector<GLenum> testTypes = { + GL_UNSIGNED_BYTE, + GL_UNSIGNED_SHORT, + GL_UNSIGNED_SHORT_5_6_5, + GL_UNSIGNED_SHORT_4_4_4_4, + GL_UNSIGNED_SHORT_5_5_5_1, + GL_FLOAT, + GL_HALF_FLOAT, + GL_UNSIGNED_INT, + GL_UNSIGNED_INT_24_8, + GL_UNSIGNED_INT_2_10_10_10_REV, + }; + + auto combinationTest = [=](GLenum internalformat, + std::vector<std::pair<GLenum, GLenum>> acceptableCombos) { + // Update the texture using various format/type combinations. + for (const GLenum &format : testFormats) + { + for (const GLenum &type : testTypes) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, format, type, data.data()); + + // A failing combination will result in GL_INVALID_OPERATION. If the combination is + // included in the acceptable list, there should be no error. + GLenum err = glGetError(); + std::pair<GLenum, GLenum> testCombo(format, type); + GLenum expectedError = std::find(acceptableCombos.begin(), acceptableCombos.end(), + testCombo) == acceptableCombos.end() + ? GL_INVALID_OPERATION + : GL_NO_ERROR; + EXPECT_TRUE(err == expectedError) + << "Unexpected error code: 0x" << std::hex << err << " | Internalformat: 0x" + << std::hex << internalformat << " | Format: 0x" << std::hex << format + << " | Type: 0x" << std::hex << type; + } + } + }; + + // Test combinations for RGBA8 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForRGBA8 = {{GL_RGBA, GL_UNSIGNED_BYTE}}; + combinationTest(GL_RGBA8, acceptableCombosForRGBA8); + + // Test combinations for RGBA4 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, + nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForRGBA4 = { + {GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, {GL_RGBA, GL_UNSIGNED_BYTE}}; + combinationTest(GL_RGBA4, acceptableCombosForRGBA4); + + // Test combinations for RGB5A1 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, + nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForRGB5A1 = { + {GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, + {GL_RGBA, GL_UNSIGNED_BYTE}, + {GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}}; + combinationTest(GL_RGB5_A1, acceptableCombosForRGB5A1); + + // Test combinations for RGBA16F + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, kWidth, kHeight, 0, GL_RGBA, GL_HALF_FLOAT, nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForRGBA16F = {{GL_RGBA, GL_HALF_FLOAT}, + {GL_RGBA, GL_FLOAT}}; + combinationTest(GL_RGBA16F, acceptableCombosForRGBA16F); + + // Test combinations for RGBA32F + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForRGBA32F = {{GL_RGBA, GL_FLOAT}}; + combinationTest(GL_RGBA32F, acceptableCombosForRGBA32F); + + // Test combinations for RGB8 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kWidth, kHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForRGB8 = {{GL_RGB, GL_UNSIGNED_BYTE}}; + if (IsGLExtensionEnabled("GL_OES_required_internalformat")) + { + acceptableCombosForRGB8.emplace_back( + std::make_pair(GL_RGB, GL_UNSIGNED_INT_2_10_10_10_REV)); + } + combinationTest(GL_RGB8, acceptableCombosForRGB8); + + // Test combinations for RGB565 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kWidth, kHeight, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, + nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForRGB565 = { + {GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, {GL_RGB, GL_UNSIGNED_BYTE}}; + if (IsGLExtensionEnabled("GL_OES_required_internalformat")) + { + acceptableCombosForRGB565.emplace_back( + std::make_pair(GL_RGB, GL_UNSIGNED_INT_2_10_10_10_REV)); + } + combinationTest(GL_RGB565, acceptableCombosForRGB565); + + // Test combinations for LUMINANCE8 + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, kWidth, kHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, + nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForL8 = { + {GL_LUMINANCE, GL_UNSIGNED_BYTE}}; + combinationTest(GL_LUMINANCE8_EXT, acceptableCombosForL8); + + // Test combinations for ALPHA8 + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, kWidth, kHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, + nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForA8 = {{GL_ALPHA, GL_UNSIGNED_BYTE}}; + combinationTest(GL_ALPHA8_EXT, acceptableCombosForA8); + + // Test combinations for R8 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, kWidth, kHeight, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForR8 = {{GL_RED, GL_UNSIGNED_BYTE}}; + combinationTest(GL_R8, acceptableCombosForR8); + + // Test combinations for LUMINANCE8_ALPHA8 + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, kWidth, kHeight, 0, GL_LUMINANCE_ALPHA, + GL_UNSIGNED_BYTE, nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForLA8 = { + {GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE}}; + combinationTest(GL_LUMINANCE8_ALPHA8_EXT, acceptableCombosForLA8); + + // Test combinations for DEPTH_COMPONENT + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, kWidth, kHeight, 0, GL_DEPTH_COMPONENT, + GL_UNSIGNED_SHORT, nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForD16 = { + {GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, {GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}}; + combinationTest(GL_DEPTH_COMPONENT16, acceptableCombosForD16); + + // Test combinations for DEPTH_STENCIL + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL, kWidth, kHeight, 0, GL_DEPTH_STENCIL, + GL_UNSIGNED_INT_24_8, nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForD24S8 = { + {GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}}; + combinationTest(GL_DEPTH24_STENCIL8, acceptableCombosForD24S8); + + // Test combinations for RGB10A2_REV + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, kWidth, kHeight, 0, GL_RGBA, + GL_UNSIGNED_INT_2_10_10_10_REV, nullptr); + ASSERT_GL_NO_ERROR(); + std::vector<std::pair<GLenum, GLenum>> acceptableCombosForRGB10A2REV = { + {GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}}; + combinationTest(GL_UNSIGNED_INT_2_10_10_10_REV, acceptableCombosForRGB10A2REV); +} + +// Tests updating an RGB5A1 texture with bytes. +TEST_P(Texture2DTestES3, FormatBytesToRGB5A1) +{ + 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); + + // Create texture program + ANGLE_GL_PROGRAM(drawTexture, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); + ASSERT_GL_NO_ERROR(); + GLint texLocation = glGetUniformLocation(drawTexture, essl1_shaders::Texture2DUniform()); + ASSERT_NE(-1, texLocation); + glUseProgram(drawTexture); + glUniform1i(texLocation, 0); + + // Create a texture using RGB5A1 + std::vector<uint16_t> colorMagenta(4 * 4, 0xF83F); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, + colorMagenta.data()); + ASSERT_GL_NO_ERROR(); + + drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0.5f); + EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::magenta); + + // Update the texture using bytes + std::vector<GLColor> colorYellow(4 * 4, GLColor::yellow); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, colorYellow.data()); + ASSERT_GL_NO_ERROR(); + + drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0.5f); + EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow); +} + +// Tests updating an RGB5A1 texture with RGB10A2_REV data. +TEST_P(Texture2DTestES3, FormatRGB10A2REVToRGB5A1) +{ + 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); + + // Create texture program + ANGLE_GL_PROGRAM(drawTexture, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); + ASSERT_GL_NO_ERROR(); + GLint texLocation = glGetUniformLocation(drawTexture, essl1_shaders::Texture2DUniform()); + ASSERT_NE(-1, texLocation); + glUseProgram(drawTexture); + glUniform1i(texLocation, 0); + + // Create a texture using RGB5A1 + std::vector<uint16_t> colorMagenta(4 * 4, 0xF83F); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, + colorMagenta.data()); + ASSERT_GL_NO_ERROR(); + + drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0.5f); + EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::magenta); + + // Update the texture using RGB10A2 (REV) + std::vector<uint32_t> colorYellow(4 * 4, 0xC00FFFFF); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, + colorYellow.data()); + ASSERT_GL_NO_ERROR(); + + drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0.5f); + EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow); +} + // Regression test for TextureMtl::mFormat becoming mismatched with the native storage format when // updating mips outside of the storage. TEST_P(Texture2DTestES3, StaleFormatCacheOutOrRangeMip)