Bug 1918529 - fix some subpixel misalignment issues with gfx.webrender.svg-filter...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / conformance / textures / misc / gl-teximage.html
blob897377534ce4dc9fefa383b4ff203c29be678b85
1 <!--
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.
5 -->
7 <!DOCTYPE html>
8 <html>
9 <head>
10 <meta charset="utf-8">
11 <title>WebGL texImage2D conformance test.</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>
15 </head>
16 <body>
17 <canvas id="example" width="256" height="16" style="width: 256px; height: 48px;"></canvas>
18 <div id="description"></div>
19 <div id="console"></div>
20 <script>
21 "use strict";
22 enableJSTestPreVerboseLogging();
23 description("Test texImage2D conversions.");
24 var wtu = WebGLTestUtils;
25 var gl = wtu.create3DContext("example");
26 gl.disable(gl.DITHER);
27 var program = wtu.setupTexturedQuad(gl);
28 var successfullyParsed;
30 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
32 var imgURLs = [
33 '../../../resources/1-channel.jpg',
34 '../../../resources/gray-ramp-256-with-128-alpha.png',
35 '../../../resources/gray-ramp-256.png',
36 '../../../resources/gray-ramp-default-gamma.png',
37 '../../../resources/gray-ramp-gamma0.1.png',
38 '../../../resources/gray-ramp-gamma1.0.png',
39 '../../../resources/gray-ramp-gamma2.0.png',
40 '../../../resources/gray-ramp-gamma4.0.png',
41 '../../../resources/gray-ramp-gamma9.0.png',
42 '../../../resources/gray-ramp.png',
43 '../../../resources/zero-alpha.png',
44 '../../../resources/3x3.png',
45 '../../../resources/blue-1x1.jpg',
46 '../../../resources/red-indexed.png',
47 '../../../resources/transparent-on-left-indexed.png',
48 '../../../resources/green-2x2-16bit.png',
49 '../../../resources/small-square-with-colorspin-profile.jpg',
50 '../../../resources/small-square-with-colorspin-profile.png',
51 '../../../resources/small-square-with-cie-rgb-profile.png',
52 '../../../resources/small-square-with-colormatch-profile.png',
53 '../../../resources/small-square-with-e-srgb-profile.png',
54 '../../../resources/small-square-with-smpte-c-profile.png',
55 '../../../resources/small-square-with-srgb-iec61966-2.1-profile.png'];
58 wtu.loadImagesAsync(imgURLs, runTests);
60 function runTests(imgs) {
61 var loc = gl.getUniformLocation(program, "tex");
62 gl.uniform1i(loc, 0);
64 gl.disable(gl.BLEND);
65 gl.disable(gl.DEPTH_TEST);
67 var width = gl.canvas.width;
68 var height = gl.canvas.height;
70 function checkPixel(x, y, color) {
71 wtu.checkCanvasRect(gl, x, y, 1, 1, color);
74 function checkPixelRange(x, y, color, allowedRange) {
75 var msg = "pixel " + x + ", " + y + " should be within " +
76 allowedRange + " units of " +
77 color[0] + ", " +
78 color[1] + ", " +
79 color[2] + ", " +
80 color[3];
81 wtu.checkCanvasRect(gl, x, y, 1, 1, color, msg, allowedRange);
84 var tex = gl.createTexture();
85 gl.bindTexture(gl.TEXTURE_2D, tex);
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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
89 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
91 var buf = new Uint8Array(width * height * 4);
93 debug("");
94 debug("check pixels are NOT pre-multiplied");
95 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
96 imgs['../../../resources/zero-alpha.png']);
97 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
98 wtu.clearAndDrawUnitQuad(gl);
100 var left = 0;
101 var middle = Math.floor(width / 2);
102 var right = width - 1;
103 var bottom = 0;
104 var center = Math.floor(height / 2);
105 var top = height - 1;
106 checkPixel(left, top, [ 0, 0, 0, 255]);
107 checkPixel(middle, top, [255, 0, 255, 255]);
108 checkPixel(right, top, [ 0, 0, 255, 255]);
109 checkPixel(left, center, [128, 128, 128, 255]);
110 checkPixel(middle, center, [255, 255, 255, 255]);
111 checkPixel(right, center, [ 0, 255, 255, 255]);
112 checkPixel(left, bottom, [255, 0, 0, 255]);
113 checkPixel(middle, bottom, [255, 255, 0, 255]);
114 checkPixel(right, bottom, [ 0, 255, 0, 255]);
116 debug("");
117 debug("check quantization");
118 var quantInfo = [
119 {format: gl.RGBA, type: gl.UNSIGNED_BYTE, counts: [256, 256, 256, 256]},
120 {format: gl.RGBA, type: gl.UNSIGNED_SHORT_4_4_4_4, counts: [ 16, 16, 16, 16]},
121 {format: gl.RGB, type: gl.UNSIGNED_SHORT_5_6_5, counts: [ 32, 64, 32, 1]},
122 {format: gl.RGBA, type: gl.UNSIGNED_SHORT_5_5_5_1, counts: [ 32, 32, 32, 2]}];
123 for (var qq = 0; qq < quantInfo.length; ++qq) {
124 var info = quantInfo[qq];
125 gl.texImage2D(
126 gl.TEXTURE_2D, 0, info.format, info.format, info.type,
127 imgs['../../../resources/gray-ramp-256.png']);
128 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
129 wtu.clearAndDrawUnitQuad(gl);
130 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
131 var counts = [{ }, { }, { }, { }];
132 var numUniqueValues = [0, 0, 0, 0];
133 // Count the number of unique values in each channel.
134 for (var ii = 0; ii < width * height * 4; ii += 4) {
135 for (var jj = 0; jj < 4; ++jj) {
136 var v = buf[ii + jj];
137 if (!counts[jj][v]) {
138 counts[jj][v] = 1;
139 ++numUniqueValues[jj];
140 } else {
141 ++counts[jj][v];
145 for (var ii = 0; ii < 4; ++ii) {
146 assertMsg(numUniqueValues[ii] == info.counts[ii],
147 "There should be " + info.counts[ii] +
148 " unique values in channel " + ii + ". Found " +
149 numUniqueValues[ii]);
153 debug("");
154 debug("Check that gamma settings don't effect 8bit pngs");
155 wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
156 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
157 imgs['../../../resources/gray-ramp-default-gamma.png']);
158 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
159 wtu.clearAndDrawUnitQuad(gl);
160 var ref = new Uint8Array(width * height * 4);
161 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, ref);
163 var gammaImages = [
164 '../../../resources/gray-ramp-gamma0.1.png',
165 '../../../resources/gray-ramp-gamma1.0.png',
166 '../../../resources/gray-ramp-gamma2.0.png',
167 '../../../resources/gray-ramp-gamma4.0.png',
168 '../../../resources/gray-ramp-gamma9.0.png'];
169 for (var ii = 0; ii < gammaImages.length; ++ii) {
170 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
171 imgs[gammaImages[ii]]);
172 wtu.clearAndDrawUnitQuad(gl);
173 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
174 var same = true;
175 for (var jj = 0; jj < width * height * 4; ++jj) {
176 if (buf[jj] != ref[jj]) {
177 same = false;
178 break;
181 assertMsg(same, "pixels should be same regardless of gamma settings.");
184 debug("");
185 debug("check pixels are UN pre-multiplied");
186 for (var ii = 0; ii < 2; ++ii) {
187 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
188 if (ii == 0) {
189 var canvas2d = document.createElement("canvas");
190 canvas2d.width = 256;
191 canvas2d.height = 1;
192 var ctx = canvas2d.getContext("2d");
193 ctx.drawImage(imgs['../../../resources/gray-ramp-256-with-128-alpha.png'], 0, 0);
194 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, canvas2d);
195 } else {
196 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
197 imgs['../../../resources/gray-ramp-256-with-128-alpha.png']);
199 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
200 wtu.clearAndDrawUnitQuad(gl);
201 var buf = new Uint8Array(width * height * 4);
202 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
203 var lt128Count = [0, 0, 0];
204 var ge128Count = [0, 0, 0];
205 for (var jj = 0; jj < width; ++jj) {
206 var off = jj * 4;
207 for (var cc = 0; cc < 3; ++cc) {
208 if (buf[off + cc] < 128) {
209 ++lt128Count[cc];
210 } else {
211 ++ge128Count[cc];
215 // Not sure the exact count here because gamma does effect drawing into the
216 // canvas but it should be close to 50% so I'll pass 45%
217 for (var jj = 0; jj < 3; ++jj) {
218 assertMsg(ge128Count[jj] > 256 * 0.45,
219 "Half the pixels in channel " + jj +
220 " should be >= 128,128,128. found " +
221 ((ge128Count[jj] / 256) * 100).toFixed() + "%");
222 assertMsg(lt128Count[jj] > 256 * 0.45,
223 "Half the pixels in channel " + jj +
224 " should be < 128,128,128. found " +
225 ((lt128Count[jj] / 256) * 100).toFixed() + "%");
229 debug("");
230 debug("check canvas pixels are UN pre-multiplied");
231 var canvas2d = document.createElement("canvas");
232 canvas2d.width = 1;
233 canvas2d.height = 1;
234 var ctx = canvas2d.getContext("2d");
235 ctx.fillStyle ="rgba(255,255,255,0.5)";
236 ctx.fillRect(0, 0, 256, 1);
237 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas2d);
238 wtu.clearAndDrawUnitQuad(gl);
239 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
240 checkPixelRange(0, 0, [255, 255, 255, 127], 4);
242 debug("");
243 debug("check canvas pixels are pre-multiplied");
244 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
245 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas2d);
246 wtu.clearAndDrawUnitQuad(gl);
247 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
248 checkPixelRange(0, 0, [127, 127, 127, 127], 4);
251 debug("");
252 debug("check pixels are pre-multiplied");
253 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
254 // TODO(gman): use different texture that won't pass on failure
255 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,
256 imgs['../../../resources/zero-alpha.png']);
257 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
258 wtu.clearAndDrawUnitQuad(gl);
259 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
261 var same = true;
262 for (var jj = 0; jj < width * height * 4; ++jj) {
263 if (buf[jj] != 0) {
264 same = false;
265 break;
268 assertMsg(same, "pixels should all be 0.");
270 debug("");
271 debug("check pixels are flipped");
272 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
273 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
274 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
275 imgs['../../../resources/3x3.png']);
276 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
277 wtu.clearAndDrawUnitQuad(gl);
279 checkPixel(left, top, [255, 0, 0, 255]);
280 checkPixel(middle, top, [255, 255, 0, 255]);
281 checkPixel(right, top, [255, 0, 0, 255]);
282 checkPixel(left, center, [255, 0, 255, 255]);
283 checkPixel(middle, center, [255, 0, 0, 255]);
284 checkPixel(right, center, [ 0, 255, 0, 255]);
285 checkPixel(left, bottom, [ 0, 0, 0, 255]);
286 checkPixel(middle, bottom, [ 0, 0, 255, 255]);
287 checkPixel(right, bottom, [255, 0, 0, 255]);
289 debug("");
290 debug("check uploading of images with no alpha channel works");
291 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
292 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
293 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
294 imgs['../../../resources/blue-1x1.jpg']);
295 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
296 wtu.clearAndDrawUnitQuad(gl);
297 checkPixelRange(middle, center, [ 0, 0, 255, 255], 10);
298 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
300 debug("");
301 debug("check uploading of 16-bit images");
302 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
303 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
304 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
305 imgs['../../../resources/green-2x2-16bit.png']);
306 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
307 wtu.clearAndDrawUnitQuad(gl);
308 checkPixelRange(middle, center, [ 15, 121, 0, 255], 10);
309 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
311 debug("");
312 debug("check uploading of images with ICC profiles");
313 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
314 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
315 wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);');
317 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
318 imgs['../../../resources/small-square-with-colorspin-profile.jpg']);
319 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
320 wtu.clearAndDrawUnitQuad(gl);
321 // The image is red. However, if we ignore the color profile, it is blue.
322 checkPixelRange(middle, center, [ 0, 0, 255, 255], 10);
324 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
325 imgs['../../../resources/small-square-with-colorspin-profile.png']);
326 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
327 wtu.clearAndDrawUnitQuad(gl);
328 // The image is red. However, if we ignore the color profile, it is blue.
329 checkPixelRange(middle, center, [ 0, 0, 255, 255], 10);
331 var iccPNGs = [
332 '../../../resources/small-square-with-cie-rgb-profile.png',
333 '../../../resources/small-square-with-colormatch-profile.png',
334 '../../../resources/small-square-with-e-srgb-profile.png',
335 '../../../resources/small-square-with-smpte-c-profile.png',
336 '../../../resources/small-square-with-srgb-iec61966-2.1-profile.png'];
337 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
338 for (var ii = 0; ii < iccPNGs.length; ++ii) {
339 var buf2 = new Uint8Array(width * height * 4);
340 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
341 imgs[iccPNGs[ii]]);
342 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
343 wtu.clearAndDrawUnitQuad(gl);
344 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf2);
345 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");
346 var same = true;
347 for (var jj = 0; jj < buf.length; ++jj) {
348 if (buf[jj] != buf2[jj]) {
349 same = false;
350 break;
353 assertMsg(same, "uploading PNGs with same data but various ICC profiles should generate the same results");
356 debug("");
357 debug("check uploading of indexed PNG images");
358 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
359 imgs['../../../resources/red-indexed.png']);
360 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
361 wtu.clearAndDrawUnitQuad(gl);
362 // The image should be red.
363 checkPixelRange(middle, center, [ 255, 0, 0, 255 ], 10);
365 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
366 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,
367 imgs['../../../resources/transparent-on-left-indexed.png']);
368 wtu.clearAndDrawUnitQuad(gl);
369 wtu.checkCanvasRect(gl, 0, 0, 128, 16, [255, 0, 255, 0], "should be transparent purple");
370 wtu.checkCanvasRect(gl, 128, 0,128, 16, [255, 255, 0, 255], "should be yellow");
372 debug("");
373 debug("check uploading of 1-channel JPG images");
374 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE,
375 imgs['../../../resources/1-channel.jpg']);
376 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
377 wtu.clearAndDrawUnitQuad(gl);
378 // The image should be gray.
379 checkPixelRange(middle, center, [ 128, 128, 128, 255 ], 28);
381 debug("")
382 debug("check calling texImage2D with NULL clears the texture");
383 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB,
384 imgs['../../../resources/red-indexed.png'].width,
385 imgs['../../../resources/red-indexed.png'].height,
386 0, gl.RGB, gl.UNSIGNED_BYTE, null);
387 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup");
388 wtu.clearAndDrawUnitQuad(gl);
389 // The image should be white.
390 checkPixelRange(middle, center, [ 0, 0, 0, 255 ], 10);
392 debug("");
393 debug("check zero size cases");
394 gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 2, 0, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, new Uint8Array());
395 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from zero sized textures");
397 debug("");
398 successfullyParsed = true;
399 shouldBeTrue("successfullyParsed");
400 debug('<br /><span class="pass">TEST COMPLETE</span>');
401 notifyFinishedToHarness();
403 </script>
404 </body>
405 </html>