Edit

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

Branch :

  • Show log

    Commit

  • Author : Jiang
    Date : 2017-10-19 16:23:07
    Hash : d922775b
    Message : Clean up passed end2end tests on Intel Windows platform Intel driver has released its latest versions, many intel driver bugs are fixed. This patch cleans up end2end test cases skipped on windows 10 and windows 7. The test environment is as follows, Hardware: Skylake(HD 530), Kabylake(HD 630) Driver version: 4815, 4821 OS: windows 10(15063), windows 7. BUG=angleproject:2205 Change-Id: Iae14763aa86a572da1221e9ea35b28da2561d3b0 Reviewed-on: https://chromium-review.googlesource.com/729549 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/tests/gl_tests/WebGLReadOutsideFramebufferTest.cpp
  • //
    // Copyright 2017 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.
    //
    
    // WebGLReadOutsideFramebufferTest.cpp : Test functions which read the framebuffer (readPixels,
    // copyTexSubImage2D, copyTexImage2D) on areas outside the framebuffer.
    
    #include "test_utils/ANGLETest.h"
    
    #include "test_utils/gl_raii.h"
    
    namespace
    {
    
    class PixelRect
    {
      public:
        PixelRect(int width, int height) : mWidth(width), mHeight(height), mData(width * height) {}
    
        // Set each pixel to a different color consisting of the x,y position and a given tag.
        // Making each pixel a different means any misplaced pixel will cause a failure.
        // Encoding the position proved valuable in debugging.
        void fill(unsigned tag)
        {
            for (int x = 0; x < mWidth; ++x)
            {
                for (int y = 0; y < mHeight; ++y)
                {
                    mData[x + y * mWidth] = angle::GLColor(x + (y << 8) + (tag << 16));
                }
            }
        }
    
        void toTexture2D(GLuint target, GLuint texid) const
        {
            glBindTexture(target, texid);
            if (target == GL_TEXTURE_CUBE_MAP)
            {
                glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA,
                             GL_UNSIGNED_BYTE, mData.data());
                glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA,
                             GL_UNSIGNED_BYTE, mData.data());
                glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA,
                             GL_UNSIGNED_BYTE, mData.data());
                glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA,
                             GL_UNSIGNED_BYTE, mData.data());
                glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA,
                             GL_UNSIGNED_BYTE, mData.data());
                glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA,
                             GL_UNSIGNED_BYTE, mData.data());
            }
            else
            {
                ASSERT(target == GL_TEXTURE_2D);
                glTexImage2D(target, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                             mData.data());
            }
            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        }
    
        void toTexture3D(GLuint texid, GLint depth) const
        {
            glBindTexture(GL_TEXTURE_3D, texid);
    
            glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, mWidth, mHeight, depth, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, nullptr);
            for (GLint z = 0; z < depth; z++)
            {
                glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, z, mWidth, mHeight, 1, GL_RGBA,
                                GL_UNSIGNED_BYTE, mData.data());
            }
            glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
        }
    
        void readFB(int x, int y)
        {
            glReadPixels(x, y, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, mData.data());
        }
    
        // Read pixels from 'other' into 'this' from position (x,y).
        // Pixels outside 'other' are untouched or zeroed according to 'zeroOutside.'
        void readPixelRect(const PixelRect &other, int x, int y, bool zeroOutside)
        {
            for (int i = 0; i < mWidth; ++i)
            {
                for (int j = 0; j < mHeight; ++j)
                {
                    angle::GLColor *dest = &mData[i + j * mWidth];
                    if (!other.getPixel(x + i, y + j, dest) && zeroOutside)
                    {
                        *dest = angle::GLColor(0);
                    }
                }
            }
        }
    
        bool getPixel(int x, int y, angle::GLColor *colorOut) const
        {
            if (0 <= x && x < mWidth && 0 <= y && y < mHeight)
            {
                *colorOut = mData[x + y * mWidth];
                return true;
            }
            return false;
        }
    
        void compare(const PixelRect &expected) const
        {
            ASSERT_EQ(mWidth, expected.mWidth);
            ASSERT_EQ(mHeight, expected.mHeight);
    
            for (int x = 0; x < mWidth; ++x)
            {
                for (int y = 0; y < mHeight; ++y)
                {
                    ASSERT_EQ(expected.mData[x + y * mWidth], mData[x + y * mWidth])
                        << "at (" << x << ", " << y << ")";
                }
            }
        }
    
      private:
        int mWidth, mHeight;
        std::vector<angle::GLColor> mData;
    };
    
    }  // namespace
    
    namespace angle
    {
    
    class WebGLReadOutsideFramebufferTest : public ANGLETest
    {
      public:
        // Read framebuffer to 'pixelsOut' via glReadPixels.
        void TestReadPixels(int x, int y, int, PixelRect *pixelsOut) { pixelsOut->readFB(x, y); }
    
        // Read framebuffer to 'pixelsOut' via glCopyTexSubImage2D and GL_TEXTURE_2D.
        void TestCopyTexSubImage2D(int x, int y, int, PixelRect *pixelsOut)
        {
            // Init texture with given pixels.
            GLTexture destTexture;
            pixelsOut->toTexture2D(GL_TEXTURE_2D, destTexture.get());
    
            // Read framebuffer -> texture -> 'pixelsOut'
            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, x, y, kReadWidth, kReadHeight);
            readTexture2D(GL_TEXTURE_2D, destTexture.get(), kReadWidth, kReadHeight, pixelsOut);
        }
    
        // Read framebuffer to 'pixelsOut' via glCopyTexSubImage2D and cube map.
        void TestCopyTexSubImageCube(int x, int y, int, PixelRect *pixelsOut)
        {
            // Init texture with given pixels.
            GLTexture destTexture;
            pixelsOut->toTexture2D(GL_TEXTURE_CUBE_MAP, destTexture.get());
    
            // Read framebuffer -> texture -> 'pixelsOut'
            glCopyTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 0, 0, x, y, kReadWidth, kReadHeight);
            readTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, destTexture.get(), kReadWidth, kReadHeight,
                          pixelsOut);
        }
    
        // Read framebuffer to 'pixelsOut' via glCopyTexSubImage3D.
        void TestCopyTexSubImage3D(int x, int y, int z, PixelRect *pixelsOut)
        {
            // Init texture with given pixels.
            GLTexture destTexture;
            pixelsOut->toTexture3D(destTexture.get(), kTextureDepth);
    
            // Read framebuffer -> texture -> 'pixelsOut'
            glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, z, x, y, kReadWidth, kReadHeight);
            readTexture3D(destTexture, kReadWidth, kReadHeight, z, pixelsOut);
        }
    
        // Read framebuffer to 'pixelsOut' via glCopyTexImage2D and GL_TEXTURE_2D.
        void TestCopyTexImage2D(int x, int y, int, PixelRect *pixelsOut)
        {
            // Init texture with given pixels.
            GLTexture destTexture;
            pixelsOut->toTexture2D(GL_TEXTURE_2D, destTexture.get());
    
            // Read framebuffer -> texture -> 'pixelsOut'
            glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, kReadWidth, kReadHeight, 0);
            readTexture2D(GL_TEXTURE_2D, destTexture.get(), kReadWidth, kReadHeight, pixelsOut);
        }
    
        // Read framebuffer to 'pixelsOut' via glCopyTexImage2D and cube map.
        void TestCopyTexImageCube(int x, int y, int, PixelRect *pixelsOut)
        {
            // Init texture with given pixels.
            GLTexture destTexture;
            pixelsOut->toTexture2D(GL_TEXTURE_CUBE_MAP, destTexture.get());
    
            // Read framebuffer -> texture -> 'pixelsOut'
            glCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, x, y, kReadWidth, kReadHeight,
                             0);
            readTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, destTexture, kReadWidth, kReadHeight,
                          pixelsOut);
        }
    
      protected:
        static constexpr int kFbWidth    = 128;
        static constexpr int kFbHeight   = 128;
        static constexpr int kTextureDepth = 16;
        static constexpr int kReadWidth  = 4;
        static constexpr int kReadHeight = 4;
        static constexpr int kReadLayer    = 2;
    
        // Tag the framebuffer pixels differently than the initial read buffer pixels, so we know for
        // sure which pixels are changed by reading.
        static constexpr GLuint fbTag   = 0x1122;
        static constexpr GLuint readTag = 0xaabb;
    
        WebGLReadOutsideFramebufferTest() : mFBData(kFbWidth, kFbHeight)
        {
            setWindowWidth(kFbWidth);
            setWindowHeight(kFbHeight);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
            setWebGLCompatibilityEnabled(true);
        }
    
        void SetUp() override
        {
            ANGLETest::SetUp();
    
            // TODO(fjhenigman): Factor out this shader and others like it in other tests, into
            // ANGLETest.
            const std::string vertexShader =
                "attribute vec3 a_position;\n"
                "varying vec2 v_texCoord;\n"
                "void main() {\n"
                "    v_texCoord = a_position.xy * 0.5 + 0.5;\n"
                "    gl_Position = vec4(a_position, 1);\n"
                "}\n";
            const std::string fragmentShader =
                "precision mediump float;\n"
                "varying vec2 v_texCoord;\n"
                "uniform sampler2D u_texture;\n"
                "void main() {\n"
                "    gl_FragColor = texture2D(u_texture, v_texCoord);\n"
                "}\n";
    
            mProgram = CompileProgram(vertexShader, fragmentShader);
            glUseProgram(mProgram);
            GLint uniformLoc = glGetUniformLocation(mProgram, "u_texture");
            ASSERT_NE(-1, uniformLoc);
            glUniform1i(uniformLoc, 0);
    
            glDisable(GL_BLEND);
            glDisable(GL_DEPTH_TEST);
    
            // fill framebuffer with unique pixels
            mFBData.fill(fbTag);
            GLTexture fbTexture;
            mFBData.toTexture2D(GL_TEXTURE_2D, fbTexture);
            drawQuad(mProgram, "a_position", 0.0f, 1.0f, true);
        }
    
        void TearDown() override
        {
            glDeleteProgram(mProgram);
            ANGLETest::TearDown();
        }
    
        using TestFunc = void (WebGLReadOutsideFramebufferTest::*)(int x,
                                                                   int y,
                                                                   int z,
                                                                   PixelRect *dest);
    
        void Main2D(TestFunc testFunc, bool zeroOutside) { mainImpl(testFunc, zeroOutside, 0); }
    
        void Main3D(TestFunc testFunc, bool zeroOutside)
        {
            mainImpl(testFunc, zeroOutside, kReadLayer);
        }
    
        void mainImpl(TestFunc testFunc, bool zeroOutside, int readLayer)
        {
            PixelRect actual(kReadWidth, kReadHeight);
            PixelRect expected(kReadWidth, kReadHeight);
    
            // Read a kReadWidth*kReadHeight rectangle of pixels from places that include:
            // - completely outside framebuffer, on all sides of it (i,j < 0 or > 2)
            // - completely inside framebuffer (i,j == 1)
            // - straddling framebuffer boundary, at each corner and side
            for (int i = -1; i < 4; ++i)
            {
                for (int j = -1; j < 4; ++j)
                {
                    int x = i * kFbWidth / 2 - kReadWidth / 2;
                    int y = j * kFbHeight / 2 - kReadHeight / 2;
    
                    // Put unique pixel values into the read destinations.
                    actual.fill(readTag);
                    expected.readPixelRect(actual, 0, 0, false);
    
                    // Read from framebuffer into 'actual.'
                    glBindFramebuffer(GL_FRAMEBUFFER, 0);
                    (this->*testFunc)(x, y, readLayer, &actual);
                    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    
                    // Simulate framebuffer read, into 'expected.'
                    expected.readPixelRect(mFBData, x, y, zeroOutside);
    
                    // See if they are the same.
                    actual.compare(expected);
                }
            }
        }
    
        // Get contents of given texture by drawing it into a framebuffer then reading with
        // glReadPixels().
        void readTexture2D(GLuint target, GLuint texture, GLsizei width, GLsizei height, PixelRect *out)
        {
            GLFramebuffer fbo;
            glBindFramebuffer(GL_FRAMEBUFFER, fbo);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, texture, 0);
            out->readFB(0, 0);
        }
    
        // Get contents of current texture by drawing it into a framebuffer then reading with
        // glReadPixels().
        void readTexture3D(GLuint texture, GLsizei width, GLsizei height, int zSlice, PixelRect *out)
        {
            GLFramebuffer fbo;
            glBindFramebuffer(GL_FRAMEBUFFER, fbo);
            glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, zSlice);
            out->readFB(0, 0);
        }
    
        PixelRect mFBData;
        GLuint mProgram;
    };
    
    class WebGL2ReadOutsideFramebufferTest : public WebGLReadOutsideFramebufferTest
    {
    };
    
    // Check that readPixels does not set a destination pixel when
    // the corresponding source pixel is outside the framebuffer.
    TEST_P(WebGLReadOutsideFramebufferTest, ReadPixels)
    {
        Main2D(&WebGLReadOutsideFramebufferTest::TestReadPixels, false);
    }
    
    // Check that copyTexSubImage2D does not set a destination pixel when
    // the corresponding source pixel is outside the framebuffer.
    TEST_P(WebGLReadOutsideFramebufferTest, CopyTexSubImage2D)
    {
        Main2D(&WebGLReadOutsideFramebufferTest::TestCopyTexSubImage2D, false);
    
    #ifdef _WIN64
        // TODO(fjhenigman): Figure out this failure.
        if (GetParam() == ES2_D3D11_FL9_3())
        {
            std::cout << "Cube map skipped on 64-bit " << GetParam() << "." << std::endl;
            return;
        }
    #endif
    
        Main2D(&WebGLReadOutsideFramebufferTest::TestCopyTexSubImageCube, false);
    }
    
    // Check that copyTexImage2D sets (0,0,0,0) for pixels outside the framebuffer.
    TEST_P(WebGLReadOutsideFramebufferTest, CopyTexImage2D)
    {
        Main2D(&WebGLReadOutsideFramebufferTest::TestCopyTexImage2D, true);
    
    #ifdef _WIN64
        // TODO(fjhenigman): Figure out this failure.
        if (GetParam() == ES2_D3D11_FL9_3())
        {
            std::cout << "Cube map skipped on 64-bit " << GetParam() << "." << std::endl;
            return;
        }
    #endif
    
        Main2D(&WebGLReadOutsideFramebufferTest::TestCopyTexImageCube, true);
    }
    
    // Check that copyTexSubImage3D does not set a destination pixel when
    // the corresponding source pixel is outside the framebuffer.
    TEST_P(WebGL2ReadOutsideFramebufferTest, CopyTexSubImage3D)
    {
        if (IsDesktopOpenGL() || IsOpenGLES())
        {
            std::cout << "Robust CopyTexSubImage3D behaviour is not implemented on OpenGL."
                      << std::endl;
            return;
        }
    
        Main3D(&WebGLReadOutsideFramebufferTest::TestCopyTexSubImage3D, false);
    }
    
    ANGLE_INSTANTIATE_TEST(WebGLReadOutsideFramebufferTest,
                           ES2_D3D9(),
                           ES2_D3D11(),
                           ES3_D3D11(),
                           ES2_D3D11_FL9_3(),
                           ES2_OPENGL(),
                           ES3_OPENGL(),
                           ES2_OPENGLES(),
                           ES3_OPENGLES());
    
    ANGLE_INSTANTIATE_TEST(WebGL2ReadOutsideFramebufferTest,
                           ES3_D3D11(),
                           ES3_OPENGL(),
                           ES2_OPENGLES(),
                           ES3_OPENGLES());
    
    }  // namespace