• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/FeaturesD3D.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 
overrideWorkaroundsD3D(FeaturesD3D * features)288     void overrideWorkaroundsD3D(FeaturesD3D *features) override
289     {
290         features->overrideFeatures({"select_view_in_geometry_shader"},
291                                    GetParam().mForceUseGeometryShaderOnD3D);
292     }
293 
testSetUp()294     virtual void testSetUp() {}
testTearDown()295     virtual void testTearDown() {}
296 
297   private:
SetUp()298     void SetUp() override
299     {
300         MultiviewFramebufferTestBase::FramebufferTestSetUp();
301         testSetUp();
302     }
TearDown()303     void TearDown() override
304     {
305         testTearDown();
306         MultiviewFramebufferTestBase::FramebufferTestTearDown();
307     }
308 };
309 
DualViewVS(ExtensionName multiviewExtension)310 std::string DualViewVS(ExtensionName multiviewExtension)
311 {
312     std::string ext;
313     switch (multiviewExtension)
314     {
315         case multiview:
316             ext = "GL_OVR_multiview";
317             break;
318         case multiview2:
319             ext = "GL_OVR_multiview2";
320             break;
321     }
322 
323     std::string dualViewVSSource =
324         "#version 300 es\n"
325         "#extension " +
326         ext +
327         " : require\n"
328         "layout(num_views = 2) in;\n"
329         "in vec4 vPosition;\n"
330         "void main()\n"
331         "{\n"
332         "   gl_Position.x = (gl_ViewID_OVR == 0u ? vPosition.x * 0.5 + 0.5 : vPosition.x * 0.5 - "
333         "0.5);\n"
334         "   gl_Position.yzw = vPosition.yzw;\n"
335         "}\n";
336     return dualViewVSSource;
337 }
338 
DualViewFS(ExtensionName multiviewExtension)339 std::string DualViewFS(ExtensionName multiviewExtension)
340 {
341     std::string ext;
342     switch (multiviewExtension)
343     {
344         case multiview:
345             ext = "GL_OVR_multiview";
346             break;
347         case multiview2:
348             ext = "GL_OVR_multiview2";
349             break;
350     }
351 
352     std::string dualViewFSSource =
353         "#version 300 es\n"
354         "#extension " +
355         ext +
356         " : require\n"
357         "precision mediump float;\n"
358         "out vec4 col;\n"
359         "void main()\n"
360         "{\n"
361         "  col = vec4(0,1,0,1);\n"
362         "}\n";
363     return dualViewFSSource;
364 }
365 
366 class MultiviewRenderDualViewTest : public MultiviewRenderTest
367 {
368   protected:
MultiviewRenderDualViewTest()369     MultiviewRenderDualViewTest() : mProgram(0u) {}
370 
testSetUp()371     void testSetUp() override
372     {
373         if (!requestMultiviewExtension(isMultisampled()))
374         {
375             return;
376         }
377 
378         updateFBOs(2, 1, 2);
379         mProgram = CompileProgram(DualViewVS(GetParam().mMultiviewExtension).c_str(),
380                                   DualViewFS(GetParam().mMultiviewExtension).c_str());
381         ASSERT_NE(mProgram, 0u);
382         glUseProgram(mProgram);
383         ASSERT_GL_NO_ERROR();
384     }
385 
testTearDown()386     void testTearDown() override
387     {
388         if (mProgram != 0u)
389         {
390             glDeleteProgram(mProgram);
391             mProgram = 0u;
392         }
393     }
394 
checkOutput()395     void checkOutput()
396     {
397         resolveMultisampledFBO();
398         EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
399         EXPECT_EQ(GLColor::green, GetViewColor(1, 0, 0));
400         EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
401         EXPECT_EQ(GLColor::transparentBlack, GetViewColor(1, 0, 1));
402     }
403 
404     GLuint mProgram;
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(); }
overrideWorkaroundsD3D(FeaturesD3D * features)531     void overrideWorkaroundsD3D(FeaturesD3D *features) final
532     {
533         features->overrideFeatures({"select_view_in_geometry_shader"},
534                                    GetParam().mForceUseGeometryShaderOnD3D);
535     }
536 };
537 
538 // The test verifies that glDraw*Indirect works for any number of views.
TEST_P(MultiviewDrawValidationTest,IndirectDraw)539 TEST_P(MultiviewDrawValidationTest, IndirectDraw)
540 {
541     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
542 
543     const std::string FS =
544         "#version 300 es\n"
545         "#extension " +
546         extensionName() +
547         ": require\n"
548         "precision mediump float;\n"
549         "out vec4 color;\n"
550         "void main()\n"
551         "{color = vec4(1);}\n";
552 
553     GLVertexArray vao;
554     GLBuffer vertexBuffer;
555     GLBuffer indexBuffer;
556     initVAO(vao, vertexBuffer, indexBuffer);
557 
558     GLFramebuffer fbo;
559     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
560 
561     GLBuffer commandBuffer;
562     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, commandBuffer);
563     const GLuint commandData[] = {1u, 1u, 0u, 0u, 0u};
564     glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(GLuint) * 5u, &commandData[0], GL_STATIC_DRAW);
565     ASSERT_GL_NO_ERROR();
566 
567     // Check that no errors are generated with the framebuffer having 2 views.
568     {
569         const std::string VS =
570             "#version 300 es\n"
571             "#extension " +
572             extensionName() +
573             ": require\n"
574             "layout(num_views = 2) in;\n"
575             "void main()\n"
576             "{}\n";
577         ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
578         glUseProgram(program);
579 
580         GLTexture tex2DArray;
581         initOnePixelColorTexture2DMultiLayered(tex2DArray);
582 
583         glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
584 
585         glDrawArraysIndirect(GL_TRIANGLES, nullptr);
586         EXPECT_GL_NO_ERROR();
587 
588         glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
589         EXPECT_GL_NO_ERROR();
590     }
591 
592     // Check that no errors are generated if the number of views is 1.
593     {
594         const std::string VS =
595             "#version 300 es\n"
596             "#extension " +
597             extensionName() +
598             ": require\n"
599             "layout(num_views = 1) in;\n"
600             "void main()\n"
601             "{}\n";
602         ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
603         glUseProgram(program);
604 
605         GLTexture tex2D;
606         initOnePixelColorTexture2DSingleLayered(tex2D);
607 
608         glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
609 
610         glDrawArraysIndirect(GL_TRIANGLES, nullptr);
611         EXPECT_GL_NO_ERROR();
612 
613         glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr);
614         EXPECT_GL_NO_ERROR();
615     }
616 }
617 
618 // The test verifies that glDraw*:
619 // 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer and
620 // program differs.
621 // 2) does not generate any error if the number of views is the same.
TEST_P(MultiviewDrawValidationTest,NumViewsMismatch)622 TEST_P(MultiviewDrawValidationTest, NumViewsMismatch)
623 {
624     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
625 
626     const std::string VS =
627         "#version 300 es\n"
628         "#extension " +
629         extensionName() +
630         ": require\n"
631         "layout(num_views = 2) in;\n"
632         "void main()\n"
633         "{}\n";
634     const std::string FS =
635         "#version 300 es\n"
636         "#extension " +
637         extensionName() +
638         ": require\n"
639         "precision mediump float;\n"
640         "out vec4 color;\n"
641         "void main()\n"
642         "{color = vec4(1);}\n";
643     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
644     glUseProgram(program);
645 
646     GLVertexArray vao;
647     GLBuffer vertexBuffer;
648     GLBuffer indexBuffer;
649     initVAO(vao, vertexBuffer, indexBuffer);
650 
651     GLFramebuffer fbo;
652     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
653 
654     // Check for a GL_INVALID_OPERATION error with the framebuffer and program having different
655     // number of views.
656     {
657         GLTexture tex2D;
658         initOnePixelColorTexture2DSingleLayered(tex2D);
659 
660         // The framebuffer has only 1 view.
661         glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
662 
663         glDrawArrays(GL_TRIANGLES, 0, 3);
664         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
665 
666         glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
667         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
668     }
669 
670     // Check that no errors are generated if the number of views in both program and draw
671     // framebuffer matches.
672     {
673         GLTexture tex2DArray;
674         initOnePixelColorTexture2DMultiLayered(tex2DArray);
675 
676         glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
677 
678         glDrawArrays(GL_TRIANGLES, 0, 3);
679         EXPECT_GL_NO_ERROR();
680 
681         glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
682         EXPECT_GL_NO_ERROR();
683     }
684 }
685 
686 // The test verifies that glDraw* generates an INVALID_OPERATION error if the program does not use
687 // the multiview extension, but the active draw framebuffer has more than one view.
TEST_P(MultiviewDrawValidationTest,NumViewsMismatchForNonMultiviewProgram)688 TEST_P(MultiviewDrawValidationTest, NumViewsMismatchForNonMultiviewProgram)
689 {
690     if (!requestMultiviewExtension())
691     {
692         return;
693     }
694 
695     constexpr char kVS[] =
696         "#version 300 es\n"
697         "void main()\n"
698         "{}\n";
699     constexpr char kFS[] =
700         "#version 300 es\n"
701         "precision mediump float;\n"
702         "void main()\n"
703         "{}\n";
704     ANGLE_GL_PROGRAM(programNoMultiview, kVS, kFS);
705     glUseProgram(programNoMultiview);
706 
707     GLVertexArray vao;
708     GLBuffer vertexBuffer;
709     GLBuffer indexBuffer;
710     initVAO(vao, vertexBuffer, indexBuffer);
711 
712     GLFramebuffer fbo;
713     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
714 
715     GLTexture tex2DArray;
716     initOnePixelColorTexture2DMultiLayered(tex2DArray);
717 
718     glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
719 
720     glDrawArrays(GL_TRIANGLES, 0, 3);
721     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
722 
723     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr);
724     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
725 }
726 
727 // The test verifies that glDraw*:
728 // 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
729 // greater than 1 and there is an active not paused transform feedback object.
730 // 2) does not generate any error if the number of views in the draw framebuffer is 1.
TEST_P(MultiviewDrawValidationTest,ActiveTransformFeedback)731 TEST_P(MultiviewDrawValidationTest, ActiveTransformFeedback)
732 {
733     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
734 
735     constexpr char kVS[] = R"(#version 300 es
736 out float tfVarying;
737 void main()
738 {
739     tfVarying = 1.0;
740 })";
741 
742     constexpr char kFS[] = R"(#version 300 es
743 precision mediump float;
744 void main()
745 {})";
746 
747     std::vector<std::string> tfVaryings;
748     tfVaryings.emplace_back("tfVarying");
749     ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(singleViewProgram, kVS, kFS, tfVaryings,
750                                         GL_SEPARATE_ATTRIBS);
751 
752     std::vector<std::string> dualViewTFVaryings;
753     dualViewTFVaryings.emplace_back("gl_Position");
754     ANGLE_GL_PROGRAM_TRANSFORM_FEEDBACK(dualViewProgram,
755                                         DualViewVS(GetParam().mMultiviewExtension).c_str(),
756                                         DualViewFS(GetParam().mMultiviewExtension).c_str(),
757                                         dualViewTFVaryings, GL_SEPARATE_ATTRIBS);
758 
759     GLVertexArray vao;
760     GLBuffer vertexBuffer;
761     GLBuffer indexBuffer;
762     initVAO(vao, vertexBuffer, indexBuffer);
763 
764     GLBuffer tbo;
765     glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
766     glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(float) * 16u, nullptr, GL_STATIC_DRAW);
767 
768     GLTransformFeedback transformFeedback;
769     glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
770 
771     glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
772 
773     glUseProgram(dualViewProgram);
774     glBeginTransformFeedback(GL_TRIANGLES);
775     ASSERT_GL_NO_ERROR();
776 
777     GLFramebuffer fbo;
778     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
779 
780     GLTexture tex2DArray;
781     initOnePixelColorTexture2DMultiLayered(tex2DArray);
782 
783     GLenum bufs[] = {GL_NONE};
784     glDrawBuffers(1, bufs);
785 
786     // Check that drawArrays generates an error when there is an active transform feedback object
787     // and the number of views in the draw framebuffer is greater than 1.
788     {
789         glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArray, 0, 0, 2);
790         glDrawArrays(GL_TRIANGLES, 0, 3);
791         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
792     }
793 
794     glEndTransformFeedback();
795 
796     // Ending transform feedback should allow the draw to succeed.
797     {
798         glDrawArrays(GL_TRIANGLES, 0, 3);
799         EXPECT_GL_NO_ERROR();
800     }
801 
802     // A paused transform feedback should not trigger an error.
803     glBeginTransformFeedback(GL_TRIANGLES);
804     glPauseTransformFeedback();
805     ASSERT_GL_NO_ERROR();
806 
807     glDrawArrays(GL_TRIANGLES, 0, 3);
808     ASSERT_GL_NO_ERROR();
809 
810     // Unbind transform feedback - should succeed.
811     glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
812     glDrawArrays(GL_TRIANGLES, 0, 3);
813     ASSERT_GL_NO_ERROR();
814 
815     // Rebind paused transform feedback - should succeed.
816     glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
817     glDrawArrays(GL_TRIANGLES, 0, 3);
818     ASSERT_GL_NO_ERROR();
819 
820     glResumeTransformFeedback();
821     glEndTransformFeedback();
822 
823     glUseProgram(singleViewProgram);
824     glBeginTransformFeedback(GL_TRIANGLES);
825     ASSERT_GL_NO_ERROR();
826 
827     GLTexture tex2D;
828     initOnePixelColorTexture2DSingleLayered(tex2D);
829 
830     // Check that drawArrays does not generate an error when the number of views in the draw
831     // framebuffer is 1.
832     {
833         glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
834         glDrawArrays(GL_TRIANGLES, 0, 3);
835         EXPECT_GL_NO_ERROR();
836     }
837 
838     glEndTransformFeedback();
839 }
840 
841 // The test verifies that glDraw*:
842 // 1) generates an INVALID_OPERATION error if the number of views in the active draw framebuffer is
843 // greater than 1 and there is an active query for target GL_TIME_ELAPSED_EXT.
844 // 2) does not generate any error if the number of views in the draw framebuffer is 1.
TEST_P(MultiviewDrawValidationTest,ActiveTimeElapsedQuery)845 TEST_P(MultiviewDrawValidationTest, ActiveTimeElapsedQuery)
846 {
847     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
848     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
849 
850     ANGLE_GL_PROGRAM(dualViewProgram, DualViewVS(GetParam().mMultiviewExtension).c_str(),
851                      DualViewFS(GetParam().mMultiviewExtension).c_str());
852 
853     constexpr char kVS[] =
854         "#version 300 es\n"
855         "void main()\n"
856         "{}\n";
857     constexpr char kFS[] =
858         "#version 300 es\n"
859         "precision mediump float;\n"
860         "void main()\n"
861         "{}\n";
862     ANGLE_GL_PROGRAM(singleViewProgram, kVS, kFS);
863     glUseProgram(singleViewProgram);
864 
865     GLVertexArray vao;
866     GLBuffer vertexBuffer;
867     GLBuffer indexBuffer;
868     initVAO(vao, vertexBuffer, indexBuffer);
869 
870     GLuint query = 0u;
871     glGenQueriesEXT(1, &query);
872     glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
873 
874     GLFramebuffer fbo;
875     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
876 
877     GLTexture tex2DArr;
878     initOnePixelColorTexture2DMultiLayered(tex2DArr);
879 
880     GLenum bufs[] = {GL_NONE};
881     glDrawBuffers(1, bufs);
882 
883     // Check first case.
884     {
885         glUseProgram(dualViewProgram);
886         glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
887         glClear(GL_COLOR_BUFFER_BIT);
888         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
889         glDrawArrays(GL_TRIANGLES, 0, 3);
890         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
891     }
892 
893     GLTexture tex2D;
894     initOnePixelColorTexture2DSingleLayered(tex2D);
895 
896     // Check second case.
897     {
898         glUseProgram(singleViewProgram);
899         glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2D, 0, 0, 1);
900         glClear(GL_COLOR_BUFFER_BIT);
901         EXPECT_GL_NO_ERROR();
902         glDrawArrays(GL_TRIANGLES, 0, 3);
903         EXPECT_GL_NO_ERROR();
904     }
905 
906     glEndQueryEXT(GL_TIME_ELAPSED_EXT);
907     glDeleteQueries(1, &query);
908 
909     // Check starting a query after a successful draw.
910     {
911         glUseProgram(dualViewProgram);
912         glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex2DArr, 0, 0, 2);
913         glClear(GL_COLOR_BUFFER_BIT);
914         EXPECT_GL_NO_ERROR();
915         glDrawArrays(GL_TRIANGLES, 0, 3);
916         EXPECT_GL_NO_ERROR();
917 
918         glGenQueriesEXT(1, &query);
919         glBeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
920 
921         glDrawArrays(GL_TRIANGLES, 0, 3);
922         EXPECT_GL_ERROR(GL_INVALID_OPERATION);
923 
924         glEndQueryEXT(GL_TIME_ELAPSED_EXT);
925         glDrawArrays(GL_TRIANGLES, 0, 3);
926         EXPECT_GL_NO_ERROR();
927 
928         glDeleteQueries(1, &query);
929     }
930 }
931 
932 // The test checks that glDrawArrays can be used to render into two views.
TEST_P(MultiviewRenderDualViewTest,DrawArrays)933 TEST_P(MultiviewRenderDualViewTest, DrawArrays)
934 {
935     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
936     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
937 
938     drawQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
939     ASSERT_GL_NO_ERROR();
940 
941     checkOutput();
942 }
943 
944 // The test checks that glDrawElements can be used to render into two views.
TEST_P(MultiviewRenderDualViewTest,DrawElements)945 TEST_P(MultiviewRenderDualViewTest, DrawElements)
946 {
947     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
948     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
949 
950     drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true);
951     ASSERT_GL_NO_ERROR();
952 
953     checkOutput();
954 }
955 
956 // The test checks that glDrawRangeElements can be used to render into two views.
TEST_P(MultiviewRenderDualViewTest,DrawRangeElements)957 TEST_P(MultiviewRenderDualViewTest, DrawRangeElements)
958 {
959     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
960     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
961 
962     drawIndexedQuad(mProgram, "vPosition", 0.0f, 1.0f, true, true);
963     ASSERT_GL_NO_ERROR();
964 
965     checkOutput();
966 }
967 
968 // The test checks that glDrawArrays can be used to render into four views.
TEST_P(MultiviewRenderTest,DrawArraysFourViews)969 TEST_P(MultiviewRenderTest, DrawArraysFourViews)
970 {
971     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
972     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
973 
974     const std::string VS =
975         "#version 300 es\n"
976         "#extension " +
977         extensionName() +
978         " : require\n"
979         "layout(num_views = 4) in;\n"
980         "in vec4 vPosition;\n"
981         "void main()\n"
982         "{\n"
983         "   if (gl_ViewID_OVR == 0u) {\n"
984         "       gl_Position.x = vPosition.x*0.25 - 0.75;\n"
985         "   } else if (gl_ViewID_OVR == 1u) {\n"
986         "       gl_Position.x = vPosition.x*0.25 - 0.25;\n"
987         "   } else if (gl_ViewID_OVR == 2u) {\n"
988         "       gl_Position.x = vPosition.x*0.25 + 0.25;\n"
989         "   } else {\n"
990         "       gl_Position.x = vPosition.x*0.25 + 0.75;\n"
991         "   }"
992         "   gl_Position.yzw = vPosition.yzw;\n"
993         "}\n";
994 
995     const std::string FS =
996         "#version 300 es\n"
997         "#extension " +
998         extensionName() +
999         " : require\n"
1000         "precision mediump float;\n"
1001         "out vec4 col;\n"
1002         "void main()\n"
1003         "{\n"
1004         "    col = vec4(0,1,0,1);\n"
1005         "}\n";
1006 
1007     updateFBOs(4, 1, 4);
1008     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1009 
1010     drawQuad(program, "vPosition", 0.0f, 1.0f, true);
1011     ASSERT_GL_NO_ERROR();
1012 
1013     resolveMultisampledFBO();
1014     for (int i = 0; i < 4; ++i)
1015     {
1016         for (int j = 0; j < 4; ++j)
1017         {
1018             if (i == j)
1019             {
1020                 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, i));
1021             }
1022             else
1023             {
1024                 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, i));
1025             }
1026         }
1027     }
1028     EXPECT_GL_NO_ERROR();
1029 }
1030 
1031 // The test checks that glDrawArraysInstanced can be used to render into two views.
TEST_P(MultiviewRenderTest,DrawArraysInstanced)1032 TEST_P(MultiviewRenderTest, DrawArraysInstanced)
1033 {
1034     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
1035     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1036 
1037     const std::string VS =
1038         "#version 300 es\n"
1039         "#extension " +
1040         extensionName() +
1041         ": require\n"
1042         "layout(num_views = 2) in;\n"
1043         "in vec4 vPosition;\n"
1044         "void main()\n"
1045         "{\n"
1046         "       vec4 p = vPosition;\n"
1047         "       if (gl_InstanceID == 1){\n"
1048         "               p.y = p.y * 0.5 + 0.5;\n"
1049         "       } else {\n"
1050         "               p.y = p.y * 0.5 - 0.5;\n"
1051         "       }\n"
1052         "       gl_Position.x = (gl_ViewID_OVR == 0u ? p.x * 0.5 + 0.5 : p.x * 0.5 - 0.5);\n"
1053         "       gl_Position.yzw = p.yzw;\n"
1054         "}\n";
1055 
1056     const std::string FS =
1057         "#version 300 es\n"
1058         "#extension " +
1059         extensionName() +
1060         ": require\n"
1061         "precision mediump float;\n"
1062         "out vec4 col;\n"
1063         "void main()\n"
1064         "{\n"
1065         "    col = vec4(0,1,0,1);\n"
1066         "}\n";
1067 
1068     const int kViewWidth  = 2;
1069     const int kViewHeight = 2;
1070     const int kNumViews   = 2;
1071     updateFBOs(kViewWidth, kViewHeight, kNumViews);
1072     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1073 
1074     drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 2u);
1075     ASSERT_GL_NO_ERROR();
1076 
1077     resolveMultisampledFBO();
1078 
1079     const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {{{0, 255}, {0, 255}},
1080                                                                               {{255, 0}, {255, 0}}};
1081 
1082     for (int view = 0; view < 2; ++view)
1083     {
1084         for (int y = 0; y < 2; ++y)
1085         {
1086             for (int x = 0; x < 2; ++x)
1087             {
1088                 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][y][x], 0,
1089                                   expectedGreenChannel[view][y][x]),
1090                           GetViewColor(x, y, view));
1091             }
1092         }
1093     }
1094 }
1095 
1096 // The test verifies that the attribute divisor is correctly adjusted when drawing with a multi-view
1097 // program. The test draws 4 instances of a quad each of which covers a single pixel. The x and y
1098 // offset of each quad are passed as separate attributes which are indexed based on the
1099 // corresponding attribute divisors. A divisor of 1 is used for the y offset to have all quads
1100 // drawn vertically next to each other. A divisor of 3 is used for the x offset to have the last
1101 // quad offsetted by one pixel to the right. Note that the number of views is divisible by 1, but
1102 // not by 3.
TEST_P(MultiviewRenderTest,AttribDivisor)1103 TEST_P(MultiviewRenderTest, AttribDivisor)
1104 {
1105     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
1106     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1107 
1108     // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
1109     // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
1110     if (IsWindows() && IsD3D11())
1111     {
1112         ignoreD3D11SDKLayersWarnings();
1113     }
1114 
1115     const std::string VS =
1116         "#version 300 es\n"
1117         "#extension " +
1118         extensionName() +
1119         " : require\n"
1120         "layout(num_views = 2) in;\n"
1121         "in vec3 vPosition;\n"
1122         "in float offsetX;\n"
1123         "in float offsetY;\n"
1124         "void main()\n"
1125         "{\n"
1126         "       vec4 p = vec4(vPosition, 1.);\n"
1127         "       p.xy = p.xy * 0.25 - vec2(0.75) + vec2(offsetX, offsetY);\n"
1128         "       gl_Position.x = (gl_ViewID_OVR == 0u ? p.x : p.x + 1.0);\n"
1129         "       gl_Position.yzw = p.yzw;\n"
1130         "}\n";
1131 
1132     const std::string FS =
1133         "#version 300 es\n"
1134         "#extension " +
1135         extensionName() +
1136         ": require\n"
1137         "precision mediump float;\n"
1138         "out vec4 col;\n"
1139         "void main()\n"
1140         "{\n"
1141         "    col = vec4(0,1,0,1);\n"
1142         "}\n";
1143 
1144     const int kViewWidth  = 4;
1145     const int kViewHeight = 4;
1146     const int kNumViews   = 2;
1147     updateFBOs(kViewWidth, kViewHeight, kNumViews);
1148     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1149 
1150     GLBuffer xOffsetVBO;
1151     glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1152     const GLfloat xOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.0f};
1153     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, xOffsetData, GL_STATIC_DRAW);
1154     GLint xOffsetLoc = glGetAttribLocation(program, "offsetX");
1155     glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1156     glVertexAttribDivisor(xOffsetLoc, 3);
1157     glEnableVertexAttribArray(xOffsetLoc);
1158 
1159     GLBuffer yOffsetVBO;
1160     glBindBuffer(GL_ARRAY_BUFFER, yOffsetVBO);
1161     const GLfloat yOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1162     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, yOffsetData, GL_STATIC_DRAW);
1163     GLint yOffsetLoc = glGetAttribLocation(program, "offsetY");
1164     glVertexAttribDivisor(yOffsetLoc, 1);
1165     glVertexAttribPointer(yOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1166     glEnableVertexAttribArray(yOffsetLoc);
1167 
1168     drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
1169     ASSERT_GL_NO_ERROR();
1170 
1171     resolveMultisampledFBO();
1172 
1173     const GLubyte expectedGreenChannel[kNumViews][kViewHeight][kViewWidth] = {
1174         {{255, 0, 0, 0}, {255, 0, 0, 0}, {255, 0, 0, 0}, {0, 255, 0, 0}},
1175         {{0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 255, 0}, {0, 0, 0, 255}}};
1176     for (int view = 0; view < 2; ++view)
1177     {
1178         for (int row = 0; row < 4; ++row)
1179         {
1180             for (int col = 0; col < 4; ++col)
1181             {
1182                 EXPECT_EQ(GLColor(0, expectedGreenChannel[view][row][col], 0,
1183                                   expectedGreenChannel[view][row][col]),
1184                           GetViewColor(col, row, view));
1185             }
1186         }
1187     }
1188 }
1189 
1190 // Test that different sequences of vertexAttribDivisor, useProgram and bindVertexArray in a
1191 // multi-view context propagate the correct divisor to the driver.
TEST_P(MultiviewRenderTest,DivisorOrderOfOperation)1192 TEST_P(MultiviewRenderTest, DivisorOrderOfOperation)
1193 {
1194     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension(isMultisampled()));
1195     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1196 
1197     updateFBOs(1, 1, 2);
1198 
1199     // Create multiview program.
1200     const std::string VS =
1201         "#version 300 es\n"
1202         "#extension " +
1203         extensionName() +
1204         ": require\n"
1205         "layout(num_views = 2) in;\n"
1206         "layout(location = 0) in vec2 vPosition;\n"
1207         "layout(location = 1) in float offsetX;\n"
1208         "void main()\n"
1209         "{\n"
1210         "       vec4 p = vec4(vPosition, 0.0, 1.0);\n"
1211         "       p.x += offsetX;\n"
1212         "       gl_Position = p;\n"
1213         "}\n";
1214 
1215     const std::string FS =
1216         "#version 300 es\n"
1217         "#extension " +
1218         extensionName() +
1219         " : require\n"
1220         "precision mediump float;\n"
1221         "out vec4 col;\n"
1222         "void main()\n"
1223         "{\n"
1224         "    col = vec4(0,1,0,1);\n"
1225         "}\n";
1226 
1227     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1228 
1229     constexpr char kStubVS[] =
1230         "#version 300 es\n"
1231         "layout(location = 0) in vec2 vPosition;\n"
1232         "layout(location = 1) in float offsetX;\n"
1233         "void main()\n"
1234         "{\n"
1235         "       gl_Position = vec4(vPosition, 0.0, 1.0);\n"
1236         "}\n";
1237 
1238     constexpr char kStubFS[] =
1239         "#version 300 es\n"
1240         "precision mediump float;\n"
1241         "out vec4 col;\n"
1242         "void main()\n"
1243         "{\n"
1244         "    col = vec4(0,0,0,1);\n"
1245         "}\n";
1246 
1247     ANGLE_GL_PROGRAM(stubProgram, kStubVS, kStubFS);
1248 
1249     GLBuffer xOffsetVBO;
1250     glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1251     const GLfloat xOffsetData[12] = {0.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f,
1252                                      4.0f, 4.0f, 4.0f, 4.0f, 4.0f, 4.0f};
1253     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 12, xOffsetData, GL_STATIC_DRAW);
1254 
1255     GLBuffer vertexVBO;
1256     glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1257     Vector2 kQuadVertices[6] = {Vector2(-1.f, -1.f), Vector2(1.f, -1.f), Vector2(1.f, 1.f),
1258                                 Vector2(-1.f, -1.f), Vector2(1.f, 1.f),  Vector2(-1.f, 1.f)};
1259     glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
1260 
1261     GLVertexArray vao[2];
1262     for (size_t i = 0u; i < 2u; ++i)
1263     {
1264         glBindVertexArray(vao[i]);
1265 
1266         glBindBuffer(GL_ARRAY_BUFFER, vertexVBO);
1267         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
1268         glEnableVertexAttribArray(0);
1269 
1270         glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1271         glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
1272         glEnableVertexAttribArray(1);
1273     }
1274     ASSERT_GL_NO_ERROR();
1275 
1276     glViewport(0, 0, 1, 1);
1277     glScissor(0, 0, 1, 1);
1278     glEnable(GL_SCISSOR_TEST);
1279     glClearColor(0, 0, 0, 1);
1280 
1281     // Clear the buffers, propagate divisor to the driver, bind the vao and keep it active.
1282     // It is necessary to call draw, so that the divisor is propagated and to guarantee that dirty
1283     // bits are cleared.
1284     glUseProgram(stubProgram);
1285     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1286     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1287     glBindVertexArray(vao[0]);
1288     glVertexAttribDivisor(1, 0);
1289     glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1290     glUseProgram(0);
1291     ASSERT_GL_NO_ERROR();
1292 
1293     // Check that vertexAttribDivisor uses the number of views to update the divisor.
1294     bindMemberDrawFramebuffer();
1295     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1296     glUseProgram(program);
1297     glVertexAttribDivisor(1, 1);
1298     glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1299 
1300     resolveMultisampledFBO();
1301     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1302     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1303 
1304     // Clear the buffers and propagate divisor to the driver.
1305     // We keep the vao active and propagate the divisor to guarantee that there are no unresolved
1306     // dirty bits when useProgram is called.
1307     glUseProgram(stubProgram);
1308     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1309     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1310     glVertexAttribDivisor(1, 1);
1311     glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1312     glUseProgram(0);
1313     ASSERT_GL_NO_ERROR();
1314 
1315     // Check that useProgram uses the number of views to update the divisor.
1316     bindMemberDrawFramebuffer();
1317     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1318     glUseProgram(program);
1319     glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1320 
1321     resolveMultisampledFBO();
1322     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1323     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1324 
1325     // We go through similar steps as before.
1326     glUseProgram(stubProgram);
1327     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
1328     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1329     glVertexAttribDivisor(1, 1);
1330     glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1331     glUseProgram(0);
1332     ASSERT_GL_NO_ERROR();
1333 
1334     // Check that bindVertexArray uses the number of views to update the divisor.
1335     {
1336         // Call useProgram with vao[1] being active to guarantee that useProgram will adjust the
1337         // divisor for vao[1] only.
1338         bindMemberDrawFramebuffer();
1339         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1340         glBindVertexArray(vao[1]);
1341         glUseProgram(program);
1342         glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1343         glBindVertexArray(0);
1344         ASSERT_GL_NO_ERROR();
1345     }
1346     // Bind vao[0] after useProgram is called to ensure that bindVertexArray is the call which
1347     // adjusts the divisor.
1348     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1349     glBindVertexArray(vao[0]);
1350     glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
1351 
1352     resolveMultisampledFBO();
1353     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 0));
1354     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
1355 }
1356 
1357 // Test that no fragments pass the occlusion query for a multi-view vertex shader which always
1358 // transforms geometry to be outside of the clip region.
TEST_P(MultiviewOcclusionQueryTest,OcclusionQueryNothingVisible)1359 TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryNothingVisible)
1360 {
1361     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1362     ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
1363     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1364 
1365     const std::string VS =
1366         "#version 300 es\n"
1367         "#extension " +
1368         extensionName() +
1369         ": require\n"
1370         "layout(num_views = 2) in;\n"
1371         "in vec3 vPosition;\n"
1372         "void main()\n"
1373         "{\n"
1374         "       gl_Position.x = 2.0;\n"
1375         "       gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1376         "}\n";
1377 
1378     const std::string FS =
1379         "#version 300 es\n"
1380         "#extension " +
1381         extensionName() +
1382         " : require\n"
1383         "precision mediump float;\n"
1384         "out vec4 col;\n"
1385         "void main()\n"
1386         "{\n"
1387         "    col = vec4(1,0,0,0);\n"
1388         "}\n";
1389     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1390     updateFBOs(1, 1, 2);
1391 
1392     GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1393     ASSERT_GL_NO_ERROR();
1394     EXPECT_GL_FALSE(result);
1395 }
1396 
1397 // Test that there are fragments passing the occlusion query if only view 0 can produce
1398 // output.
TEST_P(MultiviewOcclusionQueryTest,OcclusionQueryOnlyLeftVisible)1399 TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyLeftVisible)
1400 {
1401     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1402     ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
1403 
1404     const std::string VS =
1405         "#version 300 es\n"
1406         "#extension " +
1407         extensionName() +
1408         ": require\n"
1409         "layout(num_views = 2) in;\n"
1410         "in vec3 vPosition;\n"
1411         "void main()\n"
1412         "{\n"
1413         "       gl_Position.x = gl_ViewID_OVR == 0u ? vPosition.x : 2.0;\n"
1414         "       gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1415         "}\n";
1416 
1417     const std::string FS =
1418         "#version 300 es\n"
1419         "#extension " +
1420         extensionName() +
1421         ": require\n"
1422         "precision mediump float;\n"
1423         "out vec4 col;\n"
1424         "void main()\n"
1425         "{\n"
1426         "    col = vec4(1,0,0,0);\n"
1427         "}\n";
1428     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1429     updateFBOs(1, 1, 2);
1430 
1431     GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1432     ASSERT_GL_NO_ERROR();
1433     EXPECT_GL_TRUE(result);
1434 }
1435 
1436 // Test that there are fragments passing the occlusion query if only view 1 can produce
1437 // output.
TEST_P(MultiviewOcclusionQueryTest,OcclusionQueryOnlyRightVisible)1438 TEST_P(MultiviewOcclusionQueryTest, OcclusionQueryOnlyRightVisible)
1439 {
1440     ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
1441     ANGLE_SKIP_TEST_IF(!requestOcclusionQueryExtension());
1442 
1443     const std::string VS =
1444         "#version 300 es\n"
1445         "#extension " +
1446         extensionName() +
1447         ": require\n"
1448         "layout(num_views = 2) in;\n"
1449         "in vec3 vPosition;\n"
1450         "void main()\n"
1451         "{\n"
1452         "       gl_Position.x = gl_ViewID_OVR == 1u ? vPosition.x : 2.0;\n"
1453         "       gl_Position.yzw = vec3(vPosition.yz, 1.);\n"
1454         "}\n";
1455 
1456     const std::string FS =
1457         "#version 300 es\n"
1458         "#extension " +
1459         extensionName() +
1460         ": require\n"
1461         "precision mediump float;\n"
1462         "out vec4 col;\n"
1463         "void main()\n"
1464         "{\n"
1465         "    col = vec4(1,0,0,0);\n"
1466         "}\n";
1467     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1468     updateFBOs(1, 1, 2);
1469 
1470     GLuint result = drawAndRetrieveOcclusionQueryResult(program);
1471     ASSERT_GL_NO_ERROR();
1472     EXPECT_GL_TRUE(result);
1473 }
1474 
1475 // Test that a simple multi-view program which doesn't use gl_ViewID_OVR in neither VS nor FS
1476 // compiles and links without an error.
TEST_P(MultiviewProgramGenerationTest,SimpleProgram)1477 TEST_P(MultiviewProgramGenerationTest, SimpleProgram)
1478 {
1479     if (!requestMultiviewExtension())
1480     {
1481         return;
1482     }
1483 
1484     const std::string VS =
1485         "#version 300 es\n"
1486         "#extension " +
1487         extensionName() +
1488         ": require\n"
1489         "layout(num_views = 2) in;\n"
1490         "void main()\n"
1491         "{\n"
1492         "}\n";
1493 
1494     const std::string FS =
1495         "#version 300 es\n"
1496         "#extension " +
1497         extensionName() +
1498         ": require\n"
1499         "precision mediump float;\n"
1500         "void main()\n"
1501         "{\n"
1502         "}\n";
1503 
1504     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1505     glUseProgram(program);
1506 
1507     EXPECT_GL_NO_ERROR();
1508 }
1509 
1510 // Test that a simple multi-view program which uses gl_ViewID_OVR only in VS compiles and links
1511 // without an error.
TEST_P(MultiviewProgramGenerationTest,UseViewIDInVertexShader)1512 TEST_P(MultiviewProgramGenerationTest, UseViewIDInVertexShader)
1513 {
1514     if (!requestMultiviewExtension())
1515     {
1516         return;
1517     }
1518 
1519     const std::string VS =
1520         "#version 300 es\n"
1521         "#extension " +
1522         extensionName() +
1523         ": require\n"
1524         "layout(num_views = 2) in;\n"
1525         "void main()\n"
1526         "{\n"
1527         "   if (gl_ViewID_OVR == 0u) {\n"
1528         "       gl_Position = vec4(1,0,0,1);\n"
1529         "   } else {\n"
1530         "       gl_Position = vec4(-1,0,0,1);\n"
1531         "   }\n"
1532         "}\n";
1533 
1534     const std::string FS =
1535         "#version 300 es\n"
1536         "#extension " +
1537         extensionName() +
1538         ": require\n"
1539         "precision mediump float;\n"
1540         "void main()\n"
1541         "{\n"
1542         "}\n";
1543 
1544     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1545     glUseProgram(program);
1546 
1547     EXPECT_GL_NO_ERROR();
1548 }
1549 
1550 // Test that a simple multi-view program which uses gl_ViewID_OVR only in FS compiles and links
1551 // without an error.
TEST_P(MultiviewProgramGenerationTest,UseViewIDInFragmentShader)1552 TEST_P(MultiviewProgramGenerationTest, UseViewIDInFragmentShader)
1553 {
1554     if (!requestMultiviewExtension())
1555     {
1556         return;
1557     }
1558 
1559     const std::string VS =
1560         "#version 300 es\n"
1561         "#extension " +
1562         extensionName() +
1563         ": require\n"
1564         "layout(num_views = 2) in;\n"
1565         "void main()\n"
1566         "{\n"
1567         "}\n";
1568 
1569     const std::string FS =
1570         "#version 300 es\n"
1571         "#extension " +
1572         extensionName() +
1573         ": require\n"
1574         "precision mediump float;\n"
1575         "out vec4 col;\n"
1576         "void main()\n"
1577         "{\n"
1578         "   if (gl_ViewID_OVR == 0u) {\n"
1579         "       col = vec4(1,0,0,1);\n"
1580         "   } else {\n"
1581         "       col = vec4(-1,0,0,1);\n"
1582         "   }\n"
1583         "}\n";
1584 
1585     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1586     glUseProgram(program);
1587 
1588     EXPECT_GL_NO_ERROR();
1589 }
1590 
1591 // The test checks that GL_POINTS is correctly rendered.
TEST_P(MultiviewRenderPrimitiveTest,Points)1592 TEST_P(MultiviewRenderPrimitiveTest, Points)
1593 {
1594     if (!requestMultiviewExtension())
1595     {
1596         return;
1597     }
1598 
1599     // Test failing on P400 graphics card (anglebug.com/2228)
1600     ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1601     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1602 
1603     const std::string VS =
1604         "#version 300 es\n"
1605         "#extension " +
1606         extensionName() +
1607         ": require\n"
1608         "layout(num_views = 2) in;\n"
1609         "layout(location=0) in vec2 vPosition;\n"
1610         "void main()\n"
1611         "{\n"
1612         "   gl_PointSize = 1.0;\n"
1613         "   gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n"
1614         "}\n";
1615 
1616     const std::string FS =
1617         "#version 300 es\n"
1618         "#extension " +
1619         extensionName() +
1620         ": require\n"
1621         "precision mediump float;\n"
1622         "out vec4 col;\n"
1623         "void main()\n"
1624         "{\n"
1625         "   col = vec4(0,1,0,1);\n"
1626         "}\n";
1627     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
1628     glUseProgram(program);
1629 
1630     const int kViewWidth  = 4;
1631     const int kViewHeight = 2;
1632     const int kNumViews   = 2;
1633     updateFBOs(kViewWidth, kViewHeight, kNumViews);
1634 
1635     std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 1)};
1636     std::vector<Vector2> vertexDataInClipSpace =
1637         ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1638     setupGeometry(vertexDataInClipSpace);
1639 
1640     glDrawArrays(GL_POINTS, 0, 2);
1641 
1642     const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1643         {{255, 0, 0, 0}, {0, 0, 0, 255}}, {{255, 0, 0, 0}, {0, 0, 0, 255}}};
1644     checkGreenChannel(expectedGreenChannelData[0][0]);
1645 }
1646 
1647 // The test checks that GL_LINES is correctly rendered.
1648 // The behavior of this test is not guaranteed by the spec:
1649 // OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1650 // "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1651 // either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1652 // rule."
TEST_P(MultiviewRenderPrimitiveTest,Lines)1653 TEST_P(MultiviewRenderPrimitiveTest, Lines)
1654 {
1655     if (!requestMultiviewExtension())
1656     {
1657         return;
1658     }
1659     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1660 
1661     GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
1662     ASSERT_NE(program, 0u);
1663     glUseProgram(program);
1664     ASSERT_GL_NO_ERROR();
1665 
1666     const int kViewWidth  = 4;
1667     const int kViewHeight = 2;
1668     const int kNumViews   = 2;
1669     updateFBOs(kViewWidth, kViewHeight, kNumViews);
1670 
1671     std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(4, 0)};
1672     std::vector<Vector2> vertexDataInClipSpace =
1673         ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1674     setupGeometry(vertexDataInClipSpace);
1675 
1676     glDrawArrays(GL_LINES, 0, 2);
1677 
1678     const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1679         {{255, 255, 255, 255}, {0, 0, 0, 0}}, {{255, 255, 255, 255}, {0, 0, 0, 0}}};
1680     checkGreenChannel(expectedGreenChannelData[0][0]);
1681 
1682     glDeleteProgram(program);
1683 }
1684 
1685 // The test checks that GL_LINE_STRIP is correctly rendered.
1686 // The behavior of this test is not guaranteed by the spec:
1687 // OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1688 // "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1689 // either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1690 // rule."
TEST_P(MultiviewRenderPrimitiveTest,LineStrip)1691 TEST_P(MultiviewRenderPrimitiveTest, LineStrip)
1692 {
1693     if (!requestMultiviewExtension())
1694     {
1695         return;
1696     }
1697     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1698 
1699     GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
1700     ASSERT_NE(program, 0u);
1701     glUseProgram(program);
1702     ASSERT_GL_NO_ERROR();
1703 
1704     const int kViewWidth  = 4;
1705     const int kViewHeight = 2;
1706     const int kNumViews   = 2;
1707     updateFBOs(kViewWidth, kViewHeight, kNumViews);
1708 
1709     std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 2)};
1710     std::vector<Vector2> vertexDataInClipSpace =
1711         ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 2);
1712     setupGeometry(vertexDataInClipSpace);
1713 
1714     glDrawArrays(GL_LINE_STRIP, 0, 3);
1715 
1716     const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1717         {{255, 255, 255, 255}, {0, 0, 0, 255}}, {{255, 255, 255, 255}, {0, 0, 0, 255}}};
1718     checkGreenChannel(expectedGreenChannelData[0][0]);
1719 
1720     glDeleteProgram(program);
1721 }
1722 
1723 // The test checks that GL_LINE_LOOP is correctly rendered.
1724 // The behavior of this test is not guaranteed by the spec:
1725 // OpenGL ES 3.0.5 (November 3, 2016), Section 3.5.1 Basic Line Segment Rasterization:
1726 // "The coordinates of a fragment produced by the algorithm may not deviate by more than one unit in
1727 // either x or y window coordinates from a corresponding fragment produced by the diamond-exit
1728 // rule."
TEST_P(MultiviewRenderPrimitiveTest,LineLoop)1729 TEST_P(MultiviewRenderPrimitiveTest, LineLoop)
1730 {
1731     if (!requestMultiviewExtension())
1732     {
1733         return;
1734     }
1735     // Only this subtest fails on intel-hd-630-ubuntu-stable. Driver bug?
1736     // https://anglebug.com/3472
1737     ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
1738     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1739 
1740     GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
1741     ASSERT_NE(program, 0u);
1742     glUseProgram(program);
1743     ASSERT_GL_NO_ERROR();
1744 
1745     const int kViewWidth  = 4;
1746     const int kViewHeight = 4;
1747     const int kNumViews   = 2;
1748     updateFBOs(kViewWidth, kViewHeight, kNumViews);
1749 
1750     std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(3, 0), Vector2I(3, 3),
1751                                                Vector2I(0, 3)};
1752     std::vector<Vector2> vertexDataInClipSpace =
1753         ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 4);
1754     setupGeometry(vertexDataInClipSpace);
1755 
1756     glDrawArrays(GL_LINE_LOOP, 0, 4);
1757     EXPECT_GL_NO_ERROR();
1758 
1759     const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1760         {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}},
1761         {{255, 255, 255, 255}, {255, 0, 0, 255}, {255, 0, 0, 255}, {255, 255, 255, 255}}};
1762     checkGreenChannel(expectedGreenChannelData[0][0]);
1763 
1764     glDeleteProgram(program);
1765 }
1766 
1767 // The test checks that GL_TRIANGLE_STRIP is correctly rendered.
TEST_P(MultiviewRenderPrimitiveTest,TriangleStrip)1768 TEST_P(MultiviewRenderPrimitiveTest, TriangleStrip)
1769 {
1770     if (!requestMultiviewExtension())
1771     {
1772         return;
1773     }
1774     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1775 
1776     GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
1777     ASSERT_NE(program, 0u);
1778     glUseProgram(program);
1779     ASSERT_GL_NO_ERROR();
1780 
1781     std::vector<Vector2> vertexDataInClipSpace = {Vector2(1.0f, 0.0f), Vector2(0.0f, 0.0f),
1782                                                   Vector2(1.0f, 1.0f), Vector2(0.0f, 1.0f)};
1783     setupGeometry(vertexDataInClipSpace);
1784 
1785     const int kViewWidth  = 2;
1786     const int kViewHeight = 2;
1787     const int kNumViews   = 2;
1788     updateFBOs(kViewWidth, kViewHeight, kNumViews);
1789 
1790     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1791 
1792     const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1793         {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1794     checkGreenChannel(expectedGreenChannelData[0][0]);
1795 
1796     glDeleteProgram(program);
1797 }
1798 
1799 // The test checks that GL_TRIANGLE_FAN is correctly rendered.
TEST_P(MultiviewRenderPrimitiveTest,TriangleFan)1800 TEST_P(MultiviewRenderPrimitiveTest, TriangleFan)
1801 {
1802     if (!requestMultiviewExtension())
1803     {
1804         return;
1805     }
1806     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1807 
1808     GLuint program = CreateSimplePassthroughProgram(2, GetParam().mMultiviewExtension);
1809     ASSERT_NE(program, 0u);
1810     glUseProgram(program);
1811     ASSERT_GL_NO_ERROR();
1812 
1813     std::vector<Vector2> vertexDataInClipSpace = {Vector2(0.0f, 0.0f), Vector2(0.0f, 1.0f),
1814                                                   Vector2(1.0f, 1.0f), Vector2(1.0f, 0.0f)};
1815     setupGeometry(vertexDataInClipSpace);
1816 
1817     const int kViewWidth  = 2;
1818     const int kViewHeight = 2;
1819     const int kNumViews   = 2;
1820     updateFBOs(kViewWidth, kViewHeight, kNumViews);
1821 
1822     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1823 
1824     const GLubyte expectedGreenChannelData[kNumViews][kViewHeight][kViewWidth] = {
1825         {{0, 0}, {0, 255}}, {{0, 0}, {0, 255}}};
1826     checkGreenChannel(expectedGreenChannelData[0][0]);
1827 
1828     glDeleteProgram(program);
1829 }
1830 
1831 // Verify that re-linking a program adjusts the attribute divisor.
1832 // The test uses instacing to draw for each view a strips of two red quads and two blue quads next
1833 // to each other. The quads' position and color depend on the corresponding attribute divisors.
TEST_P(MultiviewRenderTest,ProgramRelinkUpdatesAttribDivisor)1834 TEST_P(MultiviewRenderTest, ProgramRelinkUpdatesAttribDivisor)
1835 {
1836     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1837     if (!requestMultiviewExtension(isMultisampled()))
1838     {
1839         return;
1840     }
1841 
1842     // Looks like an incorrect D3D debug layer message is generated on Windows AMD and NVIDIA.
1843     // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
1844     if (IsWindows() && IsD3D11())
1845     {
1846         ignoreD3D11SDKLayersWarnings();
1847     }
1848 
1849     const int kViewWidth  = 4;
1850     const int kViewHeight = 1;
1851     const int kNumViews   = 2;
1852 
1853     const std::string FS =
1854         "#version 300 es\n"
1855         "#extension " +
1856         extensionName() +
1857         ": require\n"
1858         "precision mediump float;\n"
1859         "in vec4 oColor;\n"
1860         "out vec4 col;\n"
1861         "void main()\n"
1862         "{\n"
1863         "    col = oColor;\n"
1864         "}\n";
1865 
1866     auto generateVertexShaderSource = [](int numViews, std::string extensionName) -> std::string {
1867         std::string source =
1868             "#version 300 es\n"
1869             "#extension " +
1870             extensionName +
1871             ": require\n"
1872             "layout(num_views = " +
1873             ToString(numViews) +
1874             ") in;\n"
1875             "in vec3 vPosition;\n"
1876             "in float vOffsetX;\n"
1877             "in vec4 vColor;\n"
1878             "out vec4 oColor;\n"
1879             "void main()\n"
1880             "{\n"
1881             "       vec4 p = vec4(vPosition, 1.);\n"
1882             "       p.x = p.x * 0.25 - 0.75 + vOffsetX;\n"
1883             "       oColor = vColor;\n"
1884             "       gl_Position = p;\n"
1885             "}\n";
1886         return source;
1887     };
1888 
1889     std::string vsSource = generateVertexShaderSource(kNumViews, extensionName());
1890     ANGLE_GL_PROGRAM(program, vsSource.c_str(), FS.c_str());
1891     glUseProgram(program);
1892 
1893     GLint positionLoc;
1894     GLBuffer xOffsetVBO;
1895     GLint xOffsetLoc;
1896     GLBuffer colorVBO;
1897     GLint colorLoc;
1898 
1899     {
1900         // Initialize buffers and setup attributes.
1901         glBindBuffer(GL_ARRAY_BUFFER, xOffsetVBO);
1902         const GLfloat kXOffsetData[4] = {0.0f, 0.5f, 1.0f, 1.5f};
1903         glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4, kXOffsetData, GL_STATIC_DRAW);
1904         xOffsetLoc = glGetAttribLocation(program, "vOffsetX");
1905         glVertexAttribPointer(xOffsetLoc, 1, GL_FLOAT, GL_FALSE, 0, 0);
1906         glVertexAttribDivisor(xOffsetLoc, 1);
1907         glEnableVertexAttribArray(xOffsetLoc);
1908 
1909         glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
1910         const GLColor kColors[2] = {GLColor::red, GLColor::blue};
1911         glBufferData(GL_ARRAY_BUFFER, sizeof(GLColor) * 2, kColors, GL_STATIC_DRAW);
1912         colorLoc = glGetAttribLocation(program, "vColor");
1913         glVertexAttribDivisor(colorLoc, 2);
1914         glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
1915         glEnableVertexAttribArray(colorLoc);
1916 
1917         positionLoc = glGetAttribLocation(program, "vPosition");
1918     }
1919 
1920     {
1921         updateFBOs(kViewWidth, kViewHeight, kNumViews);
1922 
1923         drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
1924         ASSERT_GL_NO_ERROR();
1925 
1926         resolveMultisampledFBO();
1927         EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
1928         EXPECT_EQ(GLColor::red, GetViewColor(1, 0, 0));
1929         EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, 0));
1930         EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, 0));
1931     }
1932 
1933     {
1934         const int kNewNumViews = 3;
1935         vsSource               = generateVertexShaderSource(kNewNumViews, extensionName());
1936         updateFBOs(kViewWidth, kViewHeight, kNewNumViews);
1937 
1938         GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource.c_str());
1939         ASSERT_NE(0u, vs);
1940         GLuint fs = CompileShader(GL_FRAGMENT_SHADER, FS.c_str());
1941         ASSERT_NE(0u, fs);
1942 
1943         GLint numAttachedShaders = 0;
1944         glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
1945 
1946         GLuint attachedShaders[2] = {0u};
1947         glGetAttachedShaders(program, numAttachedShaders, nullptr, attachedShaders);
1948         for (int i = 0; i < 2; ++i)
1949         {
1950             glDetachShader(program, attachedShaders[i]);
1951         }
1952 
1953         glAttachShader(program, vs);
1954         glDeleteShader(vs);
1955 
1956         glAttachShader(program, fs);
1957         glDeleteShader(fs);
1958 
1959         glBindAttribLocation(program, positionLoc, "vPosition");
1960         glBindAttribLocation(program, xOffsetLoc, "vOffsetX");
1961         glBindAttribLocation(program, colorLoc, "vColor");
1962 
1963         glLinkProgram(program);
1964 
1965         drawQuadInstanced(program, "vPosition", 0.0f, 1.0f, true, 4u);
1966         ASSERT_GL_NO_ERROR();
1967 
1968         resolveMultisampledFBO();
1969         for (int i = 0; i < kNewNumViews; ++i)
1970         {
1971             EXPECT_EQ(GLColor::red, GetViewColor(0, 0, i));
1972             EXPECT_EQ(GLColor::red, GetViewColor(1, 0, i));
1973             EXPECT_EQ(GLColor::blue, GetViewColor(2, 0, i));
1974             EXPECT_EQ(GLColor::blue, GetViewColor(3, 0, i));
1975         }
1976     }
1977 }
1978 
1979 // Test that useProgram applies the number of views in computing the final value of the attribute
1980 // divisor.
TEST_P(MultiviewRenderTest,DivisorUpdatedOnProgramChange)1981 TEST_P(MultiviewRenderTest, DivisorUpdatedOnProgramChange)
1982 {
1983     if (!requestMultiviewExtension(isMultisampled()))
1984     {
1985         return;
1986     }
1987 
1988     // Test failing on P400 graphics card (anglebug.com/2228)
1989     ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D11() && IsNVIDIA());
1990     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1991 
1992     // Looks like an incorrect D3D debug layer message is generated on Windows / AMD.
1993     // May be specific to Windows 7 / Windows Server 2008. http://anglebug.com/2778
1994     if (IsWindows() && IsD3D11())
1995     {
1996         ignoreD3D11SDKLayersWarnings();
1997     }
1998 
1999     GLVertexArray vao;
2000     glBindVertexArray(vao);
2001     GLBuffer vbo;
2002     glBindBuffer(GL_ARRAY_BUFFER, vbo);
2003     std::vector<Vector2I> windowCoordinates = {Vector2I(0, 0), Vector2I(1, 0), Vector2I(2, 0),
2004                                                Vector2I(3, 0)};
2005     std::vector<Vector2> vertexDataInClipSpace =
2006         ConvertPixelCoordinatesToClipSpace(windowCoordinates, 4, 1);
2007     // Fill with x positions so that the resulting clip space coordinate fails the clip test.
2008     glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2) * vertexDataInClipSpace.size(),
2009                  vertexDataInClipSpace.data(), GL_STATIC_DRAW);
2010     glEnableVertexAttribArray(0);
2011     glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, nullptr);
2012     glVertexAttribDivisor(0, 1);
2013     ASSERT_GL_NO_ERROR();
2014 
2015     // Create a program and fbo with N views and draw N instances of a point horizontally.
2016     for (int numViews = 2; numViews <= 4; ++numViews)
2017     {
2018         updateFBOs(4, 1, numViews);
2019         ASSERT_GL_NO_ERROR();
2020 
2021         GLuint program = CreateSimplePassthroughProgram(numViews, GetParam().mMultiviewExtension);
2022         ASSERT_NE(program, 0u);
2023         glUseProgram(program);
2024         ASSERT_GL_NO_ERROR();
2025 
2026         glDrawArraysInstanced(GL_POINTS, 0, 1, numViews);
2027 
2028         resolveMultisampledFBO();
2029         for (int view = 0; view < numViews; ++view)
2030         {
2031             for (int j = 0; j < numViews; ++j)
2032             {
2033                 EXPECT_EQ(GLColor::green, GetViewColor(j, 0, view));
2034             }
2035             for (int j = numViews; j < 4; ++j)
2036             {
2037                 EXPECT_EQ(GLColor::transparentBlack, GetViewColor(j, 0, view));
2038             }
2039         }
2040 
2041         glDeleteProgram(program);
2042     }
2043 }
2044 
2045 // The test checks that gl_ViewID_OVR is correctly propagated to the fragment shader.
TEST_P(MultiviewRenderTest,SelectColorBasedOnViewIDOVR)2046 TEST_P(MultiviewRenderTest, SelectColorBasedOnViewIDOVR)
2047 {
2048     if (!requestMultiviewExtension(isMultisampled()))
2049     {
2050         return;
2051     }
2052 
2053     const std::string VS =
2054         "#version 300 es\n"
2055         "#extension " +
2056         extensionName() +
2057         ": require\n"
2058         "layout(num_views = 3) in;\n"
2059         "in vec3 vPosition;\n"
2060         "void main()\n"
2061         "{\n"
2062         "   gl_Position = vec4(vPosition, 1.);\n"
2063         "}\n";
2064 
2065     const std::string FS =
2066         "#version 300 es\n"
2067         "#extension " +
2068         extensionName() +
2069         ": require\n"
2070         "precision mediump float;\n"
2071         "out vec4 col;\n"
2072         "void main()\n"
2073         "{\n"
2074         "    if (gl_ViewID_OVR == 0u) {\n"
2075         "       col = vec4(1,0,0,1);\n"
2076         "    } else if (gl_ViewID_OVR == 1u) {\n"
2077         "       col = vec4(0,1,0,1);\n"
2078         "    } else if (gl_ViewID_OVR == 2u) {\n"
2079         "       col = vec4(0,0,1,1);\n"
2080         "    } else {\n"
2081         "       col = vec4(0,0,0,0);\n"
2082         "    }\n"
2083         "}\n";
2084 
2085     updateFBOs(1, 1, 3);
2086     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
2087 
2088     drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2089     ASSERT_GL_NO_ERROR();
2090 
2091     resolveMultisampledFBO();
2092     EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2093     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2094     EXPECT_EQ(GLColor::blue, GetViewColor(0, 0, 2));
2095 }
2096 
2097 // The test checks that the inactive layers of a 2D texture array are not written to by a
2098 // multi-view program.
TEST_P(MultiviewLayeredRenderTest,RenderToSubrangeOfLayers)2099 TEST_P(MultiviewLayeredRenderTest, RenderToSubrangeOfLayers)
2100 {
2101     ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
2102     if (!requestMultiviewExtension())
2103     {
2104         return;
2105     }
2106 
2107     const std::string VS =
2108         "#version 300 es\n"
2109         "#extension " +
2110         extensionName() +
2111         ": require\n"
2112         "layout(num_views = 2) in;\n"
2113         "in vec3 vPosition;\n"
2114         "void main()\n"
2115         "{\n"
2116         "   gl_Position = vec4(vPosition, 1.);\n"
2117         "}\n";
2118 
2119     const std::string FS =
2120         "#version 300 es\n"
2121         "#extension " +
2122         extensionName() +
2123         ": require\n"
2124         "precision mediump float;\n"
2125         "out vec4 col;\n"
2126         "void main()\n"
2127         "{\n"
2128         "     col = vec4(0,1,0,1);\n"
2129         "}\n";
2130 
2131     updateFBOs(1, 1, 2, 4, 1);
2132     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
2133 
2134     drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2135     ASSERT_GL_NO_ERROR();
2136 
2137     resolveMultisampledFBO();
2138     EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 0));
2139     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2140     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 2));
2141     EXPECT_EQ(GLColor::transparentBlack, GetViewColor(0, 0, 3));
2142 }
2143 
2144 // The D3D11 renderer uses a GS whenever the varyings are flat interpolated which can cause
2145 // potential bugs if the view is selected in the VS. The test contains a program in which the
2146 // gl_InstanceID is passed as a flat varying to the fragment shader where it is used to discard the
2147 // fragment if its value is negative. The gl_InstanceID should never be negative and that branch is
2148 // never taken. One quad is drawn and the color is selected based on the ViewID - red for view 0 and
2149 // green for view 1.
TEST_P(MultiviewRenderTest,FlatInterpolation)2150 TEST_P(MultiviewRenderTest, FlatInterpolation)
2151 {
2152     if (!requestMultiviewExtension(isMultisampled()))
2153     {
2154         return;
2155     }
2156 
2157     const std::string VS =
2158         "#version 300 es\n"
2159         "#extension " +
2160         extensionName() +
2161         ": require\n"
2162         "layout(num_views = 2) in;\n"
2163         "in vec3 vPosition;\n"
2164         "flat out int oInstanceID;\n"
2165         "void main()\n"
2166         "{\n"
2167         "   gl_Position = vec4(vPosition, 1.);\n"
2168         "   oInstanceID = gl_InstanceID;\n"
2169         "}\n";
2170 
2171     const std::string FS =
2172         "#version 300 es\n"
2173         "#extension " +
2174         extensionName() +
2175         ": require\n"
2176         "precision mediump float;\n"
2177         "flat in int oInstanceID;\n"
2178         "out vec4 col;\n"
2179         "void main()\n"
2180         "{\n"
2181         "    if (oInstanceID < 0) {\n"
2182         "       discard;\n"
2183         "    }\n"
2184         "    if (gl_ViewID_OVR == 0u) {\n"
2185         "       col = vec4(1,0,0,1);\n"
2186         "    } else {\n"
2187         "       col = vec4(0,1,0,1);\n"
2188         "    }\n"
2189         "}\n";
2190 
2191     updateFBOs(1, 1, 2);
2192     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
2193 
2194     drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2195     ASSERT_GL_NO_ERROR();
2196 
2197     resolveMultisampledFBO();
2198     EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2199     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2200 }
2201 
2202 // This test assigns gl_ViewID_OVR to a flat int varying and then sets the color based on that
2203 // varying in the fragment shader.
TEST_P(MultiviewRenderTest,FlatInterpolation2)2204 TEST_P(MultiviewRenderTest, FlatInterpolation2)
2205 {
2206     if (!requestMultiviewExtension(isMultisampled()))
2207     {
2208         return;
2209     }
2210 
2211     const std::string VS =
2212         "#version 300 es\n"
2213         "#extension " +
2214         extensionName() +
2215         ": require\n"
2216         "layout(num_views = 2) in;\n"
2217         "in vec3 vPosition;\n"
2218         "flat out int flatVarying;\n"
2219         "void main()\n"
2220         "{\n"
2221         "   gl_Position = vec4(vPosition, 1.);\n"
2222         "   flatVarying = int(gl_ViewID_OVR);\n"
2223         "}\n";
2224 
2225     const std::string FS =
2226         "#version 300 es\n"
2227         "#extension " +
2228         extensionName() +
2229         ": require\n"
2230         "precision mediump float;\n"
2231         "flat in int flatVarying;\n"
2232         "out vec4 col;\n"
2233         "void main()\n"
2234         "{\n"
2235         "    if (flatVarying == 0) {\n"
2236         "       col = vec4(1,0,0,1);\n"
2237         "    } else {\n"
2238         "       col = vec4(0,1,0,1);\n"
2239         "    }\n"
2240         "}\n";
2241 
2242     updateFBOs(1, 1, 2);
2243     ANGLE_GL_PROGRAM(program, VS.c_str(), FS.c_str());
2244 
2245     drawQuad(program, "vPosition", 0.0f, 1.0f, true);
2246     ASSERT_GL_NO_ERROR();
2247 
2248     resolveMultisampledFBO();
2249     EXPECT_EQ(GLColor::red, GetViewColor(0, 0, 0));
2250     EXPECT_EQ(GLColor::green, GetViewColor(0, 0, 1));
2251 }
2252 
VertexShaderOpenGL(ExtensionName multiviewExtension)2253 MultiviewRenderTestParams VertexShaderOpenGL(ExtensionName multiviewExtension)
2254 {
2255     return MultiviewRenderTestParams(0, VertexShaderOpenGL(3, 0, multiviewExtension));
2256 }
2257 
VertexShaderVulkan(ExtensionName multiviewExtension)2258 MultiviewRenderTestParams VertexShaderVulkan(ExtensionName multiviewExtension)
2259 {
2260     return MultiviewRenderTestParams(0, VertexShaderVulkan(3, 0, multiviewExtension));
2261 }
2262 
GeomShaderD3D11(ExtensionName multiviewExtension)2263 MultiviewRenderTestParams GeomShaderD3D11(ExtensionName multiviewExtension)
2264 {
2265     return MultiviewRenderTestParams(0, GeomShaderD3D11(3, 0, multiviewExtension));
2266 }
2267 
VertexShaderD3D11(ExtensionName multiviewExtension)2268 MultiviewRenderTestParams VertexShaderD3D11(ExtensionName multiviewExtension)
2269 {
2270     return MultiviewRenderTestParams(0, VertexShaderD3D11(3, 0, multiviewExtension));
2271 }
2272 
MultisampledVertexShaderOpenGL(ExtensionName multiviewExtension)2273 MultiviewRenderTestParams MultisampledVertexShaderOpenGL(ExtensionName multiviewExtension)
2274 {
2275     return MultiviewRenderTestParams(2, VertexShaderOpenGL(3, 1, multiviewExtension));
2276 }
2277 
MultisampledVertexShaderVulkan(ExtensionName multiviewExtension)2278 MultiviewRenderTestParams MultisampledVertexShaderVulkan(ExtensionName multiviewExtension)
2279 {
2280     return MultiviewRenderTestParams(2, VertexShaderVulkan(3, 1, multiviewExtension));
2281 }
2282 
MultisampledVertexShaderD3D11(ExtensionName multiviewExtension)2283 MultiviewRenderTestParams MultisampledVertexShaderD3D11(ExtensionName multiviewExtension)
2284 {
2285     return MultiviewRenderTestParams(2, VertexShaderD3D11(3, 1, multiviewExtension));
2286 }
2287 
2288 #define ALL_VERTEX_SHADER_CONFIGS(minor)                         \
2289     VertexShaderOpenGL(3, minor, ExtensionName::multiview),      \
2290         VertexShaderVulkan(3, minor, ExtensionName::multiview),  \
2291         VertexShaderD3D11(3, minor, ExtensionName::multiview),   \
2292         VertexShaderOpenGL(3, minor, ExtensionName::multiview2), \
2293         VertexShaderVulkan(3, minor, ExtensionName::multiview2), \
2294         VertexShaderD3D11(3, minor, ExtensionName::multiview2)
2295 
2296 #define ALL_SINGLESAMPLE_CONFIGS()                                                              \
2297     VertexShaderOpenGL(ExtensionName::multiview), VertexShaderVulkan(ExtensionName::multiview), \
2298         VertexShaderD3D11(ExtensionName::multiview), GeomShaderD3D11(ExtensionName::multiview), \
2299         VertexShaderOpenGL(ExtensionName::multiview2),                                          \
2300         VertexShaderVulkan(ExtensionName::multiview2),                                          \
2301         VertexShaderD3D11(ExtensionName::multiview2), GeomShaderD3D11(ExtensionName::multiview2)
2302 
2303 #define ALL_MULTISAMPLE_CONFIGS()                                  \
2304     MultisampledVertexShaderOpenGL(ExtensionName::multiview),      \
2305         MultisampledVertexShaderVulkan(ExtensionName::multiview),  \
2306         MultisampledVertexShaderD3D11(ExtensionName::multiview),   \
2307         MultisampledVertexShaderOpenGL(ExtensionName::multiview2), \
2308         MultisampledVertexShaderVulkan(ExtensionName::multiview2), \
2309         MultisampledVertexShaderD3D11(ExtensionName::multiview2)
2310 
2311 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewDrawValidationTest);
2312 ANGLE_INSTANTIATE_TEST(MultiviewDrawValidationTest, ALL_VERTEX_SHADER_CONFIGS(1));
2313 
2314 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewRenderDualViewTest);
2315 ANGLE_INSTANTIATE_TEST(MultiviewRenderDualViewTest,
2316                        ALL_SINGLESAMPLE_CONFIGS(),
2317                        ALL_MULTISAMPLE_CONFIGS());
2318 
2319 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewRenderTest);
2320 ANGLE_INSTANTIATE_TEST(MultiviewRenderTest, ALL_SINGLESAMPLE_CONFIGS(), ALL_MULTISAMPLE_CONFIGS());
2321 
2322 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewOcclusionQueryTest);
2323 ANGLE_INSTANTIATE_TEST(MultiviewOcclusionQueryTest, ALL_SINGLESAMPLE_CONFIGS());
2324 
2325 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewProgramGenerationTest);
2326 ANGLE_INSTANTIATE_TEST(MultiviewProgramGenerationTest,
2327                        ALL_VERTEX_SHADER_CONFIGS(0),
2328                        GeomShaderD3D11(3, 0, ExtensionName::multiview),
2329                        GeomShaderD3D11(3, 0, ExtensionName::multiview2));
2330 
2331 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewRenderPrimitiveTest);
2332 ANGLE_INSTANTIATE_TEST(MultiviewRenderPrimitiveTest, ALL_SINGLESAMPLE_CONFIGS());
2333 
2334 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiviewLayeredRenderTest);
2335 ANGLE_INSTANTIATE_TEST(MultiviewLayeredRenderTest, ALL_SINGLESAMPLE_CONFIGS());
2336