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 <title>Invalidate Framebuffer Against WebGL
2</title>
12 <link rel=
"stylesheet" href=
"../../resources/js-test-style.css"/>
13 <script src=
"../../js/js-test-pre.js"></script>
14 <script src=
"../../js/webgl-test-utils.js"></script>
17 <div id=
"description"></div>
18 <div id=
"console"></div>
19 <canvas id=
"canvas" width=
"20" height=
"20"> </canvas>
22 description("This tests invalidateFramebuffer and invalidateSubFramebuffer");
25 debug("Canvas.getContext");
27 var wtu
= WebGLTestUtils
;
28 var canvas
= document
.getElementById("canvas");
29 var gl
= wtu
.create3DContext(canvas
, { depth
: true, stencil
: false }, 2);
31 testFailed("context does not exist");
33 testPassed("context exists");
36 debug("invalidate framebuffer.");
38 gl
.clearColor(0, 0, 0, 0);
40 // setup framebuffer with depth attachment and multi-sampled color attachment
41 var fb_m
= gl
.createFramebuffer();
42 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb_m
);
44 var rb_m
= gl
.createRenderbuffer();
45 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, rb_m
);
46 var samples
= gl
.getInternalformatParameter(gl
.RENDERBUFFER
, gl
.RGBA8
, gl
.SAMPLES
);
47 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, rb_m
);
48 // invalidate the framebuffer when the attachment is incomplete: no storage allocated to the attached renderbuffer
49 invalidateIncompleteAttachment(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
);
50 gl
.renderbufferStorageMultisample(gl
.RENDERBUFFER
, samples
[0], gl
.RGBA8
, canvas
.width
, canvas
.height
);
51 gl
.clear(gl
.COLOR_BUFFER_BIT
);
52 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
53 "should be no errors after attaching a multi-sampled renderbuffer to fbo.");
55 var rb
= gl
.createRenderbuffer();
56 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, rb
);
57 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.RENDERBUFFER
, rb
);
58 // invalidate the framebuffer when the attachment is incomplete: no storage allocated to the attached renderbuffer
59 invalidateIncompleteAttachment(gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
);
60 gl
.renderbufferStorageMultisample(gl
.RENDERBUFFER
, samples
[0], gl
.DEPTH_COMPONENT16
, canvas
.width
, canvas
.height
);
61 gl
.clear(gl
.DEPTH_BUFFER_BIT
);
62 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
63 "should be no errors after attaching a renderbuffer to fbo.");
65 // in real world case, after some drawing, we can invalidate the depth attachment of the bound fbo
66 invalidation(gl
.FRAMEBUFFER
, gl
.DEPTH_ATTACHMENT
, gl
.STENCIL_ATTACHMENT
);
68 // set up framebuffer to blit to and read back from
69 var fb
= gl
.createFramebuffer();
70 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fb
);
71 var buffer
= gl
.createRenderbuffer();
72 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, buffer
);
73 gl
.renderbufferStorage(gl
.RENDERBUFFER
, gl
.RGBA8
, canvas
.width
, canvas
.height
);
74 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, buffer
);
75 gl
.clear(gl
.COLOR_BUFFER_BIT
);
76 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
77 "should be no errors after attaching a renderbuffer to fbo.");
79 gl
.bindFramebuffer(gl
.READ_FRAMEBUFFER
, fb_m
);
80 gl
.bindFramebuffer(gl
.DRAW_FRAMEBUFFER
, fb
);
81 gl
.blitFramebuffer(0, 0, canvas
.width
, canvas
.height
, 0, 0, canvas
.width
, canvas
.height
, gl
.COLOR_BUFFER_BIT
, gl
.NEAREST
);
82 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
83 "should be no errors after bliting framebuffer.");
85 // invalidate the multi-sampled color attachment of the bound read framebuffer after blitFramebuffer.
86 invalidation(gl
.READ_FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.DEPTH_ATTACHMENT
);
88 var maxColorAttachments
= gl
.getParameter(gl
.MAX_COLOR_ATTACHMENTS
);
89 gl
.invalidateSubFramebuffer(gl
.READ_FRAMEBUFFER
, [gl
.COLOR_ATTACHMENT0
+ maxColorAttachments
], 5, 5, 10, 10);
90 wtu
.glErrorShouldBe(gl
, [gl
.INVALID_OPERATION
, gl
.INVALID_ENUM
],
91 "calling invalidateSubFramebuffer to invalidate a COLOR_ATTACHMENT that exceeds MAX_COLOR_ATTACHMENT should generate INVALID_ENUM or INVALID_OPERATION.");
92 gl
.invalidateFramebuffer(gl
.READ_FRAMEBUFFER
, [gl
.COLOR_ATTACHMENT0
+ maxColorAttachments
]);
93 wtu
.glErrorShouldBe(gl
, [gl
.INVALID_OPERATION
, gl
.INVALID_ENUM
],
94 "calling invalidateFramebuffer to invalidate a COLOR_ATTACHMENT that exceeds MAX_COLOR_ATTACHMENT should generate INVALID_ENUM or INVALID_OPERATION.");
96 // invalidate the default framebuffer
97 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, null);
98 invalidation(gl
.FRAMEBUFFER
, gl
.DEPTH
, gl
.STENCIL
);
100 gl
.deleteFramebuffer(fb_m
);
101 gl
.deleteRenderbuffer(rb_m
);
102 gl
.deleteRenderbuffer(rb
);
103 gl
.deleteFramebuffer(fb
);
104 gl
.deleteRenderbuffer(buffer
);
106 testInvalidateRGBThenDraw();
107 testInvalidateWithBlend();
110 function invalidation(target
, valid_attachment
, invalid_attachment
) {
111 gl
.invalidateSubFramebuffer(target
, [invalid_attachment
], 5, 5, 10, 10);
112 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
113 "calling invalidateSubFramebuffer to invalidate a specified attachment that does not exist will be ignored. There should be no errors.");
114 gl
.invalidateSubFramebuffer(target
, [valid_attachment
], 5, 5, 10, 10);
115 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
116 "calling invalidateSubFramebuffer should succeed.");
118 gl
.invalidateSubFramebuffer(target
, [valid_attachment
], 5, 5, -5, -5);
119 wtu
.glErrorShouldBe(gl
, gl
.INVALID_VALUE
,
120 "calling invalidateSubFramebuffer should generate INVALID_VALUE if width < 0 or height < 0.");
122 gl
.invalidateSubFramebuffer(target
, [valid_attachment
], -5, -5, 10, 10);
123 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
124 "calling invalidateSubFramebuffer should succeed, even the invalidated pixels may be outside of the framebuffer allocated to current context. These pixels are ignored.");
125 gl
.invalidateSubFramebuffer(target
, [valid_attachment
], 5, 5, 20, 20);
126 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
127 "calling invalidateSubFramebuffer should succeed, even the invalidated pixels may be outside of the framebuffer allocated to current context. These pixels are ignored.");
129 gl
.invalidateFramebuffer(target
, [invalid_attachment
]);
130 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
131 "calling invalidateFramebuffer to invalidate a specified attachment that does not exist will be ignored. There should be no errors.");
132 gl
.invalidateFramebuffer(target
, [valid_attachment
]);
133 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
134 "calling invalidateFramebuffer should succeed.");
137 function invalidateIncompleteAttachment(target
, incomplete_attachment
) {
138 shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)",
139 "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
140 gl
.invalidateSubFramebuffer(target
, [incomplete_attachment
], 5, 5, 10, 10);
141 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
142 "calling invalidateSubFramebuffer to invalidate an incomplete attachment will be ignored. There should be no errors");
143 gl
.invalidateFramebuffer(target
, [incomplete_attachment
]);
144 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
145 "calling invalidateFramebuffer to invalidate an incomplete attachment will be ignored. There should be no errors.");
148 function testInvalidateRGBThenDraw() {
149 const program
= wtu
.setupColorQuad(gl
);
151 const texture
= gl
.createTexture();
152 gl
.bindTexture(gl
.TEXTURE_2D
, texture
);
153 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGB
, 1, 1, 0, gl
.RGB
, gl
.UNSIGNED_BYTE
, null);
155 const fbo
= gl
.createFramebuffer();
156 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
157 gl
.framebufferTexture2D(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.TEXTURE_2D
, texture
, 0);
158 wtu
.framebufferStatusShouldBe(gl
, gl
.FRAMEBUFFER
, gl
.FRAMEBUFFER_COMPLETE
);
160 gl
.clearColor(0, 0, 0, 0);
161 gl
.clear(gl
.COLOR_BUFFER_BIT
);
163 // Verify that clearing alpha is ineffective on an RGB format.
164 const black
= [0, 0, 0, 255];
165 wtu
.checkCanvasRect(gl
, 0, 0, 1, 1, black
, `should be black`);
167 // Invalidate the framebuffer contents.
168 gl
.invalidateFramebuffer(gl
.FRAMEBUFFER
, [gl
.COLOR_ATTACHMENT0
]);
170 // Without an explicit clear, draw blue and make sure alpha is unaffected. If RGB is emulated
171 // with RGBA, the previous invalidate shouldn't affect the alpha value.
172 wtu
.drawFloatColorQuad(gl
, [0, 0, 1, 1]);
173 const blue
= [0, 0, 255, 255];
174 wtu
.checkCanvasRect(gl
, 0, 0, 1, 1, blue
, `should be blue`);
176 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
);
178 gl
.deleteTexture(texture
);
179 gl
.deleteFramebuffer(fbo
);
180 gl
.deleteProgram(program
);
183 function testInvalidateWithBlend() {
184 // Create the framebuffer that will be invalidated
185 const renderTarget
= gl
.createTexture();
186 gl
.bindTexture(gl
.TEXTURE_2D
, renderTarget
);
187 gl
.texImage2D(gl
.TEXTURE_2D
, 0, gl
.RGBA
, 1, 1, 0, gl
.RGBA
, gl
.UNSIGNED_BYTE
, null);
189 const drawFBO
= gl
.createFramebuffer();
190 gl
.bindFramebuffer(gl
.DRAW_FRAMEBUFFER
, drawFBO
);
191 gl
.framebufferTexture2D(gl
.DRAW_FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.TEXTURE_2D
, renderTarget
, 0);
193 // Clear the framebuffer and invalidate it.
194 gl
.clearColor(1, 1, 1, 1);
195 gl
.clear(gl
.COLOR_BUFFER_BIT
);
197 gl
.invalidateFramebuffer(gl
.DRAW_FRAMEBUFFER
, [gl
.COLOR_ATTACHMENT0
]);
200 const cyan
= new Uint8Array([0, 255, 255, 255]);
201 gl
.texSubImage2D(gl
.TEXTURE_2D
, 0, 0, 0, 1, 1, gl
.RGBA
, gl
.UNSIGNED_BYTE
, cyan
);
203 // Blend into the framebuffer, then verify that the framebuffer should have had cyan.
204 gl
.bindFramebuffer(gl
.READ_FRAMEBUFFER
, drawFBO
);
206 const program
= wtu
.setupColorQuad(gl
);
209 gl
.blendFunc(gl
.SRC_ALPHA
, gl
.ONE_MINUS_SRC_ALPHA
);
210 wtu
.drawFloatColorQuad(gl
, [1, 0, 0, 0.5]);
211 const expected
= [127, 127, 127, 191];
212 wtu
.checkCanvasRect(gl
, 0, 0, 1, 1, expected
, `should be ${expected}`, 1);
214 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
,
215 "calling invalidateFramebuffer and then uploading data to texture in framebuffer. There should be no errors");
217 gl
.deleteTexture(renderTarget
);
218 gl
.deleteFramebuffer(drawFBO
);
219 gl
.deleteProgram(program
);
220 gl
.disable(gl
.BLEND
);
224 var successfullyParsed
= true;
227 <script src=
"../../js/js-test-post.js"></script>