Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 <!--
3 /*
4 ** Copyright (c) 2012 The Khronos Group Inc.
5 **
6 ** Permission is hereby granted, free of charge, to any person obtaining a
7 ** copy of this software and/or associated documentation files (the
8 ** "Materials"), to deal in the Materials without restriction, including
9 ** without limitation the rights to use, copy, modify, merge, publish,
10 ** distribute, sublicense, and/or sell copies of the Materials, and to
11 ** permit persons to whom the Materials are furnished to do so, subject to
12 ** the following conditions:
13 **
14 ** The above copyright notice and this permission notice shall be included
15 ** in all copies or substantial portions of the Materials.
16 **
17 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
24 */
26 -->
28 <!DOCTYPE html>
29 <html>
30 <head>
31 <meta charset="utf-8">
32 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
33 <script src="../../resources/js-test-pre.js"></script>
34 <script src="../resources/webgl-test.js"></script>
35 <script src="../resources/webgl-test-utils.js"></script>
36 <title>WebGL WEBGL_compressed_texture_etc1 Conformance Tests</title>
37 <style>
38 img {
39 border: 1px solid black;
40 margin-right: 1em;
41 }
42 .testimages {
43 }
45 .testimages br {
46 clear: both;
47 }
49 .testimages > div {
50 float: left;
51 margin: 1em;
52 }
53 </style>
54 </head>
55 <body>
56 <div id="description"></div>
57 <canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
58 <div id="console"></div>
59 <script>
60 "use strict";
61 description("This test verifies the functionality of the WEBGL_compressed_texture_etc1 extension, if it is available.");
63 debug("");
65 var img_4x4_rgb_etc1 = new Uint8Array([
66 0x00, 0xc0, 0x00, 0xff, 0x07, 0x45, 0x07, 0x45
67 ]);
68 var img_8x8_rgb_etc1 = new Uint8Array([
69 0x00, 0xff, 0x55, 0xfc, 0xff, 0xff, 0x07, 0x45,
70 0x11, 0x11, 0xff, 0xfc, 0xf8, 0xba, 0x07, 0x45,
71 0xee, 0x00, 0xee, 0xfc, 0x07, 0x45, 0x07, 0x45,
72 0x00, 0x90, 0xf8, 0x92, 0x07, 0x45, 0xff, 0xff,
73 ]);
75 var wtu = WebGLTestUtils;
76 var canvas = document.getElementById("canvas");
77 var gl = wtu.create3DContext(canvas, {antialias: false});
78 var program = wtu.setupTexturedQuad(gl);
79 var ext = null;
80 var vao = null;
81 var validFormats = {
82 COMPRESSED_RGB_ETC1_WEBGL : 0x8D64
83 };
84 var name;
85 var supportedFormats;
87 if (!gl) {
88 testFailed("WebGL context does not exist");
89 } else {
90 testPassed("WebGL context exists");
92 // Run tests with extension disabled
93 runTestDisabled();
95 // Query the extension and store globally so shouldBe can access it
96 ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_etc1");
97 if (!ext) {
98 testPassed("No WEBGL_compressed_texture_etc1 support -- this is legal");
99 runSupportedTest(false);
100 } else {
101 testPassed("Successfully enabled WEBGL_compressed_texture_etc1 extension");
103 runSupportedTest(true);
104 runTestExtension();
105 }
106 }
108 function runSupportedTest(extensionEnabled) {
109 var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_etc1");
110 if (name !== undefined) {
111 if (extensionEnabled) {
112 testPassed("WEBGL_compressed_texture_etc1 listed as supported and getExtension succeeded");
113 } else {
114 testFailed("WEBGL_compressed_texture_etc1 listed as supported but getExtension failed");
115 }
116 } else {
117 if (extensionEnabled) {
118 testFailed("WEBGL_compressed_texture_etc1 not listed as supported but getExtension succeeded");
119 } else {
120 testPassed("WEBGL_compressed_texture_etc1 not listed as supported and getExtension failed -- this is legal");
121 }
122 }
123 }
126 function runTestDisabled() {
127 debug("Testing binding enum with extension disabled");
129 shouldBe('gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS)', '[]');
130 }
132 function formatExists(format, supportedFormats) {
133 for (var ii = 0; ii < supportedFormats.length; ++ii) {
134 if (format == supportedFormats[ii]) {
135 testPassed("supported format " + formatToString(format) + " is exists");
136 return;
137 }
138 }
139 testFailed("supported format " + formatToString(format) + " does not exist");
140 }
142 function formatToString(format) {
143 for (var p in ext) {
144 if (ext[p] == format) {
145 return p;
146 }
147 }
148 return "0x" + format.toString(16);
149 }
151 function runTestExtension() {
152 debug("Testing WEBGL_compressed_texture_etc1");
154 // check that all format enums exist.
155 for (name in validFormats) {
156 var expected = "0x" + validFormats[name].toString(16);
157 var actual = "ext['" + name + "']";
158 shouldBe(actual, expected);
159 }
161 supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
162 // There should be exactly 4 formats
163 shouldBe("supportedFormats.length", "1");
165 // check that all 4 formats exist
166 for (var name in validFormats.length) {
167 formatExists(validFormats[name], supportedFormats);
168 }
170 // Test each format
171 testETC1_RGB();
172 }
174 function testETC1_RGB() {
175 var tests = [
176 { width: 4,
177 height: 4,
178 channels: 3,
179 data: img_4x4_rgb_etc1,
180 format: ext.COMPRESSED_RGB_ETC1_WEBGL
181 },
182 { width: 8,
183 height: 8,
184 channels: 3,
185 data: img_8x8_rgb_etc1,
186 format: ext.COMPRESSED_RGB_ETC1_WEBGL
187 }
188 ];
189 testETCTextures(tests);
190 }
192 function testETCTextures(tests) {
193 for (var ii = 0; ii < tests.length; ++ii) {
194 debug("<hr/>");
195 testETCTexture(tests[ii]);
196 }
197 }
199 function offset_color(c, o) {
200 return [
201 Math.min(Math.max(0, c[0] + o), 255),
202 Math.min(Math.max(0, c[1] + o), 255),
203 Math.min(Math.max(0, c[2] + o), 255),
204 c[3]
205 ];
206 }
208 function uncompressETC1Block(destBuffer, destX, destY, destWidth, src) {
209 'use strict';
210 var xx, yy, basecols;
211 var _deltatable = [ 0, 1, 2, 3, -4, -3, -2, -1 ];
212 var _modtable = [
213 [ 2, 8, -2, -8 ],
214 [ 5, 17, -5, -17 ],
215 [ 9, 29, -9, -29 ],
216 [ 13, 42, -13, -42 ],
217 [ 18, 60, -18, -60 ],
218 [ 24, 80, -24, -80 ],
219 [ 33, 106, -33, -106 ],
220 [ 47, 183, -47, -183 ]
221 ];
222 var _sl = [
223 0x00, 0x01, 0x04, 0x05,
224 0x10, 0x11, 0x14, 0x15,
225 0x40, 0x41, 0x44, 0x45,
226 0x50, 0x51, 0x54, 0x55
227 ];
228 var _sh = [
229 0x00, 0x02, 0x08, 0x0a,
230 0x20, 0x22, 0x28, 0x2a,
231 0x80, 0x82, 0x88, 0x8a,
232 0xa0, 0xa2, 0xa8, 0xaa
233 ];
235 function extend_4to8bits(r, g, b) {
236 return [
237 (r & 0xf0) | ((r >> 4) & 0x0f),
238 (g & 0xf0) | ((g >> 4) & 0x0f),
239 (b & 0xf0) | ((b >> 4) & 0x0f),
240 255
241 ];
242 }
244 function extend_5to8bits(r, g, b) {
245 return [
246 (r & 0xf8) | ((r >> 5) & 0x07),
247 (g & 0xf8) | ((g >> 5) & 0x07),
248 (b & 0xf8) | ((b >> 5) & 0x07),
249 255
250 ];
251 }
253 function base_colors(src, mode) {
254 var col_1, col_2, didx, d;
255 if (mode === 'I') {
256 col_1 = extend_4to8bits(src[0], src[1], src[2]);
257 col_2 = extend_4to8bits(src[0] << 4, src[1] << 4, src[2] << 4);
258 return [ col_1, col_2 ];
259 }
261 if (mode === 'D') {
262 col_1 = extend_5to8bits(src[0], src[1], src[2]);
263 col_2 = extend_5to8bits(src[0] + 8 * _deltatable[(src[0] & 0x7)],
264 src[1] + 8 * _deltatable[(src[1] & 0x7)],
265 src[2] + 8 * _deltatable[(src[2] & 0x7)]);
266 return [ col_1, col_2 ];
267 }
269 return [];
270 }
272 function mode(src) {
273 return (src[3] & 0x2) ? 'D' : 'I';
274 }
276 function flip(src) {
277 return (src[3] & 0x1) === 0x1;
278 }
280 function subblock_modtable(src, sb) {
281 var shift = (sb ? 2 : 5);
282 var idx = (src[3] >> shift) & 0x7;
283 return _modtable[idx];
284 }
286 function interleave_table_indices(src) {
287 var result =
288 (_sl[src[7] & 0xf] | _sh[src[5] & 0xf]) |
289 ((_sl[(src[7] >> 4) & 0xf] | _sh[(src[5] >> 4) & 0xf]) << 8) |
290 ((_sl[src[6] & 0xf] | _sh[src[4] & 0xf]) << 16) |
291 ((_sl[(src[6] >> 4) & 0xf] | _sh[(src[4] >> 4) & 0xf]) << 24);
292 return result;
293 }
295 function subblock(n, flip) {
296 var mask = flip ? 0x2 : 0x8;
297 return (n & mask) ? 1 : 0;
298 }
300 var m = mode(src);
301 basecols = base_colors(src, m);
303 var alpha = 255;
304 var flipbit = flip(src);
305 var table_indices = interleave_table_indices(src);
307 var n = 0;
308 for (xx = 0; xx < 4; ++xx) {
309 for (yy = 0; yy < 4; ++yy) {
310 var dstOff = ((destY + yy) * destWidth + destX + xx) * 4;
312 var sb = subblock(n, flipbit);
313 var mod = subblock_modtable(src, sb);
314 var offset = mod[(table_indices & 0x3)];
315 var col = offset_color(basecols[sb], offset);
317 destBuffer[dstOff] = col[0];
318 destBuffer[dstOff + 1] = col[1];
319 destBuffer[dstOff + 2] = col[2];
320 destBuffer[dstOff + 3] = alpha;
321 table_indices >>= 2;
322 n++;
323 }
324 }
325 }
327 function uncompressETC1(width, height, data, format) {
328 if (width % 4 || height % 4) throw "bad width or height";
330 var dest = new Uint8Array(width * height * 4);
331 var blocksAcross = width / 4;
332 var blocksDown = height / 4;
333 var blockSize = 8;
334 for (var yy = 0; yy < blocksDown; ++yy) {
335 for (var xx = 0; xx < blocksAcross; ++xx) {
336 var srcOffset = (yy * blocksAcross + xx) * blockSize;
337 var srcblk = data.subarray(srcOffset, srcOffset + blockSize);
338 uncompressETC1Block(dest, xx * 4, yy * 4, width, srcblk);
339 }
340 }
341 return dest;
342 }
344 function testETCTexture(test) {
345 var data = new Uint8Array(test.data);
346 var width = test.width;
347 var height = test.height;
348 var format = test.format;
350 var uncompressedData = uncompressETC1(width, height, data, format);
352 canvas.width = width;
353 canvas.height = height;
354 gl.viewport(0, 0, width, height);
355 debug("testing " + formatToString(format) + " " + width + "x" + height);
357 var tex = gl.createTexture();
358 gl.bindTexture(gl.TEXTURE_2D, tex);
359 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
360 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
361 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
362 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
363 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
364 glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
365 gl.generateMipmap(gl.TEXTURE_2D);
366 glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture");
367 wtu.clearAndDrawUnitQuad(gl);
368 compareRect(width, height, test.channels, width, height, uncompressedData, data, format);
370 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 1, data);
371 glErrorShouldBe(gl, gl.INVALID_VALUE, "non 0 border");
373 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width + 4, height, 0, data);
374 glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
375 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height + 4, 0, data);
376 glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
377 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 4, height, 0, data);
378 glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
379 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 4, 0, data);
380 glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
382 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 1, height, 0, data);
383 glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
384 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 2, height, 0, data);
385 glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
386 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 1, 0, data);
387 glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
388 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 2, 0, data);
389 glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
391 if (width == 4) {
392 gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 1, height, 0, data);
393 glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
394 gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 2, height, 0, data);
395 glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
396 }
397 if (height == 4) {
398 gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 1, 0, data);
399 glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
400 gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 2, 0, data);
401 glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
402 }
404 // Reupload the complete texture before SubImage tests.
405 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
406 glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
408 /* OES_compressed_ETC1_RGB8_texture:
409 * INVALID_OPERATION is generated by CompressedTexSubImage2D,
410 * TexSubImage2D, or CopyTexSubImage2D if the texture image
411 * <level> bound to <target> has internal format ETC1_RGB8_OES.
412 */
413 gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data);
414 glErrorShouldBe(gl, gl.INVALID_OPERATION, "ETC1 should not support compressedTexSubImage2D.");
415 }
417 function insertImg(element, caption, img) {
418 var div = document.createElement("div");
419 div.appendChild(img);
420 var label = document.createElement("div");
421 label.appendChild(document.createTextNode(caption));
422 div.appendChild(label);
423 element.appendChild(div);
424 }
426 function makeImage(imageWidth, imageHeight, dataWidth, data, alpha) {
427 var scale = 8;
428 var c = document.createElement("canvas");
429 c.width = imageWidth * scale;
430 c.height = imageHeight * scale;
431 var ctx = c.getContext("2d");
432 for (var yy = 0; yy < imageHeight; ++yy) {
433 for (var xx = 0; xx < imageWidth; ++xx) {
434 var offset = (yy * dataWidth + xx) * 4;
435 ctx.fillStyle = "rgba(" +
436 data[offset + 0] + "," +
437 data[offset + 1] + "," +
438 data[offset + 2] + "," +
439 (alpha ? data[offset + 3] / 255 : 1) + ")";
440 ctx.fillRect(xx * scale, yy * scale, scale, scale);
441 }
442 }
443 var img = document.createElement("img");
444 img.src = c.toDataURL();
445 return img;
446 }
448 function compareRect(actualWidth, actualHeight, actualChannels,
449 dataWidth, dataHeight, expectedData,
450 testData, testFormat)
451 {
452 var actual = new Uint8Array(actualWidth * actualHeight * 4);
453 gl.readPixels(0, 0, actualWidth, actualHeight,
454 gl.RGBA, gl.UNSIGNED_BYTE, actual);
456 var div = document.createElement("div");
457 div.className = "testimages";
458 insertImg(div, "expected", makeImage(
459 actualWidth, actualHeight, dataWidth, expectedData,
460 actualChannels == 4));
461 insertImg(div, "actual", makeImage(
462 actualWidth, actualHeight, actualWidth, actual,
463 actualChannels == 4));
464 div.appendChild(document.createElement('br'));
465 document.getElementById("console").appendChild(div);
467 var failed = false;
468 for (var yy = 0; yy < actualHeight; ++yy) {
469 for (var xx = 0; xx < actualWidth; ++xx) {
470 var actualOffset = (yy * actualWidth + xx) * 4;
471 var expectedOffset = (yy * dataWidth + xx) * 4;
472 var expected = [
473 expectedData[expectedOffset + 0],
474 expectedData[expectedOffset + 1],
475 expectedData[expectedOffset + 2],
476 (actualChannels == 3 ? 255
477 : expectedData[expectedOffset + 3])
478 ];
480 if (actual[actualOffset + 0] != expected[0] ||
481 actual[actualOffset + 1] != expected[1] ||
482 actual[actualOffset + 2] != expected[2] ||
483 actual[actualOffset + 3] != expected[3])
484 {
485 failed = true;
486 var was = actual[actualOffset + 0].toString();
487 for (var j = 1; j < 4; ++j) {
488 was += "," + actual[actualOffset + j];
489 }
490 testFailed('at (' + xx + ', ' + yy +
491 ') expected: ' + expected + ' was ' + was);
492 }
493 }
494 }
495 if (!failed) {
496 testPassed("texture rendered correctly");
497 }
498 }
500 debug("");
501 var successfullyParsed = true;
502 </script>
503 <script>finishTest();</script>
505 </body>
506 </html>