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
7 // WebGLFramebufferTest.cpp : Framebuffer tests for GL_ANGLE_webgl_compatibility.
8 // Based on WebGL 1 test renderbuffers/framebuffer-object-attachment.
9
10 #include "test_utils/ANGLETest.h"
11
12 #include "test_utils/gl_raii.h"
13
14 namespace angle
15 {
16
17 class WebGLFramebufferTest : public ANGLETest<>
18 {
19 protected:
WebGLFramebufferTest()20 WebGLFramebufferTest()
21 {
22 setWindowWidth(128);
23 setWindowHeight(128);
24 setConfigRedBits(8);
25 setConfigGreenBits(8);
26 setConfigBlueBits(8);
27 setConfigAlphaBits(8);
28 setWebGLCompatibilityEnabled(true);
29 }
30
31 void drawUByteColorQuad(GLuint program, GLint uniformLoc, const GLColor &color);
32 void testDepthStencilDepthStencil(GLint width, GLint height);
33 void testDepthStencilRenderbuffer(GLint width,
34 GLint height,
35 GLRenderbuffer *colorBuffer,
36 GLbitfield allowedStatuses);
37 void testRenderingAndReading(GLuint program);
38 void testUsingIncompleteFramebuffer(GLenum depthFormat, GLenum depthAttachment);
39 void testDrawingMissingAttachment();
40 };
41
42 constexpr GLint ALLOW_COMPLETE = 0x1;
43 constexpr GLint ALLOW_UNSUPPORTED = 0x2;
44 constexpr GLint ALLOW_INCOMPLETE_ATTACHMENT = 0x4;
45
checkFramebufferForAllowedStatuses(GLbitfield allowedStatuses)46 void checkFramebufferForAllowedStatuses(GLbitfield allowedStatuses)
47 {
48 // If the framebuffer is in an error state for multiple reasons,
49 // we can't guarantee which one will be reported.
50 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
51 bool statusAllowed =
52 ((allowedStatuses & ALLOW_COMPLETE) && (status == GL_FRAMEBUFFER_COMPLETE)) ||
53 ((allowedStatuses & ALLOW_UNSUPPORTED) && (status == GL_FRAMEBUFFER_UNSUPPORTED)) ||
54 ((allowedStatuses & ALLOW_INCOMPLETE_ATTACHMENT) &&
55 (status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT));
56 EXPECT_TRUE(statusAllowed);
57 }
58
checkBufferBits(GLenum attachment0,GLenum attachment1)59 void checkBufferBits(GLenum attachment0, GLenum attachment1)
60 {
61 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
62 return;
63
64 bool haveDepthBuffer =
65 attachment0 == GL_DEPTH_ATTACHMENT || attachment0 == GL_DEPTH_STENCIL_ATTACHMENT ||
66 attachment1 == GL_DEPTH_ATTACHMENT || attachment1 == GL_DEPTH_STENCIL_ATTACHMENT;
67 bool haveStencilBuffer =
68 attachment0 == GL_STENCIL_ATTACHMENT || attachment0 == GL_DEPTH_STENCIL_ATTACHMENT ||
69 attachment1 == GL_STENCIL_ATTACHMENT || attachment1 == GL_DEPTH_STENCIL_ATTACHMENT;
70
71 GLint redBits = 0;
72 GLint greenBits = 0;
73 GLint blueBits = 0;
74 GLint alphaBits = 0;
75 GLint depthBits = 0;
76 GLint stencilBits = 0;
77 glGetIntegerv(GL_RED_BITS, &redBits);
78 glGetIntegerv(GL_GREEN_BITS, &greenBits);
79 glGetIntegerv(GL_BLUE_BITS, &blueBits);
80 glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
81 glGetIntegerv(GL_DEPTH_BITS, &depthBits);
82 glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
83
84 EXPECT_GE(redBits + greenBits + blueBits + alphaBits, 16);
85
86 if (haveDepthBuffer)
87 EXPECT_GE(depthBits, 16);
88 else
89 EXPECT_EQ(0, depthBits);
90
91 if (haveStencilBuffer)
92 EXPECT_GE(stencilBits, 8);
93 else
94 EXPECT_EQ(0, stencilBits);
95 }
96
97 // Tests that certain required combinations work in WebGL compatiblity.
TEST_P(WebGLFramebufferTest,TestFramebufferRequiredCombinations)98 TEST_P(WebGLFramebufferTest, TestFramebufferRequiredCombinations)
99 {
100 // Per discussion with the OpenGL ES working group, the following framebuffer attachment
101 // combinations are required to work in all WebGL implementations:
102 // 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
103 // 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16
104 // renderbuffer
105 // 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL
106 // renderbuffer
107
108 GLFramebuffer fbo;
109 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
110
111 constexpr int width = 64;
112 constexpr int height = 64;
113
114 // 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
115 GLTexture texture;
116 glBindTexture(GL_TEXTURE_2D, texture);
117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
118 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
121 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
122 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
123 EXPECT_GL_NO_ERROR();
124 checkFramebufferForAllowedStatuses(ALLOW_COMPLETE);
125 checkBufferBits(GL_NONE, GL_NONE);
126
127 // 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16
128 // renderbuffer
129 GLRenderbuffer renderbuffer;
130 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
131 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
132 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
133 EXPECT_GL_NO_ERROR();
134 checkFramebufferForAllowedStatuses(ALLOW_COMPLETE);
135 checkBufferBits(GL_DEPTH_ATTACHMENT, GL_NONE);
136 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
137
138 if (getClientMajorVersion() == 2)
139 {
140 // 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT =
141 // DEPTH_STENCIL renderbuffer
142 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
143 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
144 renderbuffer);
145 EXPECT_GL_NO_ERROR();
146 checkFramebufferForAllowedStatuses(ALLOW_COMPLETE);
147 checkBufferBits(GL_DEPTH_STENCIL_ATTACHMENT, GL_NONE);
148 }
149 }
150
testAttachment(GLint width,GLint height,GLRenderbuffer * colorBuffer,GLenum attachment,GLRenderbuffer * buffer,GLbitfield allowedStatuses)151 void testAttachment(GLint width,
152 GLint height,
153 GLRenderbuffer *colorBuffer,
154 GLenum attachment,
155 GLRenderbuffer *buffer,
156 GLbitfield allowedStatuses)
157 {
158 GLFramebuffer fbo;
159 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
160 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorBuffer);
161 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, *buffer);
162 EXPECT_GL_NO_ERROR();
163 checkFramebufferForAllowedStatuses(allowedStatuses);
164 if ((allowedStatuses & ALLOW_COMPLETE) == 0)
165 {
166 std::vector<uint8_t> tempBuffer(width * height * 4);
167
168 glClear(GL_COLOR_BUFFER_BIT);
169 EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
170 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, tempBuffer.data());
171 EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
172 }
173 checkBufferBits(attachment, GL_NONE);
174 }
175
testAttachments(GLRenderbuffer & colorBuffer,GLenum attachment0,GLRenderbuffer & buffer0,GLenum attachment1,GLRenderbuffer & buffer1,GLbitfield allowedStatuses)176 void testAttachments(GLRenderbuffer &colorBuffer,
177 GLenum attachment0,
178 GLRenderbuffer &buffer0,
179 GLenum attachment1,
180 GLRenderbuffer &buffer1,
181 GLbitfield allowedStatuses)
182 {
183 GLFramebuffer fbo;
184 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
185 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);
186 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment0, GL_RENDERBUFFER, buffer0);
187 EXPECT_GL_NO_ERROR();
188 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment1, GL_RENDERBUFFER, buffer1);
189 EXPECT_GL_NO_ERROR();
190 checkFramebufferForAllowedStatuses(allowedStatuses);
191 checkBufferBits(attachment0, attachment1);
192 }
193
testColorRenderbuffer(GLint width,GLint height,GLenum internalformat,GLbitfield allowedStatuses)194 void testColorRenderbuffer(GLint width,
195 GLint height,
196 GLenum internalformat,
197 GLbitfield allowedStatuses)
198 {
199 GLRenderbuffer colorBuffer;
200 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
201 glRenderbufferStorage(GL_RENDERBUFFER, internalformat, width, height);
202 EXPECT_GL_NO_ERROR();
203 testAttachment(width, height, &colorBuffer, GL_COLOR_ATTACHMENT0, &colorBuffer,
204 allowedStatuses);
205 }
206
getRenderbufferParameter(GLenum paramName)207 GLint getRenderbufferParameter(GLenum paramName)
208 {
209 GLint paramValue = 0;
210 glGetRenderbufferParameteriv(GL_RENDERBUFFER, paramName, ¶mValue);
211 return paramValue;
212 }
213
drawUByteColorQuad(GLuint program,GLint uniformLoc,const GLColor & color)214 void WebGLFramebufferTest::drawUByteColorQuad(GLuint program,
215 GLint uniformLoc,
216 const GLColor &color)
217 {
218 Vector4 vecColor = color.toNormalizedVector();
219 glUseProgram(program);
220 glUniform4fv(uniformLoc, 1, vecColor.data());
221 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
222 }
223
testDepthStencilDepthStencil(GLint width,GLint height)224 void WebGLFramebufferTest::testDepthStencilDepthStencil(GLint width, GLint height)
225 {
226 if (width == 0 || height == 0)
227 {
228 return;
229 }
230
231 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
232 GLint uniformLoc = glGetUniformLocation(program, essl1_shaders::ColorUniform());
233 ASSERT_NE(-1, uniformLoc);
234
235 struct TestInfo
236 {
237 GLenum firstFormat;
238 GLenum firstAttach;
239 GLenum secondFormat;
240 GLenum secondAttach;
241 };
242
243 TestInfo tests[2] = {
244 {GL_DEPTH_COMPONENT16, GL_DEPTH_ATTACHMENT, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL_ATTACHMENT},
245 {GL_DEPTH_STENCIL, GL_DEPTH_STENCIL_ATTACHMENT, GL_DEPTH_COMPONENT16, GL_DEPTH_ATTACHMENT}};
246
247 for (const TestInfo &test : tests)
248 {
249 for (GLint opIndex = 0; opIndex < 2; ++opIndex)
250 {
251 GLFramebuffer fbo;
252 GLTexture tex;
253 GLRenderbuffer firstRb;
254
255 // test: firstFormat vs secondFormat with unbind or delete.
256
257 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
258 // attach texture as color
259 glBindTexture(GL_TEXTURE_2D, tex);
260 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
261 nullptr);
262 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
263
264 // attach first
265 glBindRenderbuffer(GL_RENDERBUFFER, firstRb);
266 glRenderbufferStorage(GL_RENDERBUFFER, test.firstFormat, width, height);
267 glFramebufferRenderbuffer(GL_FRAMEBUFFER, test.firstAttach, GL_RENDERBUFFER, firstRb);
268
269 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
270
271 // TODO(jmadill): Remove clear - this should be implicit in WebGL_
272 glClear(GL_DEPTH_BUFFER_BIT);
273
274 glEnable(GL_DEPTH_TEST);
275 // Test it works
276 drawUByteColorQuad(program, uniformLoc, GLColor::green);
277 // should not draw since DEPTH_FUNC == LESS
278 drawUByteColorQuad(program, uniformLoc, GLColor::red);
279 // should be green
280 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
281
282 GLuint secondRb = 0;
283 glGenRenderbuffers(1, &secondRb);
284
285 // attach second
286 glBindRenderbuffer(GL_RENDERBUFFER, secondRb);
287 glRenderbufferStorage(GL_RENDERBUFFER, test.secondFormat, width, height);
288 glFramebufferRenderbuffer(GL_FRAMEBUFFER, test.secondAttach, GL_RENDERBUFFER, secondRb);
289
290 if (opIndex == 0)
291 {
292 // now delete it
293 glDeleteRenderbuffers(1, &secondRb);
294 secondRb = 0;
295 }
296 else
297 {
298 // unbind it
299 glFramebufferRenderbuffer(GL_FRAMEBUFFER, test.secondAttach, GL_RENDERBUFFER, 0);
300 }
301
302 // If the first attachment is not restored this may fail
303 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
304 EXPECT_GL_NO_ERROR();
305
306 // If the first attachment is not restored this may fail.
307 glClear(GL_DEPTH_BUFFER_BIT);
308 drawUByteColorQuad(program, uniformLoc, GLColor::green);
309 // should not draw since DEPTH_FUNC == LESS
310 drawUByteColorQuad(program, uniformLoc, GLColor::red);
311 // should be green
312 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
313 glDisable(GL_DEPTH_TEST);
314
315 if (opIndex == 1)
316 {
317 glDeleteRenderbuffers(1, &secondRb);
318 secondRb = 0;
319 }
320 }
321 }
322 EXPECT_GL_NO_ERROR();
323 }
324
testDepthStencilRenderbuffer(GLint width,GLint height,GLRenderbuffer * colorBuffer,GLbitfield allowedStatuses)325 void WebGLFramebufferTest::testDepthStencilRenderbuffer(GLint width,
326 GLint height,
327 GLRenderbuffer *colorBuffer,
328 GLbitfield allowedStatuses)
329 {
330 GLRenderbuffer depthStencilBuffer;
331 glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
332 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
333 EXPECT_GL_NO_ERROR();
334
335 // OpenGL itself doesn't seem to guarantee that e.g. a 2 x 0
336 // renderbuffer will report 2 for its width when queried.
337 if (!(height == 0 && width > 0))
338 {
339 EXPECT_EQ(width, getRenderbufferParameter(GL_RENDERBUFFER_WIDTH));
340 }
341 if (!(width == 0 && height > 0))
342 {
343 EXPECT_EQ(height, getRenderbufferParameter(GL_RENDERBUFFER_HEIGHT));
344 }
345 EXPECT_EQ(GL_DEPTH_STENCIL, getRenderbufferParameter(GL_RENDERBUFFER_INTERNAL_FORMAT));
346 EXPECT_EQ(0, getRenderbufferParameter(GL_RENDERBUFFER_RED_SIZE));
347 EXPECT_EQ(0, getRenderbufferParameter(GL_RENDERBUFFER_GREEN_SIZE));
348 EXPECT_EQ(0, getRenderbufferParameter(GL_RENDERBUFFER_BLUE_SIZE));
349 EXPECT_EQ(0, getRenderbufferParameter(GL_RENDERBUFFER_ALPHA_SIZE));
350
351 // Avoid verifying these for zero-sized renderbuffers for the time
352 // being since it appears that even OpenGL doesn't guarantee them.
353 if (width > 0 && height > 0)
354 {
355 EXPECT_GT(getRenderbufferParameter(GL_RENDERBUFFER_DEPTH_SIZE), 0);
356 EXPECT_GT(getRenderbufferParameter(GL_RENDERBUFFER_STENCIL_SIZE), 0);
357 }
358 EXPECT_GL_NO_ERROR();
359 testAttachment(width, height, colorBuffer, GL_DEPTH_STENCIL_ATTACHMENT, &depthStencilBuffer,
360 allowedStatuses);
361 testDepthStencilDepthStencil(width, height);
362 }
363
364 // Test various attachment combinations with WebGL framebuffers.
TEST_P(WebGLFramebufferTest,TestAttachments)365 TEST_P(WebGLFramebufferTest, TestAttachments)
366 {
367 // GL_DEPTH_STENCIL renderbuffer format is only valid for WebGL1
368 ANGLE_SKIP_TEST_IF(getClientMajorVersion() != 2);
369
370 for (GLint width = 2; width <= 2; width += 2)
371 {
372 for (GLint height = 2; height <= 2; height += 2)
373 {
374 // Dimensions width x height.
375 GLRenderbuffer colorBuffer;
376 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
377 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, width, height);
378 EXPECT_GL_NO_ERROR();
379
380 GLRenderbuffer depthBuffer;
381 glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
382 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
383 EXPECT_GL_NO_ERROR();
384
385 GLRenderbuffer stencilBuffer;
386 glBindRenderbuffer(GL_RENDERBUFFER, stencilBuffer);
387 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
388 EXPECT_GL_NO_ERROR();
389
390 GLRenderbuffer depthStencilBuffer;
391 glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
392 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
393 EXPECT_GL_NO_ERROR();
394
395 GLbitfield allowedStatusForGoodCase =
396 (width == 0 || height == 0) ? ALLOW_INCOMPLETE_ATTACHMENT : ALLOW_COMPLETE;
397
398 // some cases involving stencil seem to be implementation-dependent
399 GLbitfield allowedStatusForImplDependentCase =
400 allowedStatusForGoodCase | ALLOW_UNSUPPORTED;
401
402 // Attach depth using DEPTH_ATTACHMENT.
403 testAttachment(width, height, &colorBuffer, GL_DEPTH_ATTACHMENT, &depthBuffer,
404 allowedStatusForGoodCase);
405
406 // Attach depth using STENCIL_ATTACHMENT.
407 testAttachment(width, height, &colorBuffer, GL_STENCIL_ATTACHMENT, &depthBuffer,
408 ALLOW_INCOMPLETE_ATTACHMENT);
409
410 // Attach depth using DEPTH_STENCIL_ATTACHMENT.
411 testAttachment(width, height, &colorBuffer, GL_DEPTH_STENCIL_ATTACHMENT, &depthBuffer,
412 ALLOW_INCOMPLETE_ATTACHMENT);
413
414 // Attach stencil using STENCIL_ATTACHMENT.
415 testAttachment(width, height, &colorBuffer, GL_STENCIL_ATTACHMENT, &stencilBuffer,
416 allowedStatusForImplDependentCase);
417
418 // Attach stencil using DEPTH_ATTACHMENT.
419 testAttachment(width, height, &colorBuffer, GL_DEPTH_ATTACHMENT, &stencilBuffer,
420 ALLOW_INCOMPLETE_ATTACHMENT);
421
422 // Attach stencil using DEPTH_STENCIL_ATTACHMENT.
423 testAttachment(width, height, &colorBuffer, GL_DEPTH_STENCIL_ATTACHMENT, &stencilBuffer,
424 ALLOW_INCOMPLETE_ATTACHMENT);
425
426 // Attach depthStencil using DEPTH_STENCIL_ATTACHMENT.
427 testAttachment(width, height, &colorBuffer, GL_DEPTH_STENCIL_ATTACHMENT,
428 &depthStencilBuffer, allowedStatusForGoodCase);
429
430 // Attach depthStencil using DEPTH_ATTACHMENT.
431 testAttachment(width, height, &colorBuffer, GL_DEPTH_ATTACHMENT, &depthStencilBuffer,
432 ALLOW_INCOMPLETE_ATTACHMENT);
433
434 // Attach depthStencil using STENCIL_ATTACHMENT.
435 testAttachment(width, height, &colorBuffer, GL_STENCIL_ATTACHMENT, &depthStencilBuffer,
436 ALLOW_INCOMPLETE_ATTACHMENT);
437
438 GLbitfield allowedStatusForConflictedAttachment =
439 (width == 0 || height == 0) ? ALLOW_UNSUPPORTED | ALLOW_INCOMPLETE_ATTACHMENT
440 : ALLOW_UNSUPPORTED;
441
442 // Attach depth, then stencil, causing conflict.
443 testAttachments(colorBuffer, GL_DEPTH_ATTACHMENT, depthBuffer, GL_STENCIL_ATTACHMENT,
444 stencilBuffer, allowedStatusForConflictedAttachment);
445
446 // Attach stencil, then depth, causing conflict.
447 testAttachments(colorBuffer, GL_STENCIL_ATTACHMENT, stencilBuffer, GL_DEPTH_ATTACHMENT,
448 depthBuffer, allowedStatusForConflictedAttachment);
449
450 // Attach depth, then depthStencil, causing conflict.
451 testAttachments(colorBuffer, GL_DEPTH_ATTACHMENT, depthBuffer,
452 GL_DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer,
453 allowedStatusForConflictedAttachment);
454
455 // Attach depthStencil, then depth, causing conflict.
456 testAttachments(colorBuffer, GL_DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer,
457 GL_DEPTH_ATTACHMENT, depthBuffer, allowedStatusForConflictedAttachment);
458
459 // Attach stencil, then depthStencil, causing conflict.
460 testAttachments(colorBuffer, GL_DEPTH_ATTACHMENT, depthBuffer,
461 GL_DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer,
462 allowedStatusForConflictedAttachment);
463
464 // Attach depthStencil, then stencil, causing conflict.
465 testAttachments(colorBuffer, GL_DEPTH_STENCIL_ATTACHMENT, depthStencilBuffer,
466 GL_STENCIL_ATTACHMENT, stencilBuffer,
467 allowedStatusForConflictedAttachment);
468
469 // Attach color renderbuffer with internalformat == RGBA4.
470 testColorRenderbuffer(width, height, GL_RGBA4, allowedStatusForGoodCase);
471
472 // Attach color renderbuffer with internalformat == RGB5_A1.
473 // This particular format seems to be bugged on NVIDIA Retina. http://crbug.com/635081
474 // TODO(jmadill): Figure out if we can add a format workaround.
475 if (!(IsNVIDIA() && IsMac() && IsOpenGL()))
476 {
477 testColorRenderbuffer(width, height, GL_RGB5_A1, allowedStatusForGoodCase);
478 }
479
480 // Attach color renderbuffer with internalformat == RGB565.
481 testColorRenderbuffer(width, height, GL_RGB565, allowedStatusForGoodCase);
482
483 // Create and attach depthStencil renderbuffer.
484 testDepthStencilRenderbuffer(width, height, &colorBuffer, allowedStatusForGoodCase);
485 }
486 }
487 }
488
tryDepth(GLRenderbuffer * depthBuffer,GLenum * depthFormat,GLenum * depthAttachment,GLenum try_format,GLenum try_attachment)489 bool tryDepth(GLRenderbuffer *depthBuffer,
490 GLenum *depthFormat,
491 GLenum *depthAttachment,
492 GLenum try_format,
493 GLenum try_attachment)
494 {
495 if (*depthAttachment != GL_NONE)
496 {
497 // If we've tried once unattach the old one.
498 glFramebufferRenderbuffer(GL_FRAMEBUFFER, *depthAttachment, GL_RENDERBUFFER, 0);
499 }
500 *depthFormat = try_format;
501 *depthAttachment = try_attachment;
502 glFramebufferRenderbuffer(GL_FRAMEBUFFER, *depthAttachment, GL_RENDERBUFFER, *depthBuffer);
503 glRenderbufferStorage(GL_RENDERBUFFER, *depthFormat, 16, 16);
504 EXPECT_GL_NO_ERROR();
505 return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
506 }
507
checkValidColorDepthCombination(GLenum * depthFormat,GLenum * depthAttachment)508 bool checkValidColorDepthCombination(GLenum *depthFormat, GLenum *depthAttachment)
509 {
510 GLFramebuffer fbo;
511 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
512 GLRenderbuffer colorBuffer;
513 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
514 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);
515 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 16, 16);
516
517 GLRenderbuffer depthBuffer;
518 glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
519
520 return tryDepth(&depthBuffer, depthFormat, depthAttachment, GL_DEPTH_COMPONENT16,
521 GL_DEPTH_ATTACHMENT) ||
522 tryDepth(&depthBuffer, depthFormat, depthAttachment, GL_DEPTH_STENCIL,
523 GL_DEPTH_STENCIL_ATTACHMENT);
524 }
525
526 // glCheckFramebufferStatus(GL_FRAMEBUFFER) should be either complete or (unsupported/expected).
checkFramebuffer(GLenum expected)527 void checkFramebuffer(GLenum expected)
528 {
529 GLenum actual = glCheckFramebufferStatus(GL_FRAMEBUFFER);
530 EXPECT_TRUE(actual == expected ||
531 (expected != GL_FRAMEBUFFER_COMPLETE && actual == GL_FRAMEBUFFER_UNSUPPORTED));
532 }
533
testRenderingAndReading(GLuint program)534 void WebGLFramebufferTest::testRenderingAndReading(GLuint program)
535 {
536 EXPECT_GL_NO_ERROR();
537
538 // drawArrays with incomplete framebuffer
539 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
540 EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
541
542 // readPixels from incomplete framebuffer
543 std::vector<uint8_t> incompleteBuffer(4);
544 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, incompleteBuffer.data());
545 EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
546
547 // copyTexImage and copyTexSubImage can be either INVALID_FRAMEBUFFER_OPERATION because
548 // the framebuffer is invalid OR INVALID_OPERATION because in the case of no attachments
549 // the framebuffer is not of a compatible type.
550
551 // copyTexSubImage2D from incomplete framebuffer
552 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
553 GLenum error = glGetError();
554 EXPECT_TRUE(error == GL_INVALID_FRAMEBUFFER_OPERATION || error == GL_INVALID_OPERATION);
555
556 // copyTexImage2D from incomplete framebuffer
557 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
558 error = glGetError();
559 EXPECT_TRUE(error == GL_INVALID_FRAMEBUFFER_OPERATION || error == GL_INVALID_OPERATION);
560
561 // clear with incomplete framebuffer
562 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
563 EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
564 }
565
566 // Test drawing or reading from an incomplete framebuffer
testUsingIncompleteFramebuffer(GLenum depthFormat,GLenum depthAttachment)567 void WebGLFramebufferTest::testUsingIncompleteFramebuffer(GLenum depthFormat,
568 GLenum depthAttachment)
569 {
570 // Simple draw program.
571 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
572
573 GLFramebuffer fbo;
574 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
575 GLRenderbuffer colorBuffer;
576 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
577 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);
578 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 16, 16);
579
580 GLRenderbuffer depthBuffer;
581 glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
582 glFramebufferRenderbuffer(GL_FRAMEBUFFER, depthAttachment, GL_RENDERBUFFER, depthBuffer);
583 glRenderbufferStorage(GL_RENDERBUFFER, depthFormat, 16, 16);
584 EXPECT_GL_NO_ERROR();
585 checkFramebuffer(GL_FRAMEBUFFER_COMPLETE);
586
587 // We pick this combination because it works on desktop OpenGL but should not work on OpenGL ES
588 // 2.0
589 glRenderbufferStorage(GL_RENDERBUFFER, depthFormat, 32, 16);
590 checkFramebuffer(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
591
592 // Drawing or reading from an incomplete framebuffer should generate
593 // INVALID_FRAMEBUFFER_OPERATION.
594 testRenderingAndReading(program);
595
596 GLFramebuffer fbo2;
597 glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
598 checkFramebuffer(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
599
600 // Drawing or reading from an incomplete framebuffer should generate
601 // INVALID_FRAMEBUFFER_OPERATION.
602 testRenderingAndReading(program);
603
604 GLRenderbuffer colorBuffer2;
605 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer2);
606 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer2);
607 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 0, 0);
608
609 // Drawing or reading from an incomplete framebuffer should generate
610 // INVALID_FRAMEBUFFER_OPERATION.
611 testRenderingAndReading(program);
612 }
613
testFramebufferIncompleteAttachment(GLenum depthFormat)614 void testFramebufferIncompleteAttachment(GLenum depthFormat)
615 {
616 GLFramebuffer fbo;
617 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
618 GLRenderbuffer colorBuffer;
619 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
620 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);
621 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 16, 16);
622 checkFramebuffer(GL_FRAMEBUFFER_COMPLETE);
623
624 // Wrong storage type for type of attachment be FRAMEBUFFER_INCOMPLETE_ATTACHMENT (OpenGL ES 2.0
625 // 4.4.5).
626 glRenderbufferStorage(GL_RENDERBUFFER, depthFormat, 16, 16);
627 checkFramebuffer(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
628
629 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 16, 16);
630 checkFramebuffer(GL_FRAMEBUFFER_COMPLETE);
631
632 // 0 size attachment should be FRAMEBUFFER_INCOMPLETE_ATTACHMENT (OpenGL ES 2.0 4.4.5).
633 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 0, 0);
634 checkFramebuffer(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
635
636 EXPECT_GL_NO_ERROR();
637 }
638
639 // No attachments should be INCOMPLETE_FRAMEBUFFER_MISSING_ATTACHMENT (OpenGL ES 2.0 4.4.5).
testFramebufferIncompleteMissingAttachment()640 void testFramebufferIncompleteMissingAttachment()
641 {
642 GLFramebuffer fbo;
643 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
644 checkFramebuffer(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
645
646 GLRenderbuffer colorBuffer;
647 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
648 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);
649 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 16, 16);
650 checkFramebuffer(GL_FRAMEBUFFER_COMPLETE);
651
652 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0);
653 checkFramebuffer(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
654
655 EXPECT_GL_NO_ERROR();
656 }
657
658 // Attachments of different sizes should be FRAMEBUFFER_INCOMPLETE_DIMENSIONS (OpenGL ES 2.0 4.4.5).
testFramebufferIncompleteDimensions(GLenum depthFormat,GLenum depthAttachment)659 void testFramebufferIncompleteDimensions(GLenum depthFormat, GLenum depthAttachment)
660 {
661 GLFramebuffer fbo;
662 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
663 GLRenderbuffer colorBuffer;
664 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
665 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);
666 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 16, 16);
667
668 GLRenderbuffer depthBuffer;
669 glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
670 glFramebufferRenderbuffer(GL_FRAMEBUFFER, depthAttachment, GL_RENDERBUFFER, depthBuffer);
671 glRenderbufferStorage(GL_RENDERBUFFER, depthFormat, 16, 16);
672 EXPECT_GL_NO_ERROR();
673 checkFramebuffer(GL_FRAMEBUFFER_COMPLETE);
674
675 glRenderbufferStorage(GL_RENDERBUFFER, depthFormat, 32, 16);
676 checkFramebuffer(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
677 glRenderbufferStorage(GL_RENDERBUFFER, depthFormat, 16, 16);
678 checkFramebuffer(GL_FRAMEBUFFER_COMPLETE);
679 glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
680 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 16, 32);
681 checkFramebuffer(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
682 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 16, 16);
683 checkFramebuffer(GL_FRAMEBUFFER_COMPLETE);
684 EXPECT_GL_NO_ERROR();
685
686 GLTexture tex;
687 glBindTexture(GL_TEXTURE_2D, tex);
688 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
689 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
690 EXPECT_GL_NO_ERROR();
691 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
692 {
693 return;
694 }
695
696 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
697 checkFramebuffer(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
698 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
699 checkFramebuffer(GL_FRAMEBUFFER_COMPLETE);
700
701 EXPECT_GL_NO_ERROR();
702 }
703
704 class NoColorFB final : angle::NonCopyable
705 {
706 public:
NoColorFB(int size)707 NoColorFB(int size)
708 {
709 glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
710
711 // The only scenario we can verify is an attempt to read or copy
712 // from a missing color attachment while the framebuffer is still
713 // complete.
714 glBindRenderbuffer(GL_RENDERBUFFER, mDepthBuffer);
715 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
716 mDepthBuffer);
717 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
718
719 // After depth renderbuffer setup
720 EXPECT_GL_NO_ERROR();
721
722 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
723 {
724 // Unable to allocate a framebuffer with just a depth attachment; this is legal.
725 // Try just a depth/stencil renderbuffer.
726 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
727
728 glBindRenderbuffer(GL_RENDERBUFFER, mDepthStencilBuffer);
729 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
730 mDepthStencilBuffer);
731 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, size, size);
732
733 // After depth+stencil renderbuffer setup
734 EXPECT_GL_NO_ERROR();
735 }
736 }
737
738 private:
739 GLRenderbuffer mDepthBuffer;
740 GLRenderbuffer mDepthStencilBuffer;
741 GLFramebuffer mFBO;
742 };
743
744 // Test reading from a missing framebuffer attachment.
TestReadingMissingAttachment(int size)745 void TestReadingMissingAttachment(int size)
746 {
747 // The FBO has no color attachment. ReadPixels, CopyTexImage2D,
748 // and CopyTexSubImage2D should all generate INVALID_OPERATION.
749
750 // Before ReadPixels from missing attachment
751 std::vector<uint8_t> incompleteBuffer(4);
752 EXPECT_GL_NO_ERROR();
753 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, incompleteBuffer.data());
754 // After ReadPixels from missing attachment
755 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
756
757 GLTexture tex;
758 glBindTexture(GL_TEXTURE_2D, tex);
759 // Before CopyTexImage2D from missing attachment
760 EXPECT_GL_NO_ERROR();
761 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, size, size, 0);
762 // After CopyTexImage2D from missing attachment
763 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
764
765 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
766 // Before CopyTexSubImage2D from missing attachment
767 EXPECT_GL_NO_ERROR();
768 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size, size);
769 // After CopyTexSubImage2D from missing attachment
770 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
771 }
772
773 // Test drawing to a missing framebuffer attachment.
testDrawingMissingAttachment()774 void WebGLFramebufferTest::testDrawingMissingAttachment()
775 {
776 // Simple draw program.
777 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
778
779 glClear(GL_COLOR_BUFFER_BIT);
780 EXPECT_GL_NO_ERROR();
781
782 // try glDrawArrays
783 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
784 EXPECT_GL_NO_ERROR();
785
786 // try glDrawElements
787 drawIndexedQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
788 EXPECT_GL_NO_ERROR();
789 }
790
791 // Determine if we can attach both color and depth or color and depth_stencil
TEST_P(WebGLFramebufferTest,CheckValidColorDepthCombination)792 TEST_P(WebGLFramebufferTest, CheckValidColorDepthCombination)
793 {
794 GLenum depthFormat = GL_NONE;
795 GLenum depthAttachment = GL_NONE;
796
797 if (checkValidColorDepthCombination(&depthFormat, &depthAttachment))
798 {
799 testFramebufferIncompleteDimensions(depthFormat, depthAttachment);
800 testFramebufferIncompleteAttachment(depthFormat);
801 testFramebufferIncompleteMissingAttachment();
802 testUsingIncompleteFramebuffer(depthFormat, depthAttachment);
803
804 constexpr int size = 16;
805 NoColorFB fb(size);
806 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
807 {
808 // The FBO has no color attachment. ReadPixels, CopyTexImage2D,
809 // and CopyTexSubImage2D should all generate INVALID_OPERATION.
810 TestReadingMissingAttachment(size);
811
812 // The FBO has no color attachment. Clear, DrawArrays,
813 // and DrawElements should not generate an error.
814 testDrawingMissingAttachment();
815 }
816 }
817 }
818
819 // Test to cover a bug in preserving the texture image index for WebGL framebuffer attachments
TEST_P(WebGLFramebufferTest,TextureAttachmentCommitBug)820 TEST_P(WebGLFramebufferTest, TextureAttachmentCommitBug)
821 {
822 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_depth_texture"));
823
824 GLTexture depthTexture;
825 glBindTexture(GL_TEXTURE_2D, depthTexture);
826 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,
827 nullptr);
828
829 GLFramebuffer framebuffer;
830 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
831 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
832
833 glCheckFramebufferStatus(GL_FRAMEBUFFER);
834
835 EXPECT_GL_NO_ERROR();
836 }
837
838 // Test combinations of ordering in setting the resource format and attaching it to the depth
839 // stencil attacchment. Covers http://crbug.com/997702
TEST_P(WebGLFramebufferTest,DepthStencilAttachmentOrdering)840 TEST_P(WebGLFramebufferTest, DepthStencilAttachmentOrdering)
841 {
842 constexpr GLsizei kFramebufferSize = 16;
843
844 GLTexture color;
845 glBindTexture(GL_TEXTURE_2D, color);
846 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kFramebufferSize, kFramebufferSize, 0, GL_RGBA,
847 GL_UNSIGNED_BYTE, nullptr);
848
849 GLRenderbuffer depthStencil;
850 glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
851
852 // Attach the renderbuffer to the framebuffer when it has no format
853 GLFramebuffer framebuffer;
854 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
855 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
856 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
857 depthStencil);
858
859 // Framebuffer is incomplete because the depth stencil attachment doesn't a format/size
860 EXPECT_GL_NO_ERROR();
861 EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
862 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
863
864 // Set depth stencil attachment to a color format
865 if (EnsureGLExtensionEnabled("GL_OES_rgb8_rgba8"))
866 {
867 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kFramebufferSize, kFramebufferSize);
868
869 // Non-depth stencil format on the depth stencil attachment
870 EXPECT_GL_NO_ERROR();
871 EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
872 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
873 }
874
875 {
876 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, kFramebufferSize,
877 kFramebufferSize);
878
879 // Depth-stencil attachment only has a depth format, not complete
880 EXPECT_GL_NO_ERROR();
881 EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
882 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
883 }
884
885 if (EnsureGLExtensionEnabled("GL_OES_packed_depth_stencil"))
886 {
887 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kFramebufferSize,
888 kFramebufferSize);
889
890 // Framebuffer should be complete now with a depth-stencil format
891 EXPECT_GL_NO_ERROR();
892 EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
893 }
894 }
895
896 // Only run against WebGL 1 validation, since much was changed in 2.
897 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(WebGLFramebufferTest);
898
899 } // namespace angle
900