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 ¶ms)
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 ¶ms = 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