| // |
| // Copyright 2016 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // CopyCompressedTextureTest.cpp: Tests of the GL_CHROMIUM_copy_compressed_texture extension |
| |
| #include "test_utils/ANGLETest.h" |
| |
| namespace angle |
| { |
| |
| class CopyCompressedTextureTest : public ANGLETest |
| { |
| protected: |
| CopyCompressedTextureTest() |
| { |
| setWindowWidth(256); |
| setWindowHeight(256); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| } |
| |
| void testSetUp() override |
| { |
| glGenTextures(2, mTextures); |
| |
| constexpr char kVS[] = |
| "attribute vec2 a_position;\n" |
| "varying vec2 v_texcoord;\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(a_position, 0.0, 1.0);\n" |
| " v_texcoord = (a_position + 1.0) * 0.5;\n" |
| "}\n"; |
| |
| constexpr char kFS[] = |
| "precision mediump float;\n" |
| "uniform sampler2D u_texture;\n" |
| "varying vec2 v_texcoord;\n" |
| "void main()\n" |
| "{\n" |
| " gl_FragColor = texture2D(u_texture, v_texcoord);\n" |
| "}\n"; |
| |
| mProgram = CompileProgram(kVS, kFS); |
| ASSERT_NE(0u, mProgram); |
| } |
| |
| void testTearDown() override |
| { |
| glDeleteTextures(2, mTextures); |
| glDeleteProgram(mProgram); |
| } |
| |
| bool checkExtensions() const |
| { |
| if (!IsGLExtensionEnabled("GL_CHROMIUM_copy_compressed_texture")) |
| { |
| std::cout |
| << "Test skipped because GL_CHROMIUM_copy_compressed_texture is not available." |
| << std::endl; |
| return false; |
| } |
| |
| EXPECT_NE(nullptr, glCompressedCopyTextureCHROMIUM); |
| if (glCompressedCopyTextureCHROMIUM == nullptr) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| GLuint mProgram = 0; |
| GLuint mTextures[2] = {0, 0}; |
| }; |
| |
| namespace |
| { |
| |
| const GLColor &CompressedImageColor = GLColor::red; |
| |
| // Single compressed ATC block of source pixels all set to: |
| // CompressedImageColor. |
| const uint8_t CompressedImageATC[8] = {0x0, 0x7c, 0x0, 0xf8, 0x55, 0x55, 0x55, 0x55}; |
| |
| // Single compressed ATCIA block of source pixels all set to: |
| // CompressedImageColor. |
| const uint8_t CompressedImageATCIA[16] = {0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
| 0x0, 0x7c, 0x0, 0xf8, 0x55, 0x55, 0x55, 0x55}; |
| |
| // Single compressed DXT1 block of source pixels all set to: |
| // CompressedImageColor. |
| const uint8_t CompressedImageDXT1[8] = {0x00, 0xf8, 0x00, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa}; |
| |
| // Single compressed DXT5 block of source pixels all set to: |
| // CompressedImageColor. |
| const uint8_t CompressedImageDXT5[16] = {0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
| 0x0, 0xf8, 0x0, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa}; |
| |
| // Single compressed DXT1 block of source pixels all set to: |
| // CompressedImageColor. |
| const uint8_t CompressedImageETC1[8] = {0x0, 0x0, 0xf8, 0x2, 0xff, 0xff, 0x0, 0x0}; |
| |
| } // anonymous namespace |
| |
| // Test to ensure that the basic functionality of the extension works. |
| TEST_P(CopyCompressedTextureTest, Basic) |
| { |
| ANGLE_SKIP_TEST_IF(!checkExtensions()); |
| |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1")); |
| |
| glBindTexture(GL_TEXTURE_2D, mTextures[0]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, |
| sizeof(CompressedImageDXT1), CompressedImageDXT1); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindTexture(GL_TEXTURE_2D, mTextures[1]); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Load texture. |
| glActiveTexture(GL_TEXTURE0); |
| glBindTexture(GL_TEXTURE_2D, mTextures[1]); |
| GLint textureLoc = glGetUniformLocation(mProgram, "u_texture"); |
| glUseProgram(mProgram); |
| glUniform1i(textureLoc, 0); |
| |
| // Draw. |
| drawQuad(mProgram, "a_position", 0.5f); |
| |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, CompressedImageColor); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| // Test validation of compressed formats |
| TEST_P(CopyCompressedTextureTest, InternalFormat) |
| { |
| if (!checkExtensions()) |
| { |
| return; |
| } |
| |
| struct Data |
| { |
| GLint format; |
| const uint8_t *data; |
| GLsizei dataSize; |
| |
| Data() : Data(GL_NONE, nullptr, 0) {} |
| Data(GLint format, const uint8_t *data, GLsizei dataSize) |
| : format(format), data(data), dataSize(dataSize) |
| {} |
| }; |
| std::vector<Data> supportedFormats; |
| |
| if (IsGLExtensionEnabled("GL_AMD_compressed_ATC_texture")) |
| { |
| supportedFormats.push_back( |
| Data(GL_ATC_RGB_AMD, CompressedImageATC, sizeof(CompressedImageATC))); |
| supportedFormats.push_back(Data(GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, CompressedImageATCIA, |
| sizeof(CompressedImageATCIA))); |
| } |
| if (IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1")) |
| { |
| supportedFormats.push_back(Data(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, CompressedImageDXT1, |
| sizeof(CompressedImageDXT1))); |
| } |
| if (IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt5")) |
| { |
| supportedFormats.push_back(Data(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, CompressedImageDXT5, |
| sizeof(CompressedImageDXT5))); |
| } |
| if (IsGLExtensionEnabled("GL_OES_compressed_ETC1_RGB8_texture")) |
| { |
| supportedFormats.push_back( |
| Data(GL_ETC1_RGB8_OES, CompressedImageETC1, sizeof(CompressedImageETC1))); |
| } |
| |
| for (const auto &supportedFormat : supportedFormats) |
| { |
| glBindTexture(GL_TEXTURE_2D, mTextures[0]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, supportedFormat.format, 4, 4, 0, |
| supportedFormat.dataSize, supportedFormat.data); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindTexture(GL_TEXTURE_2D, mTextures[1]); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]); |
| ASSERT_GL_NO_ERROR(); |
| } |
| } |
| |
| // Test that uncompressed textures generate errors when copying |
| TEST_P(CopyCompressedTextureTest, InternalFormatNotSupported) |
| { |
| if (!checkExtensions()) |
| { |
| return; |
| } |
| |
| glBindTexture(GL_TEXTURE_2D, mTextures[0]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindTexture(GL_TEXTURE_2D, mTextures[1]); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| // Check that the GL_RGBA format reports an error. |
| glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| // Test validation of texture IDs |
| TEST_P(CopyCompressedTextureTest, InvalidTextureIds) |
| { |
| if (!checkExtensions()) |
| { |
| return; |
| } |
| |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1")); |
| |
| glBindTexture(GL_TEXTURE_2D, mTextures[0]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, |
| sizeof(CompressedImageDXT1), CompressedImageDXT1); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindTexture(GL_TEXTURE_2D, mTextures[1]); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| glCompressedCopyTextureCHROMIUM(mTextures[0], 99993); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| glCompressedCopyTextureCHROMIUM(99994, mTextures[1]); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| glCompressedCopyTextureCHROMIUM(99995, 99996); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| |
| glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]); |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Test that only 2D textures are valid |
| TEST_P(CopyCompressedTextureTest, BindingPoints) |
| { |
| if (!checkExtensions()) |
| { |
| return; |
| } |
| |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1")); |
| |
| glBindTexture(GL_TEXTURE_CUBE_MAP, mTextures[0]); |
| glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; |
| face++) |
| { |
| glCompressedTexImage2D(face, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, |
| sizeof(CompressedImageDXT1), CompressedImageDXT1); |
| } |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindTexture(GL_TEXTURE_CUBE_MAP, mTextures[1]); |
| glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]); |
| EXPECT_GL_ERROR(GL_INVALID_VALUE); |
| } |
| |
| // Test the destination texture cannot be immutable |
| TEST_P(CopyCompressedTextureTest, Immutable) |
| { |
| if (!checkExtensions() || getClientMajorVersion() < 3) |
| { |
| return; |
| } |
| // http://anglebug.com/4092 |
| ANGLE_SKIP_TEST_IF((IsAndroid() && IsVulkan()) || isSwiftshader()); |
| |
| glBindTexture(GL_TEXTURE_2D, mTextures[0]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, |
| sizeof(CompressedImageDXT1), CompressedImageDXT1); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindTexture(GL_TEXTURE_2D, mTextures[1]); |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| ASSERT_GL_NO_ERROR(); |
| |
| glCompressedCopyTextureCHROMIUM(mTextures[0], mTextures[1]); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| // Use this to select which configurations (e.g. which renderer, which GLES major version) these |
| // tests should be run against. |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(CopyCompressedTextureTest); |
| |
| } // namespace angle |