Edit

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

Branch :

  • Show log

    Commit

  • Author : Cody Northrop
    Date : 2020-07-27 21:05:11
    Hash : cc846039
    Message : Capture/Replay: Fix GetTexImage on Luminance GetTexImageANGLE and GetRenderbufferImageANGLE use ReadPixels to pull texture data. Luminance is not a renderable format, so it is not supported by ReadPixels. To support this, override Luminance formats to their underlying internal format. Test: angle_end2end_test --gtest_filter="*GetTexImage*" Bug: b/160014453 Bug: angleproject:4058 Change-Id: Id19344c2e2c06386a871338833e35b7747cb966b Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2321740 Reviewed-by: Manh Nguyen <nguyenmh@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Cody Northrop <cnorthrop@google.com>

  • src/tests/gl_tests/GetImageTest.cpp
  • //
    // Copyright 2019 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.
    //
    // GetImageTest:
    //   Tests for the ANGLE_get_image extension.
    //
    
    #include "test_utils/ANGLETest.h"
    #include "test_utils/gl_raii.h"
    
    using namespace angle;
    
    namespace
    {
    constexpr uint32_t kSize        = 32;
    constexpr char kExtensionName[] = "GL_ANGLE_get_image";
    constexpr uint32_t kSmallSize   = 2;
    constexpr uint8_t kUNormZero    = 0x00;
    constexpr uint8_t kUNormHalf    = 0x7F;
    constexpr uint8_t kUNormFull    = 0xFF;
    
    class GetImageTest : public ANGLETest
    {
      public:
        GetImageTest()
        {
            setWindowWidth(kSize);
            setWindowHeight(kSize);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
        }
    };
    
    class GetImageTestNoExtensions : public ANGLETest
    {
      public:
        GetImageTestNoExtensions() { setExtensionsEnabled(false); }
    };
    
    GLTexture InitTextureWithFormatAndSize(GLenum format, uint32_t size, void *pixelData)
    {
        GLTexture tex;
        glBindTexture(GL_TEXTURE_2D, tex);
        glTexImage2D(GL_TEXTURE_2D, 0, format, size, size, 0, format, GL_UNSIGNED_BYTE, pixelData);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        return tex;
    }
    
    GLTexture InitTextureWithSize(uint32_t size, void *pixelData)
    {
        // Create a simple texture.
        GLTexture tex;
        glBindTexture(GL_TEXTURE_2D, tex);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        return tex;
    }
    
    GLTexture InitSimpleTexture()
    {
        std::vector<GLColor> pixelData(kSize * kSize, GLColor::red);
        return InitTextureWithSize(kSize, pixelData.data());
    }
    
    GLRenderbuffer InitRenderbufferWithSize(uint32_t size)
    {
        // Create a simple renderbuffer.
        GLRenderbuffer renderbuf;
        glBindRenderbuffer(GL_RENDERBUFFER, renderbuf);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, size, size);
        return renderbuf;
    }
    
    GLRenderbuffer InitSimpleRenderbuffer()
    {
        return InitRenderbufferWithSize(kSize);
    }
    
    // Test validation for the extension functions.
    TEST_P(GetImageTest, NegativeAPI)
    {
        // Verify the extension is enabled.
        ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
    
        // Draw once with simple texture.
        GLTexture tex = InitSimpleTexture();
        ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
        drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
        EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
        ASSERT_GL_NO_ERROR();
    
        // Pack pixels tightly.
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
    
        // Verify GetTexImage can work with correct parameters.
        std::vector<GLColor> buffer(kSize * kSize);
        glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
        EXPECT_GL_NO_ERROR();
    
        // Test invalid texture target.
        glGetTexImageANGLE(GL_TEXTURE_CUBE_MAP, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    
        // Test invalid texture level.
        glGetTexImageANGLE(GL_TEXTURE_2D, -1, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
        glGetTexImageANGLE(GL_TEXTURE_2D, 2000, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
    
        // Test invalid format and type.
        glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_NONE, GL_UNSIGNED_BYTE, buffer.data());
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
        glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_NONE, buffer.data());
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    
        // Create a simple renderbuffer.
        GLRenderbuffer renderbuf = InitSimpleRenderbuffer();
        ASSERT_GL_NO_ERROR();
    
        // Verify GetRenderbufferImage can work with correct parameters.
        glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
        EXPECT_GL_NO_ERROR();
    
        // Test invalid renderbuffer target.
        glGetRenderbufferImageANGLE(GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    
        // Test invalid renderbuffer format/type.
        glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_NONE, GL_UNSIGNED_BYTE, buffer.data());
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
        glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_NONE, buffer.data());
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    
        // Pack buffer tests. Requires ES 3+ or extension.
        if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_NV_pixel_buffer_object"))
        {
            // Test valid pack buffer.
            GLBuffer packBuffer;
            glBindBuffer(GL_PIXEL_PACK_BUFFER, packBuffer);
            glBufferData(GL_PIXEL_PACK_BUFFER, kSize * kSize * sizeof(GLColor), nullptr,
                         GL_STATIC_DRAW);
            glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
            EXPECT_GL_ERROR(GL_INVALID_OPERATION);
            glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
            EXPECT_GL_ERROR(GL_INVALID_OPERATION);
    
            // Test too small pack buffer.
            glBufferData(GL_PIXEL_PACK_BUFFER, kSize, nullptr, GL_STATIC_DRAW);
            glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
            EXPECT_GL_ERROR(GL_INVALID_OPERATION);
            glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
            EXPECT_GL_ERROR(GL_INVALID_OPERATION);
        }
    }
    
    // Simple test for GetTexImage
    TEST_P(GetImageTest, GetTexImage)
    {
        // Verify the extension is enabled.
        ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
    
        constexpr uint32_t kSmallSize     = 2;
        std::vector<GLColor> expectedData = {GLColor::red, GLColor::blue, GLColor::green,
                                             GLColor::yellow};
    
        glViewport(0, 0, kSmallSize, kSmallSize);
    
        // Draw once with simple texture.
        GLTexture tex = InitTextureWithSize(kSmallSize, expectedData.data());
        ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
        drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
        EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
        ASSERT_GL_NO_ERROR();
    
        // Pack pixels tightly.
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
    
        // Verify GetImage.
        std::vector<GLColor> actualData(kSmallSize * kSmallSize);
        glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, actualData.data());
        EXPECT_GL_NO_ERROR();
        EXPECT_EQ(expectedData, actualData);
    }
    
    // Simple cube map test for GetTexImage
    TEST_P(GetImageTest, CubeMap)
    {
        // Verify the extension is enabled.
        ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
    
        const std::array<std::array<GLColor, kSmallSize * kSmallSize>, kCubeFaces.size()> expectedData =
            {{
                {GLColor::red, GLColor::red, GLColor::red, GLColor::red},
                {GLColor::green, GLColor::green, GLColor::green, GLColor::green},
                {GLColor::blue, GLColor::blue, GLColor::blue, GLColor::blue},
                {GLColor::yellow, GLColor::yellow, GLColor::yellow, GLColor::yellow},
                {GLColor::cyan, GLColor::cyan, GLColor::cyan, GLColor::cyan},
                {GLColor::magenta, GLColor::magenta, GLColor::magenta, GLColor::magenta},
            }};
    
        GLTexture texture;
        glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
    
        for (size_t faceIndex = 0; faceIndex < kCubeFaces.size(); ++faceIndex)
        {
            glTexImage2D(kCubeFaces[faceIndex], 0, GL_RGBA, kSmallSize, kSmallSize, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, expectedData[faceIndex].data());
        }
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    
        // Pack pixels tightly.
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
    
        // Verify GetImage.
        std::array<GLColor, kSmallSize *kSmallSize> actualData = {};
        for (size_t faceIndex = 0; faceIndex < kCubeFaces.size(); ++faceIndex)
        {
            glGetTexImageANGLE(kCubeFaces[faceIndex], 0, GL_RGBA, GL_UNSIGNED_BYTE, actualData.data());
            EXPECT_GL_NO_ERROR();
            EXPECT_EQ(expectedData[faceIndex], actualData);
        }
    }
    
    // Simple test for GetRenderbufferImage
    TEST_P(GetImageTest, GetRenderbufferImage)
    {
        // Verify the extension is enabled.
        ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
    
        std::vector<GLColor> expectedData = {GLColor::red, GLColor::blue, GLColor::green,
                                             GLColor::yellow};
    
        glViewport(0, 0, kSmallSize, kSmallSize);
    
        // Set up a simple Framebuffer with a Renderbuffer.
        GLRenderbuffer renderbuffer = InitRenderbufferWithSize(kSmallSize);
        GLFramebuffer framebuffer;
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
        ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
    
        // Draw once with simple texture.
        GLTexture tex = InitTextureWithSize(kSmallSize, expectedData.data());
        ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
        drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
        EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
        ASSERT_GL_NO_ERROR();
    
        // Pack pixels tightly.
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
    
        // Verify GetImage.
        std::vector<GLColor> actualData(kSmallSize * kSmallSize);
        glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, actualData.data());
        EXPECT_GL_NO_ERROR();
        EXPECT_EQ(expectedData, actualData);
    }
    
    // Verifies that the extension enums and entry points are invalid when the extension is disabled.
    TEST_P(GetImageTestNoExtensions, EntryPointsInactive)
    {
        // Verify the extension is not enabled.
        ASSERT_FALSE(IsGLExtensionEnabled(kExtensionName));
    
        // Draw once with simple texture.
        GLTexture tex = InitSimpleTexture();
        ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
        drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
        EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
        ASSERT_GL_NO_ERROR();
    
        // Query implementation format and type. Should give invalid enum.
        GLint param;
        glGetTexParameteriv(GL_TEXTURE_2D, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &param);
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    
        glGetTexParameteriv(GL_TEXTURE_2D, GL_IMPLEMENTATION_COLOR_READ_TYPE, &param);
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    
        // Verify calling GetTexImage produces an error.
        std::vector<GLColor> buffer(kSize * kSize, 0);
        glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
        EXPECT_GL_ERROR(GL_INVALID_OPERATION);
    
        // Create a simple renderbuffer.
        GLRenderbuffer renderbuf = InitSimpleRenderbuffer();
        ASSERT_GL_NO_ERROR();
    
        // Query implementation format and type. Should give invalid enum.
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &param);
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_IMPLEMENTATION_COLOR_READ_TYPE, &param);
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    
        // Verify calling GetRenderbufferImage produces an error.
        glGetRenderbufferImageANGLE(GL_RENDERBUFFER, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
        EXPECT_GL_ERROR(GL_INVALID_OPERATION);
    }
    
    // Test LUMINANCE_ALPHA (non-renderable) format with GetTexImage
    TEST_P(GetImageTest, GetTexImageLuminanceAlpha)
    {
        // Verify the extension is enabled.
        ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
    
        constexpr GLColorRG kMediumLumAlpha = GLColorRG(kUNormHalf, kUNormHalf);
        std::vector<GLColorRG> expectedData = {kMediumLumAlpha, kMediumLumAlpha, kMediumLumAlpha,
                                               kMediumLumAlpha};
    
        glViewport(0, 0, kSmallSize, kSmallSize);
    
        // Set up a simple LUMINANCE_ALPHA texture
        GLTexture tex =
            InitTextureWithFormatAndSize(GL_LUMINANCE_ALPHA, kSmallSize, expectedData.data());
    
        // Draw once with simple texture.
        ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
        drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
        EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(kUNormHalf, kUNormHalf, kUNormHalf, kUNormHalf));
        ASSERT_GL_NO_ERROR();
    
        // Pack pixels tightly.
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
    
        // Verify GetImage.
        std::vector<GLColorRG> actualData(kSmallSize * kSmallSize);
        glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, actualData.data());
        EXPECT_GL_NO_ERROR();
        for (uint32_t i = 0; i < kSmallSize * kSmallSize; ++i)
        {
            EXPECT_EQ(expectedData[i].R, actualData[i].R);
            EXPECT_EQ(expectedData[i].G, actualData[i].G);
        }
    }
    
    // Test LUMINANCE (non-renderable) format with GetTexImage
    TEST_P(GetImageTest, GetTexImageLuminance)
    {
        // Verify the extension is enabled.
        ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
    
        constexpr GLColorR kMediumLuminance = GLColorR(kUNormHalf);
        std::vector<GLColorR> expectedData  = {kMediumLuminance, kMediumLuminance, kMediumLuminance,
                                              kMediumLuminance};
    
        glViewport(0, 0, kSmallSize, kSmallSize);
    
        // Set up a simple LUMINANCE texture
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        GLTexture tex = InitTextureWithFormatAndSize(GL_LUMINANCE, kSmallSize, expectedData.data());
    
        // Draw once with simple texture.
        ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
        drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
        EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(kUNormHalf, kUNormHalf, kUNormHalf, kUNormFull));
        ASSERT_GL_NO_ERROR();
    
        // Pack pixels tightly.
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
    
        // Verify GetImage.
        std::vector<GLColorR> actualData(kSmallSize * kSmallSize);
        glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, actualData.data());
        EXPECT_GL_NO_ERROR();
        for (uint32_t i = 0; i < kSmallSize * kSmallSize; ++i)
        {
            EXPECT_EQ(expectedData[i].R, actualData[i].R);
        }
    }
    
    // Test ALPHA (non-renderable) format with GetTexImage
    TEST_P(GetImageTest, GetTexImageAlpha)
    {
        // Verify the extension is enabled.
        ASSERT_TRUE(IsGLExtensionEnabled(kExtensionName));
    
        constexpr GLColorR kMediumAlpha    = GLColorR(kUNormHalf);
        std::vector<GLColorR> expectedData = {kMediumAlpha, kMediumAlpha, kMediumAlpha, kMediumAlpha};
    
        glViewport(0, 0, kSmallSize, kSmallSize);
    
        // Set up a simple ALPHA texture
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        GLTexture tex = InitTextureWithFormatAndSize(GL_ALPHA, kSmallSize, expectedData.data());
    
        // Draw once with simple texture
        ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
        drawQuad(program, essl1_shaders::PositionAttrib(), 0.5, 1.0f, true);
        EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(kUNormZero, kUNormZero, kUNormZero, kUNormHalf));
        ASSERT_GL_NO_ERROR();
    
        // Pack pixels tightly.
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
    
        // Verify we get back the correct pixels from GetTexImage
        std::vector<GLColorR> actualData(kSmallSize * kSmallSize);
        glGetTexImageANGLE(GL_TEXTURE_2D, 0, GL_ALPHA, GL_UNSIGNED_BYTE, actualData.data());
        EXPECT_GL_NO_ERROR();
        for (uint32_t i = 0; i < kSmallSize * kSmallSize; ++i)
        {
            EXPECT_EQ(expectedData[i].R, actualData[i].R);
        }
    }
    
    ANGLE_INSTANTIATE_TEST(GetImageTest, ES2_VULKAN(), ES3_VULKAN());
    ANGLE_INSTANTIATE_TEST(GetImageTestNoExtensions, ES2_VULKAN(), ES3_VULKAN());
    }  // namespace