Edit

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

Branch :

  • Show log

    Commit

  • Author : Yuly Novikov
    Date : 2021-03-02 19:04:57
    Hash : a6b16d29
    Message : Suppress UNINSTANTIATED_PARAMETERIZED_TEST failures on Ozone We only support ES2 on Ozone, so tests that depend on ES3 or ES31 support are not instantiated there. Bug: chromium:1183147 Change-Id: Id58bcd9b44a5b9a70b5ae8115e27c44f5dc81226 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2726550 Reviewed-by: Jonah Ryan-Davis <jonahr@google.com> Commit-Queue: Yuly Novikov <ynovikov@chromium.org>

  • src/tests/gl_tests/FenceSyncTests.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"
    
    using namespace angle;
    
    class FenceNVTest : public ANGLETest
    {
      protected:
        FenceNVTest()
        {
            setWindowWidth(128);
            setWindowHeight(128);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
            setConfigDepthBits(24);
        }
    };
    
    class FenceSyncTest : public ANGLETest
    {
      public:
        static constexpr uint32_t kSize = 1024;
    
      protected:
        FenceSyncTest()
        {
            setWindowWidth(kSize);
            setWindowHeight(kSize);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
            setConfigDepthBits(24);
        }
    };
    
    // FenceNV objects should respond false to glIsFenceNV until they've been set
    TEST_P(FenceNVTest, IsFence)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_fence"));
    
        GLuint fence = 0;
        glGenFencesNV(1, &fence);
        EXPECT_GL_NO_ERROR();
    
        EXPECT_GL_FALSE(glIsFenceNV(fence));
        EXPECT_GL_NO_ERROR();
    
        glSetFenceNV(fence, GL_ALL_COMPLETED_NV);
        EXPECT_GL_NO_ERROR();
    
        EXPECT_GL_TRUE(glIsFenceNV(fence));
        EXPECT_GL_NO_ERROR();
    }
    
    // Test error cases for all FenceNV functions
    TEST_P(FenceNVTest, Errors)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_fence"));
    
        EXPECT_GL_TRUE(glTestFenceNV(10)) << "glTestFenceNV should still return TRUE for an invalid "
                                             "fence and generate an INVALID_OPERATION";
        EXPECT_GL_ERROR(GL_INVALID_OPERATION);
    
        GLuint fence = 20;
    
        // glGenFencesNV should generate INVALID_VALUE for a negative n and not write anything to the
        // fences pointer
        glGenFencesNV(-1, &fence);
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
        EXPECT_EQ(20u, fence);
    
        // Generate a real fence
        glGenFencesNV(1, &fence);
        EXPECT_GL_NO_ERROR();
    
        EXPECT_GL_TRUE(glTestFenceNV(fence)) << "glTestFenceNV should still return TRUE for a fence "
                                                "that is not started and generate an INVALID_OPERATION";
        EXPECT_GL_ERROR(GL_INVALID_OPERATION);
    
        // glGetFenceivNV should generate an INVALID_OPERATION for an invalid or unstarted fence and not
        // modify the params
        GLint result = 30;
        glGetFenceivNV(10, GL_FENCE_STATUS_NV, &result);
        EXPECT_GL_ERROR(GL_INVALID_OPERATION);
        EXPECT_EQ(30, result);
    
        glGetFenceivNV(fence, GL_FENCE_STATUS_NV, &result);
        EXPECT_GL_ERROR(GL_INVALID_OPERATION);
        EXPECT_EQ(30, result);
    
        // glSetFenceNV should generate an error for any condition that is not ALL_COMPLETED_NV
        glSetFenceNV(fence, 0);
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    
        // glSetFenceNV should generate INVALID_OPERATION for an invalid fence
        glSetFenceNV(10, GL_ALL_COMPLETED_NV);
        EXPECT_GL_ERROR(GL_INVALID_OPERATION);
    }
    
    // Test that basic usage works and doesn't generate errors or crash
    TEST_P(FenceNVTest, BasicOperations)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_fence"));
    
        glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
    
        constexpr size_t kFenceCount = 20;
        GLuint fences[kFenceCount]   = {0};
        glGenFencesNV(static_cast<GLsizei>(ArraySize(fences)), fences);
        EXPECT_GL_NO_ERROR();
    
        for (GLuint fence : fences)
        {
            glClear(GL_COLOR_BUFFER_BIT);
            glSetFenceNV(fence, GL_ALL_COMPLETED_NV);
        }
    
        // Finish the last fence, all fences before should be marked complete
        glFinishFenceNV(fences[kFenceCount - 1]);
    
        for (GLuint fence : fences)
        {
            GLint status = 0;
            glGetFenceivNV(fence, GL_FENCE_STATUS_NV, &status);
            EXPECT_GL_NO_ERROR();
    
            // Fence should be complete now that Finish has been called
            EXPECT_GL_TRUE(status);
        }
    
        EXPECT_PIXEL_EQ(0, 0, 255, 0, 255, 255);
    }
    
    // Sync objects should respond true to IsSync after they are created with glFenceSync
    TEST_P(FenceSyncTest, IsSync)
    {
        GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
        EXPECT_GL_NO_ERROR();
    
        EXPECT_GL_TRUE(glIsSync(sync));
        EXPECT_GL_FALSE(glIsSync(reinterpret_cast<GLsync>(40)));
    }
    
    // Test error cases for all Sync function
    TEST_P(FenceSyncTest, Errors)
    {
        GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
    
        // DeleteSync generates INVALID_VALUE when the sync is not valid
        glDeleteSync(reinterpret_cast<GLsync>(20));
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
    
        // glFenceSync generates GL_INVALID_ENUM if the condition is not GL_SYNC_GPU_COMMANDS_COMPLETE
        EXPECT_EQ(0, glFenceSync(0, 0));
        EXPECT_GL_ERROR(GL_INVALID_ENUM);
    
        // glFenceSync generates GL_INVALID_ENUM if the flags is not 0
        EXPECT_EQ(0, glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 10));
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
    
        // glClientWaitSync generates GL_INVALID_VALUE and returns GL_WAIT_FAILED if flags contains more
        // than just GL_SYNC_FLUSH_COMMANDS_BIT
        EXPECT_GLENUM_EQ(GL_WAIT_FAILED, glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT | 0x2, 0));
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
    
        // glClientWaitSync generates GL_INVALID_VALUE and returns GL_WAIT_FAILED if the sync object is
        // not valid
        EXPECT_GLENUM_EQ(GL_WAIT_FAILED,
                         glClientWaitSync(reinterpret_cast<GLsync>(30), GL_SYNC_FLUSH_COMMANDS_BIT, 0));
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
    
        // glWaitSync generates GL_INVALID_VALUE if flags is non-zero
        glWaitSync(sync, 1, GL_TIMEOUT_IGNORED);
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
    
        // glWaitSync generates GL_INVALID_VALUE if GLuint64 is not GL_TIMEOUT_IGNORED
        glWaitSync(sync, 0, 0);
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
    
        // glWaitSync generates GL_INVALID_VALUE if the sync object is not valid
        glWaitSync(reinterpret_cast<GLsync>(30), 0, GL_TIMEOUT_IGNORED);
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
    
        // glGetSynciv generates GL_INVALID_VALUE if bufSize is less than zero, results should be
        // untouched
        GLsizei length = 20;
        GLint value    = 30;
        glGetSynciv(sync, GL_OBJECT_TYPE, -1, &length, &value);
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
        EXPECT_EQ(20, length);
        EXPECT_EQ(30, value);
    
        // glGetSynciv generates GL_INVALID_VALUE if the sync object is not valid, results should be
        // untouched
        glGetSynciv(reinterpret_cast<GLsync>(30), GL_OBJECT_TYPE, 1, &length, &value);
        EXPECT_GL_ERROR(GL_INVALID_VALUE);
        EXPECT_EQ(20, length);
        EXPECT_EQ(30, value);
    }
    
    // Test usage of glGetSynciv
    TEST_P(FenceSyncTest, BasicQueries)
    {
        GLsizei length = 0;
        GLint value    = 0;
        GLsync sync    = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
    
        glGetSynciv(sync, GL_SYNC_CONDITION, 1, &length, &value);
        EXPECT_GL_NO_ERROR();
        EXPECT_EQ(GL_SYNC_GPU_COMMANDS_COMPLETE, value);
    
        glGetSynciv(sync, GL_OBJECT_TYPE, 1, &length, &value);
        EXPECT_GL_NO_ERROR();
        EXPECT_EQ(GL_SYNC_FENCE, value);
    
        glGetSynciv(sync, GL_SYNC_FLAGS, 1, &length, &value);
        EXPECT_GL_NO_ERROR();
        EXPECT_EQ(0, value);
    }
    
    // Test that basic usage works and doesn't generate errors or crash
    TEST_P(FenceSyncTest, BasicOperations)
    {
        glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
    
        GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
    
        glClear(GL_COLOR_BUFFER_BIT);
        glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
        EXPECT_GL_NO_ERROR();
    
        GLsizei length         = 0;
        GLint value            = 0;
        unsigned int loopCount = 0;
    
        glFlush();
    
        // Use 'loopCount' to make sure the test doesn't get stuck in an infinite loop
        while (value != GL_SIGNALED && loopCount <= 1000000)
        {
            loopCount++;
    
            glGetSynciv(sync, GL_SYNC_STATUS, 1, &length, &value);
            ASSERT_GL_NO_ERROR();
        }
    
        ASSERT_GLENUM_EQ(GL_SIGNALED, value);
    
        for (size_t i = 0; i < 20; i++)
        {
            glClear(GL_COLOR_BUFFER_BIT);
            glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
            EXPECT_GL_NO_ERROR();
        }
    }
    
    // Test that multiple fences and draws can be issued
    TEST_P(FenceSyncTest, MultipleFenceDraw)
    {
        constexpr int kNumIterations = 10;
        constexpr int kNumDraws      = 5;
    
        // Create a texture/FBO to draw to
        GLTexture texture;
        glBindTexture(GL_TEXTURE_2D, texture.get());
        glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
        ASSERT_GL_NO_ERROR();
        GLFramebuffer fbo;
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
        ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
    
        ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
        ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
    
        bool drawGreen = true;
        for (int numIterations = 0; numIterations < kNumIterations; ++numIterations)
        {
            glBindFramebuffer(GL_FRAMEBUFFER, fbo);
            ASSERT_GL_NO_ERROR();
    
            for (int i = 0; i < kNumDraws; ++i)
            {
                GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
                ASSERT_GL_NO_ERROR();
    
                drawGreen      = !drawGreen;
                GLuint program = 0;
                if (drawGreen)
                {
                    program = greenProgram.get();
                }
                else
                {
                    program = redProgram.get();
                }
                drawQuad(program, std::string(essl1_shaders::PositionAttrib()), 0.0f);
                ASSERT_GL_NO_ERROR();
    
                glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
                EXPECT_GL_NO_ERROR();
                glDeleteSync(sync);
                ASSERT_GL_NO_ERROR();
            }
    
            // Blit to the default FBO
            glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
            glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
            ASSERT_GL_NO_ERROR();
            swapBuffers();
    
            glBindFramebuffer(GL_FRAMEBUFFER, fbo);
            GLColor color;
            if (drawGreen)
            {
                color = GLColor::green;
            }
            else
            {
                color = GLColor::red;
            }
            EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, color);
        }
    }
    
    ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(FenceNVTest);
    
    GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FenceSyncTest);
    ANGLE_INSTANTIATE_TEST_ES3(FenceSyncTest);