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/3857
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_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(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_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(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_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(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 base view index differs.
436 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, otherTexLayered, 0, 1,
437 2);
438 ASSERT_GL_NO_ERROR();
439 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR,
440 glCheckFramebufferStatus(GL_FRAMEBUFFER));
441
442 // Test framebuffer completeness when the 1st attachment has a non-multiview layout.
443 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, otherTexLayered, 0, 0);
444 ASSERT_GL_NO_ERROR();
445 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR,
446 glCheckFramebufferStatus(GL_FRAMEBUFFER));
447
448 // Test that framebuffer is complete when the number of views, base view index and layouts are
449 // the same.
450 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, otherTexLayered, 0, 0,
451 2);
452 ASSERT_GL_NO_ERROR();
453 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
454 }
455
456 // Test that glClear clears the contents of the color buffer for only the attached layers to a
457 // layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest,ColorBufferClear)458 TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClear)
459 {
460 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
461
462 initializeFBOs(1, 1, 4, 1, 2, 1, false, false);
463
464 // Bind and specify viewport/scissor dimensions for each view.
465 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
466
467 glClearColor(0, 1, 0, 1);
468 glClear(GL_COLOR_BUFFER_BIT);
469
470 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT0));
471 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0));
472 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0));
473 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT0));
474 }
475
476 // Test that glClearBufferfv can be used to clear individual color buffers of a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest,ClearIndividualColorBuffer)477 TEST_P(FramebufferMultiviewLayeredClearTest, ClearIndividualColorBuffer)
478 {
479 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
480
481 initializeFBOs(1, 1, 4, 1, 2, 2, false, false);
482
483 for (int i = 0; i < 2; ++i)
484 {
485 for (int layer = 0; layer < 4; ++layer)
486 {
487 GLenum colorAttachment = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i);
488 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(layer, colorAttachment));
489 }
490 }
491
492 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
493
494 float clearValues0[4] = {0.f, 0.f, 1.f, 1.f};
495 glClearBufferfv(GL_COLOR, 0, clearValues0);
496
497 float clearValues1[4] = {0.f, 1.f, 0.f, 1.f};
498 glClearBufferfv(GL_COLOR, 1, clearValues1);
499
500 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT0));
501 EXPECT_EQ(GLColor::blue, getLayerColor(1, GL_COLOR_ATTACHMENT0));
502 EXPECT_EQ(GLColor::blue, getLayerColor(2, GL_COLOR_ATTACHMENT0));
503 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT0));
504
505 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT1));
506 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT1));
507 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT1));
508 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT1));
509 }
510
511 // Test that glClearBufferfi clears the contents of the stencil buffer for only the attached layers
512 // to a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest,ClearBufferfi)513 TEST_P(FramebufferMultiviewLayeredClearTest, ClearBufferfi)
514 {
515 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
516
517 // Create program to draw a quad.
518 constexpr char kVS[] =
519 "#version 300 es\n"
520 "in vec3 vPos;\n"
521 "void main(){\n"
522 " gl_Position = vec4(vPos, 1.);\n"
523 "}\n";
524 constexpr char kFS[] =
525 "#version 300 es\n"
526 "precision mediump float;\n"
527 "uniform vec3 uCol;\n"
528 "out vec4 col;\n"
529 "void main(){\n"
530 " col = vec4(uCol,1.);\n"
531 "}\n";
532 ANGLE_GL_PROGRAM(program, kVS, kFS);
533 glUseProgram(program);
534 GLuint mColorUniformLoc = glGetUniformLocation(program, "uCol");
535
536 initializeFBOs(1, 1, 4, 1, 2, 1, true, false);
537 glEnable(GL_STENCIL_TEST);
538 glDisable(GL_DEPTH_TEST);
539
540 // Set clear values.
541 glClearColor(1, 0, 0, 1);
542 glClearStencil(0xFF);
543
544 // Clear the color and stencil buffers of each layer.
545 for (size_t i = 0u; i < mNonMultiviewFBO.size(); ++i)
546 {
547 glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
548 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
549 }
550
551 // Switch to multiview framebuffer and clear portions of the texture.
552 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
553 glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.0f, 0);
554
555 // Draw a fullscreen quad, but adjust the stencil function so that only the cleared regions pass
556 // the test.
557 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
558 glStencilFunc(GL_EQUAL, 0x00, 0xFF);
559 for (size_t i = 0u; i < mNonMultiviewFBO.size(); ++i)
560 {
561 glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
562 glUniform3f(mColorUniformLoc, 0.0f, 1.0f, 0.0f);
563 drawQuad(program, "vPos", 0.0f, 1.0f, true);
564 }
565 EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0));
566 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0));
567 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0));
568 EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0));
569 }
570
571 // Test that glClear does not clear the content of a detached texture.
TEST_P(FramebufferMultiviewLayeredClearTest,UnmodifiedDetachedTexture)572 TEST_P(FramebufferMultiviewLayeredClearTest, UnmodifiedDetachedTexture)
573 {
574 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
575
576 initializeFBOs(1, 1, 4, 1, 2, 2, false, false);
577
578 // Clear all attachments.
579 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
580 glClearColor(0, 1, 0, 1);
581 glClear(GL_COLOR_BUFFER_BIT);
582
583 for (int i = 0; i < 2; ++i)
584 {
585 GLenum colorAttachment = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i);
586 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, colorAttachment));
587 EXPECT_EQ(GLColor::green, getLayerColor(1, colorAttachment));
588 EXPECT_EQ(GLColor::green, getLayerColor(2, colorAttachment));
589 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, colorAttachment));
590 }
591
592 // Detach and clear again.
593 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
594 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, 0, 0, 1, 2);
595 glClearColor(1, 1, 0, 1);
596 glClear(GL_COLOR_BUFFER_BIT);
597
598 // Check that color attachment 0 is modified.
599 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT0));
600 EXPECT_EQ(GLColor::yellow, getLayerColor(1, GL_COLOR_ATTACHMENT0));
601 EXPECT_EQ(GLColor::yellow, getLayerColor(2, GL_COLOR_ATTACHMENT0));
602 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT0));
603
604 // Check that color attachment 1 is unmodified.
605 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT1));
606 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT1));
607 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT1));
608 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT1));
609 }
610
611 // Test that glClear clears only the contents within the scissor rectangle of the attached layers.
TEST_P(FramebufferMultiviewLayeredClearTest,ScissoredClear)612 TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClear)
613 {
614 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
615
616 initializeFBOs(2, 1, 4, 1, 2, 1, false, false);
617
618 // Bind and specify viewport/scissor dimensions for each view.
619 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
620
621 glEnable(GL_SCISSOR_TEST);
622 glScissor(1, 0, 1, 1);
623 glClearColor(0, 1, 0, 1);
624 glClear(GL_COLOR_BUFFER_BIT);
625
626 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT0, 0, 0));
627 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(0, GL_COLOR_ATTACHMENT0, 1, 0));
628
629 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(1, GL_COLOR_ATTACHMENT0, 0, 0));
630 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0, 1, 0));
631
632 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(2, GL_COLOR_ATTACHMENT0, 0, 0));
633 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0, 1, 0));
634
635 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT0, 0, 0));
636 EXPECT_EQ(GLColor::transparentBlack, getLayerColor(3, GL_COLOR_ATTACHMENT0, 1, 0));
637 }
638
639 // Test that glClearBufferfi clears the contents of the stencil buffer for only the attached layers
640 // to a layered FBO.
TEST_P(FramebufferMultiviewLayeredClearTest,ScissoredClearBufferfi)641 TEST_P(FramebufferMultiviewLayeredClearTest, ScissoredClearBufferfi)
642 {
643 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
644
645 // Create program to draw a quad.
646 constexpr char kVS[] =
647 "#version 300 es\n"
648 "in vec3 vPos;\n"
649 "void main(){\n"
650 " gl_Position = vec4(vPos, 1.);\n"
651 "}\n";
652 constexpr char kFS[] =
653 "#version 300 es\n"
654 "precision mediump float;\n"
655 "uniform vec3 uCol;\n"
656 "out vec4 col;\n"
657 "void main(){\n"
658 " col = vec4(uCol,1.);\n"
659 "}\n";
660 ANGLE_GL_PROGRAM(program, kVS, kFS);
661 glUseProgram(program);
662 GLuint mColorUniformLoc = glGetUniformLocation(program, "uCol");
663
664 initializeFBOs(1, 2, 4, 1, 2, 1, true, false);
665 glEnable(GL_STENCIL_TEST);
666 glDisable(GL_DEPTH_TEST);
667
668 // Set clear values.
669 glClearColor(1, 0, 0, 1);
670 glClearStencil(0xFF);
671
672 // Clear the color and stencil buffers of each layer.
673 for (size_t i = 0u; i < mNonMultiviewFBO.size(); ++i)
674 {
675 glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
676 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
677 }
678
679 // Switch to multiview framebuffer and clear portions of the texture.
680 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
681 glEnable(GL_SCISSOR_TEST);
682 glScissor(0, 0, 1, 1);
683 glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.0f, 0);
684 glDisable(GL_SCISSOR_TEST);
685
686 // Draw a fullscreen quad, but adjust the stencil function so that only the cleared regions pass
687 // the test.
688 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
689 glStencilFunc(GL_EQUAL, 0x00, 0xFF);
690 glUniform3f(mColorUniformLoc, 0.0f, 1.0f, 0.0f);
691 for (size_t i = 0u; i < mNonMultiviewFBO.size(); ++i)
692 {
693 glBindFramebuffer(GL_FRAMEBUFFER, mNonMultiviewFBO[i]);
694 drawQuad(program, "vPos", 0.0f, 1.0f, true);
695 }
696 EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0, 0, 0));
697 EXPECT_EQ(GLColor::red, getLayerColor(0, GL_COLOR_ATTACHMENT0, 0, 1));
698 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0, 0, 0));
699 EXPECT_EQ(GLColor::red, getLayerColor(1, GL_COLOR_ATTACHMENT0, 0, 1));
700 EXPECT_EQ(GLColor::green, getLayerColor(2, GL_COLOR_ATTACHMENT0, 0, 0));
701 EXPECT_EQ(GLColor::red, getLayerColor(2, GL_COLOR_ATTACHMENT0, 0, 1));
702 EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0, 0, 0));
703 EXPECT_EQ(GLColor::red, getLayerColor(3, GL_COLOR_ATTACHMENT0, 0, 1));
704 }
705
706 // Test that detaching an attachment does not generate an error whenever the multi-view related
707 // arguments are invalid.
TEST_P(FramebufferMultiviewTest,InvalidMultiviewArgumentsOnDetach)708 TEST_P(FramebufferMultiviewTest, InvalidMultiviewArgumentsOnDetach)
709 {
710 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
711
712 GLFramebuffer fbo;
713 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
714
715 // Invalid base view index.
716 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, -1, 1);
717 EXPECT_GL_NO_ERROR();
718
719 // Invalid number of views.
720 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0, 0, 0);
721 EXPECT_GL_NO_ERROR();
722 }
723
724 // Test that glClear clears the contents of the color buffer whenever all layers of a 2D texture
725 // array are attached. The test is added because a special fast code path is used for this case.
TEST_P(FramebufferMultiviewLayeredClearTest,ColorBufferClearAllLayersAttached)726 TEST_P(FramebufferMultiviewLayeredClearTest, ColorBufferClearAllLayersAttached)
727 {
728 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
729
730 initializeFBOs(1, 1, 2, 0, 2, 1, false, false);
731
732 glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
733 glClearColor(0, 1, 0, 1);
734 glClear(GL_COLOR_BUFFER_BIT);
735
736 EXPECT_EQ(GLColor::green, getLayerColor(0, GL_COLOR_ATTACHMENT0));
737 EXPECT_EQ(GLColor::green, getLayerColor(1, GL_COLOR_ATTACHMENT0));
738 }
739
740 // Test that attaching a multisampled texture array is not possible if all the required extensions
741 // are not enabled.
TEST_P(FramebufferMultiviewTest,NegativeMultisampledFramebufferTest)742 TEST_P(FramebufferMultiviewTest, NegativeMultisampledFramebufferTest)
743 {
744 ANGLE_SKIP_TEST_IF(!requestMultiviewExtension());
745
746 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_texture_storage_multisample_2d_array"));
747
748 // We don't enable OVR_multiview2_multisample
749
750 GLTexture multisampleTexture;
751 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, multisampleTexture);
752
753 GLFramebuffer fbo;
754 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
755 glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, multisampleTexture, 0, 0,
756 2);
757 // From the extension spec: "An INVALID_OPERATION error is generated if texture is not zero, and
758 // does not name an existing texture object of type TEXTURE_2D_ARRAY."
759 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
760 }
761
762 ANGLE_INSTANTIATE_TEST(FramebufferMultiviewTest,
763 VertexShaderOpenGL(3, 0, ExtensionName::multiview),
764 GeomShaderD3D11(3, 0, ExtensionName::multiview),
765 VertexShaderOpenGL(3, 0, ExtensionName::multiview2),
766 GeomShaderD3D11(3, 0, ExtensionName::multiview2));
767 ANGLE_INSTANTIATE_TEST(FramebufferMultiviewLayeredClearTest,
768 VertexShaderOpenGL(3, 0, ExtensionName::multiview),
769 GeomShaderD3D11(3, 0, ExtensionName::multiview),
770 VertexShaderOpenGL(3, 0, ExtensionName::multiview2),
771 GeomShaderD3D11(3, 0, ExtensionName::multiview2));
772