blob: 010e2711f50de1f20ddb5ecaa1a25871fcc71c1a [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
15class MultiviewDrawTest : public ANGLETest
16{
17 protected:
18 MultiviewDrawTest()
19 {
20 setWindowWidth(128);
21 setWindowHeight(128);
22 setWebGLCompatibilityEnabled(true);
23 }
Martin Radev7cf61662017-07-26 17:10:53 +030024 virtual ~MultiviewDrawTest() {}
Martin Radev14a26ae2017-07-24 15:56:29 +030025
26 void SetUp() override
27 {
28 ANGLETest::SetUp();
29
30 glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
31 eglGetProcAddress("glRequestExtensionANGLE"));
32 }
33
34 // Requests the ANGLE_multiview extension and returns true if the operation succeeds.
35 bool requestMultiviewExtension()
36 {
37 if (extensionRequestable("GL_ANGLE_multiview"))
38 {
39 glRequestExtensionANGLE("GL_ANGLE_multiview");
40 }
41
42 if (!extensionEnabled("GL_ANGLE_multiview"))
43 {
44 std::cout << "Test skipped due to missing GL_ANGLE_multiview." << std::endl;
45 return false;
46 }
47 return true;
48 }
49
50 PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
51};
52
Martin Radev7cf61662017-07-26 17:10:53 +030053class MultiviewDrawValidationTest : public MultiviewDrawTest
54{
55 protected:
56 MultiviewDrawValidationTest() {}
57
58 void SetUp() override
59 {
60 MultiviewDrawTest::SetUp();
61
62 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
63
64 glBindTexture(GL_TEXTURE_2D, mTex2d);
65 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
66
67 glBindVertexArray(mVao);
68
69 const float kVertexData[3] = {0.0f};
70 glBindBuffer(GL_ARRAY_BUFFER, mVbo);
71 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
72
73 const unsigned int kIndices[3] = {0u, 1u, 2u};
74 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIbo);
75 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
76 GL_STATIC_DRAW);
77 ASSERT_GL_NO_ERROR();
78 }
79
80 GLTexture mTex2d;
81 GLVertexArray mVao;
82 GLBuffer mVbo;
83 GLBuffer mIbo;
84 GLFramebuffer mFramebuffer;
85};
86
Martin Radev8f276e22017-05-30 12:05:52 +030087class MultiviewSideBySideRenderTest : public MultiviewDrawTest
88{
89 protected:
90 void createFBO(int width, int height, int numViews)
91 {
92 // Assert that width is a multiple of numViews.
93 ASSERT_TRUE(width % numViews == 0);
94 const int widthPerView = width / numViews;
95
96 // Create color and depth textures.
97 glBindTexture(GL_TEXTURE_2D, mColorTexture);
98 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
99 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
101 ASSERT_GL_NO_ERROR();
102
103 glBindTexture(GL_TEXTURE_2D, mDepthTexture);
104 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT,
105 GL_FLOAT, NULL);
106 glBindTexture(GL_TEXTURE_2D, 0);
107 ASSERT_GL_NO_ERROR();
108
109 // Create draw framebuffer to be used for side-by-side rendering.
110 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
111 std::vector<GLint> viewportOffsets(numViews * 2u);
112 for (int i = 0u; i < numViews; ++i)
113 {
114 viewportOffsets[i * 2] = i * widthPerView;
115 viewportOffsets[i * 2 + 1] = 0;
116 }
117 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
118 mColorTexture, 0, numViews,
119 &viewportOffsets[0]);
120 glFramebufferTextureMultiviewSideBySideANGLE(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
121 mDepthTexture, 0, numViews,
122 &viewportOffsets[0]);
123
124 GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};
125 glDrawBuffers(1, DrawBuffers);
126 ASSERT_GL_NO_ERROR();
127 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
128
129 // Create read framebuffer to be used to retrieve the pixel information for testing
130 // purposes.
131 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer);
132 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
133 mColorTexture, 0);
134 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
135
136 // Clear the buffers.
137 glViewport(0, 0, width, height);
138 glScissor(0, 0, width, height);
139 glClearColor(0, 0, 0, 0);
140 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
141
142 // Set viewport and scissor of each view.
143 glViewport(0, 0, widthPerView, height);
144 glScissor(0, 0, widthPerView, height);
145 }
146
147 GLTexture mColorTexture;
148 GLTexture mDepthTexture;
149 GLFramebuffer mDrawFramebuffer;
150 GLFramebuffer mReadFramebuffer;
151};
152
153class MultiviewSideBySideRenderDualViewTest : public MultiviewSideBySideRenderTest
154{
155 protected:
156 MultiviewSideBySideRenderDualViewTest() : mProgram(0u) {}
157 ~MultiviewSideBySideRenderDualViewTest()
158 {
159 if (mProgram != 0u)
160 {
161 glDeleteProgram(mProgram);
162 }
163 }
164
165 void SetUp() override
166 {
167 MultiviewSideBySideRenderTest::SetUp();
168
169 if (!requestMultiviewExtension())
170 {
171 return;
172 }
173
174 const std::string vsSource =
175 "#version 300 es\n"
176 "#extension GL_OVR_multiview : require\n"
177 "layout(num_views = 2) in;\n"
178 "in vec4 vPosition;\n"
179 "void main()\n"
180 "{\n"
181 " gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x*0.5 + 0.5 : vPosition.x*0.5);\n"
182 " gl_Position.yzw = vPosition.yzw;\n"
183 "}\n";
184
185 const std::string fsSource =
186 "#version 300 es\n"
187 "#extension GL_OVR_multiview : require\n"
188 "precision mediump float;\n"
189 "out vec4 col;\n"
190 "void main()\n"
191 "{\n"
192 " col = vec4(1,0,0,0);\n"
193 "}\n";
194
195 createFBO(4, 1, 2);
196 createProgram(vsSource, fsSource);
197 }
198
199 void createProgram(const std::string &vs, const std::string &fs)
200 {
201 mProgram = CompileProgram(vs, fs);
202 if (mProgram == 0)
203 {
204 FAIL() << "shader compilation failed.";
205 }
206 glUseProgram(mProgram);
207 ASSERT_GL_NO_ERROR();
208 }
209
210 void checkOutput()
211 {
212 EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0);
213 EXPECT_PIXEL_EQ(1, 0, 255, 0, 0, 0);
214 EXPECT_PIXEL_EQ(2, 0, 255, 0, 0, 0);
215 EXPECT_PIXEL_EQ(3, 0, 0, 0, 0, 0);
216 }
217
218 GLuint mProgram;
219};
220
Martin Radev14a26ae2017-07-24 15:56:29 +0300221// The test verifies that glDraw*Indirect:
222// 1) generates an INVALID_OPERATION error if the number of views in the draw framebuffer is greater
223// than 1.
224// 2) does not generate any error if the draw framebuffer has exactly 1 view.
Martin Radev7cf61662017-07-26 17:10:53 +0300225TEST_P(MultiviewDrawValidationTest, IndirectDraw)
Martin Radev14a26ae2017-07-24 15:56:29 +0300226{
227 if (!requestMultiviewExtension())
228 {
229 return;
230 }
231
Martin Radev14a26ae2017-07-24 15:56:29 +0300232 const GLint viewportOffsets[4] = {0, 0, 2, 0};
Martin Radev14a26ae2017-07-24 15:56:29 +0300233
234 const std::string fsSource =
235 "#version 300 es\n"
236 "#extension GL_OVR_multiview : require\n"
237 "precision mediump float;\n"
238 "void main()\n"
239 "{}\n";
240
Martin Radev14a26ae2017-07-24 15:56:29 +0300241 GLBuffer commandBuffer;
242 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
243 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
244 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
245 ASSERT_GL_NO_ERROR();
246
Martin Radev14a26ae2017-07-24 15:56:29 +0300247 // Check for a GL_INVALID_OPERATION error with the framebuffer having 2 views.
248 {
249 const std::string &vsSource =
250 "#version 300 es\n"
251 "#extension GL_OVR_multiview : require\n"
252 "layout(num_views = 2) in;\n"
253 "void main()\n"
254 "{}\n";
255 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
256 glUseProgram(program);
257
Martin Radev7cf61662017-07-26 17:10:53 +0300258 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
259 0, 2, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300260
261 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
262 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
263
264 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
265 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
266 }
267
268 // Check that no errors are generated if the number of views is 1.
269 {
270 const std::string &vsSource =
271 "#version 300 es\n"
272 "#extension GL_OVR_multiview : require\n"
273 "layout(num_views = 1) in;\n"
274 "void main()\n"
275 "{}\n";
276 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
277 glUseProgram(program);
278
Martin Radev7cf61662017-07-26 17:10:53 +0300279 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
280 0, 1, &viewportOffsets[0]);
Martin Radev14a26ae2017-07-24 15:56:29 +0300281
282 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
283 EXPECT_GL_NO_ERROR();
284
285 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
286 EXPECT_GL_NO_ERROR();
287 }
288}
289
Martin Radev7cf61662017-07-26 17:10:53 +0300290// The test verifies that glDraw*:
291// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
292// program differs.
293// 2) does not generate any error if the number of views is the same.
294// 3) does not generate any error if the program does not use the multiview extension.
295TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
296{
297 if (!requestMultiviewExtension())
298 {
299 return;
300 }
301
302 const GLint viewportOffsets[4] = {0, 0, 2, 0};
303
304 const std::string &vsSource =
305 "#version 300 es\n"
306 "#extension GL_OVR_multiview : require\n"
307 "layout(num_views = 2) in;\n"
308 "void main()\n"
309 "{}\n";
310 const std::string &fsSource =
311 "#version 300 es\n"
312 "#extension GL_OVR_multiview : require\n"
313 "precision mediump float;\n"
314 "void main()\n"
315 "{}\n";
316 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
317 glUseProgram(program);
318
319 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
320 // number of views.
321 {
322 // The framebuffer has only 1 view.
323 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
324 0, 1, &viewportOffsets[0]);
325
326 glDrawArrays(GL_TRIANGLES, 0, 3);
327 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
328
329 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
330 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
331 }
332
333 // Check that no errors are generated if the number of views in both program and draw
334 // framebuffer matches.
335 {
336 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
337 0, 2, &viewportOffsets[0]);
338
339 glDrawArrays(GL_TRIANGLES, 0, 3);
340 EXPECT_GL_NO_ERROR();
341
342 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
343 EXPECT_GL_NO_ERROR();
344 }
345
346 // Check that no errors are generated if the program does not use the multiview extension.
347 {
348 const std::string &vsSourceNoMultiview =
349 "#version 300 es\n"
350 "void main()\n"
351 "{}\n";
352 const std::string &fsSourceNoMultiview =
353 "#version 300 es\n"
354 "precision mediump float;\n"
355 "void main()\n"
356 "{}\n";
357 ANGLE_GL_PROGRAM(programNoMultiview, vsSourceNoMultiview, fsSourceNoMultiview);
358 glUseProgram(programNoMultiview);
359
360 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
361 0, 2, &viewportOffsets[0]);
362
363 glDrawArrays(GL_TRIANGLES, 0, 3);
364 EXPECT_GL_NO_ERROR();
365
366 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
367 EXPECT_GL_NO_ERROR();
368 }
369}
370
Martin Radev7e69f762017-07-27 14:54:13 +0300371// The test verifies that glDraw*:
372// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
373// greater than 1 and there is an active transform feedback object.
374// 2) does not generate any error if the number of views in the draw framebuffer is 1.
375TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
376{
377 if (!requestMultiviewExtension())
378 {
379 return;
380 }
381
382 const GLint viewportOffsets[4] = {0, 0, 2, 0};
383
384 const std::string &vsSource =
385 "#version 300 es\n"
386 "void main()\n"
387 "{}\n";
388 const std::string &fsSource =
389 "#version 300 es\n"
390 "precision mediump float;\n"
391 "void main()\n"
392 "{}\n";
393 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
394 glUseProgram(program);
395
396 GLBuffer tbo;
397 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
398 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 4u, nullptr, GL_STATIC_DRAW);
399
400 GLTransformFeedback transformFeedback;
401 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
402 glBeginTransformFeedback(GL_TRIANGLES);
403 ASSERT_GL_NO_ERROR();
404
405 // Check that drawArrays generates an error when there is an active transform feedback object
406 // and the number of views in the draw framebuffer is greater than 1.
407 {
408 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
409 0, 2, &viewportOffsets[0]);
410 glDrawArrays(GL_TRIANGLES, 0, 3);
411 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
412 }
413
414 // Check that drawArrays does not generate an error when the number of views in the draw
415 // framebuffer is 1.
416 {
417 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
418 0, 1, &viewportOffsets[0]);
419 glDrawArrays(GL_TRIANGLES, 0, 3);
420 EXPECT_GL_NO_ERROR();
421 }
422
423 glEndTransformFeedback();
424}
425
Martin Radevffe754b2017-07-31 10:38:07 +0300426// The test verifies that glDraw*:
427// 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
428// greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
429// 2) does not generate any error if the number of views in the draw framebuffer is 1.
430TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
431{
432 if (!requestMultiviewExtension())
433 {
434 return;
435 }
436
437 if (!extensionEnabled("GL_EXT_disjoint_timer_query"))
438 {
439 std::cout << "Test skipped because GL_EXT_disjoint_timer_query is not available."
440 << std::endl;
441 return;
442 }
443
444 const GLint viewportOffsets[4] = {0, 0, 2, 0};
445 const std::string &vsSource =
446 "#version 300 es\n"
447 "void main()\n"
448 "{}\n";
449 const std::string &fsSource =
450 "#version 300 es\n"
451 "precision mediump float;\n"
452 "void main()\n"
453 "{}\n";
454 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
455 glUseProgram(program);
456
457 GLuint query = 0u;
458 glGenQueriesEXT(1, &query);
459 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
460
461 // Check first case.
462 {
463 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
464 0, 2, &viewportOffsets[0]);
465 glDrawArrays(GL_TRIANGLES, 0, 3);
466 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
467 }
468
469 // Check second case.
470 {
471 glFramebufferTextureMultiviewSideBySideANGLE(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTex2d,
472 0, 1, &viewportOffsets[0]);
473 glDrawArrays(GL_TRIANGLES, 0, 3);
474 EXPECT_GL_NO_ERROR();
475 }
476
477 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
478 glDeleteQueries(1, &query);
479}
480
Martin Radev8f276e22017-05-30 12:05:52 +0300481// The test checks that glDrawArrays can be used to render into two views.
482TEST_P(MultiviewSideBySideRenderDualViewTest, DrawArrays)
483{
484 if (!requestMultiviewExtension())
485 {
486 return;
487 }
488 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
489 ASSERT_GL_NO_ERROR();
490
491 checkOutput();
492}
493
494// The test checks that glDrawElements can be used to render into two views.
495TEST_P(MultiviewSideBySideRenderDualViewTest, DrawElements)
496{
497 if (!requestMultiviewExtension())
498 {
499 return;
500 }
501 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
502 ASSERT_GL_NO_ERROR();
503
504 checkOutput();
505}
506
507// The test checks that glDrawRangeElements can be used to render into two views.
508TEST_P(MultiviewSideBySideRenderDualViewTest, DrawRangeElements)
509{
510 if (!requestMultiviewExtension())
511 {
512 return;
513 }
514 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
515 ASSERT_GL_NO_ERROR();
516
517 checkOutput();
518}
519
520// The test checks that glDrawArrays can be used to render into four views.
521TEST_P(MultiviewSideBySideRenderTest, DrawArraysFourViews)
522{
523 if (!requestMultiviewExtension())
524 {
525 return;
526 }
527
528 const std::string vsSource =
529 "#version 300 es\n"
530 "#extension GL_OVR_multiview2 : require\n"
531 "layout(num_views = 4) in;\n"
532 "in vec4 vPosition;\n"
533 "void main()\n"
534 "{\n"
535 " if (gl_ViewID_OVR == 0u) {\n"
536 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
537 " } else if (gl_ViewID_OVR == 1u) {\n"
538 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
539 " } else if (gl_ViewID_OVR == 2u) {\n"
540 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
541 " } else {\n"
542 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
543 " }"
544 " gl_Position.yzw = vPosition.yzw;\n"
545 "}\n";
546
547 const std::string fsSource =
548 "#version 300 es\n"
549 "#extension GL_OVR_multiview2 : require\n"
550 "precision mediump float;\n"
551 "out vec4 col;\n"
552 "void main()\n"
553 "{\n"
554 " col = vec4(1,0,0,0);\n"
555 "}\n";
556
557 createFBO(16, 1, 4);
558 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
559 glUseProgram(program);
560
561 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
562 ASSERT_GL_NO_ERROR();
563
564 for (int i = 0; i < 4; ++i)
565 {
566 for (int j = 0; j < 4; ++j)
567 {
568 const int arrayIndex = i * 4 + j;
569 if (i == j)
570 {
571 EXPECT_PIXEL_EQ(arrayIndex, 0, 255, 0, 0, 0);
572 }
573 else
574 {
575 EXPECT_PIXEL_EQ(arrayIndex, 0, 0, 0, 0, 0);
576 }
577 }
578 }
579 EXPECT_GL_NO_ERROR();
580}
581
582// The test checks that glDrawArraysInstanced can be used to render into two views.
583TEST_P(MultiviewSideBySideRenderTest, DrawArraysInstanced)
584{
585 if (!requestMultiviewExtension())
586 {
587 return;
588 }
589
590 const std::string vsSource =
591 "#version 300 es\n"
592 "#extension GL_OVR_multiview : require\n"
593 "layout(num_views = 2) in;\n"
594 "in vec4 vPosition;\n"
595 "void main()\n"
596 "{\n"
597 " vec4 p = vPosition;\n"
598 " if (gl_InstanceID == 1){\n"
599 " p.y = .5*p.y + .5;\n"
600 " } else {\n"
601 " p.y = p.y*.5;\n"
602 " }\n"
603 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x*0.5 + 0.5 : p.x*0.5);\n"
604 " gl_Position.yzw = p.yzw;\n"
605 "}\n";
606
607 const std::string fsSource =
608 "#version 300 es\n"
609 "#extension GL_OVR_multiview : require\n"
610 "precision mediump float;\n"
611 "out vec4 col;\n"
612 "void main()\n"
613 "{\n"
614 " col = vec4(1,0,0,0);\n"
615 "}\n";
616
617 createFBO(4, 2, 2);
618 ANGLE_GL_PROGRAM(program, vsSource, fsSource);
619 glUseProgram(program);
620
621 drawQuad(program, "vPosition", 0.0f, 1.0f, true, true, 2);
622 ASSERT_GL_NO_ERROR();
623
624 const GLubyte expectedResult[4][8] = {
625 {0, 255, 255, 0}, {0, 255, 255, 0},
626 };
627 for (int row = 0; row < 2; ++row)
628 {
629 for (int col = 0; col < 4; ++col)
630 {
631 EXPECT_PIXEL_EQ(col, row, expectedResult[row][col], 0, 0, 0);
632 }
633 }
634}
635
636ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ES31_OPENGL());
637ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderDualViewTest, ES3_OPENGL());
638ANGLE_INSTANTIATE_TEST(MultiviewSideBySideRenderTest, ES3_OPENGL());