| // |
| // Copyright 2021 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. |
| // |
| // FramebufferAttachPerfTest: |
| // Performance test for attaching and detaching resources to a Framebuffer. |
| // |
| |
| #include "ANGLEPerfTest.h" |
| #include "test_utils/gl_raii.h" |
| |
| #include <iostream> |
| #include <random> |
| #include <sstream> |
| |
| namespace angle |
| { |
| constexpr unsigned int kIterationsPerStep = 256; |
| constexpr unsigned int kTextureSize = 256; |
| constexpr std::size_t kTextureCount = 4; |
| constexpr std::size_t kFboCount = kTextureCount; |
| constexpr std::size_t kAdditionalFboCount = kFboCount * kFboCount; |
| |
| struct FramebufferAttachmentParams final : public RenderTestParams |
| { |
| FramebufferAttachmentParams() |
| { |
| iterationsPerStep = kIterationsPerStep; |
| |
| // Common default params |
| majorVersion = 3; |
| minorVersion = 0; |
| windowWidth = kTextureSize; |
| windowHeight = kTextureSize; |
| } |
| |
| std::string story() const override; |
| }; |
| |
| std::ostream &operator<<(std::ostream &os, const FramebufferAttachmentParams ¶ms) |
| { |
| os << params.backendAndStory().substr(1); |
| return os; |
| } |
| |
| std::string FramebufferAttachmentParams::story() const |
| { |
| std::stringstream strstr; |
| |
| strstr << RenderTestParams::story(); |
| |
| return strstr.str(); |
| } |
| |
| class FramebufferAttachmentBenchmark |
| : public ANGLERenderTest, |
| public ::testing::WithParamInterface<FramebufferAttachmentParams> |
| { |
| public: |
| FramebufferAttachmentBenchmark() : ANGLERenderTest("Framebuffers", GetParam()) {} |
| void initializeBenchmark() override; |
| void drawBenchmark() override; |
| |
| protected: |
| void initTextures(); |
| |
| std::array<GLTexture, kTextureCount> mTextures; |
| std::array<GLFramebuffer, kFboCount> mFbo; |
| }; |
| |
| void FramebufferAttachmentBenchmark::initializeBenchmark() |
| { |
| initTextures(); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| GLint maxAttachmentCount; |
| glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxAttachmentCount); |
| if (mTextures.size() > static_cast<size_t>(maxAttachmentCount)) |
| { |
| skipTest("Texture count exceeds maximum attachment unit count"); |
| } |
| } |
| |
| void FramebufferAttachmentBenchmark::initTextures() |
| { |
| std::vector<GLubyte> textureData(kTextureSize * kTextureSize * 4); |
| for (auto &byte : textureData) |
| { |
| byte = rand() % 255u; |
| } |
| |
| for (GLTexture &texture : mTextures) |
| { |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureSize, kTextureSize, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| } |
| } |
| |
| void FramebufferAttachmentBenchmark::drawBenchmark() |
| { |
| const auto ¶ms = GetParam(); |
| |
| size_t fboCount = mFbo.size(); |
| size_t textureCount = mTextures.size(); |
| |
| for (size_t it = 0; it < params.iterationsPerStep; ++it) |
| { |
| // Attach |
| for (size_t fboIndex = 0; fboIndex < fboCount; fboIndex++) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mFbo[fboIndex]); |
| for (size_t textureIndex = 0; textureIndex < textureCount; textureIndex++) |
| { |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + textureIndex, |
| GL_TEXTURE_2D, mTextures[textureIndex], 0); |
| } |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| } |
| |
| // Detach |
| for (size_t fboIndex = 0; fboIndex < fboCount; fboIndex++) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mFbo[fboIndex]); |
| for (size_t index = 0; index < textureCount; index++) |
| { |
| size_t textureIndex = mTextures.size() - (index + 1); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + textureIndex, |
| GL_TEXTURE_2D, 0, 0); |
| } |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| } |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| class FramebufferAttachmentStateUpdateBenchmark : public FramebufferAttachmentBenchmark |
| { |
| public: |
| FramebufferAttachmentStateUpdateBenchmark() : FramebufferAttachmentBenchmark() {} |
| void initializeBenchmark() override; |
| void destroyBenchmark() override; |
| void drawBenchmark() override; |
| |
| private: |
| std::array<GLFramebuffer, kAdditionalFboCount> mAdditionalFbo; |
| }; |
| |
| void FramebufferAttachmentStateUpdateBenchmark::initializeBenchmark() |
| { |
| FramebufferAttachmentBenchmark::initializeBenchmark(); |
| |
| // Attach |
| for (size_t fboIndex = 0; fboIndex < mAdditionalFbo.size(); fboIndex++) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mAdditionalFbo[fboIndex]); |
| for (size_t textureIndex = 0; textureIndex < mTextures.size(); textureIndex++) |
| { |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + textureIndex, |
| GL_TEXTURE_2D, mTextures[textureIndex], 0); |
| } |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| } |
| } |
| |
| void FramebufferAttachmentStateUpdateBenchmark::destroyBenchmark() |
| { |
| // Detach |
| for (size_t fboIndex = 0; fboIndex < mAdditionalFbo.size(); fboIndex++) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, mAdditionalFbo[fboIndex]); |
| for (size_t index = 0; index < mTextures.size(); index++) |
| { |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, GL_TEXTURE_2D, 0, |
| 0); |
| } |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| } |
| |
| FramebufferAttachmentBenchmark::destroyBenchmark(); |
| } |
| |
| void FramebufferAttachmentStateUpdateBenchmark::drawBenchmark() |
| { |
| const auto ¶ms = GetParam(); |
| |
| size_t textureCount = mTextures.size(); |
| GLenum nearestFilter = GL_NEAREST; |
| GLenum linearFilter = GL_LINEAR; |
| for (size_t it = 0; it < params.iterationsPerStep; ++it) |
| { |
| for (size_t textureIndex = 0; textureIndex < textureCount; textureIndex++) |
| { |
| glBindTexture(GL_TEXTURE_2D, mTextures[textureIndex]); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, |
| (it % 2) ? linearFilter : nearestFilter); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| } |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| FramebufferAttachmentParams VulkanParams() |
| { |
| FramebufferAttachmentParams params; |
| params.eglParameters = egl_platform::VULKAN_NULL(); |
| |
| return params; |
| } |
| |
| TEST_P(FramebufferAttachmentBenchmark, Run) |
| { |
| run(); |
| } |
| |
| TEST_P(FramebufferAttachmentStateUpdateBenchmark, Run) |
| { |
| run(); |
| } |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferAttachmentBenchmark); |
| ANGLE_INSTANTIATE_TEST(FramebufferAttachmentBenchmark, VulkanParams()); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferAttachmentStateUpdateBenchmark); |
| ANGLE_INSTANTIATE_TEST(FramebufferAttachmentStateUpdateBenchmark, VulkanParams()); |
| } // namespace angle |