2 Copyright (c) 2019 The Khronos Group Inc.
3 Use of this source code is governed by an MIT-style license that can be
4 found in the LICENSE.txt file.
10 <meta charset=
"utf-8">
11 <link rel=
"stylesheet" href=
"../../resources/js-test-style.css"/>
12 <script src=
"../../js/js-test-pre.js"></script>
13 <script src=
"../../js/webgl-test-utils.js"></script>
16 <div id=
"description"></div>
17 <div id=
"console"></div>
21 var wtu
= WebGLTestUtils
;
24 function checkFramebuffer(expected
) {
25 var actual
= gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
);
26 if (expected
.indexOf(actual
) < 0) {
27 var msg
= "checkFramebufferStatus expects [";
28 for (var index
= 0; index
< expected
.length
; ++index
) {
29 msg
+= wtu
.glEnumToString(gl
, expected
[index
]);
30 if (index
+ 1 < expected
.length
)
33 msg
+= "], was " + wtu
.glEnumToString(gl
, actual
);
36 var msg
= "checkFramebufferStatus got " + wtu
.glEnumToString(gl
, actual
) +
42 function checkBufferBits(attachment0
, attachment1
) {
43 if (gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
) != gl
.FRAMEBUFFER_COMPLETE
)
45 var haveDepthBuffer
= attachment0
== gl
.DEPTH_ATTACHMENT
||
46 attachment0
== gl
.DEPTH_STENCIL_ATTACHMENT
||
47 attachment1
== gl
.DEPTH_ATTACHMENT
||
48 attachment1
== gl
.DEPTH_STENCIL_ATTACHMENT
;
49 var haveStencilBuffer
= attachment0
== gl
.STENCIL_ATTACHMENT
||
50 attachment0
== gl
.DEPTH_STENCIL_ATTACHMENT
||
51 attachment1
== gl
.STENCIL_ATTACHMENT
||
52 attachment1
== gl
.DEPTH_STENCIL_ATTACHMENT
;
53 shouldBeTrue("gl.getParameter(gl.RED_BITS) + gl.getParameter(gl.GREEN_BITS) + " +
54 "gl.getParameter(gl.BLUE_BITS) + gl.getParameter(gl.ALPHA_BITS) >= 16");
56 shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) >= 16");
58 shouldBeTrue("gl.getParameter(gl.DEPTH_BITS) == 0");
59 if (haveStencilBuffer
)
60 shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) >= 8");
62 shouldBeTrue("gl.getParameter(gl.STENCIL_BITS) == 0");
66 function testFramebufferWebGL1RequiredCombinations() {
67 debug("Checking combinations of framebuffer attachments required to be valid by WebGL 1");
69 // Per discussion with the OpenGL ES working group, the following framebuffer attachment
70 // combinations are required to work in all WebGL 1 implementations:
71 // 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
72 // 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
73 // 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer
75 var fbo
= gl
.createFramebuffer();
76 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
81 // 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
82 var texture
= gl
.createTexture();
83 gl
.bindTexture(gl
.TEXTURE_2D
, texture
);
84 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_MIN_FILTER
, gl
.NEAREST
);
85 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_MAG_FILTER
, gl
.NEAREST
);
86 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_WRAP_S
, gl
.CLAMP_TO_EDGE
);
87 gl
.texParameteri(gl
.TEXTURE_2D
, gl
.TEXTURE_WRAP_T
, gl
.CLAMP_TO_EDGE
);
88 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, width
, height
, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
89 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.TEXTURE_2D
, texture
, 0);
90 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
93 // 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
94 var renderbuffer
= gl
.createRenderbuffer();
95 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, renderbuffer
);
96 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_COMPONENT16
, width
, height
);
97 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, renderbuffer
);
98 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
99 checkBufferBits(gl
.DEPTH_ATTACHMENT
);
100 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, null);
102 // 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer
103 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_STENCIL
, width
, height
);
104 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.DEPTH_STENCIL_ATTACHMENT
, gl
.RENDERBUFFER
, renderbuffer
);
105 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
106 checkBufferBits(gl
.DEPTH_STENCIL_ATTACHMENT
);
109 gl
.deleteRenderbuffer(renderbuffer
);
110 gl
.deleteTexture(texture
);
111 gl
.deleteFramebuffer(fbo
);
114 function testDepthStencilAttachmentBehaviors(testOrphanedRenderbuffers
) {
115 let suffix
= testOrphanedRenderbuffers
? " with deleted renderbuffer" : "";
117 debug("Checking ES3 DEPTH_STENCIL_ATTACHMENT behaviors are implemented for WebGL 2" + suffix
);
118 // DEPTH_STENCIL_ATTACHMENT is treated as an independent attachment point in WebGL 1;
119 // however, in WebGL 2, it is treated as an alias for DEPTH_ATTACHMENT + STENCIL_ATTACHMENT.
122 var fbo
= gl
.createFramebuffer();
123 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
124 var colorBuffer
= gl
.createRenderbuffer();
125 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
126 gl
.framebufferRenderbuffer(
127 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
128 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA8
, size
, size
);
129 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
131 function createDepthBuffer() {
132 let buffer
= gl
.createRenderbuffer();
133 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, buffer
);
134 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_COMPONENT16
, size
, size
);
135 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, null);
139 function createStencilBuffer() {
140 let buffer
= gl
.createRenderbuffer();
141 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, buffer
);
142 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.STENCIL_INDEX8
, size
, size
);
143 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, null);
147 function createDepthStencilBuffer() {
148 let buffer
= gl
.createRenderbuffer();
149 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, buffer
);
150 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_STENCIL
, size
, size
);
151 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, null);
155 function orphan(renderbuffer
) {
156 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, null);
157 gl
.deleteRenderbuffer(renderbuffer
);
158 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
161 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
164 debug("color + depth" + suffix
);
165 var depthBuffer
= createDepthBuffer();
166 gl
.framebufferRenderbuffer(
167 gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, depthBuffer
);
168 if (testOrphanedRenderbuffers
)
170 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer
);
171 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
172 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
173 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
174 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
175 checkBufferBits(gl
.DEPTH_ATTACHMENT
);
178 debug("color + depth + stencil: depth != stencil" + suffix
);
179 var stencilBuffer
= createStencilBuffer();
180 gl
.framebufferRenderbuffer(
181 gl
.FRAMEBUFFER
, gl
.STENCIL_ATTACHMENT
, gl
.RENDERBUFFER
, stencilBuffer
);
182 if (testOrphanedRenderbuffers
)
183 orphan(stencilBuffer
);
184 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer
);
185 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", stencilBuffer
);
186 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
187 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
188 checkFramebuffer([gl
.FRAMEBUFFER_UNSUPPORTED
]);
190 gl
.framebufferRenderbuffer(
191 gl
.FRAMEBUFFER
, gl
.STENCIL_ATTACHMENT
, gl
.RENDERBUFFER
, null);
192 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer
);
193 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
194 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
195 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
198 debug("color + depth: DEPTH_STENCIL for DEPTH_ATTACHMENT" + suffix
);
199 var depthStencilBuffer
= createDepthStencilBuffer();
200 gl
.framebufferRenderbuffer(
201 gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, depthStencilBuffer
);
202 if (testOrphanedRenderbuffers
)
203 orphan(depthStencilBuffer
);
204 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
205 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
206 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
207 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
208 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
209 checkBufferBits(gl
.DEPTH_ATTACHMENT
);
212 debug("color + depth + stencil: DEPTH_STENCIL for DEPTH_ATTACHMENT and STENCIL_ATTACHMENT" + suffix
);
213 if (testOrphanedRenderbuffers
) {
214 depthStencilBuffer
= createDepthStencilBuffer();
215 gl
.framebufferRenderbuffer(
216 gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, depthStencilBuffer
);
218 gl
.framebufferRenderbuffer(
219 gl
.FRAMEBUFFER
, gl
.STENCIL_ATTACHMENT
, gl
.RENDERBUFFER
, depthStencilBuffer
);
220 if (testOrphanedRenderbuffers
)
221 orphan(depthStencilBuffer
);
222 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
223 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
224 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
225 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
226 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
227 checkBufferBits(gl
.DEPTH_STENCIL_ATTACHMENT
);
230 debug("color + depth_stencil" + suffix
);
231 var texture
= gl
.createTexture();
232 gl
.bindTexture(gl
.TEXTURE_2D
, texture
);
233 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.DEPTH24_STENCIL8
, size
, size
, 0, gl
.DEPTH_STENCIL
, gl
.UNSIGNED_INT_24_8
, null);
234 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.DEPTH_STENCIL_ATTACHMENT
, gl
.TEXTURE_2D
, texture
, 0);
235 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texture
);
236 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texture
);
237 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", texture
);
238 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
239 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
241 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.DEPTH_STENCIL_ATTACHMENT
, gl
.TEXTURE_2D
, null, 0);
242 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
243 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
244 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
245 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
247 if (testOrphanedRenderbuffers
)
248 depthStencilBuffer
= createDepthStencilBuffer();
249 gl
.framebufferRenderbuffer(
250 gl
.FRAMEBUFFER
, gl
.DEPTH_STENCIL_ATTACHMENT
, gl
.RENDERBUFFER
, depthStencilBuffer
);
251 if (testOrphanedRenderbuffers
)
252 orphan(depthStencilBuffer
);
253 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
254 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
255 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
256 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
257 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
258 checkBufferBits(gl
.DEPTH_STENCIL_ATTACHMENT
);
261 debug("DEPTH_STENCIL_ATTACHMENT overwrites DEPTH_ATTACHMENT/STENCIL_ATTACHMENT" + suffix
);
262 if (testOrphanedRenderbuffers
)
263 depthBuffer
= createDepthBuffer();
264 gl
.framebufferRenderbuffer(
265 gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, depthBuffer
);
266 if (testOrphanedRenderbuffers
)
268 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthBuffer
);
269 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
270 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
271 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
273 if (testOrphanedRenderbuffers
)
274 depthStencilBuffer
= createDepthStencilBuffer();
275 gl
.framebufferRenderbuffer(
276 gl
.FRAMEBUFFER
, gl
.DEPTH_STENCIL_ATTACHMENT
, gl
.RENDERBUFFER
, depthStencilBuffer
);
277 if (testOrphanedRenderbuffers
)
278 orphan(depthStencilBuffer
);
279 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
280 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
281 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
282 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
284 gl
.framebufferRenderbuffer(
285 gl
.FRAMEBUFFER
, gl
.DEPTH_STENCIL_ATTACHMENT
, gl
.RENDERBUFFER
, null);
286 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
287 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
288 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
289 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
290 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
294 debug("STENCIL_ATTACHMENT overwrites stencil set by DEPTH_STENCIL_ATTACHMENT" + suffix
);
295 if (testOrphanedRenderbuffers
)
296 depthStencilBuffer
= createDepthStencilBuffer();
297 gl
.framebufferRenderbuffer(
298 gl
.FRAMEBUFFER
, gl
.DEPTH_STENCIL_ATTACHMENT
, gl
.RENDERBUFFER
, depthStencilBuffer
);
299 if (testOrphanedRenderbuffers
)
300 orphan(depthStencilBuffer
);
301 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
302 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
303 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
304 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
306 gl
.framebufferRenderbuffer(
307 gl
.FRAMEBUFFER
, gl
.STENCIL_ATTACHMENT
, gl
.RENDERBUFFER
, null);
308 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
309 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
310 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
311 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
312 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
313 checkBufferBits(gl
.DEPTH_ATTACHMENT
);
316 debug("DEPTH_ATTACHMENT overwrites depth set by DEPTH_STENCIL_ATTACHMENT" + suffix
);
317 if (testOrphanedRenderbuffers
)
318 depthStencilBuffer
= createDepthStencilBuffer();
319 gl
.framebufferRenderbuffer(
320 gl
.FRAMEBUFFER
, gl
.DEPTH_STENCIL_ATTACHMENT
, gl
.RENDERBUFFER
, depthStencilBuffer
);
321 if (testOrphanedRenderbuffers
)
322 orphan(depthStencilBuffer
);
323 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
324 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
325 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
326 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
328 gl
.framebufferRenderbuffer(
329 gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, null);
330 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
331 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", depthStencilBuffer
);
332 shouldEvaluateTo("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", null);
333 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
);
334 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
335 checkBufferBits(gl
.STENCIL_ATTACHMENT
);
338 function testFramebufferIncompleteAttachment() {
339 var fbo
= gl
.createFramebuffer();
340 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
341 var colorBuffer
= gl
.createRenderbuffer();
342 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
343 gl
.framebufferRenderbuffer(
344 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
345 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
346 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
349 debug("Wrong storage type for type of attachment should be FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
350 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_COMPONENT16
, 16, 16);
351 checkFramebuffer([gl
.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
]);
353 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
354 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
357 debug("0 size attachment should be FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
358 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 0, 0);
359 checkFramebuffer([gl
.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
]);
361 gl
.deleteRenderbuffer(colorBuffer
);
362 gl
.deleteFramebuffer(fbo
);
363 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
366 function testFramebufferIncompleteMissingAttachment() {
368 debug("No attachments should be INCOMPLETE_FRAMEBUFFER_MISSING_ATTACHMENT");
369 var fbo
= gl
.createFramebuffer();
370 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
371 checkFramebuffer([gl
.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
]);
373 var colorBuffer
= gl
.createRenderbuffer();
374 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
375 gl
.framebufferRenderbuffer(
376 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
377 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
378 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
380 gl
.framebufferRenderbuffer(
381 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, null);
382 checkFramebuffer([gl
.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
]);
384 gl
.deleteRenderbuffer(colorBuffer
);
385 gl
.deleteFramebuffer(fbo
);
386 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
389 function testFramebufferWithImagesOfDifferentSizes() {
391 debug("Attachments of different sizes should NOT be allowed");
393 var fbo
= gl
.createFramebuffer();
394 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
395 var colorBuffer
= gl
.createRenderbuffer();
396 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
397 gl
.framebufferRenderbuffer(
398 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
399 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 16);
401 var depthBuffer
= gl
.createRenderbuffer();
402 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, depthBuffer
);
403 gl
.framebufferRenderbuffer(
404 gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, depthBuffer
);
405 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_COMPONENT16
, 16, 16);
406 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
407 checkFramebuffer([gl
.FRAMEBUFFER_COMPLETE
]);
409 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_COMPONENT16
, 32, 16);
410 checkFramebuffer([gl
.FRAMEBUFFER_INCOMPLETE_DIMENSIONS
]);
411 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
412 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 16, 32);
413 checkFramebuffer([gl
.FRAMEBUFFER_INCOMPLETE_DIMENSIONS
]);
414 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
416 var tex
= gl
.createTexture();
417 gl
.bindTexture(gl
.TEXTURE_2D
, tex
);
418 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, 16, 16, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
419 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.TEXTURE_2D
, tex
, 0);
420 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
421 if (gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
) == gl
.FRAMEBUFFER_COMPLETE
) {
422 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, 32, 16, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
423 checkFramebuffer([gl
.FRAMEBUFFER_INCOMPLETE_DIMENSIONS
]);
426 gl
.deleteTexture(tex
);
427 gl
.deleteRenderbuffer(depthBuffer
);
428 gl
.deleteRenderbuffer(colorBuffer
);
429 gl
.deleteFramebuffer(fbo
);
430 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
433 function testUsingIncompleteFramebuffer() {
435 debug("Test drawing or reading from an incomplete framebuffer");
436 var program
= wtu
.setupTexturedQuad(gl
);
437 var tex
= gl
.createTexture();
438 wtu
.fillTexture(gl
, tex
, 1, 1, [0,255,0,255]);
440 var fbo
= gl
.createFramebuffer();
441 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
442 checkFramebuffer([gl
.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
]);
444 debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
445 testRenderingAndReading();
447 var colorBuffer
= gl
.createRenderbuffer();
448 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, colorBuffer
);
449 gl
.framebufferRenderbuffer(
450 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, colorBuffer
);
451 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA4
, 0, 0);
452 checkFramebuffer([gl
.FRAMEBUFFER_INCOMPLETE_ATTACHMENT
]);
454 debug("Drawing or reading from an incomplete framebuffer should generate INVALID_FRAMEBUFFER_OPERATION");
455 testRenderingAndReading();
457 function testRenderingAndReading() {
458 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
459 wtu
.clearAndDrawUnitQuad(gl
);
460 wtu
.glErrorShouldBe(gl
, gl
.INVALID_FRAMEBUFFER_OPERATION
, "drawArrays with incomplete framebuffer");
461 gl
.readPixels(0, 0, 1, 1, gl
.RGBA
, gl
.UNSIGNED_BYTE
, new Uint8Array(4));
462 wtu
.glErrorShouldBe(gl
, gl
.INVALID_FRAMEBUFFER_OPERATION
, "readPixels from incomplete framebuffer");
463 // copyTexImage and copyTexSubImage can be either INVALID_FRAMEBUFFER_OPERATION because
464 // the framebuffer is invalid OR INVALID_OPERATION because in the case of no attachments
465 // the framebuffer is not of a compatible type.
466 gl
.copyTexSubImage2D(gl
.TEXTURE_2D
, 0, 0, 0, 0, 0, 1, 1);
467 wtu
.glErrorShouldBe(gl
, [gl
.INVALID_FRAMEBUFFER_OPERATION
, gl
.INVALID_OPERATION
],
468 "copyTexImage2D from incomplete framebuffer");
469 gl
.copyTexImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, 0, 0, 1, 1, 0);
470 wtu
.glErrorShouldBe(gl
, [gl
.INVALID_FRAMEBUFFER_OPERATION
, gl
.INVALID_OPERATION
],
471 "copyTexSubImage2D from incomplete framebuffer");
472 gl
.clear(gl
.COLOR_BUFFER_BIT
| gl
.DEPTH_BUFFER_BIT
);
473 wtu
.glErrorShouldBe(gl
, gl
.INVALID_FRAMEBUFFER_OPERATION
, "clear with incomplete framebuffer");
476 gl
.deleteRenderbuffer(colorBuffer
);
477 gl
.deleteFramebuffer(fbo
);
478 gl
.deleteTexture(tex
);
479 gl
.deleteProgram(program
);
482 function testReadingFromMissingAttachment() {
484 debug("Test drawing or reading from a framebuffer with no color image");
486 var fbo
= gl
.createFramebuffer();
487 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
488 var object_type
= gl
.getFramebufferAttachmentParameter(
489 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
);
490 if (object_type
!= gl
.NONE
)
491 testFailed("object type from empty attachment point should be NONE");
493 testPassed("object type from empty attachment point is NONE");
494 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "Query should not generate error");
496 var object_name
= gl
.getFramebufferAttachmentParameter(
497 gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME
);
499 testFailed("object name from empty attachment point should be null");
501 testPassed("object name from empty attachment point is null");
502 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "Query should not generate error");
506 // The only scenario we can verify is an attempt to read or copy
507 // from a missing color attachment while the framebuffer is still
509 var depthBuffer
= gl
.createRenderbuffer();
510 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, depthBuffer
);
511 gl
.framebufferRenderbuffer(
512 gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, depthBuffer
);
513 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.DEPTH_COMPONENT16
, size
, size
);
514 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "After depth renderbuffer setup");
515 if (gl
.checkFramebufferStatus(gl
.FRAMEBUFFER
) == gl
.FRAMEBUFFER_COMPLETE
) {
516 // The FBO has no color attachment. ReadPixels, CopyTexImage2D,
517 // and CopyTexSubImage2D should all generate INVALID_OPERATION.
518 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "Before ReadPixels from missing attachment");
519 gl
.readPixels(0, 0, 1, 1, gl
.RGBA
, gl
.UNSIGNED_BYTE
, new Uint8Array(4));
520 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "After ReadPixels from missing attachment");
522 var tex
= gl
.createTexture();
523 gl
.bindTexture(gl
.TEXTURE_2D
, tex
);
524 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "Before CopyTexImage2D from missing attachment");
525 gl
.copyTexImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, 0, 0, size
, size
, 0);
526 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "After CopyTexImage2D from missing attachment");
528 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, size
, size
, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
529 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "Before CopyTexSubImage2D from missing attachment");
530 gl
.copyTexSubImage2D(gl
.TEXTURE_2D
, 0, 0, 0, 0, 0, size
, size
);
531 wtu
.glErrorShouldBe(gl
, gl
.INVALID_OPERATION
, "After CopyTexSubImage2D from missing attachment");
533 gl
.deleteTexture(tex
);
536 gl
.deleteRenderbuffer(depthBuffer
);
537 gl
.deleteFramebuffer(fbo
);
540 description("Test framebuffer object attachment behaviors");
542 shouldBeNonNull("gl = wtu.create3DContext(undefined, undefined, 2)");
544 testFramebufferWebGL1RequiredCombinations();
545 testDepthStencilAttachmentBehaviors(false);
546 testDepthStencilAttachmentBehaviors(true);
547 testFramebufferIncompleteAttachment();
548 testFramebufferIncompleteMissingAttachment();
549 testFramebufferWithImagesOfDifferentSizes();
550 testUsingIncompleteFramebuffer();
551 testReadingFromMissingAttachment();
556 debug("Test calling framebufferTexture2D with impossible mip levels.");
558 const fb
= gl
.createFramebuffer();
559 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
561 const tex
= gl
.createTexture();
562 gl
.bindTexture(gl
.TEXTURE_2D
, tex
);
564 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.TEXTURE_2D
, tex
, 1000);
565 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
, "Mip level attachment impossibly high.");
566 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.TEXTURE_2D
, tex
, 10);
567 wtu
.glErrorShouldBe(gl
, 0, "Mip level attachment within acceptable range.");
569 // Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1636517 :
570 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.TEXTURE_2D
, null, 1000);
571 wtu
.glErrorShouldBe(gl
, 0, "Mip level detachment can be impossibly high.");
572 shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "0");
577 var successfullyParsed
= true;
580 <script src=
"../../js/js-test-post.js"></script>