1 //
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 "platform/autogen/FeaturesD3D_autogen.h"
11 #include "test_utils/MultiviewTest.h"
12 #include "test_utils/gl_raii.h"
13
14 using namespace angle;
15
16 namespace
17 {
18
ConvertPixelCoordinatesToClipSpace(const std::vector<Vector2I> & pixels,int width,int height)19 std::vector<Vector2> ConvertPixelCoordinatesToClipSpace(const std::vector<Vector2I> &pixels,
20 int width,
21 int height)
22 {
23 std::vector<Vector2> result(pixels.size());
24 for (size_t i = 0; i < pixels.size(); ++i)
25 {
26 const auto &pixel = pixels[i];
27 float pixelCenterRelativeX = (static_cast<float>(pixel.x()) + .5f) / width;
28 float pixelCenterRelativeY = (static_cast<float>(pixel.y()) + .5f) / height;
29 float xInClipSpace = 2.f * pixelCenterRelativeX - 1.f;
30 float yInClipSpace = 2.f * pixelCenterRelativeY - 1.f;
31 result[i] = Vector2(xInClipSpace, yInClipSpace);
32 }
33 return result;
34 }
35 } // namespace
36
37 struct MultiviewRenderTestParams final : public MultiviewImplementationParams
38 {
MultiviewRenderTestParamsMultiviewRenderTestParams39 MultiviewRenderTestParams(int samples,
40 const MultiviewImplementationParams &implementationParams)
41 : MultiviewImplementationParams(implementationParams), mSamples(samples)
42 {}
43 int mSamples;
44 };
45
operator <<(std::ostream & os,const MultiviewRenderTestParams & params)46 std::ostream &operator<<(std::ostream &os, const MultiviewRenderTestParams ¶ms)
47 {
48 const MultiviewImplementationParams &base =
49 static_cast<const MultiviewImplementationParams &>(params);
50 os << base;
51 os << "_layered";
52
53 if (params.mSamples > 0)
54 {
55 os << "_samples_" << params.mSamples;
56 }
57 return os;
58 }
59
60 class MultiviewFramebufferTestBase : public MultiviewTestBase,
61 public ::testing::TestWithParam<MultiviewRenderTestParams>
62 {
63 protected:
MultiviewFramebufferTestBase(const PlatformParameters & params,int samples)64 MultiviewFramebufferTestBase(const PlatformParameters ¶ms, int samples)
65 : MultiviewTestBase(params),
66 mViewWidth(0),
67 mViewHeight(0),
68 mNumViews(0),
69 mColorTexture(0u),
70 mDepthTexture(0u),
71 mDrawFramebuffer(0u),
72 mSamples(samples),
73 mResolveTexture(0u)
74 {}
75
FramebufferTestSetUp()76 void FramebufferTestSetUp() { MultiviewTestBase::MultiviewTestBaseSetUp(); }
77
FramebufferTestTearDown()78 void FramebufferTestTearDown()
79 {
80 freeFBOs();
81 MultiviewTestBase::MultiviewTestBaseTearDown();
82 }
83
updateFBOs(int viewWidth,int height,int numViews,int numLayers,int baseViewIndex)84 void updateFBOs(int viewWidth, int height, int numViews, int numLayers, int baseViewIndex)
85 {
86 ASSERT_TRUE(numViews + baseViewIndex <= numLayers);
87
88 freeFBOs();
89
90 mViewWidth = viewWidth;
91 mViewHeight = height;
92 mNumViews = numViews;
93
94 glGenTextures(1, &mColorTexture);
95 glGenTextures(1, &mDepthTexture);
96
97 CreateMultiviewBackingTextures(mSamples, viewWidth, height, numLayers, mColorTexture,
98 mDepthTexture, 0u);
99
100 glGenFramebuffers(1, &mDrawFramebuffer);
101
102 // Create draw framebuffer to be used for multiview rendering.
103 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
104 AttachMultiviewTextures(GL_DRAW_FRAMEBUFFER, viewWidth, numViews, baseViewIndex,
105 mColorTexture, mDepthTexture, 0u);
106
107 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
108
109 // Create read framebuffer to be used to retrieve the pixel information for testing
110 // purposes.
111 mReadFramebuffer.resize(numLayers);
112 glGenFramebuffers(static_cast<GLsizei>(mReadFramebuffer.size()), mReadFramebuffer.data());
113 for (int i = 0; i < numLayers; ++i)
114 {
115 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
116 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture, 0,
117 i);
118 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
119 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
120 }
121
122 // Clear the buffers.
123 glViewport(0, 0, viewWidth, height);
124 }
125
updateFBOs(int viewWidth,int height,int numViews)126 void updateFBOs(int viewWidth, int height, int numViews)
127 {
128 updateFBOs(viewWidth, height, numViews, numViews, 0);
129 }
130
bindMemberDrawFramebuffer()131 void bindMemberDrawFramebuffer() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer); }
132
133 // In case we have a multisampled framebuffer, creates and binds a resolve framebuffer as the
134 // draw framebuffer, and resolves the read framebuffer to it.
resolveMultisampledFBO()135 void resolveMultisampledFBO()
136 {
137 if (mSamples == 0)
138 {
139 return;
140 }
141 int numLayers = mReadFramebuffer.size();
142 if (mResolveFramebuffer.empty())
143 {
144 ASSERT_TRUE(mResolveTexture == 0u);
145 glGenTextures(1, &mResolveTexture);
146 CreateMultiviewBackingTextures(0, mViewWidth, mViewHeight, numLayers, mResolveTexture,
147 0u, 0u);
148
149 mResolveFramebuffer.resize(numLayers);
150 glGenFramebuffers(static_cast<GLsizei>(mResolveFramebuffer.size()),
151 mResolveFramebuffer.data());
152 for (int i = 0; i < numLayers; ++i)
153 {
154 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
155 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
156 mResolveTexture, 0, i);
157 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
158 glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
159 }
160 }
161 for (int i = 0; i < numLayers; ++i)
162 {
163 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
164 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
165 glBlitFramebuffer(0, 0, mViewWidth, mViewHeight, 0, 0, mViewWidth, mViewHeight,
166 GL_COLOR_BUFFER_BIT, GL_NEAREST);
167 }
168 }
169
GetViewColor(int x,int y,int view)170 GLColor GetViewColor(int x, int y, int view)
171 {
172 EXPECT_TRUE(static_cast<size_t>(view) < mReadFramebuffer.size());
173 if (mSamples > 0)
174 {
175 EXPECT_TRUE(static_cast<size_t>(view) < mResolveFramebuffer.size());
176 glBindFramebuffer(GL_READ_FRAMEBUFFER, mResolveFramebuffer[view]);
177 }
178 else
179 {
180 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
181 }
182 return ReadColor(x, y);
183 }
184
185 // Requests the OVR_multiview(2) extension and returns true if the operation succeeds.
requestMultiviewExtension(bool requireMultiviewMultisample)186 bool requestMultiviewExtension(bool requireMultiviewMultisample)
187 {
188 if (!EnsureGLExtensionEnabled(extensionName()))
189 {
190 std::cout << "Test skipped due to missing " << extensionName() << "." << std::endl;
191 return false;
192 }
193
194 if (requireMultiviewMultisample)
195 {
196 if (!EnsureGLExtensionEnabled("GL_OES_texture_storage_multisample_2d_array"))
197 {
198 std::cout << "Test skipped due to missing GL_ANGLE_multiview_multisample."
199 << std::endl;
200 return false;
201 }
202
203 if (!EnsureGLExtensionEnabled("GL_ANGLE_multiview_multisample"))
204 {
205 std::cout << "Test skipped due to missing GL_ANGLE_multiview_multisample."
206 << std::endl;
207 return false;
208 }
209 }
210 return true;
211 }
212
requestMultiviewExtension()213 bool requestMultiviewExtension() { return requestMultiviewExtension(false); }
extensionName()214 std::string extensionName()
215 {
216 switch (GetParam().mMultiviewExtension)
217 {
218 case multiview:
219 return "GL_OVR_multiview";
220 case multiview2:
221 return "GL_OVR_multiview2";
222 default:
223 // Ignore unknown.
224 return "";
225 }
226 }
227
isMultisampled()228 bool isMultisampled() { return mSamples > 0; }
229
230 int mViewWidth;
231 int mViewHeight;
232 int mNumViews;
233
234 GLuint mColorTexture;
235 GLuint mDepthTexture;
236
237 private:
238 GLuint mDrawFramebuffer;
239 std::vector<GLuint> mReadFramebuffer;
240 int mSamples;
241
242 // For reading back multisampled framebuffer.
243 std::vector<GLuint> mResolveFramebuffer;
244 GLuint mResolveTexture;
245
freeFBOs()246 void freeFBOs()
247 {
248 if (mDrawFramebuffer)
249 {
250 glDeleteFramebuffers(1, &mDrawFramebuffer);
251 mDrawFramebuffer = 0;
252 }
253 if (!mReadFramebuffer.empty())
254 {
255 GLsizei framebufferCount = static_cast<GLsizei>(mReadFramebuffer.size());
256 glDeleteFramebuffers(framebufferCount, mReadFramebuffer.data());
257 mReadFramebuffer.clear();
258 }
259 if (!mResolveFramebuffer.empty())
260 {
261 GLsizei framebufferCount = static_cast<GLsizei>(mResolveFramebuffer.size());
262 glDeleteFramebuffers(framebufferCount, mResolveFramebuffer.data());
263 mResolveFramebuffer.clear();
264 }
265 if (mDepthTexture)
266 {
267 glDeleteTextures(1, &mDepthTexture);
268 mDepthTexture = 0;
269 }
270 if (mColorTexture)
271 {
272 glDeleteTextures(1, &mColorTexture);
273 mColorTexture = 0;
274 }
275 if (mResolveTexture)
276 {
277 glDeleteTextures(1, &mResolveTexture);
278 mResolveTexture = 0;
279 }
280 }
281 };
282
283 class MultiviewRenderTest : public MultiviewFramebufferTestBase
284 {
285 protected:
MultiviewRenderTest()286 MultiviewRenderTest() : MultiviewFramebufferTestBase(GetParam(), GetParam().mSamples) {}
287
testSetUp()288 virtual void testSetUp() {}
testTearDown()289 virtual void testTearDown() {}
290
291 private:
SetUp()292 void SetUp() override
293 {
294 MultiviewFramebufferTestBase::FramebufferTestSetUp();
295 testSetUp();
296 }
TearDown()297 void TearDown() override
298 {
299 testTearDown();
300 MultiviewFramebufferTestBase::FramebufferTestTearDown();
301 }
302 };
303
DualViewVS(ExtensionName multiviewExtension)304 std::string DualViewVS(ExtensionName multiviewExtension)
305 {
306 std::string ext;
307 switch (multiviewExtension)
308 {
309 case multiview:
310 ext = "GL_OVR_multiview";
311 break;
312 case multiview2:
313 ext = "GL_OVR_multiview2";
314 break;
315 }
316
317 std::string dualViewVSSource =
318 "#version 300 es\n"
319 "#extension " +
320 ext +
321 " : require\n"
322 "layout(num_views = 2) in;\n"
323 "in vec4 vPosition;\n"
324 "void main()\n"
325 "{\n"
326 " gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x * 0.5 + 0.5 : vPosition.x * 0.5 - "
327 "0.5);\n"
328 " gl_Position.yzw = vPosition.yzw;\n"
329 "}\n";
330 return dualViewVSSource;
331 }
332
DualViewFS(ExtensionName multiviewExtension)333 std::string DualViewFS(ExtensionName multiviewExtension)
334 {
335 std::string ext;
336 switch (multiviewExtension)
337 {
338 case multiview:
339 ext = "GL_OVR_multiview";
340 break;
341 case multiview2:
342 ext = "GL_OVR_multiview2";
343 break;
344 }
345
346 std::string dualViewFSSource =
347 "#version 300 es\n"
348 "#extension " +
349 ext +
350 " : require\n"
351 "precision mediump float;\n"
352 "out vec4 col;\n"
353 "void main()\n"
354 "{\n"
355 " col = vec4(0,1,0,1);\n"
356 "}\n";
357 return dualViewFSSource;
358 }
359
360 class MultiviewRenderDualViewTest : public MultiviewRenderTest
361 {
362 protected:
MultiviewRenderDualViewTest()363 MultiviewRenderDualViewTest() : mProgram(0u) {}
364
testSetUp()365 void testSetUp() override
366 {
367 if (!requestMultiviewExtension(isMultisampled()))
368 {
369 return;
370 }
371
372 updateFBOs(2, 1, 2);
373 mProgram = CompileProgram(DualViewVS(GetParam().mMultiviewExtension).c_str(),
374 DualViewFS(GetParam().mMultiviewExtension).c_str());
375 ASSERT_NE(mProgram, 0u);
376 glUseProgram(mProgram);
377 ASSERT_GL_NO_ERROR();
378 }
379
testTearDown()380 void testTearDown() override
381 {
382 if (mProgram != 0u)
383 {
384 glDeleteProgram(mProgram);
385 mProgram = 0u;
386 }
387 }
388
checkOutput()389 void checkOutput()
390 {
391 resolveMultisampledFBO();
392 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
393 EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
394 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
395 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(1, 0, 1));
396 }
397
398 GLuint mProgram;
399 };
400
401 class MultiviewRenderDualViewTestNoWebGL : public MultiviewRenderDualViewTest
402 {
403 protected:
MultiviewRenderDualViewTestNoWebGL()404 MultiviewRenderDualViewTestNoWebGL() { setWebGLCompatibilityEnabled(false); }
405 };
406
407 // Base class for tests that care mostly about draw call validity and not rendering results.
408 class MultiviewDrawValidationTest : public MultiviewTest
409 {
410 protected:
MultiviewDrawValidationTest()411 MultiviewDrawValidationTest() : MultiviewTest() {}
412
initOnePixelColorTexture2DSingleLayered(GLuint texId)413 void initOnePixelColorTexture2DSingleLayered(GLuint texId)
414 {
415 glBindTexture(GL_TEXTURE_2D_ARRAY, texId);
416 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
417 nullptr);
418 }
419
initOnePixelColorTexture2DMultiLayered(GLuint texId)420 void initOnePixelColorTexture2DMultiLayered(GLuint texId)
421 {
422 glBindTexture(GL_TEXTURE_2D_ARRAY, texId);
423 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
424 nullptr);
425 }
426
427 // This initializes a simple VAO with a valid vertex buffer and index buffer with three
428 // vertices.
initVAO(GLuint vao,GLuint vertexBuffer,GLuint indexBuffer)429 void initVAO(GLuint vao, GLuint vertexBuffer, GLuint indexBuffer)
430 {
431 glBindVertexArray(vao);
432
433 const float kVertexData[3] = {0.0f};
434 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
435 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3u, &kVertexData[0], GL_STATIC_DRAW);
436
437 const unsigned int kIndices[3] = {0u, 1u, 2u};
438 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
439 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 3, &kIndices[0],
440 GL_STATIC_DRAW);
441 ASSERT_GL_NO_ERROR();
442 }
443 };
444
445 class MultiviewOcclusionQueryTest : public MultiviewRenderTest
446 {
447 protected:
MultiviewOcclusionQueryTest()448 MultiviewOcclusionQueryTest() {}
449
requestOcclusionQueryExtension()450 bool requestOcclusionQueryExtension()
451 {
452 if (!EnsureGLExtensionEnabled("GL_EXT_occlusion_query_boolean"))
453 {
454 std::cout << "Test skipped due to missing GL_EXT_occlusion_query_boolean." << std::endl;
455 return false;
456 }
457 return true;
458 }
459
drawAndRetrieveOcclusionQueryResult(GLuint program)460 GLuint drawAndRetrieveOcclusionQueryResult(GLuint program)
461 {
462 GLQueryEXT query;
463 glBeginQueryEXT(GL_ANY_SAMPLES_PASSED, query);
464 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
465 glEndQueryEXT(GL_ANY_SAMPLES_PASSED);
466
467 GLuint result = GL_TRUE;
468 glGetQueryObjectuivEXT(query, GL_QUERY_RESULT, &result);
469 return result;
470 }
471 };
472
473 class MultiviewProgramGenerationTest : public MultiviewTest
474 {
475 protected:
MultiviewProgramGenerationTest()476 MultiviewProgramGenerationTest() {}
477 };
478
479 class MultiviewRenderPrimitiveTest : public MultiviewRenderTest
480 {
481 protected:
MultiviewRenderPrimitiveTest()482 MultiviewRenderPrimitiveTest() : mVBO(0u) {}
483
testSetUp()484 void testSetUp() override { glGenBuffers(1, &mVBO); }
485
testTearDown()486 void testTearDown() override
487 {
488 if (mVBO)
489 {
490 glDeleteBuffers(1, &mVBO);
491 mVBO = 0u;
492 }
493 }
494
setupGeometry(const std::vector<Vector2> & vertexData)495 void setupGeometry(const std::vector<Vector2> &vertexData)
496 {
497 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
498 glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(Vector2), vertexData.data(),
499 GL_STATIC_DRAW);
500 glEnableVertexAttribArray(0);
501 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
502 }
503
checkGreenChannel(const GLubyte expectedGreenChannelData[])504 void checkGreenChannel(const GLubyte expectedGreenChannelData[])
505 {
506 for (int view = 0; view < mNumViews; ++view)
507 {
508 for (int w = 0; w < mViewWidth; ++w)
509 {
510 for (int h = 0; h < mViewHeight; ++h)
511 {
512 size_t flatIndex =
513 static_cast<size_t>(view * mViewWidth * mViewHeight + mViewWidth * h + w);
514 EXPECT_EQ(GLColor(0, expectedGreenChannelData[flatIndex], 0,
515 expectedGreenChannelData[flatIndex]),
516 GetViewColor(w, h, view))
517 << "view: " << view << ", w: " << w << ", h: " << h;
518 }
519 }
520 }
521 }
522 GLuint mVBO;
523 };
524
525 class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase
526 {
527 protected:
MultiviewLayeredRenderTest()528 MultiviewLayeredRenderTest() : MultiviewFramebufferTestBase(GetParam(), 0) {}
SetUp()529 void SetUp() final { MultiviewFramebufferTestBase::FramebufferTestSetUp(); }
TearDown()530 void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
531 };
532
533 // The test verifies that glDraw*Indirect works for any number of views.
TEST_P(MultiviewDrawValidationTest,IndirectDraw)534 TEST_P(MultiviewDrawValidationTest, IndirectDraw)
535 {
536 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
537
538 const std::string FS =
539 "#version 300 es\n"
540 "#extension " +
541 extensionName() +
542 ": require\n"
543 "precision mediump float;\n"
544 "out vec4 color;\n"
545 "void main()\n"
546 "{color = vec4(1);}\n";
547
548 GLVertexArray vao;
549 GLBuffer vertexBuffer;
550 GLBuffer indexBuffer;
551 initVAO(vao, vertexBuffer, indexBuffer);
552
553 GLFramebuffer fbo;
554 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
555
556 GLBuffer commandBuffer;
557 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
558 const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
559 glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
560 ASSERT_GL_NO_ERROR();
561
562 // Check that no errors are generated with the framebuffer having 2 views.
563 {
564 const std::string VS =
565 "#version 300 es\n"
566 "#extension " +
567 extensionName() +
568 ": require\n"
569 "layout(num_views = 2) in;\n"
570 "void main()\n"
571 "{}\n";
572 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
573 glUseProgram(program);
574
575 GLTexture tex2DArray;
576 initOnePixelColorTexture2DMultiLayered(tex2DArray);
577
578 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
579
580 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
581 EXPECT_GL_NO_ERROR();
582
583 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
584 EXPECT_GL_NO_ERROR();
585 }
586
587 // Check that no errors are generated if the number of views is 1.
588 {
589 const std::string VS =
590 "#version 300 es\n"
591 "#extension " +
592 extensionName() +
593 ": require\n"
594 "layout(num_views = 1) in;\n"
595 "void main()\n"
596 "{}\n";
597 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
598 glUseProgram(program);
599
600 GLTexture tex2D;
601 initOnePixelColorTexture2DSingleLayered(tex2D);
602
603 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
604
605 glDrawArraysIndirect(GL_TRIANGLES, nullptr);
606 EXPECT_GL_NO_ERROR();
607
608 glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
609 EXPECT_GL_NO_ERROR();
610 }
611 }
612
613 // The test verifies that glDraw*:
614 // 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
615 // program differs.
616 // 2) does not generate any error if the number of views is the same.
TEST_P(MultiviewDrawValidationTest,NumViewsMismatch)617 TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
618 {
619 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
620
621 const std::string VS =
622 "#version 300 es\n"
623 "#extension " +
624 extensionName() +
625 ": require\n"
626 "layout(num_views = 2) in;\n"
627 "void main()\n"
628 "{}\n";
629 const std::string FS =
630 "#version 300 es\n"
631 "#extension " +
632 extensionName() +
633 ": require\n"
634 "precision mediump float;\n"
635 "out vec4 color;\n"
636 "void main()\n"
637 "{color = vec4(1);}\n";
638 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
639 glUseProgram(program);
640
641 GLVertexArray vao;
642 GLBuffer vertexBuffer;
643 GLBuffer indexBuffer;
644 initVAO(vao, vertexBuffer, indexBuffer);
645
646 GLFramebuffer fbo;
647 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
648
649 // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
650 // number of views.
651 {
652 GLTexture tex2D;
653 initOnePixelColorTexture2DSingleLayered(tex2D);
654
655 // The framebuffer has only 1 view.
656 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
657
658 glDrawArrays(GL_TRIANGLES, 0, 3);
659 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
660
661 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
662 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
663 }
664
665 // Check that no errors are generated if the number of views in both program and draw
666 // framebuffer matches.
667 {
668 GLTexture tex2DArray;
669 initOnePixelColorTexture2DMultiLayered(tex2DArray);
670
671 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
672
673 glDrawArrays(GL_TRIANGLES, 0, 3);
674 EXPECT_GL_NO_ERROR();
675
676 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
677 EXPECT_GL_NO_ERROR();
678 }
679 }
680
681 // The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
682 // the multiview extension, but the active draw framebuffer has more than one view.
TEST_P(MultiviewDrawValidationTest,NumViewsMismatchForNonMultiviewProgram)683 TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
684 {
685 if (!requestMultiviewExtension())
686 {
687 return;
688 }
689
690 constexpr char kVS[] =
691 "#version 300 es\n"
692 "void main()\n"
693 "{}\n";
694 constexpr char kFS[] =
695 "#version 300 es\n"
696 "precision mediump float;\n"
697 "void main()\n"
698 "{}\n";
699 ANGLE_GL_PROGRAM(programNoMultiview, kVS, kFS);
700 glUseProgram(programNoMultiview);
701
702 GLVertexArray vao;
703 GLBuffer vertexBuffer;
704 GLBuffer indexBuffer;
705 initVAO(vao, vertexBuffer, indexBuffer);
706
707 GLFramebuffer fbo;
708 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
709
710 GLTexture tex2DArray;
711 initOnePixelColorTexture2DMultiLayered(tex2DArray);
712
713 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
714
715 glDrawArrays(GL_TRIANGLES, 0, 3);
716 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
717
718 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
719 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
720 }
721
722 // The test verifies that glDraw*:
723 // 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
724 // greater than 1 and there is an active not paused transform feedback object.
725 // 2) does not generate any error if the number of views in the draw framebuffer is 1.
TEST_P(MultiviewDrawValidationTest,ActiveTransformFeedback)726 TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
727 {
728 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
729
730 constexpr char kVS[] = R"(#version 300 es
731 out float tfVarying;
732 void main()
733 {
734 tfVarying = 1.0;
735 })";
736
737 constexpr char kFS[] = R"(#version 300 es
738 precision mediump float;
739 void main()
740 {})";
741
742 std::vector<std::string> tfVaryings;
743 tfVaryings.emplace_back("tfVarying");
744 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, kVS, kFS, tfVaryings,
745 GL_SEPARATE_ATTRIBS);
746
747 std::vector<std::string> dualViewTFVaryings;
748 dualViewTFVaryings.emplace_back("gl_Position");
749 ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram,
750 DualViewVS(GetParam().mMultiviewExtension).c_str(),
751 DualViewFS(GetParam().mMultiviewExtension).c_str(),
752 dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
753
754 GLVertexArray vao;
755 GLBuffer vertexBuffer;
756 GLBuffer indexBuffer;
757 initVAO(vao, vertexBuffer, indexBuffer);
758
759 GLBuffer tbo;
760 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
761 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
762
763 GLTransformFeedback transformFeedback;
764 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
765
766 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
767
768 glUseProgram(dualViewProgram);
769 glBeginTransformFeedback(GL_TRIANGLES);
770 ASSERT_GL_NO_ERROR();
771
772 GLFramebuffer fbo;
773 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
774
775 GLTexture tex2DArray;
776 initOnePixelColorTexture2DMultiLayered(tex2DArray);
777
778 GLenum bufs[] = {GL_NONE};
779 glDrawBuffers(1, bufs);
780
781 // Check that drawArrays generates an error when there is an active transform feedback object
782 // and the number of views in the draw framebuffer is greater than 1.
783 {
784 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
785 glDrawArrays(GL_TRIANGLES, 0, 3);
786 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
787 }
788
789 glEndTransformFeedback();
790
791 // Ending transform feedback should allow the draw to succeed.
792 {
793 glDrawArrays(GL_TRIANGLES, 0, 3);
794 EXPECT_GL_NO_ERROR();
795 }
796
797 // A paused transform feedback should not trigger an error.
798 glBeginTransformFeedback(GL_TRIANGLES);
799 glPauseTransformFeedback();
800 ASSERT_GL_NO_ERROR();
801
802 glDrawArrays(GL_TRIANGLES, 0, 3);
803 ASSERT_GL_NO_ERROR();
804
805 // Unbind transform feedback - should succeed.
806 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
807 glDrawArrays(GL_TRIANGLES, 0, 3);
808 ASSERT_GL_NO_ERROR();
809
810 // Rebind paused transform feedback - should succeed.
811 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
812 glDrawArrays(GL_TRIANGLES, 0, 3);
813 ASSERT_GL_NO_ERROR();
814
815 glResumeTransformFeedback();
816 glEndTransformFeedback();
817
818 glUseProgram(singleViewProgram);
819 glBeginTransformFeedback(GL_TRIANGLES);
820 ASSERT_GL_NO_ERROR();
821
822 GLTexture tex2D;
823 initOnePixelColorTexture2DSingleLayered(tex2D);
824
825 // Check that drawArrays does not generate an error when the number of views in the draw
826 // framebuffer is 1.
827 {
828 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
829 glDrawArrays(GL_TRIANGLES, 0, 3);
830 EXPECT_GL_NO_ERROR();
831 }
832
833 glEndTransformFeedback();
834 }
835
836 // The test verifies that glDraw*:
837 // 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
838 // greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
839 // 2) does not generate any error if the number of views in the draw framebuffer is 1.
TEST_P(MultiviewDrawValidationTest,ActiveTimeElapsedQuery)840 TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
841 {
842 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
843 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
844
845 ANGLE_GL_PROGRAM(dualViewProgram, DualViewVS(GetParam().mMultiviewExtension).c_str(),
846 DualViewFS(GetParam().mMultiviewExtension).c_str());
847
848 constexpr char kVS[] =
849 "#version 300 es\n"
850 "void main()\n"
851 "{}\n";
852 constexpr char kFS[] =
853 "#version 300 es\n"
854 "precision mediump float;\n"
855 "void main()\n"
856 "{}\n";
857 ANGLE_GL_PROGRAM(singleViewProgram, kVS, kFS);
858 glUseProgram(singleViewProgram);
859
860 GLVertexArray vao;
861 GLBuffer vertexBuffer;
862 GLBuffer indexBuffer;
863 initVAO(vao, vertexBuffer, indexBuffer);
864
865 GLuint query = 0u;
866 glGenQueriesEXT(1, &query);
867 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
868
869 GLFramebuffer fbo;
870 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
871
872 GLTexture tex2DArr;
873 initOnePixelColorTexture2DMultiLayered(tex2DArr);
874
875 GLenum bufs[] = {GL_NONE};
876 glDrawBuffers(1, bufs);
877
878 // Check first case.
879 {
880 glUseProgram(dualViewProgram);
881 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
882 glClear(GL_COLOR_BUFFER_BIT);
883 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
884 glDrawArrays(GL_TRIANGLES, 0, 3);
885 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
886 }
887
888 GLTexture tex2D;
889 initOnePixelColorTexture2DSingleLayered(tex2D);
890
891 // Check second case.
892 {
893 glUseProgram(singleViewProgram);
894 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
895 glClear(GL_COLOR_BUFFER_BIT);
896 EXPECT_GL_NO_ERROR();
897 glDrawArrays(GL_TRIANGLES, 0, 3);
898 EXPECT_GL_NO_ERROR();
899 }
900
901 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
902 glDeleteQueries(1, &query);
903
904 // Check starting a query after a successful draw.
905 {
906 glUseProgram(dualViewProgram);
907 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
908 glClear(GL_COLOR_BUFFER_BIT);
909 EXPECT_GL_NO_ERROR();
910 glDrawArrays(GL_TRIANGLES, 0, 3);
911 EXPECT_GL_NO_ERROR();
912
913 glGenQueriesEXT(1, &query);
914 glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
915
916 glDrawArrays(GL_TRIANGLES, 0, 3);
917 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
918
919 glEndQueryEXT(GL_TIME_ELAPSED_EXT);
920 glDrawArrays(GL_TRIANGLES, 0, 3);
921 EXPECT_GL_NO_ERROR();
922
923 glDeleteQueries(1, &query);
924 }
925 }
926
927 // The test checks that glDrawArrays can be used to render into two views.
TEST_P(MultiviewRenderDualViewTest,DrawArrays)928 TEST_P(MultiviewRenderDualViewTest, DrawArrays)
929 {
930 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
931 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
932
933 drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
934 ASSERT_GL_NO_ERROR();
935
936 checkOutput();
937 }
938
939 // The test checks that glDrawArrays can be used to render into two views, after the program
940 // executable has been installed and the program relinked (with a failing link, and using a
941 // different number of views).
TEST_P(MultiviewRenderDualViewTestNoWebGL,DrawArraysAfterFailedRelink)942 TEST_P(MultiviewRenderDualViewTestNoWebGL, DrawArraysAfterFailedRelink)
943 {
944 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
945 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D());
946
947 std::string ext =
948 GetParam().mMultiviewExtension == multiview ? "GL_OVR_multiview" : "GL_OVR_multiview2";
949
950 const std::string kVS = R"(#version 300 es
951 #extension )" + ext + R"( : require
952 layout(num_views = 2) in;
953 void main()
954 {
955 vec2 pos = vec2(0.0);
956 switch (gl_VertexID) {
957 case 0: pos = vec2(-1.0, -1.0); break;
958 case 1: pos = vec2(1.0, -1.0); break;
959 case 2: pos = vec2(-1.0, 1.0); break;
960 case 3: pos = vec2(1.0, 1.0); break;
961 };
962 pos.x = gl_ViewID_OVR == 0u ? pos.x * 0.5 + 0.5 : pos.x * 0.5 - 0.5;
963 gl_Position = vec4(pos, 0.0, 1.0);
964 })";
965
966 const std::string kFS = R"(#version 300 es
967 #extension )" + ext + R"( : require
968 precision mediump float;
969 out vec4 col;
970 void main()
971 {
972 col = vec4(0, 1, 0, 1);
973 })";
974
975 const std::string kBadVS = R"(#version 300 es
976 #extension )" + ext + R"( : require
977 layout(num_views = 4) in;
978 out vec4 linkError;
979 void main()
980 {
981 vec2 pos = vec2(0.0);
982 switch (gl_VertexID) {
983 case 0: pos = vec2(-1.0, -1.0); break;
984 case 1: pos = vec2(1.0, -1.0); break;
985 case 2: pos = vec2(-1.0, 1.0); break;
986 case 3: pos = vec2(1.0, 1.0); break;
987 };
988 pos.x = gl_ViewID_OVR == 0u ? pos.x * 0.5 + 0.5 : pos.x * 0.5 - 0.5;
989 gl_Position = vec4(pos, 0.0, 1.0);
990 linkError = vec4(0);
991 })";
992
993 const std::string kBadFS = R"(#version 300 es
994 #extension )" + ext + R"( : require
995 precision mediump float;
996 flat in uvec4 linkError;
997 out vec4 col;
998 void main()
999 {
1000 col = vec4(linkError);
1001 })";
1002
1003 // First, create a good program
1004 GLuint program = glCreateProgram();
1005 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS.c_str());
1006 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS.c_str());
1007
1008 glAttachShader(program, vs);
1009 glAttachShader(program, fs);
1010
1011 glLinkProgram(program);
1012 CheckLinkStatusAndReturnProgram(program, true);
1013
1014 // Detach the shaders for the sake of DrawArraysAfterFailedRelink
1015 glDetachShader(program, vs);
1016 glDetachShader(program, fs);
1017
1018 glDeleteShader(vs);
1019 glDeleteShader(fs);
1020
1021 // Install the executable
1022 glUseProgram(program);
1023
1024 // Relink the program but in an erroneous way
1025 GLuint badVs = CompileShader(GL_VERTEX_SHADER, kBadVS.c_str());
1026 GLuint badFs = CompileShader(GL_FRAGMENT_SHADER, kBadFS.c_str());
1027
1028 glAttachShader(program, badVs);
1029 glAttachShader(program, badFs);
1030
1031 glLinkProgram(program);
1032
1033 glDeleteShader(badVs);
1034 glDeleteShader(badFs);
1035 ASSERT_GL_NO_ERROR();
1036
1037 // Issue a draw and make sure everything works.
1038 glClearColor(0, 0, 0, 0);
1039 glClear(GL_COLOR_BUFFER_BIT);
1040 // drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
1041 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1042 ASSERT_GL_NO_ERROR();
1043
1044 checkOutput();
1045
1046 glDeleteProgram(program);
1047 }
1048
1049 // The test checks that glDrawElements can be used to render into two views.
TEST_P(MultiviewRenderDualViewTest,DrawElements)1050 TEST_P(MultiviewRenderDualViewTest, DrawElements)
1051 {
1052 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
1053 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1054
1055 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
1056 ASSERT_GL_NO_ERROR();
1057
1058 checkOutput();
1059 }
1060
1061 // The test checks that glDrawRangeElements can be used to render into two views.
TEST_P(MultiviewRenderDualViewTest,DrawRangeElements)1062 TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
1063 {
1064 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
1065 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1066
1067 drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
1068 ASSERT_GL_NO_ERROR();
1069
1070 checkOutput();
1071 }
1072
1073 // The test checks that glDrawArrays can be used to render into four views.
TEST_P(MultiviewRenderTest,DrawArraysFourViews)1074 TEST_P(MultiviewRenderTest, DrawArraysFourViews)
1075 {
1076 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
1077 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1078
1079 const std::string VS =
1080 "#version 300 es\n"
1081 "#extension " +
1082 extensionName() +
1083 " : require\n"
1084 "layout(num_views = 4) in;\n"
1085 "in vec4 vPosition;\n"
1086 "void main()\n"
1087 "{\n"
1088 " if (gl_ViewID_OVR == 0u) {\n"
1089 " gl_Position.x = vPosition.x*0.25 - 0.75;\n"
1090 " } else if (gl_ViewID_OVR == 1u) {\n"
1091 " gl_Position.x = vPosition.x*0.25 - 0.25;\n"
1092 " } else if (gl_ViewID_OVR == 2u) {\n"
1093 " gl_Position.x = vPosition.x*0.25 + 0.25;\n"
1094 " } else {\n"
1095 " gl_Position.x = vPosition.x*0.25 + 0.75;\n"
1096 " }"
1097 " gl_Position.yzw = vPosition.yzw;\n"
1098 "}\n";
1099
1100 const std::string FS =
1101 "#version 300 es\n"
1102 "#extension " +
1103 extensionName() +
1104 " : require\n"
1105 "precision mediump float;\n"
1106 "out vec4 col;\n"
1107 "void main()\n"
1108 "{\n"
1109 " col = vec4(0,1,0,1);\n"
1110 "}\n";
1111
1112 updateFBOs(4, 1, 4);
1113 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1114
1115 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1116 ASSERT_GL_NO_ERROR();
1117
1118 resolveMultisampledFBO();
1119 for (int i = 0; i < 4; ++i)
1120 {
1121 for (int j = 0; j < 4; ++j)
1122 {
1123 if (i == j)
1124 {
1125 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
1126 }
1127 else
1128 {
1129 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, i));
1130 }
1131 }
1132 }
1133 EXPECT_GL_NO_ERROR();
1134 }
1135
1136 // The test checks that glDrawArraysInstanced can be used to render into two views.
TEST_P(MultiviewRenderTest,DrawArraysInstanced)1137 TEST_P(MultiviewRenderTest, DrawArraysInstanced)
1138 {
1139 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
1140 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1141
1142 const std::string VS =
1143 "#version 300 es\n"
1144 "#extension " +
1145 extensionName() +
1146 ": require\n"
1147 "layout(num_views = 2) in;\n"
1148 "in vec4 vPosition;\n"
1149 "void main()\n"
1150 "{\n"
1151 " vec4 p = vPosition;\n"
1152 " if (gl_InstanceID == 1){\n"
1153 " p.y = p.y * 0.5 + 0.5;\n"
1154 " } else {\n"
1155 " p.y = p.y * 0.5 - 0.5;\n"
1156 " }\n"
1157 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x * 0.5 + 0.5 : p.x * 0.5 - 0.5);\n"
1158 " gl_Position.yzw = p.yzw;\n"
1159 "}\n";
1160
1161 const std::string FS =
1162 "#version 300 es\n"
1163 "#extension " +
1164 extensionName() +
1165 ": require\n"
1166 "precision mediump float;\n"
1167 "out vec4 col;\n"
1168 "void main()\n"
1169 "{\n"
1170 " col = vec4(0,1,0,1);\n"
1171 "}\n";
1172
1173 const int kViewWidth = 2;
1174 const int kViewHeight = 2;
1175 const int kNumViews = 2;
1176 updateFBOs(kViewWidth, kViewHeight, kNumViews);
1177 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1178
1179 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
1180 ASSERT_GL_NO_ERROR();
1181
1182 resolveMultisampledFBO();
1183
1184 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
1185 {{255, 0}, {255, 0}}};
1186
1187 for (int view = 0; view < 2; ++view)
1188 {
1189 for (int y = 0; y < 2; ++y)
1190 {
1191 for (int x = 0; x < 2; ++x)
1192 {
1193 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0,
1194 expectedGreenChannel[view][y][x]),
1195 GetViewColor(x, y, view));
1196 }
1197 }
1198 }
1199 }
1200
1201 // The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
1202 // program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
1203 // offset of each quad are passed as separate attributes which are indexed based on the
1204 // corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
1205 // drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
1206 // quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
1207 // not by 3.
TEST_P(MultiviewRenderTest,AttribDivisor)1208 TEST_P(MultiviewRenderTest, AttribDivisor)
1209 {
1210 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
1211 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1212
1213 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
1214 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/42261480
1215 if (IsWindows() && IsD3D11())
1216 {
1217 ignoreD3D11SDKLayersWarnings();
1218 }
1219
1220 const std::string VS =
1221 "#version 300 es\n"
1222 "#extension " +
1223 extensionName() +
1224 " : require\n"
1225 "layout(num_views = 2) in;\n"
1226 "in vec3 vPosition;\n"
1227 "in float offsetX;\n"
1228 "in float offsetY;\n"
1229 "void main()\n"
1230 "{\n"
1231 " vec4 p = vec4(vPosition, 1.);\n"
1232 " p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
1233 " gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1234 " gl_Position.yzw = p.yzw;\n"
1235 "}\n";
1236
1237 const std::string FS =
1238 "#version 300 es\n"
1239 "#extension " +
1240 extensionName() +
1241 ": require\n"
1242 "precision mediump float;\n"
1243 "out vec4 col;\n"
1244 "void main()\n"
1245 "{\n"
1246 " col = vec4(0,1,0,1);\n"
1247 "}\n";
1248
1249 const int kViewWidth = 4;
1250 const int kViewHeight = 4;
1251 const int kNumViews = 2;
1252 updateFBOs(kViewWidth, kViewHeight, kNumViews);
1253 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1254
1255 GLBuffer xOffsetVBO;
1256 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1257 const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1258 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1259 GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1260 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1261 glVertexAttribDivisor(xOffsetLoc, 3);
1262 glEnableVertexAttribArray(xOffsetLoc);
1263
1264 GLBuffer yOffsetVBO;
1265 glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1266 const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1267 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1268 GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1269 glVertexAttribDivisor(yOffsetLoc, 1);
1270 glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1271 glEnableVertexAttribArray(yOffsetLoc);
1272
1273 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
1274 ASSERT_GL_NO_ERROR();
1275
1276 resolveMultisampledFBO();
1277
1278 const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
1279 {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1280 {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1281 for (int view = 0; view < 2; ++view)
1282 {
1283 for (int row = 0; row < 4; ++row)
1284 {
1285 for (int col = 0; col < 4; ++col)
1286 {
1287 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0,
1288 expectedGreenChannel[view][row][col]),
1289 GetViewColor(col, row, view));
1290 }
1291 }
1292 }
1293 }
1294
1295 // Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1296 // multi-view context propagate the correct divisor to the driver.
TEST_P(MultiviewRenderTest,DivisorOrderOfOperation)1297 TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
1298 {
1299 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
1300 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1301
1302 updateFBOs(1, 1, 2);
1303
1304 // Create multiview program.
1305 const std::string VS =
1306 "#version 300 es\n"
1307 "#extension " +
1308 extensionName() +
1309 ": require\n"
1310 "layout(num_views = 2) in;\n"
1311 "layout(location = 0) in vec2 vPosition;\n"
1312 "layout(location = 1) in float offsetX;\n"
1313 "void main()\n"
1314 "{\n"
1315 " vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1316 " p.x += offsetX;\n"
1317 " gl_Position = p;\n"
1318 "}\n";
1319
1320 const std::string FS =
1321 "#version 300 es\n"
1322 "#extension " +
1323 extensionName() +
1324 " : require\n"
1325 "precision mediump float;\n"
1326 "out vec4 col;\n"
1327 "void main()\n"
1328 "{\n"
1329 " col = vec4(0,1,0,1);\n"
1330 "}\n";
1331
1332 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1333
1334 constexpr char kStubVS[] =
1335 "#version 300 es\n"
1336 "layout(location = 0) in vec2 vPosition;\n"
1337 "layout(location = 1) in float offsetX;\n"
1338 "void main()\n"
1339 "{\n"
1340 " gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1341 "}\n";
1342
1343 constexpr char kStubFS[] =
1344 "#version 300 es\n"
1345 "precision mediump float;\n"
1346 "out vec4 col;\n"
1347 "void main()\n"
1348 "{\n"
1349 " col = vec4(0,0,0,1);\n"
1350 "}\n";
1351
1352 ANGLE_GL_PROGRAM(stubProgram, kStubVS, kStubFS);
1353
1354 GLBuffer xOffsetVBO;
1355 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1356 const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1357 4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1358 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1359
1360 GLBuffer vertexVBO;
1361 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1362 Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1363 Vector2(-1.f, -1.f), Vector2(1.f, 1.f), Vector2(-1.f, 1.f)};
1364 glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1365
1366 GLVertexArray vao[2];
1367 for (size_t i = 0u; i < 2u; ++i)
1368 {
1369 glBindVertexArray(vao[i]);
1370
1371 glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1372 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1373 glEnableVertexAttribArray(0);
1374
1375 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1376 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1377 glEnableVertexAttribArray(1);
1378 }
1379 ASSERT_GL_NO_ERROR();
1380
1381 glViewport(0, 0, 1, 1);
1382 glScissor(0, 0, 1, 1);
1383 glEnable(GL_SCISSOR_TEST);
1384 glClearColor(0, 0, 0, 1);
1385
1386 // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1387 // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1388 // bits are cleared.
1389 glUseProgram(stubProgram);
1390 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1391 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1392 glBindVertexArray(vao[0]);
1393 glVertexAttribDivisor(1, 0);
1394 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1395 glUseProgram(0);
1396 ASSERT_GL_NO_ERROR();
1397
1398 // Check that vertexAttribDivisor uses the number of views to update the divisor.
1399 bindMemberDrawFramebuffer();
1400 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1401 glUseProgram(program);
1402 glVertexAttribDivisor(1, 1);
1403 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1404
1405 resolveMultisampledFBO();
1406 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1407 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1408
1409 // Clear the buffers and propagate divisor to the driver.
1410 // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1411 // dirty bits when useProgram is called.
1412 glUseProgram(stubProgram);
1413 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1414 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1415 glVertexAttribDivisor(1, 1);
1416 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1417 glUseProgram(0);
1418 ASSERT_GL_NO_ERROR();
1419
1420 // Check that useProgram uses the number of views to update the divisor.
1421 bindMemberDrawFramebuffer();
1422 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1423 glUseProgram(program);
1424 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1425
1426 resolveMultisampledFBO();
1427 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1428 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1429
1430 // We go through similar steps as before.
1431 glUseProgram(stubProgram);
1432 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1433 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1434 glVertexAttribDivisor(1, 1);
1435 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1436 glUseProgram(0);
1437 ASSERT_GL_NO_ERROR();
1438
1439 // Check that bindVertexArray uses the number of views to update the divisor.
1440 {
1441 // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1442 // divisor for vao[1] only.
1443 bindMemberDrawFramebuffer();
1444 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1445 glBindVertexArray(vao[1]);
1446 glUseProgram(program);
1447 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1448 glBindVertexArray(0);
1449 ASSERT_GL_NO_ERROR();
1450 }
1451 // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1452 // adjusts the divisor.
1453 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1454 glBindVertexArray(vao[0]);
1455 glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1456
1457 resolveMultisampledFBO();
1458 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1459 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1460 }
1461
1462 // Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1463 // transforms geometry to be outside of the clip region.
TEST_P(MultiviewOcclusionQueryTest,OcclusionQueryNothingVisible)1464 TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
1465 {
1466 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1467 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
1468 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1469
1470 const std::string VS =
1471 "#version 300 es\n"
1472 "#extension " +
1473 extensionName() +
1474 ": require\n"
1475 "layout(num_views = 2) in;\n"
1476 "in vec3 vPosition;\n"
1477 "void main()\n"
1478 "{\n"
1479 " gl_Position.x = 2.0;\n"
1480 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1481 "}\n";
1482
1483 const std::string FS =
1484 "#version 300 es\n"
1485 "#extension " +
1486 extensionName() +
1487 " : require\n"
1488 "precision mediump float;\n"
1489 "out vec4 col;\n"
1490 "void main()\n"
1491 "{\n"
1492 " col = vec4(1,0,0,0);\n"
1493 "}\n";
1494 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1495 updateFBOs(1, 1, 2);
1496
1497 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1498 ASSERT_GL_NO_ERROR();
1499 EXPECT_GL_FALSE(result);
1500 }
1501
1502 // Test that there are fragments passing the occlusion query if only view 0 can produce
1503 // output.
TEST_P(MultiviewOcclusionQueryTest,OcclusionQueryOnlyLeftVisible)1504 TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
1505 {
1506 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1507 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
1508
1509 const std::string VS =
1510 "#version 300 es\n"
1511 "#extension " +
1512 extensionName() +
1513 ": require\n"
1514 "layout(num_views = 2) in;\n"
1515 "in vec3 vPosition;\n"
1516 "void main()\n"
1517 "{\n"
1518 " gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1519 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1520 "}\n";
1521
1522 const std::string FS =
1523 "#version 300 es\n"
1524 "#extension " +
1525 extensionName() +
1526 ": require\n"
1527 "precision mediump float;\n"
1528 "out vec4 col;\n"
1529 "void main()\n"
1530 "{\n"
1531 " col = vec4(1,0,0,0);\n"
1532 "}\n";
1533 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1534 updateFBOs(1, 1, 2);
1535
1536 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1537 ASSERT_GL_NO_ERROR();
1538 EXPECT_GL_TRUE(result);
1539 }
1540
1541 // Test that there are fragments passing the occlusion query if only view 1 can produce
1542 // output.
TEST_P(MultiviewOcclusionQueryTest,OcclusionQueryOnlyRightVisible)1543 TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
1544 {
1545 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1546 ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
1547
1548 const std::string VS =
1549 "#version 300 es\n"
1550 "#extension " +
1551 extensionName() +
1552 ": require\n"
1553 "layout(num_views = 2) in;\n"
1554 "in vec3 vPosition;\n"
1555 "void main()\n"
1556 "{\n"
1557 " gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1558 " gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1559 "}\n";
1560
1561 const std::string FS =
1562 "#version 300 es\n"
1563 "#extension " +
1564 extensionName() +
1565 ": require\n"
1566 "precision mediump float;\n"
1567 "out vec4 col;\n"
1568 "void main()\n"
1569 "{\n"
1570 " col = vec4(1,0,0,0);\n"
1571 "}\n";
1572 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1573 updateFBOs(1, 1, 2);
1574
1575 GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1576 ASSERT_GL_NO_ERROR();
1577 EXPECT_GL_TRUE(result);
1578 }
1579
1580 // Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1581 // compiles and links without an error.
TEST_P(MultiviewProgramGenerationTest,SimpleProgram)1582 TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1583 {
1584 if (!requestMultiviewExtension())
1585 {
1586 return;
1587 }
1588
1589 const std::string VS =
1590 "#version 300 es\n"
1591 "#extension " +
1592 extensionName() +
1593 ": require\n"
1594 "layout(num_views = 2) in;\n"
1595 "void main()\n"
1596 "{\n"
1597 "}\n";
1598
1599 const std::string FS =
1600 "#version 300 es\n"
1601 "#extension " +
1602 extensionName() +
1603 ": require\n"
1604 "precision mediump float;\n"
1605 "void main()\n"
1606 "{\n"
1607 "}\n";
1608
1609 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1610 glUseProgram(program);
1611
1612 EXPECT_GL_NO_ERROR();
1613 }
1614
1615 // Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1616 // without an error.
TEST_P(MultiviewProgramGenerationTest,UseViewIDInVertexShader)1617 TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1618 {
1619 if (!requestMultiviewExtension())
1620 {
1621 return;
1622 }
1623
1624 const std::string VS =
1625 "#version 300 es\n"
1626 "#extension " +
1627 extensionName() +
1628 ": require\n"
1629 "layout(num_views = 2) in;\n"
1630 "void main()\n"
1631 "{\n"
1632 " if (gl_ViewID_OVR == 0u) {\n"
1633 " gl_Position = vec4(1,0,0,1);\n"
1634 " } else {\n"
1635 " gl_Position = vec4(-1,0,0,1);\n"
1636 " }\n"
1637 "}\n";
1638
1639 const std::string FS =
1640 "#version 300 es\n"
1641 "#extension " +
1642 extensionName() +
1643 ": require\n"
1644 "precision mediump float;\n"
1645 "void main()\n"
1646 "{\n"
1647 "}\n";
1648
1649 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1650 glUseProgram(program);
1651
1652 EXPECT_GL_NO_ERROR();
1653 }
1654
1655 // Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1656 // without an error.
TEST_P(MultiviewProgramGenerationTest,UseViewIDInFragmentShader)1657 TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1658 {
1659 if (!requestMultiviewExtension())
1660 {
1661 return;
1662 }
1663
1664 const std::string VS =
1665 "#version 300 es\n"
1666 "#extension " +
1667 extensionName() +
1668 ": require\n"
1669 "layout(num_views = 2) in;\n"
1670 "void main()\n"
1671 "{\n"
1672 "}\n";
1673
1674 const std::string FS =
1675 "#version 300 es\n"
1676 "#extension " +
1677 extensionName() +
1678 ": require\n"
1679 "precision mediump float;\n"
1680 "out vec4 col;\n"
1681 "void main()\n"
1682 "{\n"
1683 " if (gl_ViewID_OVR == 0u) {\n"
1684 " col = vec4(1,0,0,1);\n"
1685 " } else {\n"
1686 " col = vec4(-1,0,0,1);\n"
1687 " }\n"
1688 "}\n";
1689
1690 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1691 glUseProgram(program);
1692
1693 EXPECT_GL_NO_ERROR();
1694 }
1695
1696 // The test checks that GL_POINTS is correctly rendered.
TEST_P(MultiviewRenderPrimitiveTest,Points)1697 TEST_P(MultiviewRenderPrimitiveTest, Points)
1698 {
1699 if (!requestMultiviewExtension())
1700 {
1701 return;
1702 }
1703
1704 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1705
1706 const std::string VS =
1707 "#version 300 es\n"
1708 "#extension " +
1709 extensionName() +
1710 ": require\n"
1711 "layout(num_views = 2) in;\n"
1712 "layout(location=0) in vec2 vPosition;\n"
1713 "void main()\n"
1714 "{\n"
1715 " gl_PointSize = 1.0;\n"
1716 " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1717 "}\n";
1718
1719 const std::string FS =
1720 "#version 300 es\n"
1721 "#extension " +
1722 extensionName() +
1723 ": require\n"
1724 "precision mediump float;\n"
1725 "out vec4 col;\n"
1726 "void main()\n"
1727 "{\n"
1728 " col = vec4(0,1,0,1);\n"
1729 "}\n";
1730 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1731 glUseProgram(program);
1732
1733 const int kViewWidth = 4;
1734 const int kViewHeight = 2;
1735 const int kNumViews = 2;
1736 updateFBOs(kViewWidth, kViewHeight, kNumViews);
1737
1738 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1739 std::vector<Vector2> vertexDataInClipSpace =
1740 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1741 setupGeometry(vertexDataInClipSpace);
1742
1743 glDrawArrays(GL_POINTS, 0, 2);
1744
1745 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1746 {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
1747 checkGreenChannel(expectedGreenChannelData[0][0]);
1748 }
1749
1750 // The test checks that GL_LINES is correctly rendered.
1751 // The behavior of this test is not guaranteed by the spec:
1752 // OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1753 // "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1754 // either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1755 // rule."
TEST_P(MultiviewRenderPrimitiveTest,Lines)1756 TEST_P(MultiviewRenderPrimitiveTest, Lines)
1757 {
1758 if (!requestMultiviewExtension())
1759 {
1760 return;
1761 }
1762 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1763
1764 GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
1765 ASSERT_NE(program, 0u);
1766 glUseProgram(program);
1767 ASSERT_GL_NO_ERROR();
1768
1769 const int kViewWidth = 4;
1770 const int kViewHeight = 2;
1771 const int kNumViews = 2;
1772 updateFBOs(kViewWidth, kViewHeight, kNumViews);
1773
1774 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1775 std::vector<Vector2> vertexDataInClipSpace =
1776 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1777 setupGeometry(vertexDataInClipSpace);
1778
1779 glDrawArrays(GL_LINES, 0, 2);
1780
1781 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1782 {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
1783 checkGreenChannel(expectedGreenChannelData[0][0]);
1784
1785 glDeleteProgram(program);
1786 }
1787
1788 // The test checks that GL_LINE_STRIP is correctly rendered.
1789 // The behavior of this test is not guaranteed by the spec:
1790 // OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1791 // "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1792 // either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1793 // rule."
TEST_P(MultiviewRenderPrimitiveTest,LineStrip)1794 TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
1795 {
1796 if (!requestMultiviewExtension())
1797 {
1798 return;
1799 }
1800 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1801
1802 GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
1803 ASSERT_NE(program, 0u);
1804 glUseProgram(program);
1805 ASSERT_GL_NO_ERROR();
1806
1807 const int kViewWidth = 4;
1808 const int kViewHeight = 2;
1809 const int kNumViews = 2;
1810 updateFBOs(kViewWidth, kViewHeight, kNumViews);
1811
1812 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1813 std::vector<Vector2> vertexDataInClipSpace =
1814 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1815 setupGeometry(vertexDataInClipSpace);
1816
1817 glDrawArrays(GL_LINE_STRIP, 0, 3);
1818
1819 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1820 {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
1821 checkGreenChannel(expectedGreenChannelData[0][0]);
1822
1823 glDeleteProgram(program);
1824 }
1825
1826 // The test checks that GL_LINE_LOOP is correctly rendered.
1827 // The behavior of this test is not guaranteed by the spec:
1828 // OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1829 // "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1830 // either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1831 // rule."
TEST_P(MultiviewRenderPrimitiveTest,LineLoop)1832 TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
1833 {
1834 if (!requestMultiviewExtension())
1835 {
1836 return;
1837 }
1838 // Only this subtest fails on intel-hd-630-ubuntu-stable. Driver bug?
1839 // https://anglebug.com/42262137
1840 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
1841 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1842
1843 GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
1844 ASSERT_NE(program, 0u);
1845 glUseProgram(program);
1846 ASSERT_GL_NO_ERROR();
1847
1848 const int kViewWidth = 4;
1849 const int kViewHeight = 4;
1850 const int kNumViews = 2;
1851 updateFBOs(kViewWidth, kViewHeight, kNumViews);
1852
1853 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1854 Vector2I(0, 3)};
1855 std::vector<Vector2> vertexDataInClipSpace =
1856 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1857 setupGeometry(vertexDataInClipSpace);
1858
1859 glDrawArrays(GL_LINE_LOOP, 0, 4);
1860 EXPECT_GL_NO_ERROR();
1861
1862 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1863 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1864 {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
1865 checkGreenChannel(expectedGreenChannelData[0][0]);
1866
1867 glDeleteProgram(program);
1868 }
1869
1870 // The test checks that GL_TRIANGLE_STRIP is correctly rendered.
TEST_P(MultiviewRenderPrimitiveTest,TriangleStrip)1871 TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
1872 {
1873 if (!requestMultiviewExtension())
1874 {
1875 return;
1876 }
1877 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1878
1879 GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
1880 ASSERT_NE(program, 0u);
1881 glUseProgram(program);
1882 ASSERT_GL_NO_ERROR();
1883
1884 std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1885 Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1886 setupGeometry(vertexDataInClipSpace);
1887
1888 const int kViewWidth = 2;
1889 const int kViewHeight = 2;
1890 const int kNumViews = 2;
1891 updateFBOs(kViewWidth, kViewHeight, kNumViews);
1892
1893 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1894
1895 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1896 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1897 checkGreenChannel(expectedGreenChannelData[0][0]);
1898
1899 glDeleteProgram(program);
1900 }
1901
1902 // The test checks that GL_TRIANGLE_FAN is correctly rendered.
TEST_P(MultiviewRenderPrimitiveTest,TriangleFan)1903 TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
1904 {
1905 if (!requestMultiviewExtension())
1906 {
1907 return;
1908 }
1909 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1910
1911 GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
1912 ASSERT_NE(program, 0u);
1913 glUseProgram(program);
1914 ASSERT_GL_NO_ERROR();
1915
1916 std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1917 Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1918 setupGeometry(vertexDataInClipSpace);
1919
1920 const int kViewWidth = 2;
1921 const int kViewHeight = 2;
1922 const int kNumViews = 2;
1923 updateFBOs(kViewWidth, kViewHeight, kNumViews);
1924
1925 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1926
1927 const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1928 {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1929 checkGreenChannel(expectedGreenChannelData[0][0]);
1930
1931 glDeleteProgram(program);
1932 }
1933
1934 // Verify that re-linking a program adjusts the attribute divisor.
1935 // The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1936 // to each other. The quads' position and color depend on the corresponding attribute divisors.
TEST_P(MultiviewRenderTest,ProgramRelinkUpdatesAttribDivisor)1937 TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1938 {
1939 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1940 if (!requestMultiviewExtension(isMultisampled()))
1941 {
1942 return;
1943 }
1944
1945 // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
1946 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/42261480
1947 if (IsWindows() && IsD3D11())
1948 {
1949 ignoreD3D11SDKLayersWarnings();
1950 }
1951
1952 const int kViewWidth = 4;
1953 const int kViewHeight = 1;
1954 const int kNumViews = 2;
1955
1956 const std::string FS =
1957 "#version 300 es\n"
1958 "#extension " +
1959 extensionName() +
1960 ": require\n"
1961 "precision mediump float;\n"
1962 "in vec4 oColor;\n"
1963 "out vec4 col;\n"
1964 "void main()\n"
1965 "{\n"
1966 " col = oColor;\n"
1967 "}\n";
1968
1969 auto generateVertexShaderSource = [](int numViews, std::string extensionName) -> std::string {
1970 std::string source =
1971 "#version 300 es\n"
1972 "#extension " +
1973 extensionName +
1974 ": require\n"
1975 "layout(num_views = " +
1976 ToString(numViews) +
1977 ") in;\n"
1978 "in vec3 vPosition;\n"
1979 "in float vOffsetX;\n"
1980 "in vec4 vColor;\n"
1981 "out vec4 oColor;\n"
1982 "void main()\n"
1983 "{\n"
1984 " vec4 p = vec4(vPosition, 1.);\n"
1985 " p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1986 " oColor = vColor;\n"
1987 " gl_Position = p;\n"
1988 "}\n";
1989 return source;
1990 };
1991
1992 std::string vsSource = generateVertexShaderSource(kNumViews, extensionName());
1993 ANGLE_GL_PROGRAM(program, vsSource.c_str(), FS.c_str());
1994 glUseProgram(program);
1995
1996 GLint positionLoc;
1997 GLBuffer xOffsetVBO;
1998 GLint xOffsetLoc;
1999 GLBuffer colorVBO;
2000 GLint colorLoc;
2001
2002 {
2003 // Initialize buffers and setup attributes.
2004 glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
2005 const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
2006 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
2007 xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
2008 glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
2009 glVertexAttribDivisor(xOffsetLoc, 1);
2010 glEnableVertexAttribArray(xOffsetLoc);
2011
2012 glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
2013 const GLColor kColors[2] = {GLColor::red, GLColor::blue};
2014 glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
2015 colorLoc = glGetAttribLocation(program, "vColor");
2016 glVertexAttribDivisor(colorLoc, 2);
2017 glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
2018 glEnableVertexAttribArray(colorLoc);
2019
2020 positionLoc = glGetAttribLocation(program, "vPosition");
2021 }
2022
2023 {
2024 updateFBOs(kViewWidth, kViewHeight, kNumViews);
2025
2026 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
2027 ASSERT_GL_NO_ERROR();
2028
2029 resolveMultisampledFBO();
2030 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2031 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
2032 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
2033 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
2034 }
2035
2036 {
2037 const int kNewNumViews = 3;
2038 vsSource = generateVertexShaderSource(kNewNumViews, extensionName());
2039 updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
2040
2041 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource.c_str());
2042 ASSERT_NE(0u, vs);
2043 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, FS.c_str());
2044 ASSERT_NE(0u, fs);
2045
2046 GLint numAttachedShaders = 0;
2047 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
2048
2049 GLuint attachedShaders[2] = {0u};
2050 glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
2051 for (int i = 0; i < 2; ++i)
2052 {
2053 glDetachShader(program, attachedShaders[i]);
2054 }
2055
2056 glAttachShader(program, vs);
2057 glDeleteShader(vs);
2058
2059 glAttachShader(program, fs);
2060 glDeleteShader(fs);
2061
2062 glBindAttribLocation(program, positionLoc, "vPosition");
2063 glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
2064 glBindAttribLocation(program, colorLoc, "vColor");
2065
2066 glLinkProgram(program);
2067
2068 drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
2069 ASSERT_GL_NO_ERROR();
2070
2071 resolveMultisampledFBO();
2072 for (int i = 0; i < kNewNumViews; ++i)
2073 {
2074 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
2075 EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
2076 EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
2077 EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
2078 }
2079 }
2080 }
2081
2082 // Test that useProgram applies the number of views in computing the final value of the attribute
2083 // divisor.
TEST_P(MultiviewRenderTest,DivisorUpdatedOnProgramChange)2084 TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
2085 {
2086 if (!requestMultiviewExtension(isMultisampled()))
2087 {
2088 return;
2089 }
2090
2091 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
2092
2093 // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
2094 // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/42261480
2095 if (IsWindows() && IsD3D11())
2096 {
2097 ignoreD3D11SDKLayersWarnings();
2098 }
2099
2100 GLVertexArray vao;
2101 glBindVertexArray(vao);
2102 GLBuffer vbo;
2103 glBindBuffer(GL_ARRAY_BUFFER, vbo);
2104 std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
2105 Vector2I(3, 0)};
2106 std::vector<Vector2> vertexDataInClipSpace =
2107 ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
2108 // Fill with x positions so that the resulting clip space coordinate fails the clip test.
2109 glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
2110 vertexDataInClipSpace.data(), GL_STATIC_DRAW);
2111 glEnableVertexAttribArray(0);
2112 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
2113 glVertexAttribDivisor(0, 1);
2114 ASSERT_GL_NO_ERROR();
2115
2116 // Create a program and fbo with N views and draw N instances of a point horizontally.
2117 for (int numViews = 2; numViews <= 4; ++numViews)
2118 {
2119 updateFBOs(4, 1, numViews);
2120 ASSERT_GL_NO_ERROR();
2121
2122 GLuint program = CreateSimplePassthroughProgram(numViews, GetParam().mMultiviewExtension);
2123 ASSERT_NE(program, 0u);
2124 glUseProgram(program);
2125 ASSERT_GL_NO_ERROR();
2126
2127 glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
2128
2129 resolveMultisampledFBO();
2130 for (int view = 0; view < numViews; ++view)
2131 {
2132 for (int j = 0; j < numViews; ++j)
2133 {
2134 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
2135 }
2136 for (int j = numViews; j < 4; ++j)
2137 {
2138 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, view));
2139 }
2140 }
2141
2142 glDeleteProgram(program);
2143 }
2144 }
2145
2146 // The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
TEST_P(MultiviewRenderTest,SelectColorBasedOnViewIDOVR)2147 TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
2148 {
2149 if (!requestMultiviewExtension(isMultisampled()))
2150 {
2151 return;
2152 }
2153
2154 const std::string VS =
2155 "#version 300 es\n"
2156 "#extension " +
2157 extensionName() +
2158 ": require\n"
2159 "layout(num_views = 3) in;\n"
2160 "in vec3 vPosition;\n"
2161 "void main()\n"
2162 "{\n"
2163 " gl_Position = vec4(vPosition, 1.);\n"
2164 "}\n";
2165
2166 const std::string FS =
2167 "#version 300 es\n"
2168 "#extension " +
2169 extensionName() +
2170 ": require\n"
2171 "precision mediump float;\n"
2172 "out vec4 col;\n"
2173 "void main()\n"
2174 "{\n"
2175 " if (gl_ViewID_OVR == 0u) {\n"
2176 " col = vec4(1,0,0,1);\n"
2177 " } else if (gl_ViewID_OVR == 1u) {\n"
2178 " col = vec4(0,1,0,1);\n"
2179 " } else if (gl_ViewID_OVR == 2u) {\n"
2180 " col = vec4(0,0,1,1);\n"
2181 " } else {\n"
2182 " col = vec4(0,0,0,0);\n"
2183 " }\n"
2184 "}\n";
2185
2186 updateFBOs(1, 1, 3);
2187 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
2188
2189 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2190 ASSERT_GL_NO_ERROR();
2191
2192 resolveMultisampledFBO();
2193 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2194 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2195 EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
2196 }
2197
2198 // The test checks that the inactive layers of a 2D texture array are not written to by a
2199 // multi-view program.
TEST_P(MultiviewLayeredRenderTest,RenderToSubrangeOfLayers)2200 TEST_P(MultiviewLayeredRenderTest, RenderToSubrangeOfLayers)
2201 {
2202 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
2203 if (!requestMultiviewExtension())
2204 {
2205 return;
2206 }
2207
2208 const std::string VS =
2209 "#version 300 es\n"
2210 "#extension " +
2211 extensionName() +
2212 ": require\n"
2213 "layout(num_views = 2) in;\n"
2214 "in vec3 vPosition;\n"
2215 "void main()\n"
2216 "{\n"
2217 " gl_Position = vec4(vPosition, 1.);\n"
2218 "}\n";
2219
2220 const std::string FS =
2221 "#version 300 es\n"
2222 "#extension " +
2223 extensionName() +
2224 ": require\n"
2225 "precision mediump float;\n"
2226 "out vec4 col;\n"
2227 "void main()\n"
2228 "{\n"
2229 " col = vec4(0,1,0,1);\n"
2230 "}\n";
2231
2232 updateFBOs(1, 1, 2, 4, 1);
2233 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
2234
2235 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2236 ASSERT_GL_NO_ERROR();
2237
2238 resolveMultisampledFBO();
2239 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
2240 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2241 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
2242 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
2243 }
2244
2245 // The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
2246 // potential bugs if the view is selected in the VS. The test contains a program in which the
2247 // gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
2248 // fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
2249 // never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
2250 // green for view 1.
TEST_P(MultiviewRenderTest,FlatInterpolation)2251 TEST_P(MultiviewRenderTest, FlatInterpolation)
2252 {
2253 if (!requestMultiviewExtension(isMultisampled()))
2254 {
2255 return;
2256 }
2257
2258 const std::string VS =
2259 "#version 300 es\n"
2260 "#extension " +
2261 extensionName() +
2262 ": require\n"
2263 "layout(num_views = 2) in;\n"
2264 "in vec3 vPosition;\n"
2265 "flat out int oInstanceID;\n"
2266 "void main()\n"
2267 "{\n"
2268 " gl_Position = vec4(vPosition, 1.);\n"
2269 " oInstanceID = gl_InstanceID;\n"
2270 "}\n";
2271
2272 const std::string FS =
2273 "#version 300 es\n"
2274 "#extension " +
2275 extensionName() +
2276 ": require\n"
2277 "precision mediump float;\n"
2278 "flat in int oInstanceID;\n"
2279 "out vec4 col;\n"
2280 "void main()\n"
2281 "{\n"
2282 " if (oInstanceID < 0) {\n"
2283 " discard;\n"
2284 " }\n"
2285 " if (gl_ViewID_OVR == 0u) {\n"
2286 " col = vec4(1,0,0,1);\n"
2287 " } else {\n"
2288 " col = vec4(0,1,0,1);\n"
2289 " }\n"
2290 "}\n";
2291
2292 updateFBOs(1, 1, 2);
2293 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
2294
2295 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2296 ASSERT_GL_NO_ERROR();
2297
2298 resolveMultisampledFBO();
2299 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2300 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2301 }
2302
2303 // This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2304 // varying in the fragment shader.
TEST_P(MultiviewRenderTest,FlatInterpolation2)2305 TEST_P(MultiviewRenderTest, FlatInterpolation2)
2306 {
2307 if (!requestMultiviewExtension(isMultisampled()))
2308 {
2309 return;
2310 }
2311
2312 const std::string VS =
2313 "#version 300 es\n"
2314 "#extension " +
2315 extensionName() +
2316 ": require\n"
2317 "layout(num_views = 2) in;\n"
2318 "in vec3 vPosition;\n"
2319 "flat out int flatVarying;\n"
2320 "void main()\n"
2321 "{\n"
2322 " gl_Position = vec4(vPosition, 1.);\n"
2323 " flatVarying = int(gl_ViewID_OVR);\n"
2324 "}\n";
2325
2326 const std::string FS =
2327 "#version 300 es\n"
2328 "#extension " +
2329 extensionName() +
2330 ": require\n"
2331 "precision mediump float;\n"
2332 "flat in int flatVarying;\n"
2333 "out vec4 col;\n"
2334 "void main()\n"
2335 "{\n"
2336 " if (flatVarying == 0) {\n"
2337 " col = vec4(1,0,0,1);\n"
2338 " } else {\n"
2339 " col = vec4(0,1,0,1);\n"
2340 " }\n"
2341 "}\n";
2342
2343 updateFBOs(1, 1, 2);
2344 ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
2345
2346 drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2347 ASSERT_GL_NO_ERROR();
2348
2349 resolveMultisampledFBO();
2350 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2351 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2352 }
2353
2354 // Test that shader caching maintains the num_views value used in GL_OVR_multiview between shader
2355 // compilations.
TEST_P(MultiviewRenderTest,ShaderCacheVertexWithOVRMultiview)2356 TEST_P(MultiviewRenderTest, ShaderCacheVertexWithOVRMultiview)
2357 {
2358 ANGLE_SKIP_TEST_IF(!IsVulkan());
2359 if (!requestMultiviewExtension(true))
2360 {
2361 return;
2362 }
2363
2364 constexpr char kVS[] = R"(#version 300 es
2365 #extension GL_OVR_multiview : enable
2366
2367 layout (num_views = 2) in;
2368
2369 precision mediump float;
2370
2371 layout (location = 0) in vec4 a_position;
2372
2373 out float redValue;
2374 out float greenValue;
2375
2376 void main() {
2377 gl_Position = a_position;
2378 if (gl_ViewID_OVR == uint(0))
2379 {
2380 redValue = 1.;
2381 greenValue = 0.;
2382 }
2383 else
2384 {
2385 redValue = 0.;
2386 greenValue = 1.;
2387 }
2388 })";
2389
2390 constexpr char kFS[] = R"(#version 300 es
2391
2392 precision mediump float;
2393
2394 in float redValue;
2395 in float greenValue;
2396
2397 out vec4 fragColor;
2398
2399 void main()
2400 {
2401 fragColor = vec4(redValue, greenValue, 0., 1.);
2402 })";
2403
2404 // Only use a single 1x1 FBO
2405 updateFBOs(1, 1, 2);
2406
2407 ANGLE_GL_PROGRAM(unusedProgram, kVS, kFS);
2408 ASSERT_GL_NO_ERROR();
2409 // Delete the shader and recompile to fetch from cache.
2410 glDeleteProgram(unusedProgram);
2411 ANGLE_GL_PROGRAM(program, kVS, kFS);
2412 glUseProgram(program);
2413 ASSERT_GL_NO_ERROR();
2414
2415 drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f, 1.0f, true);
2416 ASSERT_GL_NO_ERROR();
2417
2418 resolveMultisampledFBO();
2419 EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2420 EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2421 }
2422
VertexShaderOpenGL(ExtensionName multiviewExtension)2423 MultiviewRenderTestParams VertexShaderOpenGL(ExtensionName multiviewExtension)
2424 {
2425 return MultiviewRenderTestParams(0, VertexShaderOpenGL(3, 0, multiviewExtension));
2426 }
2427
VertexShaderVulkan(ExtensionName multiviewExtension)2428 MultiviewRenderTestParams VertexShaderVulkan(ExtensionName multiviewExtension)
2429 {
2430 return MultiviewRenderTestParams(0, VertexShaderVulkan(3, 0, multiviewExtension));
2431 }
2432
GeomShaderD3D11(ExtensionName multiviewExtension)2433 MultiviewRenderTestParams GeomShaderD3D11(ExtensionName multiviewExtension)
2434 {
2435 return MultiviewRenderTestParams(0, GeomShaderD3D11(3, 0, multiviewExtension));
2436 }
2437
VertexShaderD3D11(ExtensionName multiviewExtension)2438 MultiviewRenderTestParams VertexShaderD3D11(ExtensionName multiviewExtension)
2439 {
2440 return MultiviewRenderTestParams(0, VertexShaderD3D11(3, 0, multiviewExtension));
2441 }
2442
MultisampledVertexShaderOpenGL(ExtensionName multiviewExtension)2443 MultiviewRenderTestParams MultisampledVertexShaderOpenGL(ExtensionName multiviewExtension)
2444 {
2445 return MultiviewRenderTestParams(2, VertexShaderOpenGL(3, 1, multiviewExtension));
2446 }
2447
MultisampledVertexShaderVulkan(ExtensionName multiviewExtension)2448 MultiviewRenderTestParams MultisampledVertexShaderVulkan(ExtensionName multiviewExtension)
2449 {
2450 return MultiviewRenderTestParams(2, VertexShaderVulkan(3, 1, multiviewExtension));
2451 }
2452
MultisampledVertexShaderD3D11(ExtensionName multiviewExtension)2453 MultiviewRenderTestParams MultisampledVertexShaderD3D11(ExtensionName multiviewExtension)
2454 {
2455 return MultiviewRenderTestParams(2, VertexShaderD3D11(3, 1, multiviewExtension));
2456 }
2457
2458 #define ALL_VERTEX_SHADER_CONFIGS(minor) \
2459 VertexShaderOpenGL(3, minor, ExtensionName::multiview), \
2460 VertexShaderVulkan(3, minor, ExtensionName::multiview), \
2461 VertexShaderD3D11(3, minor, ExtensionName::multiview), \
2462 VertexShaderOpenGL(3, minor, ExtensionName::multiview2), \
2463 VertexShaderVulkan(3, minor, ExtensionName::multiview2), \
2464 VertexShaderD3D11(3, minor, ExtensionName::multiview2)
2465
2466 #define ALL_SINGLESAMPLE_CONFIGS() \
2467 VertexShaderOpenGL(ExtensionName::multiview), VertexShaderVulkan(ExtensionName::multiview), \
2468 VertexShaderD3D11(ExtensionName::multiview), GeomShaderD3D11(ExtensionName::multiview), \
2469 VertexShaderOpenGL(ExtensionName::multiview2), \
2470 VertexShaderVulkan(ExtensionName::multiview2), \
2471 VertexShaderD3D11(ExtensionName::multiview2), GeomShaderD3D11(ExtensionName::multiview2)
2472
2473 #define ALL_MULTISAMPLE_CONFIGS() \
2474 MultisampledVertexShaderOpenGL(ExtensionName::multiview), \
2475 MultisampledVertexShaderVulkan(ExtensionName::multiview), \
2476 MultisampledVertexShaderD3D11(ExtensionName::multiview), \
2477 MultisampledVertexShaderOpenGL(ExtensionName::multiview2), \
2478 MultisampledVertexShaderVulkan(ExtensionName::multiview2), \
2479 MultisampledVertexShaderD3D11(ExtensionName::multiview2)
2480
2481 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewDrawValidationTest);
2482 ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ALL_VERTEX_SHADER_CONFIGS(1));
2483
2484 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewRenderDualViewTest);
2485 ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
2486 ALL_SINGLESAMPLE_CONFIGS(),
2487 ALL_MULTISAMPLE_CONFIGS());
2488
2489 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewRenderDualViewTestNoWebGL);
2490 ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTestNoWebGL,
2491 ALL_SINGLESAMPLE_CONFIGS(),
2492 ALL_MULTISAMPLE_CONFIGS());
2493
2494 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewRenderTest);
2495 ANGLE_INSTANTIATE_TEST(MultiviewRenderTest, ALL_SINGLESAMPLE_CONFIGS(), ALL_MULTISAMPLE_CONFIGS());
2496
2497 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewOcclusionQueryTest);
2498 ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest, ALL_SINGLESAMPLE_CONFIGS());
2499
2500 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewProgramGenerationTest);
2501 ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
2502 ALL_VERTEX_SHADER_CONFIGS(0),
2503 GeomShaderD3D11(3, 0, ExtensionName::multiview),
2504 GeomShaderD3D11(3, 0, ExtensionName::multiview2));
2505
2506 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewRenderPrimitiveTest);
2507 ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest, ALL_SINGLESAMPLE_CONFIGS());
2508
2509 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewLayeredRenderTest);
2510 ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, ALL_SINGLESAMPLE_CONFIGS());
2511