blob: 77168eddb1458d14e013a01a6e2db395f74dae8e [file] [log] [blame]
Martin Radev14a26ae2017-07-24 15:56:29 +03001//
2// Copyright 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// Multiview draw tests:
7// Test issuing multiview Draw* commands.
8//
9
10#include "test_utils/ANGLETest.h"
11#include "test_utils/gl_raii.h"
12
13using namespace angle;
14
Martin Radev61bd9992017-08-11 13:10:55 +030015namespace
16{
17GLuint CreateSimplePassthroughProgram()
18{
19 const std::string vsSource =
20 "#version 300 es\n"
21 "#extension GL_OVR_multiview : require\n"
22 "layout(num_views = 2) in;\n"
23 "layout(location=0) in vec2 vPosition;\n"
24 "void main()\n"
25 "{\n"
26 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
27 "}\n";
28
29 const std::string fsSource =
30 "#version 300 es\n"
31 "#extension GL_OVR_multiview : require\n"
32 "precision mediump float;\n"
33 "out vec4 col;\n"
34 "void main()\n"
35 "{\n"
36 " col = vec4(1,0,0,1);\n"
37 "}\n";
38 return CompileProgram(vsSource, fsSource);
39}
40
41std::vector<Vector2> ConvertPixelCoordinatesToClipSpace(const std::vector<Vector2I> &pixels,
42 int width,
43 int height)
44{
45 std::vector<Vector2> result(pixels.size());
46 for (size_t i = 0; i < pixels.size(); ++i)
47 {
48 const auto &pixel = pixels[i];
49 float pixelCenterRelativeX = (static_cast<float>(pixel.x()) + .5f) / width;
50 float pixelCenterRelativeY = (static_cast<float>(pixel.y()) + .5f) / height;
51 float xInClipSpace = 2.f * pixelCenterRelativeX - 1.f;
52 float yInClipSpace = 2.f * pixelCenterRelativeY - 1.f;
53 result[i] = Vector2(xInClipSpace, yInClipSpace);
54 }
55 return result;
56}
57} // namespace
58
Martin Radev14a26ae2017-07-24 15:56:29 +030059class MultiviewDrawTest : public ANGLETest
60{
61 protected:
62 MultiviewDrawTest()
63 {
64 setWindowWidth(128);
65 setWindowHeight(128);
66 setWebGLCompatibilityEnabled(true);
67 }
Martin Radev7cf61662017-07-26 17:10:53 +030068 virtual ~MultiviewDrawTest() {}
Martin Radev14a26ae2017-07-24 15:56:29 +030069
70 void SetUp() override
71 {
72 ANGLETest::SetUp();
73
74 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
75 eglGetProcAddress("glRequestExtensionANGLE"));
76 }
77
78 // Requests the ANGLE_multiview extension and returns true if the operation succeeds.
79 bool requestMultiviewExtension()
80 {
81 if (extensionRequestable("GL_ANGLE_multiview"))
82 {
83 glRequestExtensionANGLE("GL_ANGLE_multiview");
84 }
85
86 if (!extensionEnabled("GL_ANGLE_multiview"))
87 {
88 std::cout << "Test skipped due to missing GL_ANGLE_multiview." << std::endl;
89 return false;
90 }
91 return true;
92 }
93
94 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
95};
96
Martin Radev7cf61662017-07-26 17:10:53 +030097class MultiviewDrawValidationTest : public MultiviewDrawTest
98{
99 protected:
100 MultiviewDrawValidationTest() {}
101
102 void SetUp() override
103 {
104 MultiviewDrawTest::SetUp();
105
106 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
107
108 glBindTexture(GL_TEXTURE_2D, mTex2d);
109 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
110
111 glBindVertexArray(mVao);
112
113 const float kVertexData[3] = {0.0f};
114 glBindBuffer(GL_ARRAY_BUFFER, mVbo);
115 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
116
117 const unsigned int kIndices[3] = {0u, 1u, 2u};
118 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
119 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
120 GL_STATIC_DRAW);
121 ASSERT_GL_NO_ERROR();
122 }
123
124 GLTexture mTex2d;
125 GLVertexArray mVao;
126 GLBuffer mVbo;
127 GLBuffer mIbo;
128 GLFramebuffer mFramebuffer;
129};
130
Martin Radev8f276e22017-05-30 12:05:52 +0300131class MultiviewSideBySideRenderTest : public MultiviewDrawTest
132{
133 protected:
134 void createFBO(int width, int height, int numViews)
135 {
136 // Assert that width is a multiple of numViews.
137 ASSERT_TRUE(width % numViews == 0);
138 const int widthPerView = width / numViews;
139
140 // Create color and depth textures.
141 glBindTexture(GL_TEXTURE_2D, mColorTexture);
142 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
143 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
144 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
145 ASSERT_GL_NO_ERROR();
146
147 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
148 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT,
149 GL_FLOAT, NULL);
150 glBindTexture(GL_TEXTURE_2D, 0);
151 ASSERT_GL_NO_ERROR();
152
153 // Create draw framebuffer to be used for side-by-side rendering.
154 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
155 std::vector<GLint> viewportOffsets(numViews * 2u);
156 for (int i = 0u; i < numViews; ++i)
157 {
158 viewportOffsets[i * 2] = i * widthPerView;
159 viewportOffsets[i * 2 + 1] = 0;
160 }
161 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
162 mColorTexture, 0, numViews,
163 &viewportOffsets[0]);
164 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
165 mDepthTexture, 0, numViews,
166 &viewportOffsets[0]);
167
168 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
169 glDrawBuffers(1, DrawBuffers);
170 ASSERT_GL_NO_ERROR();
171 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
172
173 // Create read framebuffer to be used to retrieve the pixel information for testing
174 // purposes.
175 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer);
176 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
177 mColorTexture, 0);
178 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
179
180 // Clear the buffers.
Martin Radeveef80e42017-08-11 14:44:57 +0300181 glViewport(0, 0, widthPerView, height);
182 glScissor(0, 0, widthPerView, height);
183 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +0300184 glClearColor(0, 0, 0, 1);
Martin Radev8f276e22017-05-30 12:05:52 +0300185 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
186
187 // Set viewport and scissor of each view.
188 glViewport(0, 0, widthPerView, height);
189 glScissor(0, 0, widthPerView, height);
190 }
191
192 GLTexture mColorTexture;
193 GLTexture mDepthTexture;
194 GLFramebuffer mDrawFramebuffer;
195 GLFramebuffer mReadFramebuffer;
196};
197
198class MultiviewSideBySideRenderDualViewTest : public MultiviewSideBySideRenderTest
199{
200 protected:
201 MultiviewSideBySideRenderDualViewTest() : mProgram(0u) {}
202 ~MultiviewSideBySideRenderDualViewTest()
203 {
204 if (mProgram != 0u)
205 {
206 glDeleteProgram(mProgram);
207 }
208 }
209
210 void SetUp() override
211 {
212 MultiviewSideBySideRenderTest::SetUp();
213
214 if (!requestMultiviewExtension())
215 {
216 return;
217 }
218
219 const std::string vsSource =
220 "#version 300 es\n"
221 "#extension GL_OVR_multiview : require\n"
222 "layout(num_views = 2) in;\n"
223 "in vec4 vPosition;\n"
224 "void main()\n"
225 "{\n"
226 " gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x*0.5 + 0.5 : vPosition.x*0.5);\n"
227 " gl_Position.yzw = vPosition.yzw;\n"
228 "}\n";
229
230 const std::string fsSource =
231 "#version 300 es\n"
232 "#extension GL_OVR_multiview : require\n"
233 "precision mediump float;\n"
234 "out vec4 col;\n"
235 "void main()\n"
236 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300237 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300238 "}\n";
239
240 createFBO(4, 1, 2);
Martin Radev61bd9992017-08-11 13:10:55 +0300241 mProgram = CompileProgram(vsSource, fsSource);
242 ASSERT_NE(mProgram, 0u);
Martin Radev8f276e22017-05-30 12:05:52 +0300243 glUseProgram(mProgram);
244 ASSERT_GL_NO_ERROR();
245 }
246
247 void checkOutput()
248 {
Martin Radev61bd9992017-08-11 13:10:55 +0300249 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
250 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
251 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::red);
252 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::black);
Martin Radev8f276e22017-05-30 12:05:52 +0300253 }
254
255 GLuint mProgram;
256};
257
Martin Radev0d671c92017-08-10 16:41:52 +0300258class MultiviewSideBySideOcclusionQueryTest : public MultiviewSideBySideRenderTest
259{
260 protected:
261 MultiviewSideBySideOcclusionQueryTest() {}
262
263 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
264 {
265 GLuint query;
266 glGenQueries(1, &query);
267 glBeginQuery(GL_ANY_SAMPLES_PASSED, query);
268 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
269 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
270
271 GLuint result = GL_TRUE;
272 glGetQueryObjectuiv(query, GL_QUERY_RESULT, &result);
273 return result;
274 }
275};
276
Martin Radev41ac68e2017-06-06 12:16:58 +0300277class MultiviewProgramGenerationTest : public MultiviewSideBySideRenderTest
278{
279 protected:
280 MultiviewProgramGenerationTest() {}
281};
282
Martin Radev61bd9992017-08-11 13:10:55 +0300283class MultiviewSideBySideRenderPrimitiveTest : public MultiviewSideBySideRenderTest
284{
285 protected:
286 MultiviewSideBySideRenderPrimitiveTest() {}
287
288 void setupGeometry(const std::vector<Vector2> &vertexData)
289 {
290 glBindVertexArray(mVAO);
291 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
292 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
293 GL_STATIC_DRAW);
294 glEnableVertexAttribArray(0);
295 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
296 }
297
298 void checkRedChannel(const GLubyte expectedRedChannelData[], int width, int height)
299 {
300 for (int w = 0; w < width; ++w)
301 {
302 for (int h = 0; h < height; ++h)
303 {
304 int flatIndex = h * width + w;
305 EXPECT_PIXEL_COLOR_EQ(w, h, GLColor(expectedRedChannelData[flatIndex], 0, 0, 255));
306 }
307 }
308 }
309
310 GLVertexArray mVAO;
311 GLBuffer mVBO;
312};
313
Martin Radev14a26ae2017-07-24 15:56:29 +0300314// The test verifies that glDraw*Indirect:
315// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
316// than 1.
317// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300318TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300319{
320 if (!requestMultiviewExtension())
321 {
322 return;
323 }
324
Martin Radev14a26ae2017-07-24 15:56:29 +0300325 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300326
327 const std::string fsSource =
328 "#version 300 es\n"
329 "#extension GL_OVR_multiview : require\n"
330 "precision mediump float;\n"
331 "void main()\n"
332 "{}\n";
333
Martin Radev14a26ae2017-07-24 15:56:29 +0300334 GLBuffer commandBuffer;
335 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
336 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
337 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
338 ASSERT_GL_NO_ERROR();
339
Martin Radev14a26ae2017-07-24 15:56:29 +0300340 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
341 {
342 const std::string &vsSource =
343 "#version 300 es\n"
344 "#extension GL_OVR_multiview : require\n"
345 "layout(num_views = 2) in;\n"
346 "void main()\n"
347 "{}\n";
348 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
349 glUseProgram(program);
350
Martin Radev7cf61662017-07-26 17:10:53 +0300351 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
352 0, 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300353
354 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
355 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
356
357 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
358 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
359 }
360
361 // Check that no errors are generated if the number of views is 1.
362 {
363 const std::string &vsSource =
364 "#version 300 es\n"
365 "#extension GL_OVR_multiview : require\n"
366 "layout(num_views = 1) in;\n"
367 "void main()\n"
368 "{}\n";
369 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
370 glUseProgram(program);
371
Martin Radev7cf61662017-07-26 17:10:53 +0300372 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
373 0, 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300374
375 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
376 EXPECT_GL_NO_ERROR();
377
378 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
379 EXPECT_GL_NO_ERROR();
380 }
381}
382
Martin Radev7cf61662017-07-26 17:10:53 +0300383// The test verifies that glDraw*:
384// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
385// program differs.
386// 2) does not generate any error if the number of views is the same.
387// 3) does not generate any error if the program does not use the multiview extension.
388TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
389{
390 if (!requestMultiviewExtension())
391 {
392 return;
393 }
394
395 const GLint viewportOffsets[4] = {0, 0, 2, 0};
396
397 const std::string &vsSource =
398 "#version 300 es\n"
399 "#extension GL_OVR_multiview : require\n"
400 "layout(num_views = 2) in;\n"
401 "void main()\n"
402 "{}\n";
403 const std::string &fsSource =
404 "#version 300 es\n"
405 "#extension GL_OVR_multiview : require\n"
406 "precision mediump float;\n"
407 "void main()\n"
408 "{}\n";
409 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
410 glUseProgram(program);
411
412 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
413 // number of views.
414 {
415 // The framebuffer has only 1 view.
416 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
417 0, 1, &viewportOffsets[0]);
418
419 glDrawArrays(GL_TRIANGLES, 0, 3);
420 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
421
422 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
423 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
424 }
425
426 // Check that no errors are generated if the number of views in both program and draw
427 // framebuffer matches.
428 {
429 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
430 0, 2, &viewportOffsets[0]);
431
432 glDrawArrays(GL_TRIANGLES, 0, 3);
433 EXPECT_GL_NO_ERROR();
434
435 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
436 EXPECT_GL_NO_ERROR();
437 }
438
439 // Check that no errors are generated if the program does not use the multiview extension.
440 {
441 const std::string &vsSourceNoMultiview =
442 "#version 300 es\n"
443 "void main()\n"
444 "{}\n";
445 const std::string &fsSourceNoMultiview =
446 "#version 300 es\n"
447 "precision mediump float;\n"
448 "void main()\n"
449 "{}\n";
450 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
451 glUseProgram(programNoMultiview);
452
453 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
454 0, 2, &viewportOffsets[0]);
455
456 glDrawArrays(GL_TRIANGLES, 0, 3);
457 EXPECT_GL_NO_ERROR();
458
459 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
460 EXPECT_GL_NO_ERROR();
461 }
462}
463
Martin Radev7e69f762017-07-27 14:54:13 +0300464// The test verifies that glDraw*:
465// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
466// greater than 1 and there is an active transform feedback object.
467// 2) does not generate any error if the number of views in the draw framebuffer is 1.
468TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
469{
470 if (!requestMultiviewExtension())
471 {
472 return;
473 }
474
475 const GLint viewportOffsets[4] = {0, 0, 2, 0};
476
477 const std::string &vsSource =
478 "#version 300 es\n"
479 "void main()\n"
480 "{}\n";
481 const std::string &fsSource =
482 "#version 300 es\n"
483 "precision mediump float;\n"
484 "void main()\n"
485 "{}\n";
486 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
487 glUseProgram(program);
488
489 GLBuffer tbo;
490 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
491 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4u, nullptr, GL_STATIC_DRAW);
492
493 GLTransformFeedback transformFeedback;
494 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
495 glBeginTransformFeedback(GL_TRIANGLES);
496 ASSERT_GL_NO_ERROR();
497
498 // Check that drawArrays generates an error when there is an active transform feedback object
499 // and the number of views in the draw framebuffer is greater than 1.
500 {
501 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
502 0, 2, &viewportOffsets[0]);
503 glDrawArrays(GL_TRIANGLES, 0, 3);
504 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
505 }
506
507 // Check that drawArrays does not generate an error when the number of views in the draw
508 // framebuffer is 1.
509 {
510 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
511 0, 1, &viewportOffsets[0]);
512 glDrawArrays(GL_TRIANGLES, 0, 3);
513 EXPECT_GL_NO_ERROR();
514 }
515
516 glEndTransformFeedback();
517}
518
Martin Radevffe754b2017-07-31 10:38:07 +0300519// The test verifies that glDraw*:
520// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
521// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
522// 2) does not generate any error if the number of views in the draw framebuffer is 1.
523TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
524{
525 if (!requestMultiviewExtension())
526 {
527 return;
528 }
529
530 if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
531 {
532 std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
533 << std::endl;
534 return;
535 }
536
537 const GLint viewportOffsets[4] = {0, 0, 2, 0};
538 const std::string &vsSource =
539 "#version 300 es\n"
540 "void main()\n"
541 "{}\n";
542 const std::string &fsSource =
543 "#version 300 es\n"
544 "precision mediump float;\n"
545 "void main()\n"
546 "{}\n";
547 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
548 glUseProgram(program);
549
550 GLuint query = 0u;
551 glGenQueriesEXT(1, &query);
552 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
553
554 // Check first case.
555 {
556 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
557 0, 2, &viewportOffsets[0]);
558 glDrawArrays(GL_TRIANGLES, 0, 3);
559 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
560 }
561
562 // Check second case.
563 {
564 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
565 0, 1, &viewportOffsets[0]);
566 glDrawArrays(GL_TRIANGLES, 0, 3);
567 EXPECT_GL_NO_ERROR();
568 }
569
570 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
571 glDeleteQueries(1, &query);
572}
573
Martin Radev8f276e22017-05-30 12:05:52 +0300574// The test checks that glDrawArrays can be used to render into two views.
575TEST_P(MultiviewSideBySideRenderDualViewTest, DrawArrays)
576{
577 if (!requestMultiviewExtension())
578 {
579 return;
580 }
581 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
582 ASSERT_GL_NO_ERROR();
583
584 checkOutput();
585}
586
587// The test checks that glDrawElements can be used to render into two views.
588TEST_P(MultiviewSideBySideRenderDualViewTest, DrawElements)
589{
590 if (!requestMultiviewExtension())
591 {
592 return;
593 }
594 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
595 ASSERT_GL_NO_ERROR();
596
597 checkOutput();
598}
599
600// The test checks that glDrawRangeElements can be used to render into two views.
601TEST_P(MultiviewSideBySideRenderDualViewTest, DrawRangeElements)
602{
603 if (!requestMultiviewExtension())
604 {
605 return;
606 }
607 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
608 ASSERT_GL_NO_ERROR();
609
610 checkOutput();
611}
612
613// The test checks that glDrawArrays can be used to render into four views.
614TEST_P(MultiviewSideBySideRenderTest, DrawArraysFourViews)
615{
616 if (!requestMultiviewExtension())
617 {
618 return;
619 }
620
621 const std::string vsSource =
622 "#version 300 es\n"
623 "#extension GL_OVR_multiview2 : require\n"
624 "layout(num_views = 4) in;\n"
625 "in vec4 vPosition;\n"
626 "void main()\n"
627 "{\n"
628 " if (gl_ViewID_OVR == 0u) {\n"
629 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
630 " } else if (gl_ViewID_OVR == 1u) {\n"
631 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
632 " } else if (gl_ViewID_OVR == 2u) {\n"
633 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
634 " } else {\n"
635 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
636 " }"
637 " gl_Position.yzw = vPosition.yzw;\n"
638 "}\n";
639
640 const std::string fsSource =
641 "#version 300 es\n"
642 "#extension GL_OVR_multiview2 : require\n"
643 "precision mediump float;\n"
644 "out vec4 col;\n"
645 "void main()\n"
646 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300647 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300648 "}\n";
649
650 createFBO(16, 1, 4);
651 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
652 glUseProgram(program);
653
654 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
655 ASSERT_GL_NO_ERROR();
656
657 for (int i = 0; i < 4; ++i)
658 {
659 for (int j = 0; j < 4; ++j)
660 {
661 const int arrayIndex = i * 4 + j;
662 if (i == j)
663 {
Martin Radev61bd9992017-08-11 13:10:55 +0300664 EXPECT_PIXEL_COLOR_EQ(arrayIndex, 0, GLColor::red);
Martin Radev8f276e22017-05-30 12:05:52 +0300665 }
666 else
667 {
Martin Radev61bd9992017-08-11 13:10:55 +0300668 EXPECT_PIXEL_COLOR_EQ(arrayIndex, 0, GLColor::black);
Martin Radev8f276e22017-05-30 12:05:52 +0300669 }
670 }
671 }
672 EXPECT_GL_NO_ERROR();
673}
674
675// The test checks that glDrawArraysInstanced can be used to render into two views.
676TEST_P(MultiviewSideBySideRenderTest, DrawArraysInstanced)
677{
678 if (!requestMultiviewExtension())
679 {
680 return;
681 }
682
683 const std::string vsSource =
684 "#version 300 es\n"
685 "#extension GL_OVR_multiview : require\n"
686 "layout(num_views = 2) in;\n"
687 "in vec4 vPosition;\n"
688 "void main()\n"
689 "{\n"
690 " vec4 p = vPosition;\n"
691 " if (gl_InstanceID == 1){\n"
692 " p.y = .5*p.y + .5;\n"
693 " } else {\n"
694 " p.y = p.y*.5;\n"
695 " }\n"
696 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
697 " gl_Position.yzw = p.yzw;\n"
698 "}\n";
699
700 const std::string fsSource =
701 "#version 300 es\n"
702 "#extension GL_OVR_multiview : require\n"
703 "precision mediump float;\n"
704 "out vec4 col;\n"
705 "void main()\n"
706 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300707 " col = vec4(1,0,0,1);\n"
Martin Radev8f276e22017-05-30 12:05:52 +0300708 "}\n";
709
710 createFBO(4, 2, 2);
711 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
712 glUseProgram(program);
713
714 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 2);
715 ASSERT_GL_NO_ERROR();
716
Martin Radev61bd9992017-08-11 13:10:55 +0300717 const GLubyte expectedResult[2][4] = {
Martin Radev8f276e22017-05-30 12:05:52 +0300718 {0, 255, 255, 0}, {0, 255, 255, 0},
719 };
720 for (int row = 0; row < 2; ++row)
721 {
722 for (int col = 0; col < 4; ++col)
723 {
Martin Radev61bd9992017-08-11 13:10:55 +0300724 EXPECT_PIXEL_EQ(col, row, expectedResult[row][col], 0, 0, 255);
Martin Radev8f276e22017-05-30 12:05:52 +0300725 }
726 }
727}
728
Martin Radev553590a2017-07-31 16:40:39 +0300729// The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
730// program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
731// offset of each quad are passed as separate attributes which are indexed based on the
732// corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
733// drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
734// quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
735// not by 3.
736TEST_P(MultiviewSideBySideRenderTest, AttribDivisor)
737{
738 if (!requestMultiviewExtension())
739 {
740 return;
741 }
742
743 const std::string &vsSource =
744 "#version 300 es\n"
745 "#extension GL_OVR_multiview2 : require\n"
746 "layout(num_views = 2) in;\n"
747 "in vec3 vPosition;\n"
748 "in float offsetX;\n"
749 "in float offsetY;\n"
750 "void main()\n"
751 "{\n"
752 " vec4 p = vec4(vPosition, 1.);\n"
753 " p.xy = p.xy * 0.25 - 0.75 + vec2(offsetX, offsetY);\n"
754 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
755 " gl_Position.yzw = p.yzw;\n"
756 "}\n";
757
758 const std::string &fsSource =
759 "#version 300 es\n"
760 "#extension GL_OVR_multiview2 : require\n"
761 "precision mediump float;\n"
762 "out vec4 col;\n"
763 "void main()\n"
764 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300765 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300766 "}\n";
767 createFBO(8, 4, 2);
768 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
769 glUseProgram(program);
770
771 GLBuffer xOffsetVBO;
772 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
773 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
774 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
775 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
776 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
777 glVertexAttribDivisor(xOffsetLoc, 3);
778 glEnableVertexAttribArray(xOffsetLoc);
779
780 GLBuffer yOffsetVBO;
781 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
782 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
783 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
784 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
785 glVertexAttribDivisor(yOffsetLoc, 1);
786 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
787 glEnableVertexAttribArray(yOffsetLoc);
788
789 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 4);
790 ASSERT_GL_NO_ERROR();
791
792 const GLubyte expectedRedChannel[4][8] = {{255, 0, 0, 0, 0, 0, 255, 0},
793 {255, 0, 0, 0, 0, 0, 255, 0},
794 {255, 0, 0, 0, 0, 0, 255, 0},
795 {0, 255, 0, 0, 0, 0, 0, 255}};
796 for (int row = 0; row < 4; ++row)
797 {
798 for (int col = 0; col < 8; ++col)
799 {
Martin Radev61bd9992017-08-11 13:10:55 +0300800 EXPECT_PIXEL_EQ(col, row, expectedRedChannel[row][col], 0, 0, 255);
Martin Radev553590a2017-07-31 16:40:39 +0300801 }
802 }
803}
804
805// Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
806// multi-view context propagate the correct divisor to the driver.
807TEST_P(MultiviewSideBySideRenderTest, DivisorOrderOfOperation)
808{
809 if (!requestMultiviewExtension())
810 {
811 return;
812 }
813
814 createFBO(2, 1, 2);
815
816 // Create multiview program.
817 const std::string &vs =
818 "#version 300 es\n"
819 "#extension GL_OVR_multiview2 : require\n"
820 "layout(num_views = 2) in;\n"
821 "layout(location = 0) in vec2 vPosition;\n"
822 "layout(location = 1) in float offsetX;\n"
823 "void main()\n"
824 "{\n"
825 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
826 " p.x += offsetX;\n"
827 " gl_Position = p;\n"
828 "}\n";
829
830 const std::string &fs =
831 "#version 300 es\n"
832 "#extension GL_OVR_multiview2 : require\n"
833 "precision mediump float;\n"
834 "out vec4 col;\n"
835 "void main()\n"
836 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300837 " col = vec4(1,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300838 "}\n";
839
840 ANGLE_GL_PROGRAM(program, vs, fs);
841
842 const std::string &dummyVS =
843 "#version 300 es\n"
844 "layout(location = 0) in vec2 vPosition;\n"
845 "layout(location = 1) in float offsetX;\n"
846 "void main()\n"
847 "{\n"
848 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
849 "}\n";
850
851 const std::string &dummyFS =
852 "#version 300 es\n"
853 "precision mediump float;\n"
854 "out vec4 col;\n"
855 "void main()\n"
856 "{\n"
Martin Radev61bd9992017-08-11 13:10:55 +0300857 " col = vec4(0,0,0,1);\n"
Martin Radev553590a2017-07-31 16:40:39 +0300858 "}\n";
859
860 ANGLE_GL_PROGRAM(dummyProgram, dummyVS, dummyFS);
861
862 GLBuffer xOffsetVBO;
863 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
864 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
865 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
866 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
867
868 GLBuffer vertexVBO;
869 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
870 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
871 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
872 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
873
874 GLVertexArray vao[2];
875 for (size_t i = 0u; i < 2u; ++i)
876 {
877 glBindVertexArray(vao[i]);
878
879 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
880 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
881 glEnableVertexAttribArray(0);
882
883 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
884 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
885 glEnableVertexAttribArray(1);
886 }
887 ASSERT_GL_NO_ERROR();
888
889 glViewport(0, 0, 1, 1);
890 glScissor(0, 0, 1, 1);
Martin Radeveef80e42017-08-11 14:44:57 +0300891 glEnable(GL_SCISSOR_TEST);
Martin Radev61bd9992017-08-11 13:10:55 +0300892 glClearColor(0, 0, 0, 1);
Martin Radev553590a2017-07-31 16:40:39 +0300893
894 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
895 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
896 // bits are cleared.
897 glUseProgram(dummyProgram);
898 glBindVertexArray(vao[0]);
899 glVertexAttribDivisor(1, 0);
900 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
901 glUseProgram(0);
902 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
903 ASSERT_GL_NO_ERROR();
904
905 // Check that vertexAttribDivisor uses the number of views to update the divisor.
906 glUseProgram(program);
907 glVertexAttribDivisor(1, 1);
908 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev61bd9992017-08-11 13:10:55 +0300909 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
910 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Martin Radev553590a2017-07-31 16:40:39 +0300911
912 // Clear the buffers and propagate divisor to the driver.
913 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
914 // dirty bits when useProgram is called.
915 glUseProgram(dummyProgram);
916 glVertexAttribDivisor(1, 1);
917 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
918 glUseProgram(0);
919 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
920 ASSERT_GL_NO_ERROR();
921
922 // Check that useProgram uses the number of views to update the divisor.
923 glUseProgram(program);
924 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev61bd9992017-08-11 13:10:55 +0300925 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
926 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Martin Radev553590a2017-07-31 16:40:39 +0300927
928 // We go through similar steps as before.
929 glUseProgram(dummyProgram);
930 glVertexAttribDivisor(1, 1);
931 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
932 glUseProgram(0);
933 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
934 ASSERT_GL_NO_ERROR();
935
936 // Check that bindVertexArray uses the number of views to update the divisor.
937 {
938 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
939 // divisor for vao[1] only.
940 glBindVertexArray(vao[1]);
941 glUseProgram(program);
942 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
943 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
944 glBindVertexArray(0);
945 ASSERT_GL_NO_ERROR();
946 }
947 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
948 // adjusts the divisor.
949 glBindVertexArray(vao[0]);
950 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
Martin Radev61bd9992017-08-11 13:10:55 +0300951 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
952 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
Martin Radev553590a2017-07-31 16:40:39 +0300953}
954
Martin Radev0d671c92017-08-10 16:41:52 +0300955// Test that no fragments pass the occlusion query for a multi-view vertex shader which always
956// transforms geometry to be outside of the clip region.
957TEST_P(MultiviewSideBySideOcclusionQueryTest, OcclusionQueryNothingVisible)
958{
959 if (!requestMultiviewExtension())
960 {
961 return;
962 }
963
964 const std::string vsSource =
965 "#version 300 es\n"
966 "#extension GL_OVR_multiview : require\n"
967 "layout(num_views = 2) in;\n"
968 "in vec3 vPosition;\n"
969 "void main()\n"
970 "{\n"
971 " gl_Position.x = 2.0;\n"
972 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
973 "}\n";
974
975 const std::string fsSource =
976 "#version 300 es\n"
977 "#extension GL_OVR_multiview : require\n"
978 "precision mediump float;\n"
979 "out vec4 col;\n"
980 "void main()\n"
981 "{\n"
982 " col = vec4(1,0,0,0);\n"
983 "}\n";
984 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
985 glUseProgram(program);
986 createFBO(2, 1, 2);
987
988 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
989 ASSERT_GL_NO_ERROR();
990 EXPECT_GL_FALSE(result);
991}
992
993// Test that there are fragments passing the occlusion query if only view 0 can produce
994// output.
995TEST_P(MultiviewSideBySideOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
996{
997 if (!requestMultiviewExtension())
998 {
999 return;
1000 }
1001
1002 const std::string vsSource =
1003 "#version 300 es\n"
1004 "#extension GL_OVR_multiview : require\n"
1005 "layout(num_views = 2) in;\n"
1006 "in vec3 vPosition;\n"
1007 "void main()\n"
1008 "{\n"
1009 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1010 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1011 "}\n";
1012
1013 const std::string fsSource =
1014 "#version 300 es\n"
1015 "#extension GL_OVR_multiview : require\n"
1016 "precision mediump float;\n"
1017 "out vec4 col;\n"
1018 "void main()\n"
1019 "{\n"
1020 " col = vec4(1,0,0,0);\n"
1021 "}\n";
1022 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1023 glUseProgram(program);
1024 createFBO(2, 1, 2);
1025
1026 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1027 ASSERT_GL_NO_ERROR();
1028 EXPECT_GL_TRUE(result);
1029}
1030
1031// Test that there are fragments passing the occlusion query if only view 1 can produce
1032// output.
1033TEST_P(MultiviewSideBySideOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
1034{
1035 if (!requestMultiviewExtension())
1036 {
1037 return;
1038 }
1039
1040 const std::string vsSource =
1041 "#version 300 es\n"
1042 "#extension GL_OVR_multiview : require\n"
1043 "layout(num_views = 2) in;\n"
1044 "in vec3 vPosition;\n"
1045 "void main()\n"
1046 "{\n"
1047 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1048 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1049 "}\n";
1050
1051 const std::string fsSource =
1052 "#version 300 es\n"
1053 "#extension GL_OVR_multiview : require\n"
1054 "precision mediump float;\n"
1055 "out vec4 col;\n"
1056 "void main()\n"
1057 "{\n"
1058 " col = vec4(1,0,0,0);\n"
1059 "}\n";
1060 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1061 glUseProgram(program);
1062 createFBO(2, 1, 2);
1063
1064 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1065 ASSERT_GL_NO_ERROR();
1066 EXPECT_GL_TRUE(result);
1067}
1068
Martin Radev41ac68e2017-06-06 12:16:58 +03001069// Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1070// compiles and links without an error.
1071TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1072{
1073 if (!requestMultiviewExtension())
1074 {
1075 return;
1076 }
1077
1078 const std::string vsSource =
1079 "#version 300 es\n"
1080 "#extension GL_OVR_multiview : require\n"
1081 "layout(num_views = 2) in;\n"
1082 "void main()\n"
1083 "{\n"
1084 "}\n";
1085
1086 const std::string fsSource =
1087 "#version 300 es\n"
1088 "#extension GL_OVR_multiview : require\n"
1089 "precision mediump float;\n"
1090 "void main()\n"
1091 "{\n"
1092 "}\n";
1093
1094 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1095 glUseProgram(program);
1096
1097 EXPECT_GL_NO_ERROR();
1098}
1099
1100// Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1101// without an error.
1102TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1103{
1104 if (!requestMultiviewExtension())
1105 {
1106 return;
1107 }
1108
1109 const std::string vsSource =
1110 "#version 300 es\n"
1111 "#extension GL_OVR_multiview2 : require\n"
1112 "layout(num_views = 2) in;\n"
1113 "void main()\n"
1114 "{\n"
1115 " if (gl_ViewID_OVR == 0u) {\n"
1116 " gl_Position = vec4(1,0,0,1);\n"
1117 " } else {\n"
1118 " gl_Position = vec4(-1,0,0,1);\n"
1119 " }\n"
1120 "}\n";
1121
1122 const std::string fsSource =
1123 "#version 300 es\n"
1124 "#extension GL_OVR_multiview2 : require\n"
1125 "precision mediump float;\n"
1126 "void main()\n"
1127 "{\n"
1128 "}\n";
1129
1130 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1131 glUseProgram(program);
1132
1133 EXPECT_GL_NO_ERROR();
1134}
1135
1136// Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1137// without an error.
1138TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1139{
1140 if (!requestMultiviewExtension())
1141 {
1142 return;
1143 }
1144
1145 const std::string vsSource =
1146 "#version 300 es\n"
1147 "#extension GL_OVR_multiview2 : require\n"
1148 "layout(num_views = 2) in;\n"
1149 "void main()\n"
1150 "{\n"
1151 "}\n";
1152
1153 const std::string fsSource =
1154 "#version 300 es\n"
1155 "#extension GL_OVR_multiview2 : require\n"
1156 "precision mediump float;\n"
1157 "out vec4 col;\n"
1158 "void main()\n"
1159 "{\n"
1160 " if (gl_ViewID_OVR == 0u) {\n"
1161 " col = vec4(1,0,0,1);\n"
1162 " } else {\n"
1163 " col = vec4(-1,0,0,1);\n"
1164 " }\n"
1165 "}\n";
1166
1167 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1168 glUseProgram(program);
1169
1170 EXPECT_GL_NO_ERROR();
1171}
1172
Martin Radev61bd9992017-08-11 13:10:55 +03001173// The test checks that GL_POINTS is correctly rendered.
1174TEST_P(MultiviewSideBySideRenderPrimitiveTest, Points)
1175{
1176 if (!requestMultiviewExtension())
1177 {
1178 return;
1179 }
1180
1181 const std::string vsSource =
1182 "#version 300 es\n"
1183 "#extension GL_OVR_multiview : require\n"
1184 "layout(num_views = 2) in;\n"
1185 "layout(location=0) in vec2 vPosition;\n"
1186 "void main()\n"
1187 "{\n"
1188 " gl_PointSize = 1.0;\n"
1189 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1190 "}\n";
1191
1192 const std::string fsSource =
1193 "#version 300 es\n"
1194 "#extension GL_OVR_multiview : require\n"
1195 "precision mediump float;\n"
1196 "out vec4 col;\n"
1197 "void main()\n"
1198 "{\n"
1199 " col = vec4(1,0,0,1);\n"
1200 "}\n";
1201 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1202 glUseProgram(program);
1203
1204 createFBO(8, 2, 2);
1205
1206 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1207 std::vector<Vector2> vertexDataInClipSpace =
1208 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1209 setupGeometry(vertexDataInClipSpace);
1210
1211 glDrawArrays(GL_POINTS, 0, 2);
1212
1213 const GLubyte expectedRedChannelData[2][8] = {{255, 0, 0, 0, 255, 0, 0, 0},
1214 {0, 0, 0, 255, 0, 0, 0, 255}};
1215 checkRedChannel(expectedRedChannelData[0], 8, 2);
1216}
1217
1218// The test checks that GL_LINES is correctly rendered.
1219// The behavior of this test is not guaranteed by the spec:
1220// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1221// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1222// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1223// rule."
1224TEST_P(MultiviewSideBySideRenderPrimitiveTest, Lines)
1225{
1226 if (!requestMultiviewExtension())
1227 {
1228 return;
1229 }
1230
1231 GLuint program = CreateSimplePassthroughProgram();
1232 ASSERT_NE(program, 0u);
1233 glUseProgram(program);
1234 ASSERT_GL_NO_ERROR();
1235
1236 createFBO(8, 2, 2);
1237
1238 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1239 std::vector<Vector2> vertexDataInClipSpace =
1240 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1241 setupGeometry(vertexDataInClipSpace);
1242
1243 glDrawArrays(GL_LINES, 0, 2);
1244
1245 const GLubyte expectedRedChannelData[2][8] = {{255, 255, 255, 255, 255, 255, 255, 255},
1246 {0, 0, 0, 0, 0, 0, 0, 0}};
1247 checkRedChannel(expectedRedChannelData[0], 8, 2);
1248
1249 glDeleteProgram(program);
1250}
1251
1252// The test checks that GL_LINE_STRIP is correctly rendered.
1253// The behavior of this test is not guaranteed by the spec:
1254// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1255// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1256// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1257// rule."
1258TEST_P(MultiviewSideBySideRenderPrimitiveTest, LineStrip)
1259{
1260 if (!requestMultiviewExtension())
1261 {
1262 return;
1263 }
1264
1265 GLuint program = CreateSimplePassthroughProgram();
1266 ASSERT_NE(program, 0u);
1267 glUseProgram(program);
1268 ASSERT_GL_NO_ERROR();
1269
1270 createFBO(8, 2, 2);
1271
1272 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1273 std::vector<Vector2> vertexDataInClipSpace =
1274 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1275 setupGeometry(vertexDataInClipSpace);
1276
1277 glDrawArrays(GL_LINE_STRIP, 0, 3);
1278
1279 const GLubyte expectedRedChannelData[2][8] = {{255, 255, 255, 255, 255, 255, 255, 255},
1280 {0, 0, 0, 255, 0, 0, 0, 255}};
1281 checkRedChannel(expectedRedChannelData[0], 8, 2);
1282
1283 glDeleteProgram(program);
1284}
1285
1286// The test checks that GL_LINE_LOOP is correctly rendered.
1287// The behavior of this test is not guaranteed by the spec:
1288// OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1289// "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1290// either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1291// rule."
1292TEST_P(MultiviewSideBySideRenderPrimitiveTest, LineLoop)
1293{
1294 if (!requestMultiviewExtension())
1295 {
1296 return;
1297 }
1298
1299 GLuint program = CreateSimplePassthroughProgram();
1300 ASSERT_NE(program, 0u);
1301 glUseProgram(program);
1302 ASSERT_GL_NO_ERROR();
1303
1304 createFBO(8, 4, 2);
1305
1306 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1307 Vector2I(0, 3)};
1308 std::vector<Vector2> vertexDataInClipSpace =
1309 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1310 setupGeometry(vertexDataInClipSpace);
1311
1312 glDrawArrays(GL_LINE_LOOP, 0, 4);
1313
1314 const GLubyte expectedRedChannelData[4][8] = {{255, 255, 255, 255, 255, 255, 255, 255},
1315 {255, 0, 0, 255, 255, 0, 0, 255},
1316 {255, 0, 0, 255, 255, 0, 0, 255},
1317 {255, 255, 255, 255, 255, 255, 255, 255}};
1318 checkRedChannel(expectedRedChannelData[0], 8, 4);
1319
1320 glDeleteProgram(program);
1321}
1322
1323// The test checks that GL_TRIANGLE_STRIP is correctly rendered.
1324TEST_P(MultiviewSideBySideRenderPrimitiveTest, TriangleStrip)
1325{
1326 if (!requestMultiviewExtension())
1327 {
1328 return;
1329 }
1330
1331 GLuint program = CreateSimplePassthroughProgram();
1332 ASSERT_NE(program, 0u);
1333 glUseProgram(program);
1334 ASSERT_GL_NO_ERROR();
1335
1336 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1337 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1338 setupGeometry(vertexDataInClipSpace);
1339
1340 createFBO(4, 2, 2);
1341
1342 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1343
1344 const GLubyte expectedRedChannelData[2][4] = {{0, 0, 0, 0}, {0, 255, 0, 255}};
1345 checkRedChannel(expectedRedChannelData[0], 4, 2);
1346
1347 glDeleteProgram(program);
1348}
1349
1350// The test checks that GL_TRIANGLE_FAN is correctly rendered.
1351TEST_P(MultiviewSideBySideRenderPrimitiveTest, TriangleFan)
1352{
1353 if (!requestMultiviewExtension())
1354 {
1355 return;
1356 }
1357
1358 GLuint program = CreateSimplePassthroughProgram();
1359 ASSERT_NE(program, 0u);
1360 glUseProgram(program);
1361 ASSERT_GL_NO_ERROR();
1362
1363 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1364 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1365 setupGeometry(vertexDataInClipSpace);
1366
1367 createFBO(4, 2, 2);
1368
1369 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1370
1371 const GLubyte expectedRedChannelData[2][4] = {{0, 0, 0, 0}, {0, 255, 0, 255}};
1372 checkRedChannel(expectedRedChannelData[0], 4, 2);
1373
1374 glDeleteProgram(program);
1375}
1376
1377// Test that rendering enlarged points and lines does not leak fragments outside of the views'
1378// bounds. The test does not rely on the actual line width being greater than 1.0.
1379TEST_P(MultiviewSideBySideRenderPrimitiveTest, NoLeakingFragments)
1380{
1381 if (!requestMultiviewExtension())
1382 {
1383 return;
1384 }
1385
1386 createFBO(4, 1, 2);
1387
1388 GLint viewportOffsets[4] = {1, 0, 3, 0};
1389 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1390 mColorTexture, 0, 2, &viewportOffsets[0]);
1391 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
1392 mDepthTexture, 0, 2, &viewportOffsets[0]);
1393
1394 glViewport(0, 0, 1, 1);
1395 glScissor(0, 0, 1, 1);
1396 glEnable(GL_SCISSOR_TEST);
1397
1398 const std::string vsSource =
1399 "#version 300 es\n"
1400 "#extension GL_OVR_multiview2 : require\n"
1401 "layout(num_views = 2) in;\n"
1402 "layout(location=0) in vec2 vPosition;\n"
1403 "void main()\n"
1404 "{\n"
1405 " gl_PointSize = 10.0;\n"
1406 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1407 "}\n";
1408
1409 const std::string fsSource =
1410 "#version 300 es\n"
1411 "#extension GL_OVR_multiview2 : require\n"
1412 "precision mediump float;\n"
1413 "out vec4 col;\n"
1414 "void main()\n"
1415 "{\n"
1416 " if (gl_ViewID_OVR == 0u) {\n"
1417 " col = vec4(1,0,0,1);\n"
1418 " } else {\n"
1419 " col = vec4(0,1,0,1);\n"
1420 " }\n"
1421 "}\n";
1422 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
1423 glUseProgram(program);
1424
1425 const std::vector<Vector2I> &windowCoordinates = {Vector2I(0, 0), Vector2I(2, 0)};
1426 const std::vector<Vector2> &vertexDataInClipSpace =
1427 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 1, 1);
1428 setupGeometry(vertexDataInClipSpace);
1429
1430 // Test rendering points.
1431 {
1432 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1433 glDrawArrays(GL_POINTS, 0, 2);
1434 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1435 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1436 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1437 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1438 }
1439
1440 // Test rendering lines.
1441 {
1442 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1443 glLineWidth(10.f);
1444 glDrawArrays(GL_LINES, 0, 2);
1445 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
1446 EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::red);
1447 EXPECT_PIXEL_COLOR_EQ(2, 0, GLColor::black);
1448 EXPECT_PIXEL_COLOR_EQ(3, 0, GLColor::green);
1449 }
1450}
1451
Martin Radev8f276e22017-05-30 12:05:52 +03001452ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ES31_OPENGL());
1453ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderDualViewTest, ES3_OPENGL());
Martin Radev0d671c92017-08-10 16:41:52 +03001454ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest, ES3_OPENGL());
1455ANGLE_INSTANTIATE_TEST(MultiviewSideBySideOcclusionQueryTest, ES3_OPENGL());
Martin Radev41ac68e2017-06-06 12:16:58 +03001456ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest, ES3_OPENGL(), ES3_D3D11());
Martin Radev61bd9992017-08-11 13:10:55 +03001457ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderPrimitiveTest, ES3_OPENGL());