blob: 5872d92aad04cb256b54d104d439acd0f9f65b40 [file] [log] [blame]
Martin Radev6a6199b2017-06-05 17:30:55 +03001//
2// Copyright (c) 2017 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// MultiviewPerfTest:
7// Performance tests for multiview rendering.
8// - MultiviewCPUBoundBenchmark issues many draw calls and state changes to stress the CPU.
9// - MultiviewGPUBoundBenchmark draws half a million quads with multiple attributes per vertex in
10// order to stress the GPU's memory system.
11//
12
13#include "ANGLEPerfTest.h"
14#include "common/vector_utils.h"
15#include "shader_utils.h"
16#include "test_utils/gl_raii.h"
17#include "tests/test_utils/ANGLETest.h"
18
19#include <string.h>
20
21using namespace angle;
22
23namespace
24{
25
26std::string GetShaderExtensionHeader(bool usesMultiview, int numViews, GLenum shaderType)
27{
28 if (!usesMultiview)
29 {
30 return "";
31 }
32
33 if (shaderType == GL_VERTEX_SHADER)
34 {
35 return "#extension GL_OVR_multiview : require\nlayout(num_views = " + ToString(numViews) +
36 ") in;\n";
37 ;
38 }
39 ASSERT(shaderType == GL_FRAGMENT_SHADER);
40 return "#extension GL_OVR_multiview : require\n";
41}
42
43struct Vertex
44{
45 Vector4 position;
46 Vector4 colorAttributeData[6];
47};
48
49enum class MultiviewOption
50{
51 NoAcceleration,
52 SelectViewportInVertexShader,
53
54 Unspecified
55};
56
57struct MultiviewPerfParams final : public RenderTestParams
58{
59 MultiviewPerfParams()
60 {
61 majorVersion = 3;
62 minorVersion = 0;
63 windowWidth = 64;
64 windowHeight = 64;
65 eglParameters = egl_platform::OPENGL();
66 multiviewOption = MultiviewOption::Unspecified;
67 numViews = 2;
68 }
69
70 std::string suffix() const override
71 {
72 std::string name = RenderTestParams::suffix();
73 switch (multiviewOption)
74 {
75 case MultiviewOption::NoAcceleration:
76 name += "_no_acc";
77 break;
78 case MultiviewOption::SelectViewportInVertexShader:
79 name += "_viewport_in_vs";
80 break;
81 default:
82 UNREACHABLE();
83 }
84 name += "_" + ToString(numViews) + "_views";
85 return name;
86 }
87
88 MultiviewOption multiviewOption;
89 int numViews;
90};
91
92std::ostream &operator<<(std::ostream &os, const MultiviewPerfParams &params)
93{
94 os << params.suffix().substr(1);
95 return os;
96}
97
98class MultiviewBenchmark : public ANGLERenderTest,
99 public ::testing::WithParamInterface<MultiviewPerfParams>
100{
101 public:
102 MultiviewBenchmark(const std::string &testName)
103 : ANGLERenderTest(testName, GetParam(), {"GL_ANGLE_multiview"}), mProgram(0)
104 {
105 }
106 virtual ~MultiviewBenchmark()
107 {
108 if (mProgram != 0)
109 {
110 glDeleteProgram(mProgram);
111 }
112 }
113
114 void initializeBenchmark() override;
115 void drawBenchmark() final;
116
117 protected:
118 virtual void renderScene() = 0;
119
120 void createProgram(const std::string &vs, const std::string &fs)
121 {
122 mProgram = CompileProgram(vs, fs);
123 if (mProgram == 0)
124 {
125 FAIL() << "shader compilation failed.";
126 }
127 glUseProgram(mProgram);
128 ASSERT_GL_NO_ERROR();
129 }
130
131 GLuint mProgram;
132 GLVertexArray mVAO;
133 GLBuffer mVBO;
134
135 private:
136 GLFramebuffer mFramebuffer;
137 GLTexture mColorTexture;
138 GLTexture mDepthTexture;
139};
140
141class MultiviewCPUBoundBenchmark : public MultiviewBenchmark
142{
143 public:
144 MultiviewCPUBoundBenchmark() : MultiviewBenchmark("MultiviewCPUBoundBenchmark") {}
145
146 void initializeBenchmark() override;
147
148 protected:
149 void renderScene() override;
150};
151
152class MultiviewGPUBoundBenchmark : public MultiviewBenchmark
153{
154 public:
155 MultiviewGPUBoundBenchmark() : MultiviewBenchmark("MultiviewGPUBoundBenchmark") {}
156
157 void initializeBenchmark() override;
158
159 protected:
160 void renderScene() override;
161};
162
163void MultiviewBenchmark::initializeBenchmark()
164{
165 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
166 ASSERT(params->windowWidth % params->numViews == 0);
167
168 glBindTexture(GL_TEXTURE_2D, mColorTexture);
169 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, params->windowWidth, params->windowHeight, 0, GL_RGBA,
170 GL_UNSIGNED_BYTE, NULL);
171
172 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
173 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, params->windowWidth, params->windowHeight,
174 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
175
176 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
177
178 switch (params->multiviewOption)
179 {
180 case MultiviewOption::NoAcceleration:
181 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
182 mColorTexture, 0);
183 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
184 mDepthTexture, 0);
185 break;
186 case MultiviewOption::SelectViewportInVertexShader:
187 {
188 const int widthPerView = params->windowWidth / params->numViews;
189 std::vector<GLint> viewportOffsets(2 * params->numViews);
190 for (int i = 0u; i < params->numViews; ++i)
191 {
192 viewportOffsets[i * 2] = i * widthPerView;
193 viewportOffsets[i * 2 + 1] = 0;
194 }
195 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
196 mColorTexture, 0, params->numViews,
197 viewportOffsets.data());
198 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
199 mDepthTexture, 0, params->numViews,
200 viewportOffsets.data());
201 break;
202 }
203 default:
204 UNREACHABLE();
205 }
206
207 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
208 glDrawBuffers(1, DrawBuffers);
209
210 ASSERT_GL_NO_ERROR();
211}
212
213void MultiviewBenchmark::drawBenchmark()
214{
215 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
216 const int viewWidth = params->windowWidth / params->numViews;
217 const int viewHeight = params->windowHeight;
218
219 switch (params->multiviewOption)
220 {
221 case MultiviewOption::NoAcceleration:
222 glEnable(GL_SCISSOR_TEST);
223 // Iterate over each view and render the scene.
224 for (int i = 0; i < params->numViews; ++i)
225 {
226 glViewport(viewWidth * i, 0, viewWidth, viewHeight);
227 glScissor(viewWidth * i, 0, viewWidth, viewHeight);
228 renderScene();
229 }
230 break;
231 case MultiviewOption::SelectViewportInVertexShader:
232 glViewport(0, 0, viewWidth, viewHeight);
233 glScissor(0, 0, viewWidth, viewHeight);
234 renderScene();
235 break;
236 default:
237 UNREACHABLE();
238 }
239
240 ASSERT_GL_NO_ERROR();
241}
242
243void MultiviewCPUBoundBenchmark::initializeBenchmark()
244{
245 MultiviewBenchmark::initializeBenchmark();
246
247 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
248 const bool usesMultiview = (params->multiviewOption != MultiviewOption::NoAcceleration);
249
250 const std::string &vs =
251 "#version 300 es\n" +
252 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_VERTEX_SHADER) +
253 "layout(location=0) in vec4 vPosition;\n"
254 "uniform vec2 uOffset;\n"
255 "void main()\n"
256 "{\n"
257 " vec4 v = vPosition;\n"
258 " v.xy += uOffset;\n"
259 " gl_Position = v;\n"
260 "}\n";
261
262 const std::string &fs =
263 "#version 300 es\n" +
264 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_FRAGMENT_SHADER) +
265 "precision mediump float;\n"
266 "out vec4 col;\n"
267 "uniform float uColor;\n"
268 "void main()\n"
269 "{\n"
270 " col = vec4(1.);\n"
271 "}\n";
272
273 createProgram(vs, fs);
274
275 const float viewWidth = static_cast<float>(params->windowWidth / params->numViews);
276 const float viewHeight = static_cast<float>(params->windowHeight);
277 const float quadWidth = 2.f / viewWidth;
278 const float quadHeight = 2.f / viewHeight;
279 Vector4 vertices[6] = {Vector4(.0f, .0f, .0f, 1.f),
280 Vector4(quadWidth, .0f, .0f, 1.f),
281 Vector4(quadWidth, quadHeight, 0.f, 1.f),
282 Vector4(.0f, .0f, 0.f, 1.f),
283 Vector4(quadWidth, quadHeight, .0f, 1.f),
284 Vector4(.0f, quadHeight, .0f, 1.f)};
285
286 glBindVertexArray(mVAO);
287
288 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
289 glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(Vector4), vertices, GL_STATIC_DRAW);
290
291 const GLint posLoc = glGetAttribLocation(mProgram, "vPosition");
292 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, 0);
293 glEnableVertexAttribArray(posLoc);
294
295 // Render once to guarantee that the program is compiled and linked.
296 drawBenchmark();
297
298 ASSERT_GL_NO_ERROR();
299}
300
301void MultiviewCPUBoundBenchmark::renderScene()
302{
303 glClearColor(0, 0, 0, 0);
304 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
305 glUseProgram(mProgram);
306
307 glBindVertexArray(mVAO);
308
309 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
310 const int viewWidth = params->windowWidth / params->numViews;
311 const int viewHeight = params->windowHeight;
312
313 for (int w = 0; w < viewWidth; ++w)
314 {
315 for (int h = 0; h < viewHeight; ++h)
316 {
317 const float wf = static_cast<float>(w) / viewWidth;
318 const float wh = static_cast<float>(h) / viewHeight;
319 glUniform2f(glGetUniformLocation(mProgram, "uOffset"), 2.f * wf - 1.f, 2.f * wh - 1.f);
320 glUniform1f(glGetUniformLocation(mProgram, "uColor"), wf);
321 glDrawArrays(GL_TRIANGLES, 0, 6);
322 }
323 }
324}
325
326void MultiviewGPUBoundBenchmark::initializeBenchmark()
327{
328 MultiviewBenchmark::initializeBenchmark();
329
330 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
331 const bool usesMultiview = (params->multiviewOption != MultiviewOption::NoAcceleration);
332
333 const std::string &vs =
334 "#version 300 es\n" +
335 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_VERTEX_SHADER) +
336 "layout(location=0) in vec4 vPosition;\n"
337 "layout(location=1) in vec4 vert_Col0;\n"
338 "layout(location=2) in vec4 vert_Col1;\n"
339 "layout(location=3) in vec4 vert_Col2;\n"
340 "layout(location=4) in vec4 vert_Col3;\n"
341 "layout(location=5) in vec4 vert_Col4;\n"
342 "layout(location=6) in vec4 vert_Col5;\n"
343 "out vec4 frag_Col0;\n"
344 "out vec4 frag_Col1;\n"
345 "out vec4 frag_Col2;\n"
346 "out vec4 frag_Col3;\n"
347 "out vec4 frag_Col4;\n"
348 "out vec4 frag_Col5;\n"
349 "void main()\n"
350 "{\n"
351 " frag_Col0 = vert_Col0;\n"
352 " frag_Col1 = vert_Col1;\n"
353 " frag_Col2 = vert_Col2;\n"
354 " frag_Col3 = vert_Col3;\n"
355 " frag_Col4 = vert_Col4;\n"
356 " frag_Col5 = vert_Col5;\n"
357 " gl_Position = vPosition;\n"
358 "}\n";
359
360 const std::string &fs =
361 "#version 300 es\n" +
362 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_FRAGMENT_SHADER) +
363 "precision mediump float;\n"
364 "in vec4 frag_Col0;\n"
365 "in vec4 frag_Col1;\n"
366 "in vec4 frag_Col2;\n"
367 "in vec4 frag_Col3;\n"
368 "in vec4 frag_Col4;\n"
369 "in vec4 frag_Col5;\n"
370 "out vec4 col;\n"
371 "void main()\n"
372 "{\n"
373 " col += frag_Col0;\n"
374 " col += frag_Col1;\n"
375 " col += frag_Col2;\n"
376 " col += frag_Col3;\n"
377 " col += frag_Col4;\n"
378 " col += frag_Col5;\n"
379 "}\n";
380
381 createProgram(vs, fs);
382 ASSERT_GL_NO_ERROR();
383
384 // Generate a vertex buffer of triangulated quads so that we have one quad per pixel.
385 const int viewWidth = params->windowWidth / params->numViews;
386 const int viewHeight = params->windowHeight;
387 const float quadWidth = 2.f / static_cast<float>(viewWidth);
388 const float quadHeight = 2.f / static_cast<float>(viewHeight);
389 const int kNumQuads = viewWidth * viewHeight;
390 const int kNumVerticesPerQuad = 6;
391 std::vector<Vertex> vertexData(kNumQuads * kNumVerticesPerQuad);
392 for (int h = 0; h < viewHeight; ++h)
393 {
394 for (int w = 0; w < viewWidth; ++w)
395 {
396 float wf = static_cast<float>(w) / viewWidth;
397 float hf = static_cast<float>(h) / viewHeight;
398
399 size_t index = static_cast<size_t>(h * viewWidth + w) * 6u;
400
401 auto &v0 = vertexData[index];
402 v0.position = Vector4(2.f * wf - 1.f, 2.f * hf - 1.f, .0f, 1.f);
403 memset(v0.colorAttributeData, 0, sizeof(v0.colorAttributeData));
404
405 auto &v1 = vertexData[index + 1];
406 v1.position = Vector4(v0.position.x() + quadWidth, v0.position.y(), .0f, 1.f);
407 memset(v1.colorAttributeData, 0, sizeof(v1.colorAttributeData));
408
409 auto &v2 = vertexData[index + 2];
410 v2.position = Vector4(v1.position.x(), v1.position.y() + quadHeight, .0f, 1.f);
411 memset(v2.colorAttributeData, 0, sizeof(v2.colorAttributeData));
412
413 auto &v3 = vertexData[index + 3];
414 v3.position = v0.position;
415 memset(v3.colorAttributeData, 0, sizeof(v3.colorAttributeData));
416
417 auto &v4 = vertexData[index + 4];
418 v4.position = v2.position;
419 memset(v4.colorAttributeData, 0, sizeof(v4.colorAttributeData));
420
421 auto &v5 = vertexData[index + 5];
422 v5.position = Vector4(v0.position.x(), v0.position.y() + quadHeight, .0f, 1.f);
423 memset(v5.colorAttributeData, 0, sizeof(v5.colorAttributeData));
424 }
425 }
426
427 glBindVertexArray(mVAO);
428
429 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
430 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vertex), vertexData.data(),
431 GL_STATIC_DRAW);
432
433 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
434 glEnableVertexAttribArray(0);
435
436 for (unsigned int i = 0u; i < 6u; ++i)
437 {
438 size_t offset = sizeof(Vector4) * (i + 1u);
439 glVertexAttribPointer(i + 1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),
440 reinterpret_cast<const void *>(offset));
441 glEnableVertexAttribArray(i + 1);
442 }
443
444 // Render once to guarantee that the program is compiled and linked.
445 drawBenchmark();
446}
447
448void MultiviewGPUBoundBenchmark::renderScene()
449{
450 glClearColor(0, 0, 0, 0);
451 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
452 glUseProgram(mProgram);
453
454 glBindVertexArray(mVAO);
455
456 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
457 const int viewWidth = params->windowWidth / params->numViews;
458 const int viewHeight = params->windowHeight;
459 glDrawArrays(GL_TRIANGLES, 0, viewWidth * viewHeight * 6);
460}
461
462MultiviewPerfParams SmallWorkload(MultiviewOption multiviewOption)
463{
464 MultiviewPerfParams params;
465 params.multiviewOption = multiviewOption;
466 params.windowWidth = 64;
467 params.windowHeight = 64;
468 return params;
469}
470
471MultiviewPerfParams BigWorkload(MultiviewOption multiviewOption)
472{
473 MultiviewPerfParams params;
474 params.multiviewOption = multiviewOption;
475 params.windowWidth = 1024;
476 params.windowHeight = 768;
477 return params;
478}
479
480TEST_P(MultiviewCPUBoundBenchmark, Run)
481{
482 run();
483}
484
485ANGLE_INSTANTIATE_TEST(MultiviewCPUBoundBenchmark,
486 SmallWorkload(MultiviewOption::NoAcceleration),
487 SmallWorkload(MultiviewOption::SelectViewportInVertexShader));
488
489TEST_P(MultiviewGPUBoundBenchmark, Run)
490{
491 run();
492}
493
494ANGLE_INSTANTIATE_TEST(MultiviewGPUBoundBenchmark,
495 BigWorkload(MultiviewOption::NoAcceleration),
496 BigWorkload(MultiviewOption::SelectViewportInVertexShader));
497
498} // anonymous namespace