// // 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. // // ClearPerf: // Performance test for clearing framebuffers. // #include "ANGLEPerfTest.h" #include #include #include #include "test_utils/ANGLETest.h" #include "test_utils/gl_raii.h" #include "util/random_utils.h" #include "util/shader_utils.h" using namespace angle; namespace { constexpr unsigned int kIterationsPerStep = 256; struct ClearParams final : public RenderTestParams { ClearParams() { iterationsPerStep = kIterationsPerStep; trackGpuTime = true; fboSize = 2048; internalFormat = GL_RGBA8; scissoredClear = false; } std::string story() const override; GLsizei fboSize; GLsizei textureSize; GLenum internalFormat; bool scissoredClear; }; std::ostream &operator<<(std::ostream &os, const ClearParams ¶ms) { os << params.backendAndStory().substr(1); return os; } std::string ClearParams::story() const { std::stringstream strstr; strstr << RenderTestParams::story(); if (internalFormat == GL_RGB8) { strstr << "_rgb"; } if (scissoredClear) { strstr << "_scissoredClear"; } return strstr.str(); } class ClearBenchmark : public ANGLERenderTest, public ::testing::WithParamInterface { public: ClearBenchmark(); void initializeBenchmark() override; void destroyBenchmark() override; void drawBenchmark() override; private: void initShaders(); std::vector mTextures; GLuint mProgram; }; ClearBenchmark::ClearBenchmark() : ANGLERenderTest("Clear", GetParam()), mProgram(0u) { if (GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) { skipTest("http://crbug.com/945415 Crashes on nvidia+d3d11"); } } void ClearBenchmark::initializeBenchmark() { initShaders(); glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); ASSERT_GL_NO_ERROR(); } void ClearBenchmark::initShaders() { constexpr char kVS[] = R"(void main() { gl_Position = vec4(0, 0, 0, 1); })"; constexpr char kFS[] = R"(precision mediump float; void main() { gl_FragColor = vec4(0); })"; mProgram = CompileProgram(kVS, kFS); ASSERT_NE(0u, mProgram); glUseProgram(mProgram); glDisable(GL_DEPTH_TEST); ASSERT_GL_NO_ERROR(); } void ClearBenchmark::destroyBenchmark() { glDeleteProgram(mProgram); } void ClearBenchmark::drawBenchmark() { const auto ¶ms = GetParam(); GLRenderbuffer colorRbo; glBindRenderbuffer(GL_RENDERBUFFER, colorRbo); glRenderbufferStorage(GL_RENDERBUFFER, params.internalFormat, params.fboSize, params.fboSize); GLRenderbuffer depthRbo; glBindRenderbuffer(GL_RENDERBUFFER, depthRbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, params.fboSize, params.fboSize); GLFramebuffer fbo; glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRbo); glViewport(0, 0, params.fboSize, params.fboSize); glDisable(GL_SCISSOR_TEST); startGpuTimer(); if (params.scissoredClear) { angle::RNG rng; const GLuint width = params.fboSize; const GLuint height = params.fboSize; for (GLuint index = 0; index < (width - 1) / 2; index++) { // Do the first clear without the scissor. if (index > 0) { glEnable(GL_SCISSOR_TEST); glScissor(index, index, width - (index * 2), height - (index * 2)); } GLColor color = RandomColor(&rng); Vector4 floatColor = color.toNormalizedVector(); glClearColor(floatColor[0], floatColor[1], floatColor[2], floatColor[3]); glClear(GL_COLOR_BUFFER_BIT); } } else { for (size_t it = 0; it < params.iterationsPerStep; ++it) { float clearValue = (it % 2) * 0.5f + 0.2f; glClearColor(clearValue, clearValue, clearValue, clearValue); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDrawArrays(GL_TRIANGLES, 0, 3); } } stopGpuTimer(); ASSERT_GL_NO_ERROR(); } ClearParams D3D11Params() { ClearParams params; params.eglParameters = egl_platform::D3D11(); return params; } ClearParams MetalParams() { ClearParams params; params.eglParameters = egl_platform::METAL(); return params; } ClearParams OpenGLOrGLESParams() { ClearParams params; params.eglParameters = egl_platform::OPENGL_OR_GLES(); return params; } ClearParams VulkanParams(bool emulatedFormat, bool scissoredClear) { ClearParams params; params.eglParameters = egl_platform::VULKAN(); if (emulatedFormat) { params.internalFormat = GL_RGB8; } params.scissoredClear = scissoredClear; return params; } } // anonymous namespace TEST_P(ClearBenchmark, Run) { run(); } ANGLE_INSTANTIATE_TEST(ClearBenchmark, D3D11Params(), MetalParams(), OpenGLOrGLESParams(), VulkanParams(false, false), VulkanParams(true, false), VulkanParams(false, true));