1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // PreRotationBenchmark:
7 //   Performance test for pre-rotation code generation.
8 //
9 
10 #include "ANGLEPerfTest.h"
11 
12 #include <iostream>
13 #include <random>
14 #include <sstream>
15 
16 #include "test_utils/gl_raii.h"
17 #include "util/shader_utils.h"
18 
19 using namespace angle;
20 
21 namespace
22 {
23 constexpr unsigned int kIterationsPerStep = 20;
24 
25 enum class PreRotation
26 {
27     _0,
28     _90,
29     _180,
30     _270,
31 };
32 
33 struct PreRotationParams final : public RenderTestParams
34 {
PreRotationParams__anonc6ad4fa30111::PreRotationParams35     PreRotationParams()
36     {
37         iterationsPerStep = kIterationsPerStep;
38         trackGpuTime      = true;
39 
40         preRotation = PreRotation::_0;
41     }
42 
43     std::string story() const override;
44 
45     PreRotation preRotation;
46 };
47 
operator <<(std::ostream & os,const PreRotationParams & params)48 std::ostream &operator<<(std::ostream &os, const PreRotationParams &params)
49 {
50     return os << params.backendAndStory().substr(1);
51 }
52 
story() const53 std::string PreRotationParams::story() const
54 {
55     std::stringstream strstr;
56 
57     strstr << RenderTestParams::story();
58 
59     switch (preRotation)
60     {
61         case PreRotation::_0:
62             strstr << "_NoPreRotation";
63             break;
64         case PreRotation::_90:
65             strstr << "_PreRotate90";
66             break;
67         case PreRotation::_180:
68             strstr << "_PreRotate180";
69             break;
70         case PreRotation::_270:
71             strstr << "_PreRotate270";
72             break;
73     }
74 
75     return strstr.str();
76 }
77 
78 class PreRotationBenchmark : public ANGLERenderTest,
79                              public ::testing::WithParamInterface<PreRotationParams>
80 {
81   public:
82     PreRotationBenchmark();
83 
84     void initializeBenchmark() override;
85     void destroyBenchmark() override;
86 
87     void drawBenchmark() override;
88 
89   protected:
90     GLuint mProgram = 0;
91 };
92 
PreRotationBenchmark()93 PreRotationBenchmark::PreRotationBenchmark() : ANGLERenderTest("PreRotation", GetParam()) {}
94 
initializeBenchmark()95 void PreRotationBenchmark::initializeBenchmark()
96 {
97     constexpr char kVS[] = R"(
98 attribute mediump vec4 positionIn;
99 void main()
100 {
101     gl_Position = positionIn;
102 })";
103 
104     constexpr char kFS[] = R"(precision mediump float;
105 void main()
106 {
107     gl_FragColor = vec4(0);
108 })";
109 
110     mProgram = CompileProgram(kVS, kFS);
111     ASSERT_NE(0u, mProgram);
112 
113     glUseProgram(mProgram);
114 
115     ASSERT_GL_NO_ERROR();
116 
117     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
118     glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
119 
120     // Perform a draw so everything is flushed.
121     glDrawArrays(GL_TRIANGLES, 0, 3);
122 
123     ASSERT_GL_NO_ERROR();
124 }
125 
destroyBenchmark()126 void PreRotationBenchmark::destroyBenchmark()
127 {
128     glDeleteProgram(mProgram);
129 }
130 
drawBenchmark()131 void PreRotationBenchmark::drawBenchmark()
132 {
133     const auto &params = GetParam();
134 
135     constexpr uint32_t kDrawCallSize = 100'000;
136 
137     GLint attribLocation = glGetAttribLocation(mProgram, "positionIn");
138     ASSERT_NE(-1, attribLocation);
139 
140     startGpuTimer();
141     for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
142     {
143         // Set the position attribute such that every generated primitive is out of bounds and is
144         // clipped.  This means the test is spending its time almost entirely with vertex shaders.
145         // The vertex shader itself is simple so that any code that is added for pre-rotation will
146         // contribute a comparably sizable chunk of code.
147         switch (iteration % 5)
148         {
149             case 0:
150                 glVertexAttrib4f(attribLocation, -2.0f, 0.0f, 0.0f, 1.0f);
151                 break;
152             case 1:
153                 glVertexAttrib4f(attribLocation, 2.0f, 0.0f, 0.0f, 1.0f);
154                 break;
155             case 2:
156                 glVertexAttrib4f(attribLocation, 0.0f, -2.0f, 0.0f, 1.0f);
157                 break;
158             case 3:
159                 glVertexAttrib4f(attribLocation, 0.0f, 2.0f, 0.0f, 1.0f);
160                 break;
161             case 4:
162                 glVertexAttrib4f(attribLocation, 0.0f, 0.0f, -2.0f, 1.0f);
163                 break;
164         }
165 
166         // Draw many points, all which are culled.
167         glDrawArrays(GL_POINTS, 0, kDrawCallSize);
168     }
169     stopGpuTimer();
170 
171     ASSERT_GL_NO_ERROR();
172 }
173 
VulkanParams(PreRotation preRotation)174 PreRotationParams VulkanParams(PreRotation preRotation)
175 {
176     PreRotationParams params;
177     params.eglParameters = egl_platform::VULKAN();
178     params.preRotation   = preRotation;
179 
180     switch (preRotation)
181     {
182         case PreRotation::_0:
183             break;
184         case PreRotation::_90:
185             params.eglParameters.emulatedPrerotation = 90;
186             break;
187         case PreRotation::_180:
188             params.eglParameters.emulatedPrerotation = 180;
189             break;
190         case PreRotation::_270:
191             params.eglParameters.emulatedPrerotation = 270;
192             break;
193     }
194 
195     return params;
196 }
197 
198 }  // anonymous namespace
199 
TEST_P(PreRotationBenchmark,Run)200 TEST_P(PreRotationBenchmark, Run)
201 {
202     run();
203 }
204 
205 using namespace params;
206 
207 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PreRotationBenchmark);
208 ANGLE_INSTANTIATE_TEST(PreRotationBenchmark,
209                        VulkanParams(PreRotation::_0),
210                        VulkanParams(PreRotation::_90),
211                        VulkanParams(PreRotation::_180),
212                        VulkanParams(PreRotation::_270));
213