Edit

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

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2016-12-20 10:11:45
    Hash : 408293f8
    Message : D3D11: Fix stale SRVs with tiny depth textures. When the tiny depth texture would get re-created on change, it was not freeing any cached SRVs which were pointing to the old tex. Fix this by erasing the cache entry if the texure is recreated. Also include a test which hooks into the workarounds to force testing on every platform. Also narrow the workaround to only apply to depth/stencil textures which use these mips in GL, rather than D3D, where we always create a full mip chain. BUG=angleproject:1664 Change-Id: If0ac396b8847e1bf9b50165e5332da573e9bb3e4 Reviewed-on: https://chromium-review.googlesource.com/421567 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>

  • src/tests/gl_tests/DepthStencilFormatsTest.cpp
  • //
    // Copyright 2015 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.
    //
    
    #include "test_utils/ANGLETest.h"
    #include "test_utils/gl_raii.h"
    
    #include "common/mathutil.h"
    #include "platform/WorkaroundsD3D.h"
    
    using namespace angle;
    
    class DepthStencilFormatsTestBase : public ANGLETest
    {
      protected:
        DepthStencilFormatsTestBase()
        {
            setWindowWidth(128);
            setWindowHeight(128);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
        }
    
        bool checkTexImageFormatSupport(GLenum format, GLenum type)
        {
            EXPECT_GL_NO_ERROR();
    
            GLuint tex = 0;
            glGenTextures(1, &tex);
            glBindTexture(GL_TEXTURE_2D, tex);
            glTexImage2D(GL_TEXTURE_2D, 0, format, 1, 1, 0, format, type, NULL);
            glDeleteTextures(1, &tex);
    
            return (glGetError() == GL_NO_ERROR);
        }
    
        bool checkTexStorageFormatSupport(GLenum internalFormat)
        {
            EXPECT_GL_NO_ERROR();
    
            GLuint tex = 0;
            glGenTextures(1, &tex);
            glBindTexture(GL_TEXTURE_2D, tex);
            glTexStorage2DEXT(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
            glDeleteTextures(1, &tex);
    
            return (glGetError() == GL_NO_ERROR);
        }
    
        bool checkRenderbufferFormatSupport(GLenum internalFormat)
        {
            EXPECT_GL_NO_ERROR();
    
            GLuint rb = 0;
            glGenRenderbuffers(1, &rb);
            glBindRenderbuffer(GL_RENDERBUFFER, rb);
            glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, 1, 1);
            glDeleteRenderbuffers(1, &rb);
    
            return (glGetError() == GL_NO_ERROR);
        }
    
        virtual void SetUp()
        {
            ANGLETest::SetUp();
    
            const std::string vertexShaderSource = SHADER_SOURCE
            (
                precision highp float;
                attribute vec4 position;
                varying vec2 texcoord;
    
                void main()
                {
                    gl_Position = position;
                    texcoord = (position.xy * 0.5) + 0.5;
                }
            );
    
            const std::string fragmentShaderSource = SHADER_SOURCE
            (
                precision highp float;
                uniform sampler2D tex;
                varying vec2 texcoord;
    
                void main()
                {
                    gl_FragColor = texture2D(tex, texcoord);
                }
            );
    
            mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
            if (mProgram == 0)
            {
                FAIL() << "shader compilation failed.";
            }
    
            mTextureUniformLocation = glGetUniformLocation(mProgram, "tex");
            EXPECT_NE(-1, mTextureUniformLocation);
    
            glGenTextures(1, &mTexture);
            ASSERT_GL_NO_ERROR();
        }
    
        virtual void TearDown()
        {
            glDeleteProgram(mProgram);
            glDeleteTextures(1, &mTexture);
    
            ANGLETest::TearDown();
        }
    
        GLuint mProgram;
        GLuint mTexture;
        GLint mTextureUniformLocation;
    };
    
    class DepthStencilFormatsTest : public DepthStencilFormatsTestBase
    {};
    
    class DepthStencilFormatsTestES3 : public DepthStencilFormatsTestBase
    {};
    
    TEST_P(DepthStencilFormatsTest, DepthTexture)
    {
        bool shouldHaveTextureSupport = extensionEnabled("GL_ANGLE_depth_texture");
        EXPECT_EQ(shouldHaveTextureSupport, checkTexImageFormatSupport(GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT));
        EXPECT_EQ(shouldHaveTextureSupport, checkTexImageFormatSupport(GL_DEPTH_COMPONENT, GL_UNSIGNED_INT));
    
        if (extensionEnabled("GL_EXT_texture_storage"))
        {
            EXPECT_EQ(shouldHaveTextureSupport, checkTexStorageFormatSupport(GL_DEPTH_COMPONENT16));
            EXPECT_EQ(shouldHaveTextureSupport, checkTexStorageFormatSupport(GL_DEPTH_COMPONENT32_OES));
        }
    }
    
    TEST_P(DepthStencilFormatsTest, PackedDepthStencil)
    {
        // Expected to fail in D3D9 if GL_OES_packed_depth_stencil is not present.
        // Expected to fail in D3D11 if GL_OES_packed_depth_stencil or GL_ANGLE_depth_texture is not present.
    
        bool shouldHaveRenderbufferSupport = extensionEnabled("GL_OES_packed_depth_stencil");
        EXPECT_EQ(shouldHaveRenderbufferSupport, checkRenderbufferFormatSupport(GL_DEPTH24_STENCIL8_OES));
    
        bool shouldHaveTextureSupport = extensionEnabled("GL_OES_packed_depth_stencil") &&
                                        extensionEnabled("GL_ANGLE_depth_texture");
        EXPECT_EQ(shouldHaveTextureSupport, checkTexImageFormatSupport(GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES));
    
        if (extensionEnabled("GL_EXT_texture_storage"))
        {
            EXPECT_EQ(shouldHaveTextureSupport, checkTexStorageFormatSupport(GL_DEPTH24_STENCIL8_OES));
        }
    }
    
    TEST_P(DepthStencilFormatsTestES3, DrawWithDepthStencil)
    {
        GLushort data[16];
        for (unsigned int i = 0; i < 16; i++)
        {
            data[i] = std::numeric_limits<GLushort>::max();
        }
        glBindTexture(GL_TEXTURE_2D, mTexture);
        glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, 4, 4);
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, data);
    
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    
        glUseProgram(mProgram);
        glUniform1i(mTextureUniformLocation, 0);
    
        glClear(GL_COLOR_BUFFER_BIT);
        drawQuad(mProgram, "position", 0.5f);
    
        ASSERT_GL_NO_ERROR();
    
        GLubyte pixel[4];
        glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
    
        // Only require the red and alpha channels have the correct values, the depth texture extensions
        // leave the green and blue channels undefined
        ASSERT_NEAR(255, pixel[0], 2.0);
        ASSERT_EQ(255, pixel[3]);
    }
    
    // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
    ANGLE_INSTANTIATE_TEST(DepthStencilFormatsTest,
                           ES2_D3D9(),
                           ES2_D3D11(),
                           ES2_OPENGL(),
                           ES2_OPENGLES());
    ANGLE_INSTANTIATE_TEST(DepthStencilFormatsTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
    
    class TinyDepthStencilWorkaroundTest : public ANGLETest
    {
      public:
        TinyDepthStencilWorkaroundTest()
        {
            setWindowWidth(512);
            setWindowHeight(512);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
        }
    
        // Override the workarounds to enable "tiny" depth/stencil textures.
        void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
        {
            workarounds->emulateTinyStencilTextures = true;
        }
    };
    
    // Tests that the tiny depth stencil textures workaround does not "stick" depth textures.
    // http://anglebug.com/1664
    TEST_P(TinyDepthStencilWorkaroundTest, DepthTexturesStick)
    {
        const std::string &drawVS =
            "#version 100\n"
            "attribute vec3 vertex;\n"
            "void main () {\n"
            "  gl_Position = vec4(vertex.x, vertex.y, vertex.z * 2.0 - 1.0, 1);\n"
            "}\n";
    
        const std::string &drawFS =
            "#version 100\n"
            "void main () {\n"
            "  gl_FragColor = vec4 (1.);\n"
            "}\n";
    
        ANGLE_GL_PROGRAM(drawProgram, drawVS, drawFS);
    
        const std::string &blitVS =
            "#version 100\n"
            "attribute vec2 vertex;\n"
            "varying vec2 position;\n"
            "void main () {\n"
            "  position = vertex * .5 + .5;\n"
            "  gl_Position = vec4(vertex, 0, 1);\n"
            "}\n";
    
        const std::string &blitFS =
            "#version 100\n"
            "precision mediump float;\n"
            "uniform sampler2D texture;\n"
            "varying vec2 position;\n"
            "void main () {\n"
            "  gl_FragColor = vec4 (texture2D (texture, position).rrr, 1.);\n"
            "}\n";
    
        ANGLE_GL_PROGRAM(blitProgram, blitVS, blitFS);
    
        GLint blitTextureLocation = glGetUniformLocation(blitProgram.get(), "texture");
        ASSERT_NE(-1, blitTextureLocation);
    
        GLTexture colorTex;
        glBindTexture(GL_TEXTURE_2D, colorTex.get());
        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_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
                     GL_UNSIGNED_BYTE, nullptr);
        glBindTexture(GL_TEXTURE_2D, 0);
    
        GLTexture depthTex;
        glBindTexture(GL_TEXTURE_2D, depthTex.get());
        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_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
        ASSERT_EQ(getWindowWidth(), getWindowHeight());
        int levels = gl::log2(getWindowWidth());
        for (int mipLevel = 0; mipLevel <= levels; ++mipLevel)
        {
            int size = getWindowWidth() >> mipLevel;
            glTexImage2D(GL_TEXTURE_2D, mipLevel, GL_DEPTH_STENCIL, size, size, 0, GL_DEPTH_STENCIL,
                         GL_UNSIGNED_INT_24_8_OES, nullptr);
        }
    
        glBindTexture(GL_TEXTURE_2D, 0);
    
        ASSERT_GL_NO_ERROR();
    
        GLFramebuffer framebuffer;
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
    
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex.get(), 0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTex.get(), 0);
    
        ASSERT_GL_NO_ERROR();
    
        glDepthRangef(0.0f, 1.0f);
        glViewport(0, 0, getWindowWidth(), getWindowHeight());
        glClearColor(0, 0, 0, 1);
    
        // Draw loop.
        for (unsigned int frame = 0; frame < 3; ++frame)
        {
            // draw into FBO
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
            glEnable(GL_DEPTH_TEST);
    
            float depth = ((frame % 2 == 0) ? 0.0f : 1.0f);
            drawQuad(drawProgram.get(), "vertex", depth);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
    
            // blit FBO
            glDisable(GL_DEPTH_TEST);
    
            glUseProgram(blitProgram.get());
            glUniform1i(blitTextureLocation, 0);
            glBindTexture(GL_TEXTURE_2D, depthTex.get());
    
            drawQuad(blitProgram.get(), "vertex", 0.5f);
    
            Vector4 depthVec(depth, depth, depth, 1);
            GLColor depthColor(depthVec);
    
            EXPECT_PIXEL_COLOR_NEAR(0, 0, depthColor, 1);
            ASSERT_GL_NO_ERROR();
        }
    }
    
    ANGLE_INSTANTIATE_TEST(TinyDepthStencilWorkaroundTest, ES3_D3D11());