xref: /aosp_15_r20/external/angle/src/tests/gl_tests/MultiviewDrawTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 &params)
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 &params, 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