| // | |
| // Copyright 2020 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. | |
| // | |
| // PreRotationBenchmark: | |
| // Performance test for pre-rotation code generation. | |
| // | |
| #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 = 20; | |
| enum class PreRotation | |
| { | |
| _0, | |
| _90, | |
| _180, | |
| _270, | |
| }; | |
| struct PreRotationParams final : public RenderTestParams | |
| { | |
| PreRotationParams() | |
| { | |
| iterationsPerStep = kIterationsPerStep; | |
| trackGpuTime = true; | |
| preRotation = PreRotation::_0; | |
| } | |
| std::string story() const override; | |
| PreRotation preRotation; | |
| }; | |
| std::ostream &operator<<(std::ostream &os, const PreRotationParams ¶ms) | |
| { | |
| return os << params.backendAndStory().substr(1); | |
| } | |
| std::string PreRotationParams::story() const | |
| { | |
| std::stringstream strstr; | |
| strstr << RenderTestParams::story(); | |
| switch (preRotation) | |
| { | |
| case PreRotation::_0: | |
| strstr << "_NoPreRotation"; | |
| break; | |
| case PreRotation::_90: | |
| strstr << "_PreRotate90"; | |
| break; | |
| case PreRotation::_180: | |
| strstr << "_PreRotate180"; | |
| break; | |
| case PreRotation::_270: | |
| strstr << "_PreRotate270"; | |
| break; | |
| } | |
| return strstr.str(); | |
| } | |
| class PreRotationBenchmark : public ANGLERenderTest, | |
| public ::testing::WithParamInterface<PreRotationParams> | |
| { | |
| public: | |
| PreRotationBenchmark(); | |
| void initializeBenchmark() override; | |
| void destroyBenchmark() override; | |
| void drawBenchmark() override; | |
| protected: | |
| GLuint mProgram = 0; | |
| }; | |
| PreRotationBenchmark::PreRotationBenchmark() : ANGLERenderTest("PreRotation", GetParam()) {} | |
| void PreRotationBenchmark::initializeBenchmark() | |
| { | |
| constexpr char kVS[] = R"( | |
| attribute mediump vec4 positionIn; | |
| void main() | |
| { | |
| gl_Position = positionIn; | |
| })"; | |
| constexpr char kFS[] = R"(precision mediump float; | |
| void main() | |
| { | |
| gl_FragColor = vec4(0); | |
| })"; | |
| mProgram = CompileProgram(kVS, kFS); | |
| ASSERT_NE(0u, mProgram); | |
| glUseProgram(mProgram); | |
| ASSERT_GL_NO_ERROR(); | |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | |
| glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); | |
| // Perform a draw so everything is flushed. | |
| glDrawArrays(GL_TRIANGLES, 0, 3); | |
| ASSERT_GL_NO_ERROR(); | |
| } | |
| void PreRotationBenchmark::destroyBenchmark() | |
| { | |
| glDeleteProgram(mProgram); | |
| } | |
| void PreRotationBenchmark::drawBenchmark() | |
| { | |
| const auto ¶ms = GetParam(); | |
| constexpr uint32_t kDrawCallSize = 100'000; | |
| GLint attribLocation = glGetAttribLocation(mProgram, "positionIn"); | |
| ASSERT_NE(-1, attribLocation); | |
| startGpuTimer(); | |
| for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration) | |
| { | |
| // Set the position attribute such that every generated primitive is out of bounds and is | |
| // clipped. This means the test is spending its time almost entirely with vertex shaders. | |
| // The vertex shader itself is simple so that any code that is added for pre-rotation will | |
| // contribute a comparably sizable chunk of code. | |
| switch (iteration % 5) | |
| { | |
| case 0: | |
| glVertexAttrib4f(attribLocation, -2.0f, 0.0f, 0.0f, 1.0f); | |
| break; | |
| case 1: | |
| glVertexAttrib4f(attribLocation, 2.0f, 0.0f, 0.0f, 1.0f); | |
| break; | |
| case 2: | |
| glVertexAttrib4f(attribLocation, 0.0f, -2.0f, 0.0f, 1.0f); | |
| break; | |
| case 3: | |
| glVertexAttrib4f(attribLocation, 0.0f, 2.0f, 0.0f, 1.0f); | |
| break; | |
| case 4: | |
| glVertexAttrib4f(attribLocation, 0.0f, 0.0f, -2.0f, 1.0f); | |
| break; | |
| } | |
| // Draw many points, all which are culled. | |
| glDrawArrays(GL_POINTS, 0, kDrawCallSize); | |
| } | |
| stopGpuTimer(); | |
| ASSERT_GL_NO_ERROR(); | |
| } | |
| PreRotationParams VulkanParams(PreRotation preRotation) | |
| { | |
| PreRotationParams params; | |
| params.eglParameters = egl_platform::VULKAN(); | |
| params.preRotation = preRotation; | |
| switch (preRotation) | |
| { | |
| case PreRotation::_0: | |
| break; | |
| case PreRotation::_90: | |
| params.eglParameters.enable(Feature::EmulatedPrerotation90); | |
| break; | |
| case PreRotation::_180: | |
| params.eglParameters.enable(Feature::EmulatedPrerotation180); | |
| break; | |
| case PreRotation::_270: | |
| params.eglParameters.enable(Feature::EmulatedPrerotation270); | |
| break; | |
| } | |
| return params; | |
| } | |
| } // anonymous namespace | |
| TEST_P(PreRotationBenchmark, Run) | |
| { | |
| run(); | |
| } | |
| using namespace params; | |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PreRotationBenchmark); | |
| ANGLE_INSTANTIATE_TEST(PreRotationBenchmark, | |
| VulkanParams(PreRotation::_0), | |
| VulkanParams(PreRotation::_90), | |
| VulkanParams(PreRotation::_180), | |
| VulkanParams(PreRotation::_270)); |