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