blob: a56d6ee5cbc58394c288eb1bbe508e7b0adec215 [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"
Martin Radevfca78132017-09-06 13:51:39 +030015#include "platform/WorkaroundsD3D.h"
Martin Radev6a6199b2017-06-05 17:30:55 +030016#include "shader_utils.h"
17#include "test_utils/gl_raii.h"
18#include "tests/test_utils/ANGLETest.h"
19
20#include <string.h>
21
22using namespace angle;
23
24namespace
25{
26
27std::string GetShaderExtensionHeader(bool usesMultiview, int numViews, GLenum shaderType)
28{
29 if (!usesMultiview)
30 {
31 return "";
32 }
33
34 if (shaderType == GL_VERTEX_SHADER)
35 {
36 return "#extension GL_OVR_multiview : require\nlayout(num_views = " + ToString(numViews) +
37 ") in;\n";
38 ;
39 }
40 ASSERT(shaderType == GL_FRAGMENT_SHADER);
41 return "#extension GL_OVR_multiview : require\n";
42}
43
44struct Vertex
45{
46 Vector4 position;
47 Vector4 colorAttributeData[6];
48};
49
50enum class MultiviewOption
51{
52 NoAcceleration,
Martin Radevfca78132017-09-06 13:51:39 +030053 InstancedMultiviewVertexShader,
54 InstancedMultiviewGeometryShader,
Martin Radev6a6199b2017-06-05 17:30:55 +030055
56 Unspecified
57};
58
Martin Radevfca78132017-09-06 13:51:39 +030059using MultiviewPerfWorkload = std::pair<int, int>;
60
Martin Radev6a6199b2017-06-05 17:30:55 +030061struct MultiviewPerfParams final : public RenderTestParams
62{
Martin Radevfca78132017-09-06 13:51:39 +030063 MultiviewPerfParams(const EGLPlatformParameters &platformParametersIn,
64 const MultiviewPerfWorkload &workloadIn,
65 MultiviewOption multiviewOptionIn)
Martin Radev6a6199b2017-06-05 17:30:55 +030066 {
67 majorVersion = 3;
68 minorVersion = 0;
Martin Radevfca78132017-09-06 13:51:39 +030069 eglParameters = platformParametersIn;
70 windowWidth = workloadIn.first;
71 windowHeight = workloadIn.second;
72 multiviewOption = multiviewOptionIn;
Martin Radev6a6199b2017-06-05 17:30:55 +030073 numViews = 2;
74 }
75
76 std::string suffix() const override
77 {
78 std::string name = RenderTestParams::suffix();
79 switch (multiviewOption)
80 {
81 case MultiviewOption::NoAcceleration:
82 name += "_no_acc";
83 break;
Martin Radevfca78132017-09-06 13:51:39 +030084 case MultiviewOption::InstancedMultiviewVertexShader:
85 name += "_instanced_multiview_vertex_shader";
86 break;
87 case MultiviewOption::InstancedMultiviewGeometryShader:
88 name += "_instanced_multiview_geometry_shader";
Martin Radev6a6199b2017-06-05 17:30:55 +030089 break;
90 default:
91 UNREACHABLE();
92 }
93 name += "_" + ToString(numViews) + "_views";
94 return name;
95 }
96
97 MultiviewOption multiviewOption;
98 int numViews;
99};
100
101std::ostream &operator<<(std::ostream &os, const MultiviewPerfParams &params)
102{
103 os << params.suffix().substr(1);
104 return os;
105}
106
107class MultiviewBenchmark : public ANGLERenderTest,
108 public ::testing::WithParamInterface<MultiviewPerfParams>
109{
110 public:
111 MultiviewBenchmark(const std::string &testName)
Jamie Madill0ea96212018-10-30 15:14:51 -0400112 : ANGLERenderTest(testName, GetParam()), mProgram(0)
Martin Radev6a6199b2017-06-05 17:30:55 +0300113 {
Jamie Madill0ea96212018-10-30 15:14:51 -0400114 addExtensionPrerequisite("GL_ANGLE_multiview");
Martin Radev6a6199b2017-06-05 17:30:55 +0300115 }
Jamie Madill0ea96212018-10-30 15:14:51 -0400116
Martin Radev6a6199b2017-06-05 17:30:55 +0300117 virtual ~MultiviewBenchmark()
118 {
119 if (mProgram != 0)
120 {
121 glDeleteProgram(mProgram);
122 }
123 }
124
125 void initializeBenchmark() override;
126 void drawBenchmark() final;
127
Martin Radevfca78132017-09-06 13:51:39 +0300128 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
129 {
130 workarounds->selectViewInGeometryShader =
131 (GetParam().multiviewOption == MultiviewOption::InstancedMultiviewGeometryShader);
132 }
133
Martin Radev6a6199b2017-06-05 17:30:55 +0300134 protected:
135 virtual void renderScene() = 0;
136
137 void createProgram(const std::string &vs, const std::string &fs)
138 {
139 mProgram = CompileProgram(vs, fs);
140 if (mProgram == 0)
141 {
142 FAIL() << "shader compilation failed.";
143 }
144 glUseProgram(mProgram);
145 ASSERT_GL_NO_ERROR();
146 }
147
148 GLuint mProgram;
149 GLVertexArray mVAO;
150 GLBuffer mVBO;
151
152 private:
153 GLFramebuffer mFramebuffer;
154 GLTexture mColorTexture;
155 GLTexture mDepthTexture;
156};
157
158class MultiviewCPUBoundBenchmark : public MultiviewBenchmark
159{
160 public:
161 MultiviewCPUBoundBenchmark() : MultiviewBenchmark("MultiviewCPUBoundBenchmark") {}
162
163 void initializeBenchmark() override;
164
165 protected:
166 void renderScene() override;
167};
168
169class MultiviewGPUBoundBenchmark : public MultiviewBenchmark
170{
171 public:
172 MultiviewGPUBoundBenchmark() : MultiviewBenchmark("MultiviewGPUBoundBenchmark") {}
173
174 void initializeBenchmark() override;
175
176 protected:
177 void renderScene() override;
178};
179
180void MultiviewBenchmark::initializeBenchmark()
181{
182 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
183 ASSERT(params->windowWidth % params->numViews == 0);
184
185 glBindTexture(GL_TEXTURE_2D, mColorTexture);
186 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, params->windowWidth, params->windowHeight, 0, GL_RGBA,
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500187 GL_UNSIGNED_BYTE, nullptr);
Martin Radev6a6199b2017-06-05 17:30:55 +0300188
189 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
190 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, params->windowWidth, params->windowHeight,
Luc Ferronadcf0ae2018-01-24 08:27:37 -0500191 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
Martin Radev6a6199b2017-06-05 17:30:55 +0300192
193 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
194
195 switch (params->multiviewOption)
196 {
197 case MultiviewOption::NoAcceleration:
198 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
199 mColorTexture, 0);
200 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
201 mDepthTexture, 0);
202 break;
Martin Radevfca78132017-09-06 13:51:39 +0300203 case MultiviewOption::InstancedMultiviewVertexShader:
204 case MultiviewOption::InstancedMultiviewGeometryShader:
Martin Radev6a6199b2017-06-05 17:30:55 +0300205 {
206 const int widthPerView = params->windowWidth / params->numViews;
207 std::vector<GLint> viewportOffsets(2 * params->numViews);
208 for (int i = 0u; i < params->numViews; ++i)
209 {
210 viewportOffsets[i * 2] = i * widthPerView;
211 viewportOffsets[i * 2 + 1] = 0;
212 }
213 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
214 mColorTexture, 0, params->numViews,
215 viewportOffsets.data());
216 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
217 mDepthTexture, 0, params->numViews,
218 viewportOffsets.data());
219 break;
220 }
221 default:
222 UNREACHABLE();
223 }
224
225 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
226 glDrawBuffers(1, DrawBuffers);
227
228 ASSERT_GL_NO_ERROR();
229}
230
231void MultiviewBenchmark::drawBenchmark()
232{
233 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
234 const int viewWidth = params->windowWidth / params->numViews;
235 const int viewHeight = params->windowHeight;
236
237 switch (params->multiviewOption)
238 {
239 case MultiviewOption::NoAcceleration:
240 glEnable(GL_SCISSOR_TEST);
241 // Iterate over each view and render the scene.
242 for (int i = 0; i < params->numViews; ++i)
243 {
244 glViewport(viewWidth * i, 0, viewWidth, viewHeight);
245 glScissor(viewWidth * i, 0, viewWidth, viewHeight);
246 renderScene();
247 }
248 break;
Martin Radevfca78132017-09-06 13:51:39 +0300249 case MultiviewOption::InstancedMultiviewVertexShader:
250 case MultiviewOption::InstancedMultiviewGeometryShader:
Martin Radev6a6199b2017-06-05 17:30:55 +0300251 glViewport(0, 0, viewWidth, viewHeight);
252 glScissor(0, 0, viewWidth, viewHeight);
253 renderScene();
254 break;
255 default:
256 UNREACHABLE();
257 }
258
259 ASSERT_GL_NO_ERROR();
260}
261
262void MultiviewCPUBoundBenchmark::initializeBenchmark()
263{
264 MultiviewBenchmark::initializeBenchmark();
265
266 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
267 const bool usesMultiview = (params->multiviewOption != MultiviewOption::NoAcceleration);
268
269 const std::string &vs =
270 "#version 300 es\n" +
271 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_VERTEX_SHADER) +
272 "layout(location=0) in vec4 vPosition;\n"
273 "uniform vec2 uOffset;\n"
274 "void main()\n"
275 "{\n"
276 " vec4 v = vPosition;\n"
277 " v.xy += uOffset;\n"
278 " gl_Position = v;\n"
279 "}\n";
280
281 const std::string &fs =
282 "#version 300 es\n" +
283 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_FRAGMENT_SHADER) +
284 "precision mediump float;\n"
285 "out vec4 col;\n"
286 "uniform float uColor;\n"
287 "void main()\n"
288 "{\n"
289 " col = vec4(1.);\n"
290 "}\n";
291
292 createProgram(vs, fs);
293
294 const float viewWidth = static_cast<float>(params->windowWidth / params->numViews);
295 const float viewHeight = static_cast<float>(params->windowHeight);
296 const float quadWidth = 2.f / viewWidth;
297 const float quadHeight = 2.f / viewHeight;
298 Vector4 vertices[6] = {Vector4(.0f, .0f, .0f, 1.f),
299 Vector4(quadWidth, .0f, .0f, 1.f),
300 Vector4(quadWidth, quadHeight, 0.f, 1.f),
301 Vector4(.0f, .0f, 0.f, 1.f),
302 Vector4(quadWidth, quadHeight, .0f, 1.f),
303 Vector4(.0f, quadHeight, .0f, 1.f)};
304
305 glBindVertexArray(mVAO);
306
307 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
308 glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(Vector4), vertices, GL_STATIC_DRAW);
309
310 const GLint posLoc = glGetAttribLocation(mProgram, "vPosition");
311 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, 0);
312 glEnableVertexAttribArray(posLoc);
313
314 // Render once to guarantee that the program is compiled and linked.
315 drawBenchmark();
316
317 ASSERT_GL_NO_ERROR();
318}
319
320void MultiviewCPUBoundBenchmark::renderScene()
321{
322 glClearColor(0, 0, 0, 0);
323 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
324 glUseProgram(mProgram);
325
326 glBindVertexArray(mVAO);
327
328 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
329 const int viewWidth = params->windowWidth / params->numViews;
330 const int viewHeight = params->windowHeight;
331
332 for (int w = 0; w < viewWidth; ++w)
333 {
334 for (int h = 0; h < viewHeight; ++h)
335 {
336 const float wf = static_cast<float>(w) / viewWidth;
337 const float wh = static_cast<float>(h) / viewHeight;
338 glUniform2f(glGetUniformLocation(mProgram, "uOffset"), 2.f * wf - 1.f, 2.f * wh - 1.f);
339 glUniform1f(glGetUniformLocation(mProgram, "uColor"), wf);
340 glDrawArrays(GL_TRIANGLES, 0, 6);
341 }
342 }
343}
344
345void MultiviewGPUBoundBenchmark::initializeBenchmark()
346{
347 MultiviewBenchmark::initializeBenchmark();
348
349 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
350 const bool usesMultiview = (params->multiviewOption != MultiviewOption::NoAcceleration);
351
352 const std::string &vs =
353 "#version 300 es\n" +
354 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_VERTEX_SHADER) +
355 "layout(location=0) in vec4 vPosition;\n"
356 "layout(location=1) in vec4 vert_Col0;\n"
357 "layout(location=2) in vec4 vert_Col1;\n"
358 "layout(location=3) in vec4 vert_Col2;\n"
359 "layout(location=4) in vec4 vert_Col3;\n"
360 "layout(location=5) in vec4 vert_Col4;\n"
361 "layout(location=6) in vec4 vert_Col5;\n"
362 "out vec4 frag_Col0;\n"
363 "out vec4 frag_Col1;\n"
364 "out vec4 frag_Col2;\n"
365 "out vec4 frag_Col3;\n"
366 "out vec4 frag_Col4;\n"
367 "out vec4 frag_Col5;\n"
368 "void main()\n"
369 "{\n"
370 " frag_Col0 = vert_Col0;\n"
371 " frag_Col1 = vert_Col1;\n"
372 " frag_Col2 = vert_Col2;\n"
373 " frag_Col3 = vert_Col3;\n"
374 " frag_Col4 = vert_Col4;\n"
375 " frag_Col5 = vert_Col5;\n"
376 " gl_Position = vPosition;\n"
377 "}\n";
378
379 const std::string &fs =
380 "#version 300 es\n" +
381 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_FRAGMENT_SHADER) +
382 "precision mediump float;\n"
383 "in vec4 frag_Col0;\n"
384 "in vec4 frag_Col1;\n"
385 "in vec4 frag_Col2;\n"
386 "in vec4 frag_Col3;\n"
387 "in vec4 frag_Col4;\n"
388 "in vec4 frag_Col5;\n"
389 "out vec4 col;\n"
390 "void main()\n"
391 "{\n"
392 " col += frag_Col0;\n"
393 " col += frag_Col1;\n"
394 " col += frag_Col2;\n"
395 " col += frag_Col3;\n"
396 " col += frag_Col4;\n"
397 " col += frag_Col5;\n"
398 "}\n";
399
400 createProgram(vs, fs);
401 ASSERT_GL_NO_ERROR();
402
403 // Generate a vertex buffer of triangulated quads so that we have one quad per pixel.
404 const int viewWidth = params->windowWidth / params->numViews;
405 const int viewHeight = params->windowHeight;
406 const float quadWidth = 2.f / static_cast<float>(viewWidth);
407 const float quadHeight = 2.f / static_cast<float>(viewHeight);
408 const int kNumQuads = viewWidth * viewHeight;
409 const int kNumVerticesPerQuad = 6;
410 std::vector<Vertex> vertexData(kNumQuads * kNumVerticesPerQuad);
411 for (int h = 0; h < viewHeight; ++h)
412 {
413 for (int w = 0; w < viewWidth; ++w)
414 {
415 float wf = static_cast<float>(w) / viewWidth;
416 float hf = static_cast<float>(h) / viewHeight;
417
418 size_t index = static_cast<size_t>(h * viewWidth + w) * 6u;
419
420 auto &v0 = vertexData[index];
421 v0.position = Vector4(2.f * wf - 1.f, 2.f * hf - 1.f, .0f, 1.f);
422 memset(v0.colorAttributeData, 0, sizeof(v0.colorAttributeData));
423
424 auto &v1 = vertexData[index + 1];
425 v1.position = Vector4(v0.position.x() + quadWidth, v0.position.y(), .0f, 1.f);
426 memset(v1.colorAttributeData, 0, sizeof(v1.colorAttributeData));
427
428 auto &v2 = vertexData[index + 2];
429 v2.position = Vector4(v1.position.x(), v1.position.y() + quadHeight, .0f, 1.f);
430 memset(v2.colorAttributeData, 0, sizeof(v2.colorAttributeData));
431
432 auto &v3 = vertexData[index + 3];
433 v3.position = v0.position;
434 memset(v3.colorAttributeData, 0, sizeof(v3.colorAttributeData));
435
436 auto &v4 = vertexData[index + 4];
437 v4.position = v2.position;
438 memset(v4.colorAttributeData, 0, sizeof(v4.colorAttributeData));
439
440 auto &v5 = vertexData[index + 5];
441 v5.position = Vector4(v0.position.x(), v0.position.y() + quadHeight, .0f, 1.f);
442 memset(v5.colorAttributeData, 0, sizeof(v5.colorAttributeData));
443 }
444 }
445
446 glBindVertexArray(mVAO);
447
448 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
449 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vertex), vertexData.data(),
450 GL_STATIC_DRAW);
451
452 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
453 glEnableVertexAttribArray(0);
454
455 for (unsigned int i = 0u; i < 6u; ++i)
456 {
457 size_t offset = sizeof(Vector4) * (i + 1u);
458 glVertexAttribPointer(i + 1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),
459 reinterpret_cast<const void *>(offset));
460 glEnableVertexAttribArray(i + 1);
461 }
462
463 // Render once to guarantee that the program is compiled and linked.
464 drawBenchmark();
465}
466
467void MultiviewGPUBoundBenchmark::renderScene()
468{
469 glClearColor(0, 0, 0, 0);
470 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
471 glUseProgram(mProgram);
472
473 glBindVertexArray(mVAO);
474
475 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
476 const int viewWidth = params->windowWidth / params->numViews;
477 const int viewHeight = params->windowHeight;
478 glDrawArrays(GL_TRIANGLES, 0, viewWidth * viewHeight * 6);
479}
480
Martin Radevfca78132017-09-06 13:51:39 +0300481namespace
Martin Radev6a6199b2017-06-05 17:30:55 +0300482{
Martin Radevfca78132017-09-06 13:51:39 +0300483MultiviewPerfWorkload SmallWorkload()
484{
485 return MultiviewPerfWorkload(64, 64);
Martin Radev6a6199b2017-06-05 17:30:55 +0300486}
487
Martin Radevfca78132017-09-06 13:51:39 +0300488MultiviewPerfWorkload BigWorkload()
Martin Radev6a6199b2017-06-05 17:30:55 +0300489{
Martin Radevfca78132017-09-06 13:51:39 +0300490 return MultiviewPerfWorkload(1024, 768);
Martin Radev6a6199b2017-06-05 17:30:55 +0300491}
492
Martin Radevfca78132017-09-06 13:51:39 +0300493MultiviewPerfParams NoAcceleration(const EGLPlatformParameters &eglParameters,
494 const MultiviewPerfWorkload &workload)
495{
496 return MultiviewPerfParams(eglParameters, workload, MultiviewOption::NoAcceleration);
497}
498
499MultiviewPerfParams SelectViewInGeometryShader(const MultiviewPerfWorkload &workload)
500{
501 return MultiviewPerfParams(egl_platform::D3D11(), workload,
502 MultiviewOption::InstancedMultiviewGeometryShader);
503}
504
505MultiviewPerfParams SelectViewInVertexShader(const EGLPlatformParameters &eglParameters,
506 const MultiviewPerfWorkload &workload)
507{
508 return MultiviewPerfParams(eglParameters, workload,
509 MultiviewOption::InstancedMultiviewVertexShader);
510}
511} // namespace
512
Martin Radev6a6199b2017-06-05 17:30:55 +0300513TEST_P(MultiviewCPUBoundBenchmark, Run)
514{
515 run();
516}
517
518ANGLE_INSTANTIATE_TEST(MultiviewCPUBoundBenchmark,
Yuly Novikovb8d26642017-10-27 18:14:14 -0400519 NoAcceleration(egl_platform::OPENGL_OR_GLES(false), SmallWorkload()),
Martin Radevfca78132017-09-06 13:51:39 +0300520 NoAcceleration(egl_platform::D3D11(), SmallWorkload()),
521 SelectViewInGeometryShader(SmallWorkload()),
Yuly Novikovb8d26642017-10-27 18:14:14 -0400522 SelectViewInVertexShader(egl_platform::OPENGL_OR_GLES(false),
523 SmallWorkload()),
Martin Radevfca78132017-09-06 13:51:39 +0300524 SelectViewInVertexShader(egl_platform::D3D11(), SmallWorkload()));
Martin Radev6a6199b2017-06-05 17:30:55 +0300525
526TEST_P(MultiviewGPUBoundBenchmark, Run)
527{
528 run();
529}
530
531ANGLE_INSTANTIATE_TEST(MultiviewGPUBoundBenchmark,
Yuly Novikovb8d26642017-10-27 18:14:14 -0400532 NoAcceleration(egl_platform::OPENGL_OR_GLES(false), BigWorkload()),
Martin Radevfca78132017-09-06 13:51:39 +0300533 NoAcceleration(egl_platform::D3D11(), BigWorkload()),
534 SelectViewInGeometryShader(BigWorkload()),
Yuly Novikovb8d26642017-10-27 18:14:14 -0400535 SelectViewInVertexShader(egl_platform::OPENGL_OR_GLES(false), BigWorkload()),
Martin Radevfca78132017-09-06 13:51:39 +0300536 SelectViewInVertexShader(egl_platform::D3D11(), BigWorkload()));
Martin Radev6a6199b2017-06-05 17:30:55 +0300537
Yuly Novikovb8d26642017-10-27 18:14:14 -0400538} // anonymous namespace