Edit

kc3-lang/angle/src/tests/gl_tests/BPTCCompressedTextureTest.cpp

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2018-10-04 13:54:42
    Hash : f2ed2995
    Message : Add support for EXT_texture_compression_bptc After validation, the enums are simply forwarded to the native drivers. The BPTC formats are supported on both OpenGL and D3D. The included test coverage covers the API quite well, but only has basic coverage for correct decoding of texture data. More coverage for texture data could be added later. BUG=angleproject:2869 TEST=angle_end2end_tests Change-Id: I3de37972dcf13c6fa3fc1bc429a2627523a4a082 Reviewed-on: https://chromium-review.googlesource.com/c/1261675 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/tests/gl_tests/BPTCCompressedTextureTest.cpp
  • //
    // 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 SetUp() override
        {
            ANGLETest::SetUp();
    
            const std::string vsSource =
                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;
                })";
    
            const std::string textureFSSource =
                R"(precision highp float;
                uniform sampler2D tex;
                varying vec2 texcoord;
    
                void main()
                {
                    gl_FragColor = texture2D(tex, texcoord);
                })";
    
            mTextureProgram = CompileProgram(vsSource, textureFSSource);
            if (mTextureProgram == 0)
            {
                FAIL() << "shader compilation failed.";
            }
    
            mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
    
            ASSERT_GL_NO_ERROR();
        }
    
        void TearDown() override
        {
            glDeleteProgram(mTextureProgram);
    
            ANGLETest::TearDown();
        }
    
        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(!extensionEnabled("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(!extensionEnabled("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(!extensionEnabled("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(!extensionEnabled("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(!extensionEnabled("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(!extensionEnabled("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(!extensionEnabled("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(!extensionEnabled("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(!extensionEnabled("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(!extensionEnabled("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(!extensionEnabled("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(BPTCCompressedTextureTest,
                           ES2_D3D9(),
                           ES2_D3D11(),
                           ES3_D3D11(),
                           ES2_OPENGL(),
                           ES3_OPENGL(),
                           ES2_OPENGLES(),
                           ES3_OPENGLES(),
                           ES2_VULKAN());
    
    ANGLE_INSTANTIATE_TEST(BPTCCompressedTextureTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());