Edit

kc3-lang/angle/src/tests/perf_tests/TextureUploadPerf.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2020-02-19 09:39:44
    Hash : ce4918f1
    Message : Vulkan: Sanitize Images & Buffers with non-zero values. Only enabled for specific tests at the moment. This CL allows our tests to sanitizes memory for the robust resource access extension. It is quite slow so should not be enabled by default. Only works for 1 level 2D color textures and buffers. Makes several flaky robust resource initialization tests consistently fail. Controlled via an angle::Feature in FeaturesVk. It works by initializing memory to an abitrary non-zero value: - if newly allocated memory is mappable, we map it in init and set it - if a buffer or texture can be a transfer destination, we use a staging resource - otherwise we don't attempt to initialize the resource. Bug: angleproject:4384 Change-Id: I9b4f347bfcddf3096f491ed0243bef86837feaa0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2043271 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Cody Northrop <cnorthrop@google.com>

  • src/tests/perf_tests/TextureUploadPerf.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.
    //
    // TextureUploadBenchmark:
    //   Performance test for uploading texture data.
    //
    
    #include "ANGLEPerfTest.h"
    
    #include <iostream>
    #include <random>
    #include <sstream>
    
    #include "test_utils/gl_raii.h"
    #include "util/shader_utils.h"
    
    using namespace angle;
    
    namespace
    {
    constexpr unsigned int kIterationsPerStep = 2;
    
    struct TextureUploadParams final : public RenderTestParams
    {
        TextureUploadParams()
        {
            iterationsPerStep = kIterationsPerStep;
            trackGpuTime      = true;
    
            baseSize     = 1024;
            subImageSize = 64;
    
            webgl = false;
        }
    
        std::string story() const override;
    
        GLsizei baseSize;
        GLsizei subImageSize;
    
        bool webgl;
    };
    
    std::ostream &operator<<(std::ostream &os, const TextureUploadParams &params)
    {
        os << params.backendAndStory().substr(1);
        return os;
    }
    
    std::string TextureUploadParams::story() const
    {
        std::stringstream strstr;
    
        strstr << RenderTestParams::story();
    
        if (webgl)
        {
            strstr << "_webgl";
        }
    
        return strstr.str();
    }
    
    class TextureUploadBenchmarkBase : public ANGLERenderTest,
                                       public ::testing::WithParamInterface<TextureUploadParams>
    {
      public:
        TextureUploadBenchmarkBase(const char *benchmarkName);
    
        void initializeBenchmark() override;
        void destroyBenchmark() override;
    
      protected:
        void initShaders();
    
        GLuint mProgram    = 0;
        GLint mPositionLoc = -1;
        GLint mSamplerLoc  = -1;
        GLuint mTexture    = 0;
        std::vector<float> mTextureData;
    };
    
    class TextureUploadSubImageBenchmark : public TextureUploadBenchmarkBase
    {
      public:
        TextureUploadSubImageBenchmark() : TextureUploadBenchmarkBase("TexSubImage")
        {
            addExtensionPrerequisite("GL_EXT_texture_storage");
        }
    
        void initializeBenchmark() override
        {
            TextureUploadBenchmarkBase::initializeBenchmark();
    
            const auto &params = GetParam();
            glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, params.baseSize, params.baseSize);
        }
    
        void drawBenchmark() override;
    };
    
    class TextureUploadFullMipBenchmark : public TextureUploadBenchmarkBase
    {
      public:
        TextureUploadFullMipBenchmark() : TextureUploadBenchmarkBase("TextureUpload") {}
    
        void drawBenchmark() override;
    };
    
    class PBOSubImageBenchmark : public TextureUploadBenchmarkBase
    {
      public:
        PBOSubImageBenchmark() : TextureUploadBenchmarkBase("PBO") {}
    
        void initializeBenchmark() override
        {
            TextureUploadBenchmarkBase::initializeBenchmark();
    
            const auto &params = GetParam();
    
            glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, params.baseSize, params.baseSize);
    
            glGenBuffers(1, &mPBO);
            glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO);
            glBufferData(GL_PIXEL_UNPACK_BUFFER, params.baseSize * params.baseSize * 4,
                         mTextureData.data(), GL_STREAM_DRAW);
        }
    
        void destroyBenchmark()
        {
            TextureUploadBenchmarkBase::destroyBenchmark();
            glDeleteBuffers(1, &mPBO);
        }
    
        void drawBenchmark() override;
    
      private:
        GLuint mPBO;
    };
    
    class PBOCompressedSubImageBenchmark : public TextureUploadBenchmarkBase
    {
      public:
        PBOCompressedSubImageBenchmark() : TextureUploadBenchmarkBase("PBOCompressed") {}
    
        void initializeBenchmark() override
        {
            TextureUploadBenchmarkBase::initializeBenchmark();
    
            const auto &params = GetParam();
    
            glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB8_ETC2, params.baseSize,
                              params.baseSize);
    
            glGenBuffers(1, &mPBO);
            glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO);
            glBufferData(GL_PIXEL_UNPACK_BUFFER, params.subImageSize * params.subImageSize / 2,
                         mTextureData.data(), GL_STREAM_DRAW);
        }
    
        void destroyBenchmark()
        {
            TextureUploadBenchmarkBase::destroyBenchmark();
            glDeleteBuffers(1, &mPBO);
        }
    
        void drawBenchmark() override;
    
      private:
        GLuint mPBO;
    };
    
    TextureUploadBenchmarkBase::TextureUploadBenchmarkBase(const char *benchmarkName)
        : ANGLERenderTest(benchmarkName, GetParam())
    {
        setWebGLCompatibilityEnabled(GetParam().webgl);
        setRobustResourceInit(GetParam().webgl);
    
        // Crashes on nvidia+d3d11. http://crbug.com/945415
        if (GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
        {
            mSkipTest = true;
        }
    }
    
    void TextureUploadBenchmarkBase::initializeBenchmark()
    {
        const auto &params = GetParam();
    
        initShaders();
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
    
        if (params.webgl)
        {
            glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
        }
    
        glActiveTexture(GL_TEXTURE0);
        glGenTextures(1, &mTexture);
        glBindTexture(GL_TEXTURE_2D, mTexture);
    
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
        ASSERT_TRUE(params.baseSize >= params.subImageSize);
        mTextureData.resize(params.baseSize * params.baseSize * 4, 0.5);
    
        ASSERT_GL_NO_ERROR();
    }
    
    void TextureUploadBenchmarkBase::initShaders()
    {
        constexpr char kVS[] = R"(attribute vec4 a_position;
    void main()
    {
        gl_Position = a_position;
    })";
    
        constexpr char kFS[] = R"(precision mediump float;
    uniform sampler2D s_texture;
    void main()
    {
        gl_FragColor = texture2D(s_texture, vec2(0, 0));
    })";
    
        mProgram = CompileProgram(kVS, kFS);
        ASSERT_NE(0u, mProgram);
    
        mPositionLoc = glGetAttribLocation(mProgram, "a_position");
        mSamplerLoc  = glGetUniformLocation(mProgram, "s_texture");
        glUseProgram(mProgram);
        glUniform1i(mSamplerLoc, 0);
    
        glDisable(GL_DEPTH_TEST);
    
        ASSERT_GL_NO_ERROR();
    }
    
    void TextureUploadBenchmarkBase::destroyBenchmark()
    {
        glDeleteTextures(1, &mTexture);
        glDeleteProgram(mProgram);
    }
    
    void TextureUploadSubImageBenchmark::drawBenchmark()
    {
        const auto &params = GetParam();
    
        startGpuTimer();
        for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
        {
            glTexSubImage2D(GL_TEXTURE_2D, 0, rand() % (params.baseSize - params.subImageSize),
                            rand() % (params.baseSize - params.subImageSize), params.subImageSize,
                            params.subImageSize, GL_RGBA, GL_UNSIGNED_BYTE, mTextureData.data());
    
            // Perform a draw just so the texture data is flushed.  With the position attributes not
            // set, a constant default value is used, resulting in a very cheap draw.
            glDrawArrays(GL_TRIANGLES, 0, 3);
        }
        stopGpuTimer();
    
        ASSERT_GL_NO_ERROR();
    }
    
    void TextureUploadFullMipBenchmark::drawBenchmark()
    {
        const auto &params = GetParam();
    
        startGpuTimer();
        for (size_t it = 0; it < params.iterationsPerStep; ++it)
        {
            // Stage data for all mips
            GLint mip = 0;
            for (GLsizei levelSize = params.baseSize; levelSize > 0; levelSize >>= 1)
            {
                glTexImage2D(GL_TEXTURE_2D, mip++, GL_RGBA, levelSize, levelSize, 0, GL_RGBA,
                             GL_UNSIGNED_BYTE, mTextureData.data());
            }
    
            // Perform a draw just so the texture data is flushed.  With the position attributes not
            // set, a constant default value is used, resulting in a very cheap draw.
            glDrawArrays(GL_TRIANGLES, 0, 3);
        }
        stopGpuTimer();
    
        ASSERT_GL_NO_ERROR();
    }
    
    void PBOSubImageBenchmark::drawBenchmark()
    {
        const auto &params = GetParam();
    
        startGpuTimer();
        for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
        {
            glTexSubImage2D(GL_TEXTURE_2D, 0, rand() % (params.baseSize - params.subImageSize),
                            rand() % (params.baseSize - params.subImageSize), params.subImageSize,
                            params.subImageSize, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    
            // Perform a draw just so the texture data is flushed.  With the position attributes not
            // set, a constant default value is used, resulting in a very cheap draw.
            glDrawArrays(GL_TRIANGLES, 0, 3);
        }
        stopGpuTimer();
    
        ASSERT_GL_NO_ERROR();
    }
    
    void PBOCompressedSubImageBenchmark::drawBenchmark()
    {
        const auto &params = GetParam();
    
        startGpuTimer();
        for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
        {
            glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, params.subImageSize, params.subImageSize,
                                      GL_COMPRESSED_RGB8_ETC2,
                                      params.subImageSize * params.subImageSize / 2, 0);
    
            // Perform a draw just so the texture data is flushed.  With the position attributes not
            // set, a constant default value is used, resulting in a very cheap draw.
            glDrawArrays(GL_TRIANGLES, 0, 3);
        }
        stopGpuTimer();
    
        ASSERT_GL_NO_ERROR();
    }
    
    TextureUploadParams D3D11Params(bool webglCompat)
    {
        TextureUploadParams params;
        params.eglParameters = egl_platform::D3D11();
        params.webgl         = webglCompat;
        return params;
    }
    
    TextureUploadParams OpenGLOrGLESParams(bool webglCompat)
    {
        TextureUploadParams params;
        params.eglParameters = egl_platform::OPENGL_OR_GLES();
        params.webgl         = webglCompat;
        return params;
    }
    
    TextureUploadParams VulkanParams(bool webglCompat)
    {
        TextureUploadParams params;
        params.eglParameters = egl_platform::VULKAN();
        params.webgl         = webglCompat;
        return params;
    }
    
    TextureUploadParams VulkanPBOParams(GLsizei baseSize, GLsizei subImageSize)
    {
        TextureUploadParams params;
        params.eglParameters = egl_platform::VULKAN();
        params.webgl         = false;
        params.trackGpuTime  = false;
        params.baseSize      = baseSize;
        params.subImageSize  = subImageSize;
        return params;
    }
    
    TextureUploadParams ES3OpenGLPBOParams(GLsizei baseSize, GLsizei subImageSize)
    {
        TextureUploadParams params;
        params.eglParameters = egl_platform::OPENGL();
        params.majorVersion  = 3;
        params.minorVersion  = 0;
        params.webgl         = false;
        params.trackGpuTime  = false;
        params.baseSize      = baseSize;
        params.subImageSize  = subImageSize;
        return params;
    }
    
    }  // anonymous namespace
    
    TEST_P(TextureUploadSubImageBenchmark, Run)
    {
        run();
    }
    
    TEST_P(TextureUploadFullMipBenchmark, Run)
    {
        run();
    }
    
    TEST_P(PBOSubImageBenchmark, Run)
    {
        run();
    }
    
    TEST_P(PBOCompressedSubImageBenchmark, Run)
    {
        run();
    }
    
    using namespace params;
    
    ANGLE_INSTANTIATE_TEST(TextureUploadSubImageBenchmark,
                           D3D11Params(false),
                           D3D11Params(true),
                           OpenGLOrGLESParams(false),
                           OpenGLOrGLESParams(true),
                           VulkanParams(false),
                           NullDevice(VulkanParams(false)),
                           VulkanParams(true));
    
    ANGLE_INSTANTIATE_TEST(TextureUploadFullMipBenchmark,
                           D3D11Params(false),
                           D3D11Params(true),
                           OpenGLOrGLESParams(false),
                           OpenGLOrGLESParams(true),
                           VulkanParams(false),
                           VulkanParams(true));
    
    ANGLE_INSTANTIATE_TEST(PBOSubImageBenchmark,
                           ES3OpenGLPBOParams(1024, 128),
                           VulkanPBOParams(1024, 128));
    
    ANGLE_INSTANTIATE_TEST(PBOCompressedSubImageBenchmark,
                           ES3OpenGLPBOParams(128, 128),
                           VulkanPBOParams(128, 128));