1 //
2 // Copyright 2015 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 tests:
7 // Various tests related for Frambuffers.
8 //
9
10 #include "platform/FeaturesD3D.h"
11 #include "test_utils/ANGLETest.h"
12 #include "test_utils/gl_raii.h"
13
14 using namespace angle;
15
16 namespace
17 {
18
ExpectFramebufferCompleteOrUnsupported(GLenum binding)19 void ExpectFramebufferCompleteOrUnsupported(GLenum binding)
20 {
21 GLenum status = glCheckFramebufferStatus(binding);
22 EXPECT_TRUE(status == GL_FRAMEBUFFER_COMPLETE || status == GL_FRAMEBUFFER_UNSUPPORTED);
23 }
24
25 } // anonymous namespace
26
27 class FramebufferFormatsTest : public ANGLETest
28 {
29 protected:
FramebufferFormatsTest()30 FramebufferFormatsTest() : mFramebuffer(0), mTexture(0), mRenderbuffer(0), mProgram(0)
31 {
32 setWindowWidth(128);
33 setWindowHeight(128);
34 setConfigRedBits(8);
35 setConfigGreenBits(8);
36 setConfigBlueBits(8);
37 setConfigAlphaBits(8);
38 }
39
checkBitCount(GLuint fbo,GLenum channel,GLint minBits)40 void checkBitCount(GLuint fbo, GLenum channel, GLint minBits)
41 {
42 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
43
44 GLint bits = 0;
45 glGetIntegerv(channel, &bits);
46
47 if (minBits == 0)
48 {
49 EXPECT_EQ(minBits, bits);
50 }
51 else
52 {
53 EXPECT_GE(bits, minBits);
54 }
55 }
56
testBitCounts(GLuint fbo,GLint minRedBits,GLint minGreenBits,GLint minBlueBits,GLint minAlphaBits,GLint minDepthBits,GLint minStencilBits)57 void testBitCounts(GLuint fbo,
58 GLint minRedBits,
59 GLint minGreenBits,
60 GLint minBlueBits,
61 GLint minAlphaBits,
62 GLint minDepthBits,
63 GLint minStencilBits)
64 {
65 checkBitCount(fbo, GL_RED_BITS, minRedBits);
66 checkBitCount(fbo, GL_GREEN_BITS, minGreenBits);
67 checkBitCount(fbo, GL_BLUE_BITS, minBlueBits);
68 checkBitCount(fbo, GL_ALPHA_BITS, minAlphaBits);
69 checkBitCount(fbo, GL_DEPTH_BITS, minDepthBits);
70 checkBitCount(fbo, GL_STENCIL_BITS, minStencilBits);
71 }
72
testTextureFormat(GLenum internalFormat,GLint minRedBits,GLint minGreenBits,GLint minBlueBits,GLint minAlphaBits)73 void testTextureFormat(GLenum internalFormat,
74 GLint minRedBits,
75 GLint minGreenBits,
76 GLint minBlueBits,
77 GLint minAlphaBits)
78 {
79 glGenTextures(1, &mTexture);
80 glBindTexture(GL_TEXTURE_2D, mTexture);
81
82 if (getClientMajorVersion() >= 3)
83 {
84 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
85 }
86 else
87 {
88 glTexStorage2DEXT(GL_TEXTURE_2D, 1, internalFormat, 1, 1);
89 }
90
91 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
92
93 testBitCounts(mFramebuffer, minRedBits, minGreenBits, minBlueBits, minAlphaBits, 0, 0);
94 }
95
testRenderbufferMultisampleFormat(int minESVersion,GLenum attachmentType,GLenum internalFormat)96 void testRenderbufferMultisampleFormat(int minESVersion,
97 GLenum attachmentType,
98 GLenum internalFormat)
99 {
100 int clientVersion = getClientMajorVersion();
101 if (clientVersion < minESVersion)
102 {
103 return;
104 }
105
106 // Check that multisample is supported with at least two samples (minimum required is 1)
107 bool supports2Samples = false;
108
109 if (clientVersion == 2)
110 {
111 if (IsGLExtensionEnabled("ANGLE_framebuffer_multisample"))
112 {
113 int maxSamples;
114 glGetIntegerv(GL_MAX_SAMPLES_ANGLE, &maxSamples);
115 supports2Samples = maxSamples >= 2;
116 }
117 }
118 else
119 {
120 assert(clientVersion >= 3);
121 int maxSamples;
122 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
123 supports2Samples = maxSamples >= 2;
124 }
125
126 if (!supports2Samples)
127 {
128 return;
129 }
130
131 glGenRenderbuffers(1, &mRenderbuffer);
132 glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
133
134 EXPECT_GL_NO_ERROR();
135 glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, 2, internalFormat, 128, 128);
136 EXPECT_GL_NO_ERROR();
137 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentType, GL_RENDERBUFFER, mRenderbuffer);
138 EXPECT_GL_NO_ERROR();
139 }
140
testZeroHeightRenderbuffer()141 void testZeroHeightRenderbuffer()
142 {
143 glGenRenderbuffers(1, &mRenderbuffer);
144 glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
145 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 0);
146 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
147 mRenderbuffer);
148 EXPECT_GL_NO_ERROR();
149 }
150
testSetUp()151 void testSetUp() override
152 {
153 glGenFramebuffers(1, &mFramebuffer);
154 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
155 }
156
testTearDown()157 void testTearDown() override
158 {
159 if (mTexture != 0)
160 {
161 glDeleteTextures(1, &mTexture);
162 mTexture = 0;
163 }
164
165 if (mRenderbuffer != 0)
166 {
167 glDeleteRenderbuffers(1, &mRenderbuffer);
168 mRenderbuffer = 0;
169 }
170
171 if (mFramebuffer != 0)
172 {
173 glDeleteFramebuffers(1, &mFramebuffer);
174 mFramebuffer = 0;
175 }
176
177 if (mProgram != 0)
178 {
179 glDeleteProgram(mProgram);
180 mProgram = 0;
181 }
182 }
183
184 GLuint mFramebuffer;
185 GLuint mTexture;
186 GLuint mRenderbuffer;
187 GLuint mProgram;
188 };
189
TEST_P(FramebufferFormatsTest,RGBA4)190 TEST_P(FramebufferFormatsTest, RGBA4)
191 {
192 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
193 !IsGLExtensionEnabled("GL_EXT_texture_storage"));
194
195 testTextureFormat(GL_RGBA4, 4, 4, 4, 4);
196 }
197
TEST_P(FramebufferFormatsTest,RGB565)198 TEST_P(FramebufferFormatsTest, RGB565)
199 {
200 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
201 !IsGLExtensionEnabled("GL_EXT_texture_storage"));
202
203 testTextureFormat(GL_RGB565, 5, 6, 5, 0);
204 }
205
TEST_P(FramebufferFormatsTest,RGB8)206 TEST_P(FramebufferFormatsTest, RGB8)
207 {
208 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
209 (!IsGLExtensionEnabled("GL_OES_rgb8_rgba8") ||
210 !IsGLExtensionEnabled("GL_EXT_texture_storage")));
211
212 testTextureFormat(GL_RGB8_OES, 8, 8, 8, 0);
213 }
214
TEST_P(FramebufferFormatsTest,BGRA8)215 TEST_P(FramebufferFormatsTest, BGRA8)
216 {
217 ANGLE_SKIP_TEST_IF(
218 !IsGLExtensionEnabled("GL_EXT_texture_format_BGRA8888") ||
219 (getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_EXT_texture_storage")));
220
221 testTextureFormat(GL_BGRA8_EXT, 8, 8, 8, 8);
222 }
223
TEST_P(FramebufferFormatsTest,RGBA8)224 TEST_P(FramebufferFormatsTest, RGBA8)
225 {
226 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
227 (!IsGLExtensionEnabled("GL_OES_rgb8_rgba8") ||
228 !IsGLExtensionEnabled("GL_EXT_texture_storage")));
229
230 testTextureFormat(GL_RGBA8_OES, 8, 8, 8, 8);
231 }
232
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_DEPTH16)233 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_DEPTH16)
234 {
235 testRenderbufferMultisampleFormat(2, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT16);
236 }
237
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_DEPTH24)238 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_DEPTH24)
239 {
240 testRenderbufferMultisampleFormat(3, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT24);
241 }
242
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_DEPTH32F)243 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_DEPTH32F)
244 {
245 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
246
247 testRenderbufferMultisampleFormat(3, GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT32F);
248 }
249
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_DEPTH24_STENCIL8)250 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_DEPTH24_STENCIL8)
251 {
252 testRenderbufferMultisampleFormat(3, GL_DEPTH_STENCIL_ATTACHMENT, GL_DEPTH24_STENCIL8);
253 }
254
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_DEPTH32F_STENCIL8)255 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_DEPTH32F_STENCIL8)
256 {
257 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
258
259 testRenderbufferMultisampleFormat(3, GL_DEPTH_STENCIL_ATTACHMENT, GL_DEPTH32F_STENCIL8);
260 }
261
TEST_P(FramebufferFormatsTest,RenderbufferMultisample_STENCIL_INDEX8)262 TEST_P(FramebufferFormatsTest, RenderbufferMultisample_STENCIL_INDEX8)
263 {
264 // TODO(geofflang): Figure out how to support GLSTENCIL_INDEX8 on desktop GL
265 ANGLE_SKIP_TEST_IF(IsDesktopOpenGL());
266
267 testRenderbufferMultisampleFormat(2, GL_STENCIL_ATTACHMENT, GL_STENCIL_INDEX8);
268 }
269
270 // Test that binding an incomplete cube map is rejected by ANGLE.
TEST_P(FramebufferFormatsTest,IncompleteCubeMap)271 TEST_P(FramebufferFormatsTest, IncompleteCubeMap)
272 {
273 // http://anglebug.com/3145
274 ANGLE_SKIP_TEST_IF(IsFuchsia() && IsIntel() && IsVulkan());
275
276 // First make a complete CubeMap.
277 glGenTextures(1, &mTexture);
278 glBindTexture(GL_TEXTURE_CUBE_MAP, mTexture);
279 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
280 nullptr);
281 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
282 nullptr);
283 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
284 nullptr);
285 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
286 nullptr);
287 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
288 nullptr);
289 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
290 nullptr);
291 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
292 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
293
294 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
295 mTexture, 0);
296
297 // Verify the framebuffer is complete.
298 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
299
300 // Make the CubeMap cube-incomplete.
301 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
302 nullptr);
303
304 // Verify the framebuffer is incomplete.
305 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
306 glCheckFramebufferStatus(GL_FRAMEBUFFER));
307
308 ASSERT_GL_NO_ERROR();
309
310 // Verify drawing with the incomplete framebuffer produces a GL error
311 mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
312 ASSERT_NE(0u, mProgram);
313 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
314 ASSERT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
315 }
316
317 // Test that a renderbuffer with zero height but nonzero width is handled without crashes/asserts.
TEST_P(FramebufferFormatsTest,ZeroHeightRenderbuffer)318 TEST_P(FramebufferFormatsTest, ZeroHeightRenderbuffer)
319 {
320 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
321
322 testZeroHeightRenderbuffer();
323 }
324
325 // Test to cover a bug where the read framebuffer affects the completeness of the draw framebuffer.
TEST_P(FramebufferFormatsTest,ReadDrawCompleteness)326 TEST_P(FramebufferFormatsTest, ReadDrawCompleteness)
327 {
328 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
329
330 GLTexture incompleteTexture;
331 glBindTexture(GL_TEXTURE_2D, incompleteTexture);
332
333 GLFramebuffer incompleteFBO;
334 glBindFramebuffer(GL_FRAMEBUFFER, incompleteFBO);
335 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, incompleteTexture,
336 0);
337 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
338 glCheckFramebufferStatus(GL_FRAMEBUFFER));
339
340 GLTexture completeTexture;
341 glBindTexture(GL_TEXTURE_2D, completeTexture);
342 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight());
343
344 GLFramebuffer completeFBO;
345 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, completeFBO);
346 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
347 completeTexture, 0);
348
349 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
350 glCheckFramebufferStatus(GL_READ_FRAMEBUFFER));
351 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
352
353 ASSERT_GL_NO_ERROR();
354
355 // Simple draw program.
356 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
357
358 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
359 EXPECT_GL_NO_ERROR();
360
361 glBindFramebuffer(GL_READ_FRAMEBUFFER, completeFBO);
362 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
363 }
364
365 class FramebufferTest_ES3 : public ANGLETest
366 {};
367
368 // Covers invalidating an incomplete framebuffer. This should be a no-op, but should not error.
TEST_P(FramebufferTest_ES3,InvalidateIncomplete)369 TEST_P(FramebufferTest_ES3, InvalidateIncomplete)
370 {
371 GLFramebuffer framebuffer;
372 GLRenderbuffer renderbuffer;
373
374 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
375 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
376 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
377 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
378 glCheckFramebufferStatus(GL_FRAMEBUFFER));
379
380 std::vector<GLenum> attachments;
381 attachments.push_back(GL_COLOR_ATTACHMENT0);
382
383 glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments.data());
384 EXPECT_GL_NO_ERROR();
385 }
386
387 // Test that the framebuffer state tracking robustly handles a depth-only attachment being set
388 // as a depth-stencil attachment. It is equivalent to detaching the depth-stencil attachment.
TEST_P(FramebufferTest_ES3,DepthOnlyAsDepthStencil)389 TEST_P(FramebufferTest_ES3, DepthOnlyAsDepthStencil)
390 {
391 GLFramebuffer framebuffer;
392 GLRenderbuffer renderbuffer;
393
394 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
395 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
396 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 4, 4);
397
398 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
399 renderbuffer);
400 EXPECT_GLENUM_NE(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
401 }
402
403 // Test that the framebuffer correctly returns that it is not complete if invalid texture mip levels
404 // are bound
TEST_P(FramebufferTest_ES3,TextureAttachmentMipLevels)405 TEST_P(FramebufferTest_ES3, TextureAttachmentMipLevels)
406 {
407 GLFramebuffer framebuffer;
408 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
409
410 GLTexture texture;
411 glBindTexture(GL_TEXTURE_2D, texture);
412
413 // Create a complete mip chain in mips 1 to 3
414 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
415 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
416 glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
417
418 // Create another complete mip chain in mips 4 to 5
419 glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
420 glTexImage2D(GL_TEXTURE_2D, 5, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
421
422 // Create a non-complete mip chain in mip 6
423 glTexImage2D(GL_TEXTURE_2D, 6, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
424
425 // Incomplete, mipLevel != baseLevel and texture is not mip complete
426 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
427 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
428 glCheckFramebufferStatus(GL_FRAMEBUFFER));
429
430 // Complete, mipLevel == baseLevel
431 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
432 ExpectFramebufferCompleteOrUnsupported(GL_FRAMEBUFFER);
433
434 // Complete, mipLevel != baseLevel but texture is now mip complete
435 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 2);
436 ExpectFramebufferCompleteOrUnsupported(GL_FRAMEBUFFER);
437 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 3);
438 ExpectFramebufferCompleteOrUnsupported(GL_FRAMEBUFFER);
439
440 // Incomplete, attached level below the base level
441 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2);
442 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
443 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
444 glCheckFramebufferStatus(GL_FRAMEBUFFER));
445
446 // Incomplete, attached level is beyond effective max level
447 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 4);
448 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
449 glCheckFramebufferStatus(GL_FRAMEBUFFER));
450
451 // Complete, mipLevel == baseLevel
452 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 4);
453 ExpectFramebufferCompleteOrUnsupported(GL_FRAMEBUFFER);
454
455 // Complete, mipLevel != baseLevel but texture is now mip complete
456 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 5);
457 ExpectFramebufferCompleteOrUnsupported(GL_FRAMEBUFFER);
458
459 // Complete, mipLevel == baseLevel
460 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 6);
461 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 6);
462 ExpectFramebufferCompleteOrUnsupported(GL_FRAMEBUFFER);
463 }
464
TEST_P(FramebufferTest_ES3,TextureAttachmentMipLevelsReadBack)465 TEST_P(FramebufferTest_ES3, TextureAttachmentMipLevelsReadBack)
466 {
467 // http://anglebug.com/4695
468 ANGLE_SKIP_TEST_IF(IsVulkan());
469
470 GLFramebuffer framebuffer;
471 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
472
473 GLTexture texture;
474 glBindTexture(GL_TEXTURE_2D, texture);
475
476 const std::array<GLColor, 2 * 2> mip0Data = {GLColor::red, GLColor::red, GLColor::red,
477 GLColor::red};
478 const std::array<GLColor, 1 * 1> mip1Data = {GLColor::green};
479
480 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip0Data.data());
481 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip1Data.data());
482
483 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
484 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1);
485 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
486
487 glClearColor(0, 0, 1.0f, 1.0f);
488 glClear(GL_COLOR_BUFFER_BIT);
489 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
490 }
491
492 // Test that passing an attachment COLOR_ATTACHMENTm where m is equal to MAX_COLOR_ATTACHMENTS
493 // generates an INVALID_OPERATION.
494 // OpenGL ES Version 3.0.5 (November 3, 2016), 4.4.2.4 Attaching Texture Images to a Framebuffer, p.
495 // 208
TEST_P(FramebufferTest_ES3,ColorAttachmentIndexOutOfBounds)496 TEST_P(FramebufferTest_ES3, ColorAttachmentIndexOutOfBounds)
497 {
498 GLFramebuffer framebuffer;
499 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
500
501 GLint maxColorAttachments = 0;
502 glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxColorAttachments);
503 GLenum attachment = static_cast<GLenum>(maxColorAttachments + GL_COLOR_ATTACHMENT0);
504
505 GLTexture texture;
506 glBindTexture(GL_TEXTURE_2D, texture.get());
507 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
508 glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture.get(), 0);
509 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
510 }
511
512 // Check that depth-only attachments report the correct number of samples.
TEST_P(FramebufferTest_ES3,MultisampleDepthOnly)513 TEST_P(FramebufferTest_ES3, MultisampleDepthOnly)
514 {
515 GLRenderbuffer renderbuffer;
516 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
517 glRenderbufferStorageMultisample(GL_RENDERBUFFER, 2, GL_DEPTH_COMPONENT24, 32, 32);
518
519 GLFramebuffer framebuffer;
520 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
521 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
522 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
523 EXPECT_GL_NO_ERROR();
524
525 GLint samples = 0;
526 glGetIntegerv(GL_SAMPLES, &samples);
527 EXPECT_GL_NO_ERROR();
528 EXPECT_GE(samples, 2);
529 }
530
531 // Check that we only compare width and height of attachments, not depth.
TEST_P(FramebufferTest_ES3,AttachmentWith3DLayers)532 TEST_P(FramebufferTest_ES3, AttachmentWith3DLayers)
533 {
534 GLTexture texA;
535 glBindTexture(GL_TEXTURE_2D, texA);
536 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
537
538 GLTexture texB;
539 glBindTexture(GL_TEXTURE_3D, texB);
540 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 4, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
541
542 GLFramebuffer framebuffer;
543 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
544 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texA, 0);
545 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texB, 0, 0);
546 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
547 EXPECT_GL_NO_ERROR();
548 }
549
550 // Test that clearing the stencil buffer when the framebuffer only has a color attachment does not
551 // crash.
TEST_P(FramebufferTest_ES3,ClearNonexistentStencil)552 TEST_P(FramebufferTest_ES3, ClearNonexistentStencil)
553 {
554 GLRenderbuffer rbo;
555 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
556 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
557
558 GLFramebuffer fbo;
559 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
560 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
561
562 GLint clearValue = 0;
563 glClearBufferiv(GL_STENCIL, 0, &clearValue);
564
565 // There's no error specified for clearing nonexistent buffers, it's simply a no-op.
566 EXPECT_GL_NO_ERROR();
567 }
568
569 // Test that clearing the depth buffer when the framebuffer only has a color attachment does not
570 // crash.
TEST_P(FramebufferTest_ES3,ClearNonexistentDepth)571 TEST_P(FramebufferTest_ES3, ClearNonexistentDepth)
572 {
573 GLRenderbuffer rbo;
574 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
575 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
576
577 GLFramebuffer fbo;
578 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
579 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
580
581 GLfloat clearValue = 0.0f;
582 glClearBufferfv(GL_DEPTH, 0, &clearValue);
583
584 // There's no error specified for clearing nonexistent buffers, it's simply a no-op.
585 EXPECT_GL_NO_ERROR();
586 }
587
588 // Test that clearing a nonexistent color attachment does not crash.
TEST_P(FramebufferTest_ES3,ClearNonexistentColor)589 TEST_P(FramebufferTest_ES3, ClearNonexistentColor)
590 {
591 GLRenderbuffer rbo;
592 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
593 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
594
595 GLFramebuffer fbo;
596 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
597 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
598
599 std::vector<GLfloat> clearValue = {{0.0f, 1.0f, 0.0f, 1.0f}};
600 glClearBufferfv(GL_COLOR, 1, clearValue.data());
601
602 // There's no error specified for clearing nonexistent buffers, it's simply a no-op.
603 EXPECT_GL_NO_ERROR();
604 }
605
606 // Test that clearing the depth and stencil buffers when the framebuffer only has a color attachment
607 // does not crash.
TEST_P(FramebufferTest_ES3,ClearNonexistentDepthStencil)608 TEST_P(FramebufferTest_ES3, ClearNonexistentDepthStencil)
609 {
610 GLRenderbuffer rbo;
611 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
612 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
613
614 GLFramebuffer fbo;
615 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
616 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
617
618 glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.0f, 0);
619
620 // There's no error specified for clearing nonexistent buffers, it's simply a no-op.
621 EXPECT_GL_NO_ERROR();
622 }
623
624 // Test that clearing a color attachment that has been deleted doesn't crash.
TEST_P(FramebufferTest_ES3,ClearDeletedAttachment)625 TEST_P(FramebufferTest_ES3, ClearDeletedAttachment)
626 {
627 // An INVALID_FRAMEBUFFER_OPERATION error was seen in this test on Mac, not sure where it might
628 // be originating from. http://anglebug.com/2834
629 ANGLE_SKIP_TEST_IF(IsOSX() && IsOpenGL());
630
631 GLFramebuffer fbo;
632 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
633
634 // There used to be a bug where some draw buffer state used to remain set even after the
635 // attachment was detached via deletion. That's why we create, attach and delete this RBO here.
636 GLuint rbo = 0u;
637 glGenRenderbuffers(1, &rbo);
638 glBindRenderbuffer(GL_RENDERBUFFER, rbo);
639 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
640 glDeleteRenderbuffers(1, &rbo);
641
642 // There needs to be at least one color attachment to prevent early out from the clear calls.
643 GLRenderbuffer rbo2;
644 glBindRenderbuffer(GL_RENDERBUFFER, rbo2);
645 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
646 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rbo2);
647
648 ASSERT_GL_NO_ERROR();
649
650 // There's no error specified for clearing nonexistent buffers, it's simply a no-op, so we
651 // expect no GL errors below.
652 std::array<GLfloat, 4> floatClearValue = {0.0f, 0.0f, 0.0f, 0.0f};
653 glClearBufferfv(GL_COLOR, 0, floatClearValue.data());
654 EXPECT_GL_NO_ERROR();
655 std::array<GLuint, 4> uintClearValue = {0u, 0u, 0u, 0u};
656 glClearBufferuiv(GL_COLOR, 0, uintClearValue.data());
657 EXPECT_GL_NO_ERROR();
658 std::array<GLint, 4> intClearValue = {0, 0, 0, 0};
659 glClearBufferiv(GL_COLOR, 0, intClearValue.data());
660 EXPECT_GL_NO_ERROR();
661 }
662
663 // Test that resizing the color attachment is handled correctly.
TEST_P(FramebufferTest_ES3,ResizeColorAttachmentSmallToLarge)664 TEST_P(FramebufferTest_ES3, ResizeColorAttachmentSmallToLarge)
665 {
666 GLFramebuffer fbo;
667 GLTexture smallTexture;
668 GLTexture largeTexture;
669
670 ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
671 ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
672
673 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
674
675 // Bind the small texture
676 glBindTexture(GL_TEXTURE_2D, smallTexture);
677 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGBA,
678 GL_UNSIGNED_BYTE, nullptr);
679 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
680 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
681 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, smallTexture, 0);
682 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
683
684 // Draw to FBO backed by the small texture
685 glUseProgram(greenProgram);
686 drawQuad(greenProgram.get(), std::string(essl1_shaders::PositionAttrib()), 0.0f);
687 ASSERT_GL_NO_ERROR();
688 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
689 EXPECT_PIXEL_COLOR_EQ((getWindowWidth() / 2) - 1, (getWindowHeight() / 2) - 1, GLColor::green);
690
691 // Change the attachment to the larger texture that fills the window
692 glBindTexture(GL_TEXTURE_2D, largeTexture);
693 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
694 GL_UNSIGNED_BYTE, nullptr);
695 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
696 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
697 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, largeTexture, 0);
698 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
699
700 // Draw to FBO backed by the large texture
701 glUseProgram(blueProgram);
702 drawQuad(blueProgram.get(), std::string(essl1_shaders::PositionAttrib()), 0.0f);
703 ASSERT_GL_NO_ERROR();
704 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
705 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::blue);
706 }
707
708 // Test that resizing the color attachment is handled correctly.
TEST_P(FramebufferTest_ES3,ResizeColorAttachmentLargeToSmall)709 TEST_P(FramebufferTest_ES3, ResizeColorAttachmentLargeToSmall)
710 {
711 GLFramebuffer fbo;
712 GLTexture smallTexture;
713 GLTexture largeTexture;
714
715 ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
716 ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
717
718 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
719
720 // Bind the large texture
721 glBindTexture(GL_TEXTURE_2D, largeTexture);
722 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
723 GL_UNSIGNED_BYTE, nullptr);
724 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
725 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
726 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, largeTexture, 0);
727 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
728
729 // Draw to FBO backed by the large texture
730 glUseProgram(blueProgram);
731 drawQuad(blueProgram.get(), std::string(essl1_shaders::PositionAttrib()), 0.0f);
732 ASSERT_GL_NO_ERROR();
733 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
734 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::blue);
735
736 // Change the attachment to the smaller texture
737 glBindTexture(GL_TEXTURE_2D, smallTexture);
738 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGBA,
739 GL_UNSIGNED_BYTE, nullptr);
740 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
741 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
742 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, smallTexture, 0);
743 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
744
745 // Draw to FBO backed by the small texture
746 glUseProgram(greenProgram);
747 drawQuad(greenProgram.get(), std::string(essl1_shaders::PositionAttrib()), 0.0f);
748 ASSERT_GL_NO_ERROR();
749 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
750 EXPECT_PIXEL_COLOR_EQ((getWindowWidth() / 2) - 1, (getWindowHeight() / 2) - 1, GLColor::green);
751 }
752
753 // Test that resizing the texture is handled correctly.
TEST_P(FramebufferTest_ES3,ResizeTextureLargeToSmall)754 TEST_P(FramebufferTest_ES3, ResizeTextureLargeToSmall)
755 {
756 GLFramebuffer fbo;
757 GLTexture texture;
758
759 ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
760 ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
761
762 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
763
764 // Allocate a large texture
765 glBindTexture(GL_TEXTURE_2D, texture);
766 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
767 GL_UNSIGNED_BYTE, nullptr);
768 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
769 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
770 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
771 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
772
773 // Draw to FBO backed by the large texture
774 glUseProgram(blueProgram);
775 drawQuad(blueProgram.get(), std::string(essl1_shaders::PositionAttrib()), 0.0f);
776 ASSERT_GL_NO_ERROR();
777 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
778 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::blue);
779
780 // Shrink the texture
781 glBindTexture(GL_TEXTURE_2D, texture);
782 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGBA,
783 GL_UNSIGNED_BYTE, nullptr);
784 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
785 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
786 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
787 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
788
789 // Draw to FBO backed by the small texture
790 glUseProgram(greenProgram);
791 drawQuad(greenProgram.get(), std::string(essl1_shaders::PositionAttrib()), 0.0f);
792 ASSERT_GL_NO_ERROR();
793 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
794 EXPECT_PIXEL_COLOR_EQ((getWindowWidth() / 2) - 1, (getWindowHeight() / 2) - 1, GLColor::green);
795 }
796
797 // Test that resizing the texture is handled correctly.
TEST_P(FramebufferTest_ES3,ResizeTextureSmallToLarge)798 TEST_P(FramebufferTest_ES3, ResizeTextureSmallToLarge)
799 {
800 GLFramebuffer fbo;
801 GLTexture texture;
802
803 ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
804 ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
805
806 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
807
808 // Allocate a small texture
809 glBindTexture(GL_TEXTURE_2D, texture);
810 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGBA,
811 GL_UNSIGNED_BYTE, nullptr);
812 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
813 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
814 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
815 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
816
817 // Draw to FBO backed by the large texture
818 glUseProgram(blueProgram);
819 drawQuad(blueProgram.get(), std::string(essl1_shaders::PositionAttrib()), 0.0f);
820 ASSERT_GL_NO_ERROR();
821 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
822 EXPECT_PIXEL_COLOR_EQ((getWindowWidth() / 2) - 1, (getWindowHeight() / 2) - 1, GLColor::blue);
823
824 // Grow the texture
825 glBindTexture(GL_TEXTURE_2D, texture);
826 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
827 GL_UNSIGNED_BYTE, nullptr);
828 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
829 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
830 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
831 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
832
833 // Draw to FBO backed by the small texture
834 glUseProgram(greenProgram);
835 drawQuad(greenProgram.get(), std::string(essl1_shaders::PositionAttrib()), 0.0f);
836 ASSERT_GL_NO_ERROR();
837 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
838 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::green);
839 }
840
841 // Test that fewer outputs than framebuffer attachments doesn't crash. This causes a Vulkan
842 // validation warning, but should not be fatal.
TEST_P(FramebufferTest_ES3,FewerShaderOutputsThanAttachments)843 TEST_P(FramebufferTest_ES3, FewerShaderOutputsThanAttachments)
844 {
845 constexpr char kFS[] = R"(#version 300 es
846 precision highp float;
847
848 layout(location = 0) out vec4 color0;
849 layout(location = 1) out vec4 color1;
850 layout(location = 2) out vec4 color2;
851
852 void main()
853 {
854 color0 = vec4(1.0, 0.0, 0.0, 1.0);
855 color1 = vec4(0.0, 1.0, 0.0, 1.0);
856 color2 = vec4(0.0, 0.0, 1.0, 1.0);
857 }
858 )";
859
860 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
861
862 constexpr GLint kDrawBufferCount = 4;
863
864 GLint maxDrawBuffers;
865 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
866 ASSERT_GE(maxDrawBuffers, kDrawBufferCount);
867
868 GLTexture textures[kDrawBufferCount];
869
870 for (GLint texIndex = 0; texIndex < kDrawBufferCount; ++texIndex)
871 {
872 glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
873 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
874 GL_UNSIGNED_BYTE, nullptr);
875 }
876
877 GLenum allBufs[kDrawBufferCount] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
878 GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
879
880 GLFramebuffer fbo;
881 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
882
883 // Enable all draw buffers.
884 for (GLint texIndex = 0; texIndex < kDrawBufferCount; ++texIndex)
885 {
886 glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
887 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,
888 textures[texIndex], 0);
889 }
890 glDrawBuffers(kDrawBufferCount, allBufs);
891
892 // Draw with simple program.
893 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
894 ASSERT_GL_NO_ERROR();
895 }
896
897 class FramebufferTest_ES31 : public ANGLETest
898 {
899 protected:
validateSamplePass(GLuint & query,GLuint & passedCount,GLint width,GLint height)900 void validateSamplePass(GLuint &query, GLuint &passedCount, GLint width, GLint height)
901 {
902 glUniform2i(0, width - 1, height - 1);
903 glBeginQuery(GL_ANY_SAMPLES_PASSED, query);
904 glDrawArrays(GL_TRIANGLES, 0, 6);
905 glEndQuery(GL_ANY_SAMPLES_PASSED);
906 glGetQueryObjectuiv(query, GL_QUERY_RESULT, &passedCount);
907 EXPECT_GT(static_cast<GLint>(passedCount), 0);
908
909 glUniform2i(0, width - 1, height);
910 glBeginQuery(GL_ANY_SAMPLES_PASSED, query);
911 glDrawArrays(GL_TRIANGLES, 0, 6);
912 glEndQuery(GL_ANY_SAMPLES_PASSED);
913 glGetQueryObjectuiv(query, GL_QUERY_RESULT, &passedCount);
914 EXPECT_EQ(static_cast<GLint>(passedCount), 0);
915
916 glUniform2i(0, width, height - 1);
917 glBeginQuery(GL_ANY_SAMPLES_PASSED, query);
918 glDrawArrays(GL_TRIANGLES, 0, 6);
919 glEndQuery(GL_ANY_SAMPLES_PASSED);
920 glGetQueryObjectuiv(query, GL_QUERY_RESULT, &passedCount);
921 EXPECT_EQ(static_cast<GLint>(passedCount), 0);
922 }
923 };
924
925 // Test that without attachment, if either the value of FRAMEBUFFER_DEFAULT_WIDTH or
926 // FRAMEBUFFER_DEFAULT_HEIGHT parameters is zero, the framebuffer is incomplete.
TEST_P(FramebufferTest_ES31,IncompleteMissingAttachmentDefaultParam)927 TEST_P(FramebufferTest_ES31, IncompleteMissingAttachmentDefaultParam)
928 {
929 // anglebug.com/3565
930 ANGLE_SKIP_TEST_IF(IsVulkan());
931
932 GLFramebuffer mFramebuffer;
933 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());
934
935 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 1);
936 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, 1);
937 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
938
939 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 0);
940 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, 0);
941 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,
942 glCheckFramebufferStatus(GL_FRAMEBUFFER));
943
944 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 1);
945 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, 0);
946 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,
947 glCheckFramebufferStatus(GL_FRAMEBUFFER));
948
949 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 0);
950 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, 1);
951 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,
952 glCheckFramebufferStatus(GL_FRAMEBUFFER));
953
954 ASSERT_GL_NO_ERROR();
955 }
956
957 // Test that the sample count of a mix of texture and renderbuffer should be same.
TEST_P(FramebufferTest_ES31,IncompleteMultisampleSampleCountMix)958 TEST_P(FramebufferTest_ES31, IncompleteMultisampleSampleCountMix)
959 {
960 // anglebug.com/3565
961 ANGLE_SKIP_TEST_IF(IsVulkan());
962
963 GLFramebuffer mFramebuffer;
964 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());
965
966 // Lookup the supported number of sample counts (rely on fact that ANGLE uses the same set of
967 // sample counts for textures and renderbuffers)
968 GLint numSampleCounts = 0;
969 std::vector<GLint> sampleCounts;
970 GLsizei queryBufferSize = 1;
971 glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_NUM_SAMPLE_COUNTS,
972 queryBufferSize, &numSampleCounts);
973 ANGLE_SKIP_TEST_IF((numSampleCounts < 2));
974 sampleCounts.resize(numSampleCounts);
975 queryBufferSize = numSampleCounts;
976 glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, queryBufferSize,
977 sampleCounts.data());
978
979 GLTexture mTexture;
980 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTexture.get());
981 glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCounts[0], GL_RGBA8, 1, 1, true);
982
983 GLRenderbuffer mRenderbuffer;
984 glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer.get());
985 glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCounts[1], GL_RGBA8, 1, 1);
986 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
987 mTexture.get(), 0);
988 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER,
989 mRenderbuffer.get());
990 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
991 glCheckFramebufferStatus(GL_FRAMEBUFFER));
992
993 ASSERT_GL_NO_ERROR();
994 }
995
996 // Test that the sample count of texture attachments should be same.
TEST_P(FramebufferTest_ES31,IncompleteMultisampleSampleCountTex)997 TEST_P(FramebufferTest_ES31, IncompleteMultisampleSampleCountTex)
998 {
999 // anglebug.com/3565
1000 ANGLE_SKIP_TEST_IF(IsVulkan());
1001
1002 GLFramebuffer mFramebuffer;
1003 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());
1004
1005 // Lookup the supported number of sample counts
1006 GLint numSampleCounts = 0;
1007 std::vector<GLint> sampleCounts;
1008 GLsizei queryBufferSize = 1;
1009 glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_NUM_SAMPLE_COUNTS,
1010 queryBufferSize, &numSampleCounts);
1011 ANGLE_SKIP_TEST_IF((numSampleCounts < 2));
1012 sampleCounts.resize(numSampleCounts);
1013 queryBufferSize = numSampleCounts;
1014 glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, queryBufferSize,
1015 sampleCounts.data());
1016
1017 GLTexture mTextures[2];
1018 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTextures[0].get());
1019 glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCounts[0], GL_RGBA8, 1, 1, true);
1020 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTextures[1].get());
1021 glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, sampleCounts[1], GL_RGBA8, 1, 1, true);
1022 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
1023 mTextures[0].get(), 0);
1024 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE,
1025 mTextures[1].get(), 0);
1026 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
1027 glCheckFramebufferStatus(GL_FRAMEBUFFER));
1028
1029 ASSERT_GL_NO_ERROR();
1030 }
1031
1032 // Test that if the attached images are a mix of renderbuffers and textures, the value of
1033 // TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
TEST_P(FramebufferTest_ES31,IncompleteMultisampleFixedSampleLocationsMix)1034 TEST_P(FramebufferTest_ES31, IncompleteMultisampleFixedSampleLocationsMix)
1035 {
1036 // anglebug.com/3565
1037 ANGLE_SKIP_TEST_IF(IsVulkan());
1038
1039 GLFramebuffer mFramebuffer;
1040 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());
1041
1042 GLTexture mTexture;
1043 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTexture.get());
1044 glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 1, GL_RGBA8, 1, 1, false);
1045
1046 GLRenderbuffer mRenderbuffer;
1047 glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer.get());
1048 glRenderbufferStorageMultisample(GL_RENDERBUFFER, 1, GL_RGBA8, 1, 1);
1049 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
1050 mTexture.get(), 0);
1051 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER,
1052 mRenderbuffer.get());
1053 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
1054 glCheckFramebufferStatus(GL_FRAMEBUFFER));
1055
1056 ASSERT_GL_NO_ERROR();
1057 }
1058
1059 // Test that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS is the same for all attached textures.
TEST_P(FramebufferTest_ES31,IncompleteMultisampleFixedSampleLocationsTex)1060 TEST_P(FramebufferTest_ES31, IncompleteMultisampleFixedSampleLocationsTex)
1061 {
1062 // anglebug.com/3565
1063 ANGLE_SKIP_TEST_IF(IsVulkan());
1064
1065 GLFramebuffer mFramebuffer;
1066 glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer.get());
1067
1068 GLTexture mTextures[2];
1069 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTextures[0].get());
1070 glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 1, GL_RGBA8, 1, 1, false);
1071 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
1072 mTextures[0].get(), 0);
1073 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mTextures[1].get());
1074 glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 1, GL_RGB8, 1, 1, true);
1075 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE,
1076 mTextures[1].get(), 0);
1077 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE,
1078 glCheckFramebufferStatus(GL_FRAMEBUFFER));
1079
1080 ASSERT_GL_NO_ERROR();
1081 }
1082
1083 // If there are no attachments, rendering will be limited to a rectangle having a lower left of
1084 // (0, 0) and an upper right of(width, height), where width and height are the framebuffer
1085 // object's default width and height.
TEST_P(FramebufferTest_ES31,RenderingLimitToDefaultFBOSizeWithNoAttachments)1086 TEST_P(FramebufferTest_ES31, RenderingLimitToDefaultFBOSizeWithNoAttachments)
1087 {
1088 // anglebug.com/2253
1089 ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD() && IsDesktopOpenGL());
1090 // Occlusion query reports fragments outside the render area are still rendered
1091 ANGLE_SKIP_TEST_IF(IsAndroid() || (IsWindows() && (IsIntel() || IsAMD())));
1092
1093 constexpr char kVS1[] = R"(#version 310 es
1094 in layout(location = 0) highp vec2 a_position;
1095 void main()
1096 {
1097 gl_Position = vec4(a_position, 0.0, 1.0);
1098 })";
1099
1100 constexpr char kFS1[] = R"(#version 310 es
1101 uniform layout(location = 0) highp ivec2 u_expectedSize;
1102 out layout(location = 3) mediump vec4 f_color;
1103 void main()
1104 {
1105 if (ivec2(gl_FragCoord.xy) != u_expectedSize) discard;
1106 f_color = vec4(1.0, 0.5, 0.25, 1.0);
1107 })";
1108
1109 constexpr char kVS2[] = R"(#version 310 es
1110 in layout(location = 0) highp vec2 a_position;
1111 void main()
1112 {
1113 gl_Position = vec4(a_position, 0.0, 1.0);
1114 })";
1115
1116 constexpr char kFS2[] = R"(#version 310 es
1117 uniform layout(location = 0) highp ivec2 u_expectedSize;
1118 out layout(location = 2) mediump vec4 f_color;
1119 void main()
1120 {
1121 if (ivec2(gl_FragCoord.xy) != u_expectedSize) discard;
1122 f_color = vec4(1.0, 0.5, 0.25, 1.0);
1123 })";
1124
1125 GLuint program1 = CompileProgram(kVS1, kFS1);
1126 ASSERT_NE(program1, 0u);
1127
1128 GLuint program2 = CompileProgram(kVS2, kFS2);
1129 ASSERT_NE(program2, 0u);
1130
1131 glUseProgram(program1);
1132
1133 GLFramebuffer mFramebuffer;
1134 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer);
1135 GLuint defaultWidth = 1;
1136 GLuint defaultHeight = 1;
1137
1138 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, defaultWidth);
1139 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, defaultHeight);
1140 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1141
1142 const float data[] = {
1143 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f,
1144 };
1145
1146 GLuint vertexArray = 0;
1147 GLuint vertexBuffer = 0;
1148 GLuint query = 0;
1149 GLuint passedCount = 0;
1150
1151 glGenQueries(1, &query);
1152 glGenVertexArrays(1, &vertexArray);
1153 glBindVertexArray(vertexArray);
1154
1155 glGenBuffers(1, &vertexBuffer);
1156 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
1157 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
1158
1159 glEnableVertexAttribArray(0);
1160 glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
1161 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1162
1163 validateSamplePass(query, passedCount, defaultWidth, defaultHeight);
1164
1165 glUseProgram(program2);
1166 validateSamplePass(query, passedCount, defaultWidth, defaultHeight);
1167
1168 glUseProgram(program1);
1169 // If fbo has attachments, the rendering size should be the same as its attachment.
1170 GLTexture mTexture;
1171 GLuint width = 2;
1172 GLuint height = 2;
1173 glBindTexture(GL_TEXTURE_2D, mTexture.get());
1174 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
1175
1176 const GLenum bufs[] = {GL_NONE, GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT3};
1177
1178 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mTexture.get(),
1179 0);
1180 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1181 glDrawBuffers(4, bufs);
1182
1183 validateSamplePass(query, passedCount, width, height);
1184
1185 // If fbo's attachment has been removed, the rendering size should be the same as framebuffer
1186 // default size.
1187 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, 0, 0, 0);
1188 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1189
1190 validateSamplePass(query, passedCount, defaultWidth, defaultHeight);
1191
1192 glDisableVertexAttribArray(0);
1193 glBindBuffer(GL_ARRAY_BUFFER, 0);
1194 glBindVertexArray(0);
1195 glDeleteBuffers(1, &vertexBuffer);
1196 glDeleteVertexArrays(1, &vertexArray);
1197
1198 ASSERT_GL_NO_ERROR();
1199 }
1200
1201 class AddDummyTextureNoRenderTargetTest : public ANGLETest
1202 {
1203 public:
AddDummyTextureNoRenderTargetTest()1204 AddDummyTextureNoRenderTargetTest()
1205 {
1206 setWindowWidth(512);
1207 setWindowHeight(512);
1208 setConfigRedBits(8);
1209 setConfigGreenBits(8);
1210 setConfigBlueBits(8);
1211 setConfigAlphaBits(8);
1212 }
1213
overrideWorkaroundsD3D(FeaturesD3D * features)1214 void overrideWorkaroundsD3D(FeaturesD3D *features) override
1215 {
1216 features->overrideFeatures({"add_dummy_texture_no_render_target"}, true);
1217 }
1218 };
1219
1220 // Test to verify workaround succeeds when no program outputs exist http://anglebug.com/2283
TEST_P(AddDummyTextureNoRenderTargetTest,NoProgramOutputWorkaround)1221 TEST_P(AddDummyTextureNoRenderTargetTest, NoProgramOutputWorkaround)
1222 {
1223 constexpr char kVS[] = "void main() {}";
1224 constexpr char kFS[] = "void main() {}";
1225
1226 ANGLE_GL_PROGRAM(drawProgram, kVS, kFS);
1227
1228 glUseProgram(drawProgram);
1229
1230 glDrawArrays(GL_TRIANGLES, 0, 6);
1231
1232 ASSERT_GL_NO_ERROR();
1233 }
1234
1235 // Covers a bug in ANGLE's Vulkan back-end framebuffer cache which ignored depth/stencil after
1236 // calls to DrawBuffers.
TEST_P(FramebufferTest_ES3,AttachmentStateChange)1237 TEST_P(FramebufferTest_ES3, AttachmentStateChange)
1238 {
1239 constexpr GLuint kSize = 2;
1240
1241 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
1242
1243 GLTexture colorTexture;
1244 glBindTexture(GL_TEXTURE_2D, colorTexture);
1245 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1246
1247 GLFramebuffer fbo;
1248 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1249 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
1250
1251 ASSERT_GL_NO_ERROR();
1252 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1253
1254 // First draw without a depth buffer.
1255 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
1256
1257 GLRenderbuffer depthBuffer;
1258 glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
1259 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, kSize, kSize);
1260
1261 // Bind just a renderbuffer and draw.
1262 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
1263
1264 ASSERT_GL_NO_ERROR();
1265 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1266
1267 glDrawBuffers(0, nullptr);
1268 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
1269
1270 // Re-enable color buffer and draw one final time. This previously triggered a crash.
1271 GLenum drawBuffs = {GL_COLOR_ATTACHMENT0};
1272 glDrawBuffers(1, &drawBuffs);
1273
1274 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
1275 ASSERT_GL_NO_ERROR();
1276 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1277 }
1278
1279 // Tests that we can support a feedback loop between a depth textures and the depth buffer.
1280 // Does not totally mirror the case used in Manhattan. The Manhattan case seems to handle
1281 // "clear" specially instead of rendering to depth in the same RP.
TEST_P(FramebufferTest_ES3,DepthFeedbackLoopSupported)1282 TEST_P(FramebufferTest_ES3, DepthFeedbackLoopSupported)
1283 {
1284 // Feedback loops not supported on D3D11 and may not ever be.
1285 ANGLE_SKIP_TEST_IF(IsD3D11());
1286
1287 // Also this particular test doesn't work on Android despite similar support in Manhattan.
1288 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
1289
1290 constexpr GLuint kSize = 2;
1291 glViewport(0, 0, kSize, kSize);
1292
1293 constexpr char kFS[] = R"(precision mediump float;
1294 varying vec2 v_texCoord;
1295 uniform sampler2D depth;
1296 void main()
1297 {
1298 if (abs(texture2D(depth, v_texCoord).x - 0.5) < 0.1)
1299 {
1300 gl_FragColor = vec4(0, 1, 0, 1);
1301 }
1302 else
1303 {
1304 gl_FragColor = vec4(1, 0, 0, 1);
1305 }
1306 })";
1307
1308 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), kFS);
1309
1310 GLFramebuffer framebuffer;
1311 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
1312
1313 GLTexture colorTexture;
1314 glBindTexture(GL_TEXTURE_2D, colorTexture);
1315 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1316
1317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1318 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1319 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
1320
1321 GLTexture depthTexture;
1322 glBindTexture(GL_TEXTURE_2D, depthTexture);
1323 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, kSize, kSize, 0, GL_DEPTH_COMPONENT,
1324 GL_UNSIGNED_INT, nullptr);
1325 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1326 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1327 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
1328
1329 ASSERT_GL_NO_ERROR();
1330 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1331
1332 // Clear depth to 0.5.
1333 glClearDepthf(0.5f);
1334 glClear(GL_DEPTH_BUFFER_BIT);
1335
1336 // Disable the depth mask. Although this does not remove the feedback loop as defined by the
1337 // spec it mimics what gfxbench does in its rendering tests.
1338 glDepthMask(false);
1339
1340 // Verify we can sample the depth texture and get 0.5.
1341 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5);
1342
1343 ASSERT_GL_NO_ERROR();
1344 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1345 }
1346
1347 // Covers a bug in ANGLE's Vulkan back-end. Our VkFramebuffer cache would in some cases forget to
1348 // check the draw states when computing a cache key.
TEST_P(FramebufferTest_ES3,DisabledAttachmentRedefinition)1349 TEST_P(FramebufferTest_ES3, DisabledAttachmentRedefinition)
1350 {
1351 constexpr GLuint kSize = 2;
1352
1353 // Make a Framebuffer with two attachments with one enabled and one disabled.
1354 GLTexture texA, texB;
1355 glBindTexture(GL_TEXTURE_2D, texA);
1356 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1357 glBindTexture(GL_TEXTURE_2D, texB);
1358 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1359
1360 GLFramebuffer fbo;
1361 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1362 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texA, 0);
1363 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texB, 0);
1364
1365 // Mask out the second texture.
1366 constexpr GLenum kOneDrawBuf = GL_COLOR_ATTACHMENT0;
1367 glDrawBuffers(1, &kOneDrawBuf);
1368
1369 ASSERT_GL_NO_ERROR();
1370 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1371
1372 // Set up a very simple shader.
1373 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
1374 glViewport(0, 0, kSize, kSize);
1375
1376 // Draw
1377 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
1378 ASSERT_GL_NO_ERROR();
1379 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1380
1381 // Update the masked out attachment and draw again.
1382 std::vector<GLColor> redPixels(kSize * kSize, GLColor::red);
1383 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_UNSIGNED_BYTE,
1384 redPixels.data());
1385
1386 // Draw
1387 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
1388 ASSERT_GL_NO_ERROR();
1389 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1390
1391 glReadBuffer(GL_COLOR_ATTACHMENT1);
1392 ASSERT_GL_NO_ERROR();
1393 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1394 }
1395
1396 class FramebufferTest : public ANGLETest
1397 {};
1398
1399 template <typename T>
FillTexture2D(GLuint texture,GLsizei width,GLsizei height,const T & onePixelData,GLint level,GLint internalFormat,GLenum format,GLenum type)1400 void FillTexture2D(GLuint texture,
1401 GLsizei width,
1402 GLsizei height,
1403 const T &onePixelData,
1404 GLint level,
1405 GLint internalFormat,
1406 GLenum format,
1407 GLenum type)
1408 {
1409 std::vector<T> allPixelsData(width * height, onePixelData);
1410
1411 glBindTexture(GL_TEXTURE_2D, texture);
1412 glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, 0, format, type,
1413 allPixelsData.data());
1414 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1415 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1416 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1417 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1418 }
1419
1420 // Multi-context uses of textures should not cause rendering feedback loops.
TEST_P(FramebufferTest,MultiContextNoRenderingFeedbackLoops)1421 TEST_P(FramebufferTest, MultiContextNoRenderingFeedbackLoops)
1422 {
1423 constexpr char kTextureVS[] =
1424 R"(attribute vec4 a_position;
1425 varying vec2 v_texCoord;
1426 void main() {
1427 gl_Position = a_position;
1428 v_texCoord = (a_position.xy * 0.5) + 0.5;
1429 })";
1430
1431 constexpr char kTextureFS[] =
1432 R"(precision mediump float;
1433 varying vec2 v_texCoord;
1434 uniform sampler2D u_texture;
1435 void main() {
1436 gl_FragColor = texture2D(u_texture, v_texCoord).rgba;
1437 })";
1438
1439 ANGLE_GL_PROGRAM(textureProgram, kTextureVS, kTextureFS);
1440
1441 glUseProgram(textureProgram.get());
1442 GLint uniformLoc = glGetUniformLocation(textureProgram.get(), "u_texture");
1443 ASSERT_NE(-1, uniformLoc);
1444 glUniform1i(uniformLoc, 0);
1445
1446 GLTexture texture;
1447 FillTexture2D(texture.get(), 1, 1, GLColor::red, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
1448 glBindTexture(GL_TEXTURE_2D, texture.get());
1449 // Note that _texture_ is still bound to GL_TEXTURE_2D in this context at this point.
1450
1451 EGLWindow *window = getEGLWindow();
1452 EGLDisplay display = window->getDisplay();
1453 EGLConfig config = window->getConfig();
1454 EGLSurface surface = window->getSurface();
1455 EGLint contextAttributes[] = {
1456 EGL_CONTEXT_MAJOR_VERSION_KHR,
1457 GetParam().majorVersion,
1458 EGL_CONTEXT_MINOR_VERSION_KHR,
1459 GetParam().minorVersion,
1460 EGL_NONE,
1461 };
1462 EGLContext context1 = eglGetCurrentContext();
1463 // Create context2, sharing resources with context1.
1464 EGLContext context2 = eglCreateContext(display, config, context1, contextAttributes);
1465 ASSERT_NE(context2, EGL_NO_CONTEXT);
1466 eglMakeCurrent(display, surface, surface, context2);
1467
1468 constexpr char kVS[] =
1469 R"(attribute vec4 a_position;
1470 void main() {
1471 gl_Position = a_position;
1472 })";
1473
1474 constexpr char kFS[] =
1475 R"(precision mediump float;
1476 void main() {
1477 gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
1478 })";
1479
1480 ANGLE_GL_PROGRAM(program, kVS, kFS);
1481 glUseProgram(program.get());
1482
1483 ASSERT_GL_NO_ERROR();
1484
1485 // Render to the texture in context2.
1486 GLFramebuffer framebuffer;
1487 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
1488 // Texture is still a valid name in context2.
1489 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.get(), 0);
1490 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
1491 // There is no rendering feedback loop at this point.
1492
1493 glDisable(GL_BLEND);
1494 glDisable(GL_DEPTH_TEST);
1495 ASSERT_GL_NO_ERROR();
1496
1497 // If draw is no-op'ed, texture will not be filled appropriately.
1498 drawQuad(program.get(), "a_position", 0.5f, 1.0f, true);
1499 ASSERT_GL_NO_ERROR();
1500 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1501
1502 // Make context1 current again.
1503 eglMakeCurrent(display, surface, surface, context1);
1504
1505 // Render texture to screen.
1506 drawQuad(textureProgram.get(), "a_position", 0.5f, 1.0f, true);
1507 ASSERT_GL_NO_ERROR();
1508 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1509
1510 eglDestroyContext(display, context2);
1511 }
1512
1513 // Ensure cube-incomplete attachments cause incomplete Framebuffers.
TEST_P(FramebufferTest,IncompleteCubeMap)1514 TEST_P(FramebufferTest, IncompleteCubeMap)
1515 {
1516 constexpr GLuint kSize = 2;
1517
1518 GLTexture srcTex;
1519 glBindTexture(GL_TEXTURE_CUBE_MAP, srcTex);
1520 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA,
1521 GL_UNSIGNED_BYTE, nullptr);
1522
1523 GLFramebuffer fbo;
1524 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1525 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
1526 srcTex, 0);
1527
1528 ASSERT_GL_NO_ERROR();
1529 ASSERT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1530 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
1531 }
1532
1533 ANGLE_INSTANTIATE_TEST_ES2(AddDummyTextureNoRenderTargetTest);
1534 ANGLE_INSTANTIATE_TEST_ES2(FramebufferTest);
1535 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(FramebufferFormatsTest);
1536 ANGLE_INSTANTIATE_TEST_ES3(FramebufferTest_ES3);
1537 ANGLE_INSTANTIATE_TEST_ES31(FramebufferTest_ES31);
1538