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 // Framebuffer multiview tests:
7 // The tests modify and examine the multiview state.
8 //
9
10 #include "test_utils/MultiviewTest.h"
11 #include "test_utils/gl_raii.h"
12
13 using namespace angle;
14
15 namespace
16 {
GetDrawBufferRange(size_t numColorAttachments)17 std::vector<GLenum> GetDrawBufferRange(size_t numColorAttachments)
18 {
19 std::vector<GLenum> drawBuffers(numColorAttachments);
20 const size_t kBase = static_cast<size_t>(GL_COLOR_ATTACHMENT0);
21 for (size_t i = 0u; i < drawBuffers.size(); ++i)
22 {
23 drawBuffers[i] = static_cast<GLenum>(kBase + i);
24 }
25 return drawBuffers;
26 }
27 } // namespace
28
29 // Base class for tests that care mostly about draw call validity and not rendering results.
30 class FramebufferMultiviewTest : public MultiviewTest
31 {
32 protected:
FramebufferMultiviewTest()33 FramebufferMultiviewTest() : MultiviewTest() {}
34 };
35
36 class FramebufferMultiviewLayeredClearTest : public FramebufferMultiviewTest
37 {
38 protected:
FramebufferMultiviewLayeredClearTest()39 FramebufferMultiviewLayeredClearTest() : mMultiviewFBO(0), mDepthTex(0), mDepthStencilTex(0) {}
40
testTearDown()41 void testTearDown() override
42 {
43 if (mMultiviewFBO != 0)
44 {
45 glDeleteFramebuffers(1, &mMultiviewFBO);
46 mMultiviewFBO = 0u;
47 }
48 if (!mNonMultiviewFBO.empty())
49 {
50 GLsizei textureCount = static_cast<GLsizei>(mNonMultiviewFBO.size());
51 glDeleteTextures(textureCount, mNonMultiviewFBO.data());
52 mNonMultiviewFBO.clear();
53 }
54 if (!mColorTex.empty())
55 {
56 GLsizei textureCount = static_cast<GLsizei>(mColorTex.size());
57 glDeleteTextures(textureCount, mColorTex.data());
58 mColorTex.clear();
59 }
60 if (mDepthStencilTex != 0u)
61 {
62 glDeleteTextures(1, &mDepthStencilTex);
63 mDepthStencilTex = 0u;
64 }
65 if (mDepthTex != 0u)
66 {
67 glDeleteTextures(1, &mDepthTex);
68 mDepthTex = 0u;
69 }
70 MultiviewTest::testTearDown();
71 }
72
initializeFBOs(int width,int height,int numLayers,int baseViewIndex,int numViews,int numColorAttachments,bool stencil,bool depth)73 void initializeFBOs(int width,
74 int height,
75 int numLayers,
76 int baseViewIndex,
77 int numViews,
78 int numColorAttachments,
79 bool stencil,
80 bool depth)
81 {
82 ASSERT_TRUE(mColorTex.empty());
83 ASSERT_EQ(0u, mDepthStencilTex);
84 ASSERT_EQ(0u, mDepthTex);
85 ASSERT_LE(baseViewIndex + numViews, numLayers);
86
87 // Generate textures.
88 mColorTex.resize(numColorAttachments);
89 GLsizei textureCount = static_cast<GLsizei>(mColorTex.size());
90 glGenTextures(textureCount, mColorTex.data());
91 if (stencil)
92 {
93 glGenTextures(1, &mDepthStencilTex);
94 }
95 else if (depth)
96 {
97 glGenTextures(1, &mDepthTex);
98 }
99
100 CreateMultiviewBackingTextures(0, width, height, numLayers, mColorTex, mDepthTex,
101 mDepthStencilTex);
102
103 glGenFramebuffers(1, &mMultiviewFBO);
104
105 // Generate multiview FBO and attach textures.
106 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
107 AttachMultiviewTextures(GL_FRAMEBUFFER, width, numViews, baseViewIndex, mColorTex,
108 mDepthTex, mDepthStencilTex);
109
110 const auto &drawBuffers = GetDrawBufferRange(numColorAttachments);
111 glDrawBuffers(numColorAttachments, drawBuffers.data());
112
113 // Generate non-multiview FBOs and attach textures.
114 mNonMultiviewFBO.resize(numLayers);
115 GLsizei framebufferCount = static_cast<GLsizei>(mNonMultiviewFBO.size());
116 glGenFramebuffers(framebufferCount, mNonMultiviewFBO.data());
117 for (int i = 0; i < numLayers; ++i)
118 {
119 glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
120 for (int j = 0; j < numColorAttachments; ++j)
121 {
122 glFramebufferTextureLayer(GL_FRAMEBUFFER,
123 static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + j),
124 mColorTex[j], 0, i);
125 }
126 if (stencil)
127 {
128 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
129 mDepthStencilTex, 0, i);
130 }
131 else if (depth)
132 {
133 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mDepthTex, 0, i);
134 }
135 glDrawBuffers(numColorAttachments, drawBuffers.data());
136 }
137
138 ASSERT_GL_NO_ERROR();
139 }
140
getLayerColor(size_t layer,GLenum attachment,GLint x,GLint y)141 GLColor getLayerColor(size_t layer, GLenum attachment, GLint x, GLint y)
142 {
143 EXPECT_LT(layer, mNonMultiviewFBO.size());
144 glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[layer]);
145 glReadBuffer(attachment);
146 return angle::ReadColor(x, y);
147 }
148
getLayerColor(size_t layer,GLenum attachment)149 GLColor getLayerColor(size_t layer, GLenum attachment)
150 {
151 return getLayerColor(layer, attachment, 0, 0);
152 }
153
154 GLuint mMultiviewFBO;
155 std::vector<GLuint> mNonMultiviewFBO;
156
157 private:
158 std::vector<GLuint> mColorTex;
159 GLuint mDepthTex;
160 GLuint mDepthStencilTex;
161 };
162
163 // Test that the framebuffer tokens introduced by OVR_multiview2 can be used to query the
164 // framebuffer state and that their corresponding default values are correctly set.
TEST_P(FramebufferMultiviewTest,DefaultState)165 TEST_P(FramebufferMultiviewTest, DefaultState)
166 {
167 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
168
169 GLFramebuffer fbo;
170 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
171
172 GLTexture tex;
173 glBindTexture(GL_TEXTURE_2D, tex);
174 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
175 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
176
177 GLint numViews = -1;
178 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
179 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR,
180 &numViews);
181 ASSERT_GL_NO_ERROR();
182 EXPECT_EQ(1, numViews);
183
184 GLint baseViewIndex = -1;
185 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
186 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR,
187 &baseViewIndex);
188 ASSERT_GL_NO_ERROR();
189 EXPECT_EQ(0, baseViewIndex);
190 }
191
192 // Test that without having the OVR_multiview2 extension, querying for the framebuffer state using
193 // the OVR_multiview2 tokens results in an INVALID_ENUM error.
TEST_P(FramebufferMultiviewTest,NegativeFramebufferStateQueries)194 TEST_P(FramebufferMultiviewTest, NegativeFramebufferStateQueries)
195 {
196 GLFramebuffer fbo;
197 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
198
199 GLTexture tex;
200 glBindTexture(GL_TEXTURE_2D, tex);
201 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
202 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
203
204 GLint numViews = -1;
205 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
206 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR,
207 &numViews);
208 EXPECT_GL_ERROR(GL_INVALID_ENUM);
209
210 GLint baseViewIndex = -1;
211 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
212 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR,
213 &baseViewIndex);
214 EXPECT_GL_ERROR(GL_INVALID_ENUM);
215 }
216
217 // Test that the correct errors are generated whenever glFramebufferTextureMultiviewOVR is
218 // called with invalid arguments.
TEST_P(FramebufferMultiviewTest,InvalidMultiviewLayeredArguments)219 TEST_P(FramebufferMultiviewTest, InvalidMultiviewLayeredArguments)
220 {
221 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
222
223 GLFramebuffer fbo;
224 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
225
226 GLTexture tex;
227 glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
228 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
229 ASSERT_GL_NO_ERROR();
230
231 // Negative base view index.
232 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, -1, 1);
233 EXPECT_GL_ERROR(GL_INVALID_VALUE);
234
235 // baseViewIndex + numViews is greater than MAX_TEXTURE_LAYERS.
236 GLint maxTextureLayers = 0;
237 glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers);
238 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, maxTextureLayers,
239 1);
240 EXPECT_GL_ERROR(GL_INVALID_VALUE);
241 }
242
243 // Test that an INVALID_OPERATION error is generated whenever the OVR_multiview2 extension is not
244 // available.
TEST_P(FramebufferMultiviewTest,ExtensionNotAvailableCheck)245 TEST_P(FramebufferMultiviewTest, ExtensionNotAvailableCheck)
246 {
247 GLFramebuffer fbo;
248 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
249
250 GLTexture tex;
251 glBindTexture(GL_TEXTURE_2D, tex);
252 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
253
254 ASSERT_GL_NO_ERROR();
255 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 1, 1);
256 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
257 }
258
259 // Test that the active read framebuffer can be read with glCopyTex* if it only has one layered
260 // view.
TEST_P(FramebufferMultiviewTest,CopyTex)261 TEST_P(FramebufferMultiviewTest, CopyTex)
262 {
263 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
264
265 // glCopyTexImage2D generates GL_INVALID_FRAMEBUFFER_OPERATION. http://anglebug.com/42262501
266 ANGLE_SKIP_TEST_IF(IsWindows() && IsOpenGL());
267
268 GLFramebuffer fbo;
269 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
270
271 GLTexture tex;
272 glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
273 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
274
275 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0, 1);
276 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
277 ASSERT_GL_NO_ERROR();
278
279 // Test glCopyTexImage2D and glCopyTexSubImage2D.
280 {
281 GLTexture tex2;
282 glBindTexture(GL_TEXTURE_2D, tex2);
283 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
284
285 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
286 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
287 glClear(GL_COLOR_BUFFER_BIT);
288
289 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 1, 1, 0);
290 ASSERT_GL_NO_ERROR();
291
292 // Test texture contents.
293 glBindFramebuffer(GL_FRAMEBUFFER, 0);
294 draw2DTexturedQuad(0.0f, 1.0f, true);
295 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
296
297 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
298 glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
299 glClear(GL_COLOR_BUFFER_BIT);
300
301 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
302 ASSERT_GL_NO_ERROR();
303
304 glBindFramebuffer(GL_FRAMEBUFFER, 0);
305 draw2DTexturedQuad(0.0f, 1.0f, true);
306 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
307 }
308
309 // Test glCopyTexSubImage3D.
310 {
311 GLTexture tex2;
312 glBindTexture(GL_TEXTURE_3D, tex2);
313 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
314
315 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
316 glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
317 glClear(GL_COLOR_BUFFER_BIT);
318 glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 1, 1);
319 ASSERT_GL_NO_ERROR();
320
321 glBindFramebuffer(GL_FRAMEBUFFER, 0);
322 draw3DTexturedQuad(0.0f, 1.0f, true, 0.0f);
323 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
324 }
325 }
326
327 // Test that glBlitFramebuffer succeeds if the current read framebuffer has just one layered view.
TEST_P(FramebufferMultiviewTest,Blit)328 TEST_P(FramebufferMultiviewTest, Blit)
329 {
330 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
331
332 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
333 glClear(GL_COLOR_BUFFER_BIT);
334
335 GLFramebuffer fbo;
336 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
337
338 GLTexture tex;
339 glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
340 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
341
342 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0, 1);
343 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
344 ASSERT_GL_NO_ERROR();
345
346 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
347 glClear(GL_COLOR_BUFFER_BIT);
348
349 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
350 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
351 glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
352 ASSERT_GL_NO_ERROR();
353
354 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
355 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
356 }
357
358 // Test that glReadPixels succeeds from a layered multiview framebuffer with just one view.
TEST_P(FramebufferMultiviewTest,ReadPixels)359 TEST_P(FramebufferMultiviewTest, ReadPixels)
360 {
361 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
362
363 GLFramebuffer fbo;
364 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
365
366 GLTexture tex;
367 glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
368 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
369
370 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0, 1);
371 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
372 ASSERT_GL_NO_ERROR();
373
374 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
375 glClear(GL_COLOR_BUFFER_BIT);
376
377 GLColor pixelColor;
378 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixelColor.R);
379 ASSERT_GL_NO_ERROR();
380 EXPECT_COLOR_NEAR(GLColor::green, pixelColor, 2);
381 }
382
383 // Test that glFramebufferTextureMultiviewOVR modifies the internal multiview state.
TEST_P(FramebufferMultiviewTest,ModifyLayeredState)384 TEST_P(FramebufferMultiviewTest, ModifyLayeredState)
385 {
386 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
387
388 GLFramebuffer multiviewFBO;
389 glBindFramebuffer(GL_FRAMEBUFFER, multiviewFBO);
390
391 GLTexture tex;
392 glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
393 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
394 ASSERT_GL_NO_ERROR();
395
396 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 1, 2);
397 ASSERT_GL_NO_ERROR();
398
399 GLint numViews = -1;
400 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
401 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR,
402 &numViews);
403 ASSERT_GL_NO_ERROR();
404 EXPECT_EQ(2, numViews);
405
406 GLint baseViewIndex = -1;
407 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
408 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR,
409 &baseViewIndex);
410 ASSERT_GL_NO_ERROR();
411 EXPECT_EQ(1, baseViewIndex);
412 }
413
414 // Test framebuffer completeness status of a layered framebuffer with color attachments.
TEST_P(FramebufferMultiviewTest,IncompleteViewTargetsLayered)415 TEST_P(FramebufferMultiviewTest, IncompleteViewTargetsLayered)
416 {
417 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
418
419 GLFramebuffer fbo;
420 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
421
422 GLTexture tex;
423 glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
424 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
425
426 // Set the 0th attachment and keep it as it is till the end of the test. The 1st color
427 // attachment will be modified to change the framebuffer's status.
428 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, 0, 2);
429 ASSERT_GL_NO_ERROR();
430
431 GLTexture otherTexLayered;
432 glBindTexture(GL_TEXTURE_2D_ARRAY, otherTexLayered);
433 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
434
435 // Test framebuffer completeness when the 1st attachment has a non-multiview layout.
436 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, otherTexLayered, 0, 0);
437 ASSERT_GL_NO_ERROR();
438 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR,
439 glCheckFramebufferStatus(GL_FRAMEBUFFER));
440
441 // Test that framebuffer is complete when the base view index differs.
442 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, otherTexLayered, 0, 1,
443 2);
444 ASSERT_GL_NO_ERROR();
445 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
446
447 // Test framebuffer completeness when an attachment's base+count layers is beyond the texture
448 // layers.
449 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, otherTexLayered, 0, 3,
450 2);
451 ASSERT_GL_NO_ERROR();
452 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR,
453 glCheckFramebufferStatus(GL_FRAMEBUFFER));
454
455 // Test that framebuffer is complete when the number of views, base view index and layouts are
456 // the same.
457 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, otherTexLayered, 0, 0,
458 2);
459 ASSERT_GL_NO_ERROR();
460 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
461 }
462
463 // Test that glClear clears the contents of the color buffer for only the attached layers to a
464 // layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest,ColorBufferClear)465 TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClear)
466 {
467 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
468
469 initializeFBOs(1, 1, 4, 1, 2, 1, false, false);
470
471 // Bind and specify viewport/scissor dimensions for each view.
472 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
473
474 glClearColor(0, 1, 0, 1);
475 glClear(GL_COLOR_BUFFER_BIT);
476
477 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT0));
478 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0));
479 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0));
480 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT0));
481 }
482
483 // Test that glClearBufferfv can be used to clear individual color buffers of a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest,ClearIndividualColorBuffer)484 TEST_P(FramebufferMultiviewLayeredClearTest, ClearIndividualColorBuffer)
485 {
486 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
487
488 initializeFBOs(1, 1, 4, 1, 2, 2, false, false);
489
490 for (int i = 0; i < 2; ++i)
491 {
492 for (int layer = 0; layer < 4; ++layer)
493 {
494 GLenum colorAttachment = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i);
495 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(layer, colorAttachment));
496 }
497 }
498
499 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
500
501 float clearValues0[4] = {0.f, 0.f, 1.f, 1.f};
502 glClearBufferfv(GL_COLOR, 0, clearValues0);
503
504 float clearValues1[4] = {0.f, 1.f, 0.f, 1.f};
505 glClearBufferfv(GL_COLOR, 1, clearValues1);
506
507 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT0));
508 EXPECT_EQ(GLColor::blue, getLayerColor(1, GL_COLOR_ATTACHMENT0));
509 EXPECT_EQ(GLColor::blue, getLayerColor(2, GL_COLOR_ATTACHMENT0));
510 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT0));
511
512 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT1));
513 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT1));
514 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT1));
515 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT1));
516 }
517
518 // Test that glClearBufferfi clears the contents of the stencil buffer for only the attached layers
519 // to a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest,ClearBufferfi)520 TEST_P(FramebufferMultiviewLayeredClearTest, ClearBufferfi)
521 {
522 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
523
524 // Create program to draw a quad.
525 constexpr char kVS[] =
526 "#version 300 es\n"
527 "in vec3 vPos;\n"
528 "void main(){\n"
529 " gl_Position = vec4(vPos, 1.);\n"
530 "}\n";
531 constexpr char kFS[] =
532 "#version 300 es\n"
533 "precision mediump float;\n"
534 "uniform vec3 uCol;\n"
535 "out vec4 col;\n"
536 "void main(){\n"
537 " col = vec4(uCol,1.);\n"
538 "}\n";
539 ANGLE_GL_PROGRAM(program, kVS, kFS);
540 glUseProgram(program);
541 GLuint mColorUniformLoc = glGetUniformLocation(program, "uCol");
542
543 initializeFBOs(1, 1, 4, 1, 2, 1, true, false);
544 glEnable(GL_STENCIL_TEST);
545 glDisable(GL_DEPTH_TEST);
546
547 // Set clear values.
548 glClearColor(1, 0, 0, 1);
549 glClearStencil(0xFF);
550
551 // Clear the color and stencil buffers of each layer.
552 for (size_t i = 0u; i < mNonMultiviewFBO.size(); ++i)
553 {
554 glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
555 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
556 }
557
558 // Switch to multiview framebuffer and clear portions of the texture.
559 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
560 glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.0f, 0);
561
562 // Draw a fullscreen quad, but adjust the stencil function so that only the cleared regions pass
563 // the test.
564 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
565 glStencilFunc(GL_EQUAL, 0x00, 0xFF);
566 for (size_t i = 0u; i < mNonMultiviewFBO.size(); ++i)
567 {
568 glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
569 glUniform3f(mColorUniformLoc, 0.0f, 1.0f, 0.0f);
570 drawQuad(program, "vPos", 0.0f, 1.0f, true);
571 }
572 EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0));
573 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0));
574 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0));
575 EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0));
576 }
577
578 // Test that glClear does not clear the content of a detached texture.
TEST_P(FramebufferMultiviewLayeredClearTest,UnmodifiedDetachedTexture)579 TEST_P(FramebufferMultiviewLayeredClearTest, UnmodifiedDetachedTexture)
580 {
581 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
582
583 initializeFBOs(1, 1, 4, 1, 2, 2, false, false);
584
585 // Clear all attachments.
586 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
587 glClearColor(0, 1, 0, 1);
588 glClear(GL_COLOR_BUFFER_BIT);
589
590 for (int i = 0; i < 2; ++i)
591 {
592 GLenum colorAttachment = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i);
593 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, colorAttachment));
594 EXPECT_EQ(GLColor::green, getLayerColor(1, colorAttachment));
595 EXPECT_EQ(GLColor::green, getLayerColor(2, colorAttachment));
596 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, colorAttachment));
597 }
598
599 // Detach and clear again.
600 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
601 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, 0, 0, 1, 2);
602 glClearColor(1, 1, 0, 1);
603 glClear(GL_COLOR_BUFFER_BIT);
604
605 // Check that color attachment 0 is modified.
606 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT0));
607 EXPECT_EQ(GLColor::yellow, getLayerColor(1, GL_COLOR_ATTACHMENT0));
608 EXPECT_EQ(GLColor::yellow, getLayerColor(2, GL_COLOR_ATTACHMENT0));
609 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT0));
610
611 // Check that color attachment 1 is unmodified.
612 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT1));
613 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT1));
614 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT1));
615 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT1));
616 }
617
618 // Test that glClear clears only the contents within the scissor rectangle of the attached layers.
TEST_P(FramebufferMultiviewLayeredClearTest,ScissoredClear)619 TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClear)
620 {
621 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
622
623 initializeFBOs(2, 1, 4, 1, 2, 1, false, false);
624
625 // Bind and specify viewport/scissor dimensions for each view.
626 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
627
628 glEnable(GL_SCISSOR_TEST);
629 glScissor(1, 0, 1, 1);
630 glClearColor(0, 1, 0, 1);
631 glClear(GL_COLOR_BUFFER_BIT);
632
633 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT0, 0, 0));
634 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT0, 1, 0));
635
636 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(1, GL_COLOR_ATTACHMENT0, 0, 0));
637 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0, 1, 0));
638
639 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(2, GL_COLOR_ATTACHMENT0, 0, 0));
640 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0, 1, 0));
641
642 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT0, 0, 0));
643 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT0, 1, 0));
644 }
645
646 // Test that glClearBufferfi clears the contents of the stencil buffer for only the attached layers
647 // to a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest,ScissoredClearBufferfi)648 TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClearBufferfi)
649 {
650 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
651
652 // Create program to draw a quad.
653 constexpr char kVS[] =
654 "#version 300 es\n"
655 "in vec3 vPos;\n"
656 "void main(){\n"
657 " gl_Position = vec4(vPos, 1.);\n"
658 "}\n";
659 constexpr char kFS[] =
660 "#version 300 es\n"
661 "precision mediump float;\n"
662 "uniform vec3 uCol;\n"
663 "out vec4 col;\n"
664 "void main(){\n"
665 " col = vec4(uCol,1.);\n"
666 "}\n";
667 ANGLE_GL_PROGRAM(program, kVS, kFS);
668 glUseProgram(program);
669 GLuint mColorUniformLoc = glGetUniformLocation(program, "uCol");
670
671 initializeFBOs(1, 2, 4, 1, 2, 1, true, false);
672 glEnable(GL_STENCIL_TEST);
673 glDisable(GL_DEPTH_TEST);
674
675 // Set clear values.
676 glClearColor(1, 0, 0, 1);
677 glClearStencil(0xFF);
678
679 // Clear the color and stencil buffers of each layer.
680 for (size_t i = 0u; i < mNonMultiviewFBO.size(); ++i)
681 {
682 glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
683 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
684 }
685
686 // Switch to multiview framebuffer and clear portions of the texture.
687 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
688 glEnable(GL_SCISSOR_TEST);
689 glScissor(0, 0, 1, 1);
690 glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.0f, 0);
691 glDisable(GL_SCISSOR_TEST);
692
693 // Draw a fullscreen quad, but adjust the stencil function so that only the cleared regions pass
694 // the test.
695 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
696 glStencilFunc(GL_EQUAL, 0x00, 0xFF);
697 glUniform3f(mColorUniformLoc, 0.0f, 1.0f, 0.0f);
698 for (size_t i = 0u; i < mNonMultiviewFBO.size(); ++i)
699 {
700 glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
701 drawQuad(program, "vPos", 0.0f, 1.0f, true);
702 }
703 EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0, 0, 0));
704 EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0, 0, 1));
705 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0, 0, 0));
706 EXPECT_EQ(GLColor::red, getLayerColor(1, GL_COLOR_ATTACHMENT0, 0, 1));
707 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0, 0, 0));
708 EXPECT_EQ(GLColor::red, getLayerColor(2, GL_COLOR_ATTACHMENT0, 0, 1));
709 EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0, 0, 0));
710 EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0, 0, 1));
711 }
712
713 // Test that detaching an attachment does not generate an error whenever the multi-view related
714 // arguments are invalid.
TEST_P(FramebufferMultiviewTest,InvalidMultiviewArgumentsOnDetach)715 TEST_P(FramebufferMultiviewTest, InvalidMultiviewArgumentsOnDetach)
716 {
717 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
718
719 GLFramebuffer fbo;
720 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
721
722 // Invalid base view index.
723 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, -1, 1);
724 EXPECT_GL_NO_ERROR();
725
726 // Invalid number of views.
727 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, 0, 0);
728 EXPECT_GL_NO_ERROR();
729 }
730
731 // Test that glClear clears the contents of the color buffer whenever all layers of a 2D texture
732 // array are attached. The test is added because a special fast code path is used for this case.
TEST_P(FramebufferMultiviewLayeredClearTest,ColorBufferClearAllLayersAttached)733 TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClearAllLayersAttached)
734 {
735 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
736
737 initializeFBOs(1, 1, 2, 0, 2, 1, false, false);
738
739 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
740 glClearColor(0, 1, 0, 1);
741 glClear(GL_COLOR_BUFFER_BIT);
742
743 EXPECT_EQ(GLColor::green, getLayerColor(0, GL_COLOR_ATTACHMENT0));
744 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0));
745 }
746
747 // Test that attaching a multisampled texture array is not possible if all the required extensions
748 // are not enabled.
TEST_P(FramebufferMultiviewTest,NegativeMultisampledFramebufferTest)749 TEST_P(FramebufferMultiviewTest, NegativeMultisampledFramebufferTest)
750 {
751 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
752
753 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_storage_multisample_2d_array"));
754
755 // We don't enable OVR_multiview2_multisample
756
757 GLTexture multisampleTexture;
758 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, multisampleTexture);
759
760 GLFramebuffer fbo;
761 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
762 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, multisampleTexture, 0, 0,
763 2);
764 // From the extension spec: "An INVALID_OPERATION error is generated if texture is not zero, and
765 // does not name an existing texture object of type TEXTURE_2D_ARRAY."
766 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
767 }
768
769 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferMultiviewTest);
770 ANGLE_INSTANTIATE_TEST(FramebufferMultiviewTest,
771 VertexShaderOpenGL(3, 0, ExtensionName::multiview),
772 VertexShaderVulkan(3, 0, ExtensionName::multiview),
773 GeomShaderD3D11(3, 0, ExtensionName::multiview),
774 VertexShaderOpenGL(3, 0, ExtensionName::multiview2),
775 VertexShaderVulkan(3, 0, ExtensionName::multiview2),
776 GeomShaderD3D11(3, 0, ExtensionName::multiview2));
777
778 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferMultiviewLayeredClearTest);
779 ANGLE_INSTANTIATE_TEST(FramebufferMultiviewLayeredClearTest,
780 VertexShaderOpenGL(3, 0, ExtensionName::multiview),
781 VertexShaderVulkan(3, 0, ExtensionName::multiview),
782 GeomShaderD3D11(3, 0, ExtensionName::multiview),
783 VertexShaderOpenGL(3, 0, ExtensionName::multiview2),
784 VertexShaderVulkan(3, 0, ExtensionName::multiview2),
785 GeomShaderD3D11(3, 0, ExtensionName::multiview2));
786