4 ** Copyright (c) 2013 The Khronos Group Inc.
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:
14 ** The above copyright notice and this permission notice shall be included
15 ** in all copies or substantial portions of the Materials.
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.
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-utils.js"></script>
35 <title>WebGL WEBGL_compressed_texture_atc Conformance Tests</title>
38 border: 1px solid black;
55 <div id="description"></div>
56 <canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
57 <div id="console"></div>
60 description("This test verifies the functionality of the WEBGL_compressed_texture_atc extension, if it is available.");
64 // Compressed textures generated with AMD's Compressonator tool
65 // http://developer.amd.com/resources/archive/archived-tools/gpu-tools-archive/the-compressonator/
66 var img_4x4_rgba_raw = new Uint8Array([
67 0xff,0x00,0x00,0x69,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,
68 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,
69 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,
70 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,
72 var img_4x4_rgb_atc = new Uint8Array([
73 0x00,0x7c,0xe0,0x07,0xcc,0xcf,0xc0,0xff,
75 var img_4x4_rgba_atc_explicit = new Uint8Array([
76 0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x7c,0xe0,0x07,0xcc,0xcf,0xc0,0xff,
78 var img_4x4_rgba_atc_interpolated = new Uint8Array([
79 0xff,0x6a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xe0,0x07,0xcc,0xcf,0xc0,0xff,
81 var img_8x8_rgba_raw = new Uint8Array([
82 0xff,0x00,0x00,0x69,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,
83 0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,
84 0x00,0xff,0x00,0x69,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,
85 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,
86 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,
87 0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,
88 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,
89 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,
90 0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,
91 0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,
92 0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,
93 0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,
94 0x00,0xff,0x00,0x69,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,
95 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,
96 0xff,0x00,0xff,0x69,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,
97 0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,
99 var img_8x8_rgb_atc = new Uint8Array([
100 0x00,0x7c,0xe0,0x07,0xcc,0xcf,0xc0,0xff,0x1f,0x00,0xe0,0xff,0x33,0x30,0x3f,0x00,
101 0x1f,0x7c,0xe0,0x07,0x33,0x30,0x3f,0x00,0x1f,0x00,0xff,0x07,0xcc,0xcf,0xc0,0xff,
103 var img_8x8_rgba_atc_explicit = new Uint8Array([
104 0xf6,0xff,0xf6,0xff,0xff,0xff,0xff,0xff,0x00,0x7c,0xe0,0x07,0xcc,0xcf,0xc0,0xff,
105 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0xe0,0xff,0x33,0x30,0x3f,0x00,
106 0xff,0xff,0xff,0xff,0xf6,0xff,0xf6,0xff,0x1f,0x7c,0xe0,0x07,0x33,0x30,0x3f,0x00,
107 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0xff,0x07,0xcc,0xcf,0xc0,0xff,
109 var img_8x8_rgba_atc_interpolated = new Uint8Array([
110 0xff,0x6a,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x7c,0xe0,0x07,0xcc,0xcf,0xc0,0xff,
111 0x00,0xff,0x49,0x92,0x24,0x49,0x92,0x24,0x1f,0x00,0xe0,0xff,0x33,0x30,0x3f,0x00,
112 0xff,0x69,0x00,0x00,0x00,0x01,0x10,0x00,0x1f,0x7c,0xe0,0x07,0x33,0x30,0x3f,0x00,
113 0x00,0xff,0x49,0x92,0x24,0x49,0x92,0x24,0x1f,0x00,0xff,0x07,0xcc,0xcf,0xc0,0xff,
116 var wtu = WebGLTestUtils;
117 var canvas = document.getElementById("canvas");
118 var gl = wtu.create3DContext(canvas, {antialias: false});
119 var program = wtu.setupTexturedQuad(gl);
123 COMPRESSED_RGB_ATC_WEBGL : 0x8C92,
124 COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL : 0x8C93,
125 COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL : 0x87EE,
128 var supportedFormats;
131 testFailed("WebGL context does not exist");
133 testPassed("WebGL context exists");
135 // Run tests with extension disabled
138 // Query the extension and store globally so shouldBe can access it
139 ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_atc");
141 testPassed("No WEBGL_compressed_texture_atc support -- this is legal");
142 runSupportedTest(false);
144 testPassed("Successfully enabled WEBGL_compressed_texture_atc extension");
146 runSupportedTest(true);
151 function runSupportedTest(extensionEnabled) {
152 var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_atc");
153 if (name !== undefined) {
154 if (extensionEnabled) {
155 testPassed("WEBGL_compressed_texture_atc listed as supported and getExtension succeeded");
157 testFailed("WEBGL_compressed_texture_atc listed as supported but getExtension failed");
160 if (extensionEnabled) {
161 testFailed("WEBGL_compressed_texture_atc not listed as supported but getExtension succeeded");
163 testPassed("WEBGL_compressed_texture_atc not listed as supported and getExtension failed -- this is legal");
169 function runTestDisabled() {
170 debug("Testing binding enum with extension disabled");
172 shouldBe('gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS)', '[]');
175 function formatExists(format, supportedFormats) {
176 for (var ii = 0; ii < supportedFormats.length; ++ii) {
177 if (format == supportedFormats[ii]) {
178 testPassed("supported format " + formatToString(format) + " is exists");
182 testFailed("supported format " + formatToString(format) + " does not exist");
185 function formatToString(format) {
187 if (ext[p] == format) {
191 return "0x" + format.toString(16);
194 function runTestExtension() {
195 debug("Testing WEBGL_compressed_texture_atc");
197 // check that all format enums exist.
198 for (name in validFormats) {
199 var expected = "0x" + validFormats[name].toString(16);
200 var actual = "ext['" + name + "']";
201 shouldBe(actual, expected);
204 supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
205 // There should be exactly 3 formats
206 shouldBe("supportedFormats.length", "3");
208 // check that all 3 formats exist
209 for (var name in validFormats.length) {
210 formatExists(validFormats[name], supportedFormats);
215 testATC_RGBA_Explicit();
216 testATC_RGBA_Interpolated();
219 function testATC_RGB() {
224 data: img_4x4_rgb_atc,
225 raw: img_4x4_rgba_raw,
226 format: ext.COMPRESSED_RGB_ATC_WEBGL
231 data: img_8x8_rgb_atc,
232 raw: img_8x8_rgba_raw,
233 format: ext.COMPRESSED_RGB_ATC_WEBGL
236 testACTTextures(tests);
239 function testATC_RGBA_Explicit() {
244 data: img_4x4_rgba_atc_explicit,
245 raw: img_4x4_rgba_raw,
246 format: ext.COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL
251 data: img_8x8_rgba_atc_explicit,
252 raw: img_8x8_rgba_raw,
253 format: ext.COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL
256 testACTTextures(tests);
259 function testATC_RGBA_Interpolated() {
264 data: img_4x4_rgba_atc_interpolated,
265 raw: img_4x4_rgba_raw,
266 format: ext.COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL
271 data: img_8x8_rgba_atc_interpolated,
272 raw: img_8x8_rgba_raw,
273 format: ext.COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL
276 testACTTextures(tests);
279 function testACTTextures(tests) {
281 for (var ii = 0; ii < tests.length; ++ii) {
282 testACTTexture(tests[ii]);
286 function testACTTexture(test) {
287 var data = new Uint8Array(test.data);
288 var width = test.width;
289 var height = test.height;
290 var format = test.format;
291 var uncompressedData = test.raw;
293 canvas.width = width;
294 canvas.height = height;
295 gl.viewport(0, 0, width, height);
296 debug("testing " + formatToString(format) + " " + width + "x" + height);
298 var tex = gl.createTexture();
299 gl.bindTexture(gl.TEXTURE_2D, tex);
300 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
301 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
302 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
303 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
304 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
305 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
306 gl.generateMipmap(gl.TEXTURE_2D);
307 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture");
308 wtu.clearAndDrawUnitQuad(gl);
309 compareRect(width, height, test.channels, width, height, uncompressedData, data, format);
311 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width + 4, height, 0, data);
312 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
313 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height + 4, 0, data);
314 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
315 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 4, height, 0, data);
316 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
317 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 4, 0, data);
318 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
320 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 1, height, 0, data);
321 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
322 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 2, height, 0, data);
323 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
324 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 1, 0, data);
325 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
326 gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 2, 0, data);
327 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
329 gl.compressedTexImage2D(gl.TEXTURE_2D, -1, format, 1, height, 0, data);
330 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "cannot specify negative mip level");
332 // ATC Does not allow use of CompressedTexSubImage
333 gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data);
334 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "compressedTexSubImage2D not allowed");
337 function insertImg(element, caption, img) {
338 var div = document.createElement("div");
339 div.appendChild(img);
340 var label = document.createElement("div");
341 label.appendChild(document.createTextNode(caption));
342 div.appendChild(label);
343 element.appendChild(div);
346 function makeImage(imageWidth, imageHeight, dataWidth, data, alpha) {
348 var c = document.createElement("canvas");
349 c.width = imageWidth * scale;
350 c.height = imageHeight * scale;
351 var ctx = c.getContext("2d");
352 for (var yy = 0; yy < imageHeight; ++yy) {
353 for (var xx = 0; xx < imageWidth; ++xx) {
354 var offset = (yy * dataWidth + xx) * 4;
355 ctx.fillStyle = "rgba(" +
356 data[offset + 0] + "," +
357 data[offset + 1] + "," +
358 data[offset + 2] + "," +
359 (alpha ? data[offset + 3] / 255 : 1) + ")";
360 ctx.fillRect(xx * scale, yy * scale, scale, scale);
363 return wtu.makeImageFromCanvas(c);
365 function compareRect(
366 actualWidth, actualHeight, actualChannels,
367 dataWidth, dataHeight, expectedData,
368 testData, testFormat, tolerance) {
369 if(typeof(tolerance) == 'undefined') { tolerance = 5; }
370 var actual = new Uint8Array(actualWidth * actualHeight * 4);
372 0, 0, actualWidth, actualHeight, gl.RGBA, gl.UNSIGNED_BYTE, actual);
374 var div = document.createElement("div");
375 div.className = "testimages";
376 insertImg(div, "expected", makeImage(
377 actualWidth, actualHeight, dataWidth, expectedData,
378 actualChannels == 4));
379 insertImg(div, "actual", makeImage(
380 actualWidth, actualHeight, actualWidth, actual,
381 actualChannels == 4));
382 div.appendChild(document.createElement('br'));
383 document.getElementById("console").appendChild(div);
386 for (var yy = 0; yy < actualHeight; ++yy) {
387 for (var xx = 0; xx < actualWidth; ++xx) {
388 var actualOffset = (yy * actualWidth + xx) * 4;
389 var expectedOffset = (yy * dataWidth + xx) * 4;
391 expectedData[expectedOffset + 0],
392 expectedData[expectedOffset + 1],
393 expectedData[expectedOffset + 2],
394 (actualChannels == 3 ? 255 : expectedData[expectedOffset + 3])
396 for (var jj = 0; jj < 4; ++jj) {
397 if (Math.abs(actual[actualOffset + jj] - expected[jj]) > tolerance) {
399 var was = actual[actualOffset + 0].toString();
400 for (j = 1; j < 4; ++j) {
401 was += "," + actual[actualOffset + j];
403 testFailed('at (' + xx + ', ' + yy +
404 ') expected: ' + expected + ' was ' + was);
410 testPassed("texture rendered correctly");
415 var successfullyParsed = true;
417 <script src="../../resources/js-test-post.js"></script>