summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance2/renderbuffers/invalidate-framebuffer.html
blob: 426148cf5e5450da06025676d0537fba1441ff3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
<!--
Copyright (c) 2019 The Khronos Group Inc.
Use of this source code is governed by an MIT-style license that can be
found in the LICENSE.txt file.
-->

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Invalidate Framebuffer Against WebGL 2</title>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<script src="../../js/js-test-pre.js"></script>
<script src="../../js/webgl-test-utils.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="canvas" width="20" height="20"> </canvas>
<script>
"use strict";
description("This tests invalidateFramebuffer and invalidateSubFramebuffer");

debug("");
debug("Canvas.getContext");

var wtu = WebGLTestUtils;
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas, { depth : true, stencil : false }, 2);
if (!gl) {
  testFailed("context does not exist");
} else {
  testPassed("context exists");

  debug("");
  debug("invalidate framebuffer.");

  gl.clearColor(0, 0, 0, 0);

  // setup framebuffer with depth attachment and multi-sampled color attachment
  var fb_m = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, fb_m);

  var rb_m = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, rb_m);
  var samples = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES);
  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb_m);
  // invalidate the framebuffer when the attachment is incomplete: no storage allocated to the attached renderbuffer
  invalidateIncompleteAttachment(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0);
  gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples[0], gl.RGBA8, canvas.width, canvas.height);
  gl.clear(gl.COLOR_BUFFER_BIT);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "should be no errors after attaching a multi-sampled renderbuffer to fbo.");

  var rb = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb);
  // invalidate the framebuffer when the attachment is incomplete: no storage allocated to the attached renderbuffer
  invalidateIncompleteAttachment(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT);
  gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples[0], gl.DEPTH_COMPONENT16, canvas.width, canvas.height);
  gl.clear(gl.DEPTH_BUFFER_BIT);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "should be no errors after attaching a renderbuffer to fbo.");

  // in real world case, after some drawing, we can invalidate the depth attachment of the bound fbo
  invalidation(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.STENCIL_ATTACHMENT);

  // set up framebuffer to blit to and read back from
  var fb = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
  var buffer = gl.createRenderbuffer();
  gl.bindRenderbuffer(gl.RENDERBUFFER, buffer);
  gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, canvas.width, canvas.height);
  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, buffer);
  gl.clear(gl.COLOR_BUFFER_BIT);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "should be no errors after attaching a renderbuffer to fbo.");

  gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fb_m);
  gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb);
  gl.blitFramebuffer(0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "should be no errors after bliting framebuffer.");

  // invalidate the multi-sampled color attachment of the bound read framebuffer after blitFramebuffer.
  invalidation(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.DEPTH_ATTACHMENT);

  var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
  gl.invalidateSubFramebuffer(gl.READ_FRAMEBUFFER, [gl.COLOR_ATTACHMENT0 + maxColorAttachments], 5, 5, 10, 10);
  wtu.glErrorShouldBe(gl, [gl.INVALID_OPERATION, gl.INVALID_ENUM],
      "calling invalidateSubFramebuffer to invalidate a COLOR_ATTACHMENT that exceeds MAX_COLOR_ATTACHMENT should generate INVALID_ENUM or INVALID_OPERATION.");
  gl.invalidateFramebuffer(gl.READ_FRAMEBUFFER, [gl.COLOR_ATTACHMENT0 + maxColorAttachments]);
  wtu.glErrorShouldBe(gl, [gl.INVALID_OPERATION, gl.INVALID_ENUM],
      "calling invalidateFramebuffer to invalidate a COLOR_ATTACHMENT that exceeds MAX_COLOR_ATTACHMENT should generate INVALID_ENUM or INVALID_OPERATION.");

  // invalidate the default framebuffer
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  invalidation(gl.FRAMEBUFFER, gl.DEPTH, gl.STENCIL);

  gl.deleteFramebuffer(fb_m);
  gl.deleteRenderbuffer(rb_m);
  gl.deleteRenderbuffer(rb);
  gl.deleteFramebuffer(fb);
  gl.deleteRenderbuffer(buffer);

  testInvalidateRGBThenDraw();
  testInvalidateWithBlend();
}

function invalidation(target, valid_attachment, invalid_attachment) {
  gl.invalidateSubFramebuffer(target, [invalid_attachment], 5, 5, 10, 10);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "calling invalidateSubFramebuffer to invalidate a specified attachment that does not exist will be ignored. There should be no errors.");
  gl.invalidateSubFramebuffer(target, [valid_attachment], 5, 5, 10, 10);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "calling invalidateSubFramebuffer should succeed.");

  gl.invalidateSubFramebuffer(target, [valid_attachment], 5, 5, -5, -5);
  wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
      "calling invalidateSubFramebuffer should generate INVALID_VALUE if width < 0 or height < 0.");

  gl.invalidateSubFramebuffer(target, [valid_attachment], -5, -5, 10, 10);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "calling invalidateSubFramebuffer should succeed, even the invalidated pixels may be outside of the framebuffer allocated to current context. These pixels are ignored.");
  gl.invalidateSubFramebuffer(target, [valid_attachment], 5, 5, 20, 20);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "calling invalidateSubFramebuffer should succeed, even the invalidated pixels may be outside of the framebuffer allocated to current context. These pixels are ignored.");

  gl.invalidateFramebuffer(target, [invalid_attachment]);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "calling invalidateFramebuffer to invalidate a specified attachment that does not exist will be ignored. There should be no errors.");
  gl.invalidateFramebuffer(target, [valid_attachment]);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "calling invalidateFramebuffer should succeed.");
}

function invalidateIncompleteAttachment(target, incomplete_attachment) {
  shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)",
           "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
  gl.invalidateSubFramebuffer(target, [incomplete_attachment], 5, 5, 10, 10);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "calling invalidateSubFramebuffer to invalidate an incomplete attachment will be ignored. There should be no errors");
  gl.invalidateFramebuffer(target, [incomplete_attachment]);
  wtu.glErrorShouldBe(gl, gl.NO_ERROR,
      "calling invalidateFramebuffer to invalidate an incomplete attachment will be ignored. There should be no errors.");
}

function testInvalidateRGBThenDraw() {
    const program = wtu.setupColorQuad(gl);

    const texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, null);

    const fbo = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
    wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);

    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT);

    // Verify that clearing alpha is ineffective on an RGB format.
    const black = [0, 0, 0, 255];
    wtu.checkCanvasRect(gl, 0, 0, 1, 1, black, `should be black`);

    // Invalidate the framebuffer contents.
    gl.invalidateFramebuffer(gl.FRAMEBUFFER, [gl.COLOR_ATTACHMENT0]);

    // Without an explicit clear, draw blue and make sure alpha is unaffected.  If RGB is emulated
    // with RGBA, the previous invalidate shouldn't affect the alpha value.
    wtu.drawFloatColorQuad(gl, [0, 0, 1, 1]);
    const blue = [0, 0, 255, 255];
    wtu.checkCanvasRect(gl, 0, 0, 1, 1, blue, `should be blue`);

    wtu.glErrorShouldBe(gl, gl.NO_ERROR);

    gl.deleteTexture(texture);
    gl.deleteFramebuffer(fbo);
    gl.deleteProgram(program);
}

function testInvalidateWithBlend() {
    // Create the framebuffer that will be invalidated
    const renderTarget = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, renderTarget);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

    const drawFBO = gl.createFramebuffer();
    gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, drawFBO);
    gl.framebufferTexture2D(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, renderTarget, 0);

    // Clear the framebuffer and invalidate it.
    gl.clearColor(1, 1, 1, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    gl.invalidateFramebuffer(gl.DRAW_FRAMEBUFFER, [gl.COLOR_ATTACHMENT0]);

    // Upload data to it
    const cyan = new Uint8Array([0, 255, 255, 255]);
    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, cyan);

    // Blend into the framebuffer, then verify that the framebuffer should have had cyan.
    gl.bindFramebuffer(gl.READ_FRAMEBUFFER, drawFBO);

    const program = wtu.setupColorQuad(gl);

    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    wtu.drawFloatColorQuad(gl, [1, 0, 0, 0.5]);
    const expected = [127, 127, 127, 191];
    wtu.checkCanvasRect(gl, 0, 0, 1, 1, expected, `should be ${expected}`, 1);

    wtu.glErrorShouldBe(gl, gl.NO_ERROR,
        "calling invalidateFramebuffer and then uploading data to texture in framebuffer. There should be no errors");

    gl.deleteTexture(renderTarget);
    gl.deleteFramebuffer(drawFBO);
    gl.deleteProgram(program);
    gl.disable(gl.BLEND);
}

debug("");
var successfullyParsed = true;

</script>
<script src="../../js/js-test-post.js"></script>

</body>
</html>