blob: 8c106b493b181bef68446486264724209d2b935a [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)
112 : ANGLERenderTest(testName, GetParam(), {"GL_ANGLE_multiview"}), mProgram(0)
113 {
114 }
115 virtual ~MultiviewBenchmark()
116 {
117 if (mProgram != 0)
118 {
119 glDeleteProgram(mProgram);
120 }
121 }
122
123 void initializeBenchmark() override;
124 void drawBenchmark() final;
125
Martin Radevfca78132017-09-06 13:51:39 +0300126 void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
127 {
128 workarounds->selectViewInGeometryShader =
129 (GetParam().multiviewOption == MultiviewOption::InstancedMultiviewGeometryShader);
130 }
131
Martin Radev6a6199b2017-06-05 17:30:55 +0300132 protected:
133 virtual void renderScene() = 0;
134
135 void createProgram(const std::string &vs, const std::string &fs)
136 {
137 mProgram = CompileProgram(vs, fs);
138 if (mProgram == 0)
139 {
140 FAIL() << "shader compilation failed.";
141 }
142 glUseProgram(mProgram);
143 ASSERT_GL_NO_ERROR();
144 }
145
146 GLuint mProgram;
147 GLVertexArray mVAO;
148 GLBuffer mVBO;
149
150 private:
151 GLFramebuffer mFramebuffer;
152 GLTexture mColorTexture;
153 GLTexture mDepthTexture;
154};
155
156class MultiviewCPUBoundBenchmark : public MultiviewBenchmark
157{
158 public:
159 MultiviewCPUBoundBenchmark() : MultiviewBenchmark("MultiviewCPUBoundBenchmark") {}
160
161 void initializeBenchmark() override;
162
163 protected:
164 void renderScene() override;
165};
166
167class MultiviewGPUBoundBenchmark : public MultiviewBenchmark
168{
169 public:
170 MultiviewGPUBoundBenchmark() : MultiviewBenchmark("MultiviewGPUBoundBenchmark") {}
171
172 void initializeBenchmark() override;
173
174 protected:
175 void renderScene() override;
176};
177
178void MultiviewBenchmark::initializeBenchmark()
179{
180 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
181 ASSERT(params->windowWidth % params->numViews == 0);
182
183 glBindTexture(GL_TEXTURE_2D, mColorTexture);
184 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, params->windowWidth, params->windowHeight, 0, GL_RGBA,
185 GL_UNSIGNED_BYTE, NULL);
186
187 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
188 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, params->windowWidth, params->windowHeight,
189 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
190
191 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
192
193 switch (params->multiviewOption)
194 {
195 case MultiviewOption::NoAcceleration:
196 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
197 mColorTexture, 0);
198 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
199 mDepthTexture, 0);
200 break;
Martin Radevfca78132017-09-06 13:51:39 +0300201 case MultiviewOption::InstancedMultiviewVertexShader:
202 case MultiviewOption::InstancedMultiviewGeometryShader:
Martin Radev6a6199b2017-06-05 17:30:55 +0300203 {
204 const int widthPerView = params->windowWidth / params->numViews;
205 std::vector<GLint> viewportOffsets(2 * params->numViews);
206 for (int i = 0u; i < params->numViews; ++i)
207 {
208 viewportOffsets[i * 2] = i * widthPerView;
209 viewportOffsets[i * 2 + 1] = 0;
210 }
211 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
212 mColorTexture, 0, params->numViews,
213 viewportOffsets.data());
214 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
215 mDepthTexture, 0, params->numViews,
216 viewportOffsets.data());
217 break;
218 }
219 default:
220 UNREACHABLE();
221 }
222
223 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
224 glDrawBuffers(1, DrawBuffers);
225
226 ASSERT_GL_NO_ERROR();
227}
228
229void MultiviewBenchmark::drawBenchmark()
230{
231 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
232 const int viewWidth = params->windowWidth / params->numViews;
233 const int viewHeight = params->windowHeight;
234
235 switch (params->multiviewOption)
236 {
237 case MultiviewOption::NoAcceleration:
238 glEnable(GL_SCISSOR_TEST);
239 // Iterate over each view and render the scene.
240 for (int i = 0; i < params->numViews; ++i)
241 {
242 glViewport(viewWidth * i, 0, viewWidth, viewHeight);
243 glScissor(viewWidth * i, 0, viewWidth, viewHeight);
244 renderScene();
245 }
246 break;
Martin Radevfca78132017-09-06 13:51:39 +0300247 case MultiviewOption::InstancedMultiviewVertexShader:
248 case MultiviewOption::InstancedMultiviewGeometryShader:
Martin Radev6a6199b2017-06-05 17:30:55 +0300249 glViewport(0, 0, viewWidth, viewHeight);
250 glScissor(0, 0, viewWidth, viewHeight);
251 renderScene();
252 break;
253 default:
254 UNREACHABLE();
255 }
256
257 ASSERT_GL_NO_ERROR();
258}
259
260void MultiviewCPUBoundBenchmark::initializeBenchmark()
261{
262 MultiviewBenchmark::initializeBenchmark();
263
264 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
265 const bool usesMultiview = (params->multiviewOption != MultiviewOption::NoAcceleration);
266
267 const std::string &vs =
268 "#version 300 es\n" +
269 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_VERTEX_SHADER) +
270 "layout(location=0) in vec4 vPosition;\n"
271 "uniform vec2 uOffset;\n"
272 "void main()\n"
273 "{\n"
274 " vec4 v = vPosition;\n"
275 " v.xy += uOffset;\n"
276 " gl_Position = v;\n"
277 "}\n";
278
279 const std::string &fs =
280 "#version 300 es\n" +
281 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_FRAGMENT_SHADER) +
282 "precision mediump float;\n"
283 "out vec4 col;\n"
284 "uniform float uColor;\n"
285 "void main()\n"
286 "{\n"
287 " col = vec4(1.);\n"
288 "}\n";
289
290 createProgram(vs, fs);
291
292 const float viewWidth = static_cast<float>(params->windowWidth / params->numViews);
293 const float viewHeight = static_cast<float>(params->windowHeight);
294 const float quadWidth = 2.f / viewWidth;
295 const float quadHeight = 2.f / viewHeight;
296 Vector4 vertices[6] = {Vector4(.0f, .0f, .0f, 1.f),
297 Vector4(quadWidth, .0f, .0f, 1.f),
298 Vector4(quadWidth, quadHeight, 0.f, 1.f),
299 Vector4(.0f, .0f, 0.f, 1.f),
300 Vector4(quadWidth, quadHeight, .0f, 1.f),
301 Vector4(.0f, quadHeight, .0f, 1.f)};
302
303 glBindVertexArray(mVAO);
304
305 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
306 glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(Vector4), vertices, GL_STATIC_DRAW);
307
308 const GLint posLoc = glGetAttribLocation(mProgram, "vPosition");
309 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, 0);
310 glEnableVertexAttribArray(posLoc);
311
312 // Render once to guarantee that the program is compiled and linked.
313 drawBenchmark();
314
315 ASSERT_GL_NO_ERROR();
316}
317
318void MultiviewCPUBoundBenchmark::renderScene()
319{
320 glClearColor(0, 0, 0, 0);
321 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
322 glUseProgram(mProgram);
323
324 glBindVertexArray(mVAO);
325
326 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
327 const int viewWidth = params->windowWidth / params->numViews;
328 const int viewHeight = params->windowHeight;
329
330 for (int w = 0; w < viewWidth; ++w)
331 {
332 for (int h = 0; h < viewHeight; ++h)
333 {
334 const float wf = static_cast<float>(w) / viewWidth;
335 const float wh = static_cast<float>(h) / viewHeight;
336 glUniform2f(glGetUniformLocation(mProgram, "uOffset"), 2.f * wf - 1.f, 2.f * wh - 1.f);
337 glUniform1f(glGetUniformLocation(mProgram, "uColor"), wf);
338 glDrawArrays(GL_TRIANGLES, 0, 6);
339 }
340 }
341}
342
343void MultiviewGPUBoundBenchmark::initializeBenchmark()
344{
345 MultiviewBenchmark::initializeBenchmark();
346
347 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
348 const bool usesMultiview = (params->multiviewOption != MultiviewOption::NoAcceleration);
349
350 const std::string &vs =
351 "#version 300 es\n" +
352 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_VERTEX_SHADER) +
353 "layout(location=0) in vec4 vPosition;\n"
354 "layout(location=1) in vec4 vert_Col0;\n"
355 "layout(location=2) in vec4 vert_Col1;\n"
356 "layout(location=3) in vec4 vert_Col2;\n"
357 "layout(location=4) in vec4 vert_Col3;\n"
358 "layout(location=5) in vec4 vert_Col4;\n"
359 "layout(location=6) in vec4 vert_Col5;\n"
360 "out vec4 frag_Col0;\n"
361 "out vec4 frag_Col1;\n"
362 "out vec4 frag_Col2;\n"
363 "out vec4 frag_Col3;\n"
364 "out vec4 frag_Col4;\n"
365 "out vec4 frag_Col5;\n"
366 "void main()\n"
367 "{\n"
368 " frag_Col0 = vert_Col0;\n"
369 " frag_Col1 = vert_Col1;\n"
370 " frag_Col2 = vert_Col2;\n"
371 " frag_Col3 = vert_Col3;\n"
372 " frag_Col4 = vert_Col4;\n"
373 " frag_Col5 = vert_Col5;\n"
374 " gl_Position = vPosition;\n"
375 "}\n";
376
377 const std::string &fs =
378 "#version 300 es\n" +
379 GetShaderExtensionHeader(usesMultiview, params->numViews, GL_FRAGMENT_SHADER) +
380 "precision mediump float;\n"
381 "in vec4 frag_Col0;\n"
382 "in vec4 frag_Col1;\n"
383 "in vec4 frag_Col2;\n"
384 "in vec4 frag_Col3;\n"
385 "in vec4 frag_Col4;\n"
386 "in vec4 frag_Col5;\n"
387 "out vec4 col;\n"
388 "void main()\n"
389 "{\n"
390 " col += frag_Col0;\n"
391 " col += frag_Col1;\n"
392 " col += frag_Col2;\n"
393 " col += frag_Col3;\n"
394 " col += frag_Col4;\n"
395 " col += frag_Col5;\n"
396 "}\n";
397
398 createProgram(vs, fs);
399 ASSERT_GL_NO_ERROR();
400
401 // Generate a vertex buffer of triangulated quads so that we have one quad per pixel.
402 const int viewWidth = params->windowWidth / params->numViews;
403 const int viewHeight = params->windowHeight;
404 const float quadWidth = 2.f / static_cast<float>(viewWidth);
405 const float quadHeight = 2.f / static_cast<float>(viewHeight);
406 const int kNumQuads = viewWidth * viewHeight;
407 const int kNumVerticesPerQuad = 6;
408 std::vector<Vertex> vertexData(kNumQuads * kNumVerticesPerQuad);
409 for (int h = 0; h < viewHeight; ++h)
410 {
411 for (int w = 0; w < viewWidth; ++w)
412 {
413 float wf = static_cast<float>(w) / viewWidth;
414 float hf = static_cast<float>(h) / viewHeight;
415
416 size_t index = static_cast<size_t>(h * viewWidth + w) * 6u;
417
418 auto &v0 = vertexData[index];
419 v0.position = Vector4(2.f * wf - 1.f, 2.f * hf - 1.f, .0f, 1.f);
420 memset(v0.colorAttributeData, 0, sizeof(v0.colorAttributeData));
421
422 auto &v1 = vertexData[index + 1];
423 v1.position = Vector4(v0.position.x() + quadWidth, v0.position.y(), .0f, 1.f);
424 memset(v1.colorAttributeData, 0, sizeof(v1.colorAttributeData));
425
426 auto &v2 = vertexData[index + 2];
427 v2.position = Vector4(v1.position.x(), v1.position.y() + quadHeight, .0f, 1.f);
428 memset(v2.colorAttributeData, 0, sizeof(v2.colorAttributeData));
429
430 auto &v3 = vertexData[index + 3];
431 v3.position = v0.position;
432 memset(v3.colorAttributeData, 0, sizeof(v3.colorAttributeData));
433
434 auto &v4 = vertexData[index + 4];
435 v4.position = v2.position;
436 memset(v4.colorAttributeData, 0, sizeof(v4.colorAttributeData));
437
438 auto &v5 = vertexData[index + 5];
439 v5.position = Vector4(v0.position.x(), v0.position.y() + quadHeight, .0f, 1.f);
440 memset(v5.colorAttributeData, 0, sizeof(v5.colorAttributeData));
441 }
442 }
443
444 glBindVertexArray(mVAO);
445
446 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
447 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vertex), vertexData.data(),
448 GL_STATIC_DRAW);
449
450 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
451 glEnableVertexAttribArray(0);
452
453 for (unsigned int i = 0u; i < 6u; ++i)
454 {
455 size_t offset = sizeof(Vector4) * (i + 1u);
456 glVertexAttribPointer(i + 1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),
457 reinterpret_cast<const void *>(offset));
458 glEnableVertexAttribArray(i + 1);
459 }
460
461 // Render once to guarantee that the program is compiled and linked.
462 drawBenchmark();
463}
464
465void MultiviewGPUBoundBenchmark::renderScene()
466{
467 glClearColor(0, 0, 0, 0);
468 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
469 glUseProgram(mProgram);
470
471 glBindVertexArray(mVAO);
472
473 const MultiviewPerfParams *params = static_cast<const MultiviewPerfParams *>(&mTestParams);
474 const int viewWidth = params->windowWidth / params->numViews;
475 const int viewHeight = params->windowHeight;
476 glDrawArrays(GL_TRIANGLES, 0, viewWidth * viewHeight * 6);
477}
478
Martin Radevfca78132017-09-06 13:51:39 +0300479namespace
Martin Radev6a6199b2017-06-05 17:30:55 +0300480{
Martin Radevfca78132017-09-06 13:51:39 +0300481MultiviewPerfWorkload SmallWorkload()
482{
483 return MultiviewPerfWorkload(64, 64);
Martin Radev6a6199b2017-06-05 17:30:55 +0300484}
485
Martin Radevfca78132017-09-06 13:51:39 +0300486MultiviewPerfWorkload BigWorkload()
Martin Radev6a6199b2017-06-05 17:30:55 +0300487{
Martin Radevfca78132017-09-06 13:51:39 +0300488 return MultiviewPerfWorkload(1024, 768);
Martin Radev6a6199b2017-06-05 17:30:55 +0300489}
490
Martin Radevfca78132017-09-06 13:51:39 +0300491MultiviewPerfParams NoAcceleration(const EGLPlatformParameters &eglParameters,
492 const MultiviewPerfWorkload &workload)
493{
494 return MultiviewPerfParams(eglParameters, workload, MultiviewOption::NoAcceleration);
495}
496
497MultiviewPerfParams SelectViewInGeometryShader(const MultiviewPerfWorkload &workload)
498{
499 return MultiviewPerfParams(egl_platform::D3D11(), workload,
500 MultiviewOption::InstancedMultiviewGeometryShader);
501}
502
503MultiviewPerfParams SelectViewInVertexShader(const EGLPlatformParameters &eglParameters,
504 const MultiviewPerfWorkload &workload)
505{
506 return MultiviewPerfParams(eglParameters, workload,
507 MultiviewOption::InstancedMultiviewVertexShader);
508}
509} // namespace
510
Martin Radev6a6199b2017-06-05 17:30:55 +0300511TEST_P(MultiviewCPUBoundBenchmark, Run)
512{
513 run();
514}
515
516ANGLE_INSTANTIATE_TEST(MultiviewCPUBoundBenchmark,
Yuly Novikovb8d26642017-10-27 18:14:14 -0400517 NoAcceleration(egl_platform::OPENGL_OR_GLES(false), SmallWorkload()),
Martin Radevfca78132017-09-06 13:51:39 +0300518 NoAcceleration(egl_platform::D3D11(), SmallWorkload()),
519 SelectViewInGeometryShader(SmallWorkload()),
Yuly Novikovb8d26642017-10-27 18:14:14 -0400520 SelectViewInVertexShader(egl_platform::OPENGL_OR_GLES(false),
521 SmallWorkload()),
Martin Radevfca78132017-09-06 13:51:39 +0300522 SelectViewInVertexShader(egl_platform::D3D11(), SmallWorkload()));
Martin Radev6a6199b2017-06-05 17:30:55 +0300523
524TEST_P(MultiviewGPUBoundBenchmark, Run)
525{
526 run();
527}
528
529ANGLE_INSTANTIATE_TEST(MultiviewGPUBoundBenchmark,
Yuly Novikovb8d26642017-10-27 18:14:14 -0400530 NoAcceleration(egl_platform::OPENGL_OR_GLES(false), BigWorkload()),
Martin Radevfca78132017-09-06 13:51:39 +0300531 NoAcceleration(egl_platform::D3D11(), BigWorkload()),
532 SelectViewInGeometryShader(BigWorkload()),
Yuly Novikovb8d26642017-10-27 18:14:14 -0400533 SelectViewInVertexShader(egl_platform::OPENGL_OR_GLES(false), BigWorkload()),
Martin Radevfca78132017-09-06 13:51:39 +0300534 SelectViewInVertexShader(egl_platform::D3D11(), BigWorkload()));
Martin Radev6a6199b2017-06-05 17:30:55 +0300535
Yuly Novikovb8d26642017-10-27 18:14:14 -0400536} // anonymous namespace