| // | |
| // Copyright 2018 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. | |
| // | |
| // BPTCCompressedTextureTest.cpp: Tests of the GL_EXT_texture_compression_bptc extension | |
| #include "test_utils/ANGLETest.h" | |
| #include "test_utils/gl_raii.h" | |
| using namespace angle; | |
| namespace | |
| { | |
| const unsigned int kPixelTolerance = 1u; | |
| // The pixel data represents a 4x4 pixel image with the left side colored red and the right side | |
| // green. It was BC7 encoded using Microsoft's BC6HBC7Encoder. | |
| const std::array<GLubyte, 16> kBC7Data4x4 = {0x50, 0x1f, 0xfc, 0xf, 0x0, 0xf0, 0xe3, 0xe1, | |
| 0xe1, 0xe1, 0xc1, 0xf, 0xfc, 0xc0, 0xf, 0xfc}; | |
| } // anonymous namespace | |
| class BPTCCompressedTextureTest : public ANGLETest | |
| { | |
| protected: | |
| BPTCCompressedTextureTest() | |
| { | |
| setWindowWidth(128); | |
| setWindowHeight(128); | |
| setConfigRedBits(8); | |
| setConfigGreenBits(8); | |
| setConfigBlueBits(8); | |
| setConfigAlphaBits(8); | |
| } | |
| void testSetUp() override | |
| { | |
| constexpr char kVS[] = R"(precision highp float; | |
| attribute vec4 position; | |
| varying vec2 texcoord; | |
| void main() | |
| { | |
| gl_Position = position; | |
| texcoord = (position.xy * 0.5) + 0.5; | |
| texcoord.y = 1.0 - texcoord.y; | |
| })"; | |
| constexpr char kFS[] = R"(precision highp float; | |
| uniform sampler2D tex; | |
| varying vec2 texcoord; | |
| void main() | |
| { | |
| gl_FragColor = texture2D(tex, texcoord); | |
| })"; | |
| mTextureProgram = CompileProgram(kVS, kFS); | |
| if (mTextureProgram == 0) | |
| { | |
| FAIL() << "shader compilation failed."; | |
| } | |
| mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex"); | |
| ASSERT_GL_NO_ERROR(); | |
| } | |
| void testTearDown() override { glDeleteProgram(mTextureProgram); } | |
| void setupTextureParameters(GLuint texture) | |
| { | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| } | |
| void drawTexture() | |
| { | |
| glUseProgram(mTextureProgram); | |
| glUniform1i(mTextureUniformLocation, 0); | |
| drawQuad(mTextureProgram, "position", 0.5f); | |
| EXPECT_GL_NO_ERROR(); | |
| } | |
| GLuint mTextureProgram; | |
| GLint mTextureUniformLocation; | |
| }; | |
| class BPTCCompressedTextureTestES3 : public BPTCCompressedTextureTest | |
| { | |
| public: | |
| BPTCCompressedTextureTestES3() : BPTCCompressedTextureTest() {} | |
| }; | |
| // Test sampling from a BC7 non-SRGB image. | |
| TEST_P(BPTCCompressedTextureTest, CompressedTexImageBC7) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| GLTexture texture; | |
| setupTextureParameters(texture); | |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, 4, 4, 0, | |
| kBC7Data4x4.size(), kBC7Data4x4.data()); | |
| EXPECT_GL_NO_ERROR(); | |
| drawTexture(); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::red, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(0, getWindowHeight() - 1, GLColor::red, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() - 1, 0, GLColor::green, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::green, | |
| kPixelTolerance); | |
| } | |
| // Test sampling from a BC7 SRGB image. | |
| TEST_P(BPTCCompressedTextureTest, CompressedTexImageBC7SRGB) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| GLTexture texture; | |
| setupTextureParameters(texture); | |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT, 4, 4, 0, | |
| kBC7Data4x4.size(), kBC7Data4x4.data()); | |
| EXPECT_GL_NO_ERROR(); | |
| drawTexture(); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::red, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(0, getWindowHeight() - 1, GLColor::red, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() - 1, 0, GLColor::green, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::green, | |
| kPixelTolerance); | |
| } | |
| // Test that using the BC6H floating point formats doesn't crash. | |
| TEST_P(BPTCCompressedTextureTest, CompressedTexImageBC6HNoCrash) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| GLTexture texture; | |
| setupTextureParameters(texture); | |
| // This dummy pixel data represents a 4x4 pixel image. | |
| // TODO(http://anglebug.com/2869): Add pixel tests for these formats. These need HDR source | |
| // images. | |
| std::vector<GLubyte> data; | |
| data.resize(16u, 0u); | |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, 4, 4, 0, | |
| data.size(), data.data()); | |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT, 4, 4, 0, | |
| data.size(), data.data()); | |
| EXPECT_GL_NO_ERROR(); | |
| drawTexture(); | |
| } | |
| // Test texStorage2D with a BPTC format. | |
| TEST_P(BPTCCompressedTextureTestES3, CompressedTexStorage) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); | |
| GLTexture texture; | |
| setupTextureParameters(texture); | |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, 4, 4); | |
| EXPECT_GL_NO_ERROR(); | |
| glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, | |
| kBC7Data4x4.size(), kBC7Data4x4.data()); | |
| EXPECT_GL_NO_ERROR(); | |
| drawTexture(); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::red, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(0, getWindowHeight() - 1, GLColor::red, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() - 1, 0, GLColor::green, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::green, | |
| kPixelTolerance); | |
| } | |
| // Test validation of glCompressedTexSubImage2D with BPTC formats | |
| TEST_P(BPTCCompressedTextureTest, CompressedTexSubImageValidation) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| GLTexture texture; | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| std::vector<GLubyte> data(16 * 2 * 2); // 2x2 blocks, thats 8x8 pixels. | |
| // Size mip 0 to a large size. | |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, 8, 8, 0, | |
| data.size(), data.data()); | |
| ASSERT_GL_NO_ERROR(); | |
| // Test a sub image with an offset that isn't a multiple of the block size. | |
| glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 1, 0, 4, 4, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, | |
| kBC7Data4x4.size(), kBC7Data4x4.data()); | |
| ASSERT_GL_ERROR(GL_INVALID_OPERATION); | |
| glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 3, 4, 4, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, | |
| kBC7Data4x4.size(), kBC7Data4x4.data()); | |
| ASSERT_GL_ERROR(GL_INVALID_OPERATION); | |
| // Test a sub image with a negative offset. | |
| glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, -1, 0, 4, 4, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, | |
| kBC7Data4x4.size(), kBC7Data4x4.data()); | |
| ASSERT_GL_ERROR(GL_INVALID_VALUE); | |
| glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, -1, 4, 4, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, | |
| kBC7Data4x4.size(), kBC7Data4x4.data()); | |
| ASSERT_GL_ERROR(GL_INVALID_VALUE); | |
| } | |
| // Test that copying BPTC textures is not allowed. This restriction exists only in | |
| // EXT_texture_compression_bptc, and not in the ARB variant. | |
| TEST_P(BPTCCompressedTextureTest, CopyTexImage2DDisallowed) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| GLTexture texture; | |
| setupTextureParameters(texture); | |
| glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, 0, 0, 4, 4, 0); | |
| ASSERT_GL_ERROR(GL_INVALID_OPERATION); | |
| } | |
| // Test that copying BPTC textures is not allowed. This restriction exists only in | |
| // EXT_texture_compression_bptc, and not in the ARB variant. | |
| TEST_P(BPTCCompressedTextureTest, CopyTexSubImage2DDisallowed) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| GLTexture texture; | |
| setupTextureParameters(texture); | |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, 4, 4, 0, | |
| kBC7Data4x4.size(), kBC7Data4x4.data()); | |
| ASSERT_GL_NO_ERROR(); | |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 4, 4); | |
| ASSERT_GL_ERROR(GL_INVALID_OPERATION); | |
| } | |
| // Test that copying BPTC textures is not allowed. This restriction exists only in | |
| // EXT_texture_compression_bptc, and not in the ARB variant. | |
| TEST_P(BPTCCompressedTextureTestES3, CopyTexSubImage3DDisallowed) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| GLTexture texture; | |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture); | |
| glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, 4, 4, 1); | |
| ASSERT_GL_NO_ERROR(); | |
| glCopyTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 0, 0, 4, 4); | |
| ASSERT_GL_ERROR(GL_INVALID_OPERATION); | |
| } | |
| // Test uploading texture data from a PBO to a texture. | |
| TEST_P(BPTCCompressedTextureTestES3, PBOCompressedTexImage) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| GLTexture texture; | |
| setupTextureParameters(texture); | |
| GLBuffer buffer; | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer); | |
| glBufferData(GL_PIXEL_UNPACK_BUFFER, kBC7Data4x4.size(), kBC7Data4x4.data(), GL_STREAM_DRAW); | |
| ASSERT_GL_NO_ERROR(); | |
| glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, 4, 4, 0, | |
| kBC7Data4x4.size(), nullptr); | |
| ASSERT_GL_NO_ERROR(); | |
| drawTexture(); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::red, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(0, getWindowHeight() - 1, GLColor::red, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() - 1, 0, GLColor::green, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::green, | |
| kPixelTolerance); | |
| } | |
| // Test uploading texture data from a PBO to a texture allocated with texStorage2D. | |
| TEST_P(BPTCCompressedTextureTestES3, PBOCompressedTexStorage) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| GLTexture texture; | |
| setupTextureParameters(texture); | |
| glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, 4, 4); | |
| ASSERT_GL_NO_ERROR(); | |
| GLBuffer buffer; | |
| glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer); | |
| glBufferData(GL_PIXEL_UNPACK_BUFFER, kBC7Data4x4.size(), kBC7Data4x4.data(), GL_STREAM_DRAW); | |
| ASSERT_GL_NO_ERROR(); | |
| glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, | |
| kBC7Data4x4.size(), nullptr); | |
| ASSERT_GL_NO_ERROR(); | |
| drawTexture(); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::red, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(0, getWindowHeight() - 1, GLColor::red, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() - 1, 0, GLColor::green, kPixelTolerance); | |
| EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::green, | |
| kPixelTolerance); | |
| } | |
| // Test validation of glCompressedTexSubImage3D with BPTC formats | |
| TEST_P(BPTCCompressedTextureTestES3, CompressedTexSubImage3DValidation) | |
| { | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_bptc")); | |
| GLTexture texture; | |
| glBindTexture(GL_TEXTURE_2D_ARRAY, texture.get()); | |
| std::vector<GLubyte> data(16 * 2 * 2); // 2x2x1 blocks, thats 8x8x1 pixels. | |
| // Size mip 0 to a large size. | |
| glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, 8, 8, 1, 0, | |
| data.size(), data.data()); | |
| ASSERT_GL_NO_ERROR(); | |
| // Test a sub image with an offset that isn't a multiple of the block size. | |
| glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 2, 0, 0, 4, 4, 1, | |
| GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, kBC7Data4x4.size(), | |
| kBC7Data4x4.data()); | |
| ASSERT_GL_ERROR(GL_INVALID_OPERATION); | |
| glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 2, 0, 4, 4, 1, | |
| GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, kBC7Data4x4.size(), | |
| kBC7Data4x4.data()); | |
| ASSERT_GL_ERROR(GL_INVALID_OPERATION); | |
| // Test a sub image with a negative offset. | |
| glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, -1, 0, 0, 4, 4, 1, | |
| GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, kBC7Data4x4.size(), | |
| kBC7Data4x4.data()); | |
| ASSERT_GL_ERROR(GL_INVALID_VALUE); | |
| glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, -1, 0, 4, 4, 1, | |
| GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, kBC7Data4x4.size(), | |
| kBC7Data4x4.data()); | |
| ASSERT_GL_ERROR(GL_INVALID_VALUE); | |
| glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, -1, 4, 4, 1, | |
| GL_COMPRESSED_RGBA_BPTC_UNORM_EXT, kBC7Data4x4.size(), | |
| kBC7Data4x4.data()); | |
| ASSERT_GL_ERROR(GL_INVALID_VALUE); | |
| } | |
| // 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(BPTCCompressedTextureTest); | |
| ANGLE_INSTANTIATE_TEST_ES3(BPTCCompressedTextureTestES3); |