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 ¶ms)
47 {
48 const MultiviewImplementationParams &base =
49 static_cast<const MultiviewImplementationParams &>(params);
50 os << base;
51 os << "_layered";
52
53 if (params.mSamples > 0)
54 {
55 os << "_samples_" << params.mSamples;
56 }
57 return os;
58 }
59
60 class MultiviewFramebufferTestBase : public MultiviewTestBase,
61 public ::testing::TestWithParam<MultiviewRenderTestParams>
62 {
63 protected:
MultiviewFramebufferTestBase(const PlatformParameters & params,int samples)64 MultiviewFramebufferTestBase(const PlatformParameters ¶ms, int samples)
65 : MultiviewTestBase(params),
66 mViewWidth(0),
67 mViewHeight(0),
68 mNumViews(0),
69 mColorTexture(0u),
70 mDepthTexture(0u),
71 mDrawFramebuffer(0u),
72 mSamples(samples),
73 mResolveTexture(0u)
74 {}
75
FramebufferTestSetUp()76 void FramebufferTestSetUp() { MultiviewTestBase::MultiviewTestBaseSetUp(); }
77
FramebufferTestTearDown()78 void FramebufferTestTearDown()
79 {
80 freeFBOs();
81 MultiviewTestBase::MultiviewTestBaseTearDown();
82 }
83
updateFBOs(int viewWidth,int height,int numViews,int numLayers,int baseViewIndex)84 void updateFBOs(int viewWidth, int height, int numViews, int numLayers, int baseViewIndex)
85 {
86 ASSERT_TRUE(numViews + baseViewIndex <= numLayers);
87
88 freeFBOs();
89
90 mViewWidth = viewWidth;
91 mViewHeight = height;
92 mNumViews = numViews;
93
94 glGenTextures(1, &mColorTexture);
95 glGenTextures(1, &mDepthTexture);
96
97 CreateMultiviewBackingTextures(mSamples, viewWidth, height, numLayers, mColorTexture,
98 mDepthTexture, 0u);
99
100 glGenFramebuffers(1, &mDrawFramebuffer);
101
102 // Create draw framebuffer to be used for multiview rendering.
103 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer);
104 AttachMultiviewTextures(GL_DRAW_FRAMEBUFFER, viewWidth, numViews, baseViewIndex,
105 mColorTexture, mDepthTexture, 0u);
106
107 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
108
109 // Create read framebuffer to be used to retrieve the pixel information for testing
110 // purposes.
111 mReadFramebuffer.resize(numLayers);
112 glGenFramebuffers(static_cast<GLsizei>(mReadFramebuffer.size()), mReadFramebuffer.data());
113 for (int i = 0; i < numLayers; ++i)
114 {
115 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
116 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture, 0,
117 i);
118 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
119 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
120 }
121
122 // Clear the buffers.
123 glViewport(0, 0, viewWidth, height);
124 }
125
updateFBOs(int viewWidth,int height,int numViews)126 void updateFBOs(int viewWidth, int height, int numViews)
127 {
128 updateFBOs(viewWidth, height, numViews, numViews, 0);
129 }
130
bindMemberDrawFramebuffer()131 void bindMemberDrawFramebuffer() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDrawFramebuffer); }
132
133 // In case we have a multisampled framebuffer, creates and binds a resolve framebuffer as the
134 // draw framebuffer, and resolves the read framebuffer to it.
resolveMultisampledFBO()135 void resolveMultisampledFBO()
136 {
137 if (mSamples == 0)
138 {
139 return;
140 }
141 int numLayers = mReadFramebuffer.size();
142 if (mResolveFramebuffer.empty())
143 {
144 ASSERT_TRUE(mResolveTexture == 0u);
145 glGenTextures(1, &mResolveTexture);
146 CreateMultiviewBackingTextures(0, mViewWidth, mViewHeight, numLayers, mResolveTexture,
147 0u, 0u);
148
149 mResolveFramebuffer.resize(numLayers);
150 glGenFramebuffers(static_cast<GLsizei>(mResolveFramebuffer.size()),
151 mResolveFramebuffer.data());
152 for (int i = 0; i < numLayers; ++i)
153 {
154 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
155 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
156 mResolveTexture, 0, i);
157 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE,
158 glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
159 }
160 }
161 for (int i = 0; i < numLayers; ++i)
162 {
163 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[i]);
164 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFramebuffer[i]);
165 glBlitFramebuffer(0, 0, mViewWidth, mViewHeight, 0, 0, mViewWidth, mViewHeight,
166 GL_COLOR_BUFFER_BIT, GL_NEAREST);
167 }
168 }
169
GetViewColor(int x,int y,int view)170 GLColor GetViewColor(int x, int y, int view)
171 {
172 EXPECT_TRUE(static_cast<size_t>(view) < mReadFramebuffer.size());
173 if (mSamples > 0)
174 {
175 EXPECT_TRUE(static_cast<size_t>(view) < mResolveFramebuffer.size());
176 glBindFramebuffer(GL_READ_FRAMEBUFFER, mResolveFramebuffer[view]);
177 }
178 else
179 {
180 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer[view]);
181 }
182 return ReadColor(x, y);
183 }
184
185 // Requests the OVR_multiview(2) extension and returns true if the operation succeeds.
requestMultiviewExtension(bool requireMultiviewMultisample)186 bool requestMultiviewExtension(bool requireMultiviewMultisample)
187 {
188 if (!EnsureGLExtensionEnabled(extensionName()))
189 {
190 std::cout << "Test skipped due to missing " << extensionName() << "." << std::endl;
191 return false;
192 }
193
194 if (requireMultiviewMultisample)
195 {
196 if (!EnsureGLExtensionEnabled("GL_OES_texture_storage_multisample_2d_array"))
197 {
198 std::cout << "Test skipped due to missing GL_ANGLE_multiview_multisample."
199 << std::endl;
200 return false;
201 }
202
203 if (!EnsureGLExtensionEnabled("GL_ANGLE_multiview_multisample"))
204 {
205 std::cout << "Test skipped due to missing GL_ANGLE_multiview_multisample."
206 << std::endl;
207 return false;
208 }
209 }
210 return true;
211 }
212
requestMultiviewExtension()213 bool requestMultiviewExtension() { return requestMultiviewExtension(false); }
extensionName()214 std::string extensionName()
215 {
216 switch (GetParam().mMultiviewExtension)
217 {
218 case multiview:
219 return "GL_OVR_multiview";
220 case multiview2:
221 return "GL_OVR_multiview2";
222 default:
223 // Ignore unknown.
224 return "";
225 }
226 }
227
isMultisampled()228 bool isMultisampled() { return mSamples > 0; }
229
230 int mViewWidth;
231 int mViewHeight;
232 int mNumViews;
233
234 GLuint mColorTexture;
235 GLuint mDepthTexture;
236
237 private:
238 GLuint mDrawFramebuffer;
239 std::vector<GLuint> mReadFramebuffer;
240 int mSamples;
241
242 // For reading back multisampled framebuffer.
243 std::vector<GLuint> mResolveFramebuffer;
244 GLuint mResolveTexture;
245
freeFBOs()246 void freeFBOs()
247 {
248 if (mDrawFramebuffer)
249 {
250 glDeleteFramebuffers(1, &mDrawFramebuffer);
251 mDrawFramebuffer = 0;
252 }
253 if (!mReadFramebuffer.empty())
254 {
255 GLsizei framebufferCount = static_cast<GLsizei>(mReadFramebuffer.size());
256 glDeleteFramebuffers(framebufferCount, mReadFramebuffer.data());
257 mReadFramebuffer.clear();
258 }
259 if (!mResolveFramebuffer.empty())
260 {
261 GLsizei framebufferCount = static_cast<GLsizei>(mResolveFramebuffer.size());
262 glDeleteFramebuffers(framebufferCount, mResolveFramebuffer.data());
263 mResolveFramebuffer.clear();
264 }
265 if (mDepthTexture)
266 {
267 glDeleteTextures(1, &mDepthTexture);
268 mDepthTexture = 0;
269 }
270 if (mColorTexture)
271 {
272 glDeleteTextures(1, &mColorTexture);
273 mColorTexture = 0;
274 }
275 if (mResolveTexture)
276 {
277 glDeleteTextures(1, &mResolveTexture);
278 mResolveTexture = 0;
279 }
280 }
281 };
282
283 class MultiviewRenderTest : public MultiviewFramebufferTestBase
284 {
285 protected:
MultiviewRenderTest()286 MultiviewRenderTest() : MultiviewFramebufferTestBase(GetParam(), GetParam().mSamples) {}
287
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