Edit

kc3-lang/angle/src/tests/egl_tests/EGLProgramCacheControlTest.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2019-05-07 15:49:22
    Hash : 5cbaa3f8
    Message : Don't inherit ANGLETest SetUp and TearDown. Instead of inheriting from testing::Test's SetUp and TearDown we add new methods 'testSetUp' and 'testTearDown'. This helps prevent a common error of forgetting to call the base class method. Also add a check in the ANGLETest destructor that SetUp and TearDown have been called. Bug: angleproject:3393 Change-Id: Iab211305cc06ffea9ca649e864ddc9b180f2cba0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1593960 Reviewed-by: Geoff Lang <geofflang@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/tests/egl_tests/EGLProgramCacheControlTest.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.
    //
    // EGLProgramCacheControlTest:
    //   Unit tests for the EGL_ANGLE_program_cache_control extension.
    
    #include "common/angleutils.h"
    #include "test_utils/ANGLETest.h"
    #include "test_utils/gl_raii.h"
    #include "util/EGLWindow.h"
    
    using namespace angle;
    
    constexpr EGLint kEnabledCacheSize = 0x10000;
    constexpr char kEGLExtName[]       = "EGL_ANGLE_program_cache_control";
    
    void TestCacheProgram(PlatformMethods *platform,
                          const ProgramKeyType &key,
                          size_t programSize,
                          const uint8_t *programBytes);
    
    class EGLProgramCacheControlTest : public ANGLETest
    {
      public:
        void onCache(const ProgramKeyType &key, size_t programSize, const uint8_t *programBytes)
        {
            mCachedKey = key;
            mCachedBinary.assign(&programBytes[0], &programBytes[programSize]);
        }
    
      protected:
        EGLProgramCacheControlTest()
        {
            // Test flakiness was noticed when reusing displays.
            forceNewDisplay();
            setDeferContextInit(true);
            setContextProgramCacheEnabled(true);
            gDefaultPlatformMethods.cacheProgram = TestCacheProgram;
        }
    
        void testSetUp() override
        {
            if (extensionAvailable())
            {
                EGLDisplay display = getEGLWindow()->getDisplay();
                eglProgramCacheResizeANGLE(display, kEnabledCacheSize, EGL_PROGRAM_CACHE_RESIZE_ANGLE);
                ASSERT_EGL_SUCCESS();
            }
    
            ASSERT_TRUE(getEGLWindow()->initializeContext());
        }
    
        void testTearDown() override { gDefaultPlatformMethods.cacheProgram = DefaultCacheProgram; }
    
        bool extensionAvailable()
        {
            EGLDisplay display = getEGLWindow()->getDisplay();
            return IsEGLDisplayExtensionEnabled(display, kEGLExtName);
        }
    
        bool programBinaryAvailable()
        {
            return (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_OES_get_program_binary"));
        }
    
        ProgramKeyType mCachedKey;
        std::vector<uint8_t> mCachedBinary;
    };
    
    void TestCacheProgram(PlatformMethods *platform,
                          const ProgramKeyType &key,
                          size_t programSize,
                          const uint8_t *programBytes)
    {
        auto *testPlatformContext = static_cast<TestPlatformContext *>(platform->context);
        auto *testCase =
            reinterpret_cast<EGLProgramCacheControlTest *>(testPlatformContext->currentTest);
        testCase->onCache(key, programSize, programBytes);
    }
    
    // Tests error conditions of the APIs.
    TEST_P(EGLProgramCacheControlTest, NegativeAPI)
    {
        ANGLE_SKIP_TEST_IF(!extensionAvailable());
    
        constexpr char kDefaultKey[]        = "defaultMakeItLongEnough";
        constexpr char kDefaultBinary[]     = "defaultMakeItLongEnough";
        constexpr EGLint kDefaultKeySize    = static_cast<EGLint>(ArraySize(kDefaultKey));
        constexpr EGLint kDefaultBinarySize = static_cast<EGLint>(ArraySize(kDefaultBinary));
    
        // Test that passing an invalid display to the entry point methods fails.
        eglProgramCacheGetAttribANGLE(EGL_NO_DISPLAY, EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE);
        EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
    
        eglProgramCachePopulateANGLE(EGL_NO_DISPLAY, kDefaultKey, kDefaultKeySize, kDefaultBinary,
                                     kDefaultBinarySize);
        EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
    
        EGLint tempKeySize    = 0;
        EGLint tempBinarySize = 0;
        eglProgramCacheQueryANGLE(EGL_NO_DISPLAY, 0, nullptr, &tempKeySize, nullptr, &tempBinarySize);
        EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
    
        eglProgramCacheResizeANGLE(EGL_NO_DISPLAY, 0, EGL_PROGRAM_CACHE_TRIM_ANGLE);
        EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
    
        // Test querying properties with bad parameters.
        EGLDisplay display = getEGLWindow()->getDisplay();
        eglProgramCacheGetAttribANGLE(display, EGL_PROGRAM_CACHE_RESIZE_ANGLE);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        // Test populating with invalid parameters.
        EGLint keySize = eglProgramCacheGetAttribANGLE(display, EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE);
        EXPECT_GT(kDefaultKeySize, keySize);
        eglProgramCachePopulateANGLE(display, kDefaultKey, keySize + 1, kDefaultBinary,
                                     kDefaultBinarySize);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        eglProgramCachePopulateANGLE(display, kDefaultKey, keySize, kDefaultBinary, -1);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        eglProgramCachePopulateANGLE(display, nullptr, keySize, kDefaultBinary, kDefaultBinarySize);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        eglProgramCachePopulateANGLE(display, kDefaultKey, keySize, nullptr, kDefaultBinarySize);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        // Test querying cache entries with invalid parameters.
        eglProgramCachePopulateANGLE(display, kDefaultKey, keySize, kDefaultBinary, kDefaultBinarySize);
        ASSERT_EGL_SUCCESS();
    
        EGLint cacheSize = eglProgramCacheGetAttribANGLE(display, EGL_PROGRAM_CACHE_SIZE_ANGLE);
        ASSERT_EQ(1, cacheSize);
    
        eglProgramCacheQueryANGLE(display, -1, nullptr, &tempKeySize, nullptr, &tempBinarySize);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        eglProgramCacheQueryANGLE(display, 1, nullptr, &tempKeySize, nullptr, &tempBinarySize);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        eglProgramCacheQueryANGLE(display, 0, nullptr, nullptr, nullptr, &tempBinarySize);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        eglProgramCacheQueryANGLE(display, 0, nullptr, &tempKeySize, nullptr, nullptr);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        eglProgramCacheQueryANGLE(display, 0, nullptr, &tempKeySize, nullptr, &tempBinarySize);
        ASSERT_EGL_SUCCESS();
        ASSERT_EQ(keySize, tempKeySize);
        ASSERT_EQ(kDefaultBinarySize, tempBinarySize);
    
        std::vector<uint8_t> tempKey(tempKeySize + 5);
        std::vector<uint8_t> tempBinary(tempBinarySize + 5);
    
        tempKeySize--;
    
        eglProgramCacheQueryANGLE(display, 0, tempKey.data(), &tempKeySize, tempBinary.data(),
                                  &tempBinarySize);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        tempKeySize++;
        tempBinarySize--;
    
        eglProgramCacheQueryANGLE(display, 0, tempKey.data(), &tempKeySize, tempBinary.data(),
                                  &tempBinarySize);
        EXPECT_EGL_ERROR(EGL_BAD_ACCESS);
    
        // Test resizing with invalid parameters.
        eglProgramCacheResizeANGLE(display, -1, EGL_PROGRAM_CACHE_TRIM_ANGLE);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    
        eglProgramCacheResizeANGLE(display, 0, EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE);
        EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
    }
    
    // Tests a basic use case.
    TEST_P(EGLProgramCacheControlTest, SaveAndReload)
    {
        ANGLE_SKIP_TEST_IF(!extensionAvailable() || !programBinaryAvailable());
    
        constexpr char kVS[] = "attribute vec4 position; void main() { gl_Position = position; }";
        constexpr char kFS[] = "void main() { gl_FragColor = vec4(1, 0, 0, 1); }";
    
        // Link a program, which will miss the cache.
        {
            glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
            EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
    
            ANGLE_GL_PROGRAM(program, kVS, kFS);
            drawQuad(program, "position", 0.5f);
            EXPECT_GL_NO_ERROR();
            EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
        }
    
        EGLDisplay display = getEGLWindow()->getDisplay();
        EGLint cacheSize   = eglProgramCacheGetAttribANGLE(display, EGL_PROGRAM_CACHE_SIZE_ANGLE);
        EXPECT_EQ(1, cacheSize);
    
        EGLint keySize    = 0;
        EGLint binarySize = 0;
        eglProgramCacheQueryANGLE(display, 0, nullptr, &keySize, nullptr, &binarySize);
        EXPECT_EQ(static_cast<EGLint>(mCachedKey.size()), keySize);
        ASSERT_EGL_SUCCESS();
    
        ProgramKeyType keyBuffer;
        std::vector<uint8_t> binaryBuffer(binarySize);
        eglProgramCacheQueryANGLE(display, 0, keyBuffer.data(), &keySize, binaryBuffer.data(),
                                  &binarySize);
        ASSERT_EGL_SUCCESS();
    
        EXPECT_EQ(mCachedKey, keyBuffer);
        EXPECT_EQ(mCachedBinary, binaryBuffer);
    
        // Restart EGL and GL.
        recreateTestFixture();
    
        // Warm up the cache.
        EGLint newCacheSize = eglProgramCacheGetAttribANGLE(display, EGL_PROGRAM_CACHE_SIZE_ANGLE);
        EXPECT_EQ(0, newCacheSize);
        eglProgramCachePopulateANGLE(display, keyBuffer.data(), keySize, binaryBuffer.data(),
                                     binarySize);
    
        mCachedBinary.clear();
    
        // Link a program, which will hit the cache.
        {
            glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
            EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
    
            ANGLE_GL_PROGRAM(program, kVS, kFS);
            drawQuad(program, "position", 0.5f);
            EXPECT_GL_NO_ERROR();
            EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
        }
    
        // Verify no new shader was compiled.
        EXPECT_TRUE(mCachedBinary.empty());
    }
    
    // Tests that trying to link a program without correct shaders doesn't buggily call the cache.
    TEST_P(EGLProgramCacheControlTest, LinkProgramWithBadShaders)
    {
        ANGLE_SKIP_TEST_IF(!extensionAvailable());
    
        GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
    
        GLuint program = glCreateProgram();
        glAttachShader(program, shader);
        glLinkProgram(program);
    
        GLint linkStatus = 0;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
        EXPECT_GL_FALSE(linkStatus);
        EXPECT_GL_NO_ERROR();
    
        glDeleteShader(shader);
        glDeleteProgram(program);
    }
    
    ANGLE_INSTANTIATE_TEST(EGLProgramCacheControlTest,
                           ES2_D3D9(),
                           ES2_D3D11(),
                           ES2_OPENGL(),
                           ES2_VULKAN());