1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/canvas/test/webgl-conformance/conformance/extensions/webgl-compressed-texture-s3tc.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,614 @@ 1.4 +<!-- 1.5 +Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.6 +Use of this source code is governed by a BSD-style license that can be 1.7 +found in the LICENSE file. 1.8 + --> 1.9 +<!DOCTYPE html> 1.10 +<html> 1.11 +<head> 1.12 +<meta charset="utf-8"> 1.13 +<link rel="stylesheet" href="../../resources/js-test-style.css"/> 1.14 +<script src="../../resources/js-test-pre.js"></script> 1.15 +<script src="../resources/webgl-test.js"></script> 1.16 +<script src="../resources/webgl-test-utils.js"></script> 1.17 +<title>WebGL WEBGL_compressed_texture_s3tc Conformance Tests</title> 1.18 +<style> 1.19 +img { 1.20 + border: 1px solid black; 1.21 + margin-right: 1em; 1.22 +} 1.23 +.testimages { 1.24 +} 1.25 + 1.26 +.testimages br { 1.27 + clear: both; 1.28 +} 1.29 + 1.30 +.testimages > div { 1.31 + float: left; 1.32 + margin: 1em; 1.33 +} 1.34 +</style> 1.35 +</head> 1.36 +<body> 1.37 +<div id="description"></div> 1.38 +<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas> 1.39 +<div id="console"></div> 1.40 +<script> 1.41 +description("This test verifies the functionality of the WEBGL_compressed_texture_s3tc extension, if it is available."); 1.42 + 1.43 +debug(""); 1.44 + 1.45 +var img_4x4_rgba_raw = new Uint8Array([ 1.46 + 0xff,0x00,0x00,0x69,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, 1.47 +]); 1.48 +var img_4x4_rgb_dxt1 = new Uint8Array([ 1.49 + 0xe0,0x07,0x00,0xf8,0x11,0x10,0x15,0x00, 1.50 +]); 1.51 +var img_4x4_rgba_dxt1 = new Uint8Array([ 1.52 + 0xe0,0x07,0x00,0xf8,0x13,0x10,0x15,0x00, 1.53 +]); 1.54 +var img_4x4_rgba_dxt3 = new Uint8Array([ 1.55 + 0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0xe0,0x07,0x44,0x45,0x40,0x55, 1.56 +]); 1.57 +var img_4x4_rgba_dxt5 = new Uint8Array([ 1.58 + 0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0xe0,0x07,0x44,0x45,0x40,0x55, 1.59 +]); 1.60 +var img_8x8_rgba_raw = new Uint8Array([ 1.61 + 0xff,0x00,0x00,0x69,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0x00,0x69,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0x00,0x69,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0x69,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff, 1.62 +]); 1.63 +var img_8x8_rgb_dxt1 = new Uint8Array([ 1.64 + 0xe0,0x07,0x00,0xf8,0x11,0x10,0x15,0x00,0x1f,0x00,0xe0,0xff,0x11,0x10,0x15,0x00,0xe0,0x07,0x1f,0xf8,0x44,0x45,0x40,0x55,0x1f,0x00,0xff,0x07,0x44,0x45,0x40,0x55, 1.65 +]); 1.66 +var img_8x8_rgba_dxt1 = new Uint8Array([ 1.67 + 0xe0,0x07,0x00,0xf8,0x13,0x13,0x15,0x00,0x1f,0x00,0xe0,0xff,0x11,0x10,0x15,0x00,0xe0,0x07,0x1f,0xf8,0x44,0x45,0x43,0x57,0x1f,0x00,0xff,0x07,0x44,0x45,0x40,0x55, 1.68 +]); 1.69 +var img_8x8_rgba_dxt3 = new Uint8Array([ 1.70 + 0xf6,0xff,0xf6,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0xe0,0x07,0x44,0x45,0x40,0x55,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0xff,0x1f,0x00,0x44,0x45,0x40,0x55,0xff,0xff,0xff,0xff,0xf6,0xff,0xf6,0xff,0x1f,0xf8,0xe0,0x07,0x11,0x10,0x15,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0x1f,0x00,0x11,0x10,0x15,0x00, 1.71 +]); 1.72 +var img_8x8_rgba_dxt5 = new Uint8Array([ 1.73 + 0xff,0x69,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0xf8,0xe0,0x07,0x44,0x45,0x40,0x55,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xff,0x1f,0x00,0x44,0x45,0x40,0x55,0xff,0x69,0x00,0x00,0x00,0x01,0x10,0x00,0x1f,0xf8,0xe0,0x07,0x11,0x10,0x15,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x07,0x1f,0x00,0x11,0x10,0x15,0x00, 1.74 +]); 1.75 + 1.76 +var wtu = WebGLTestUtils; 1.77 +var canvas = document.getElementById("canvas"); 1.78 +var gl = wtu.create3DContext(canvas, {antialias: false}); 1.79 +var program = wtu.setupTexturedQuad(gl); 1.80 +var ext = null; 1.81 +var vao = null; 1.82 +var validFormats = { 1.83 + COMPRESSED_RGB_S3TC_DXT1_EXT : 0x83F0, 1.84 + COMPRESSED_RGBA_S3TC_DXT1_EXT : 0x83F1, 1.85 + COMPRESSED_RGBA_S3TC_DXT3_EXT : 0x83F2, 1.86 + COMPRESSED_RGBA_S3TC_DXT5_EXT : 0x83F3, 1.87 +}; 1.88 +var name; 1.89 +var supportedFormats; 1.90 + 1.91 +if (!gl) { 1.92 + testFailed("WebGL context does not exist"); 1.93 +} else { 1.94 + testPassed("WebGL context exists"); 1.95 + 1.96 + // Run tests with extension disabled 1.97 + runTestDisabled(); 1.98 + 1.99 + // Query the extension and store globally so shouldBe can access it 1.100 + ext = gl.getExtension("WEBGL_compressed_texture_s3tc"); 1.101 + if (!ext) { 1.102 + ext = gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc"); 1.103 + } 1.104 + if (!ext) { 1.105 + testPassed("No WEBGL_compressed_texture_s3tc support -- this is legal"); 1.106 + runSupportedTest(false); 1.107 + } else { 1.108 + testPassed("Successfully enabled WEBGL_compressed_texture_s3tc extension"); 1.109 + 1.110 + runSupportedTest(true); 1.111 + runTestExtension(); 1.112 + } 1.113 +} 1.114 + 1.115 +function runSupportedTest(extensionEnabled) { 1.116 + var supported = gl.getSupportedExtensions(); 1.117 + if (supported.indexOf("WEBGL_compressed_texture_s3tc") >= 0 || 1.118 + supported.indexOf("WEBKIT_WEBGL_compressed_texture_s3tc") >= 0) { 1.119 + if (extensionEnabled) { 1.120 + testPassed("WEBGL_compressed_texture_s3tc listed as supported and getExtension succeeded"); 1.121 + } else { 1.122 + testFailed("WEBGL_compressed_texture_s3tc listed as supported but getExtension failed"); 1.123 + } 1.124 + } else { 1.125 + if (extensionEnabled) { 1.126 + testFailed("WEBGL_compressed_texture_s3tc not listed as supported but getExtension succeeded"); 1.127 + } else { 1.128 + testPassed("WEBGL_compressed_texture_s3tc not listed as supported and getExtension failed -- this is legal"); 1.129 + } 1.130 + } 1.131 +} 1.132 + 1.133 + 1.134 +function runTestDisabled() { 1.135 + debug("Testing binding enum with extension disabled"); 1.136 + 1.137 + shouldBe('gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS)', '[]'); 1.138 +} 1.139 + 1.140 +function formatExists(format, supportedFormats) { 1.141 + for (var ii = 0; ii < supportedFormats.length; ++ii) { 1.142 + if (format == supportedFormats[ii]) { 1.143 + testPassed("supported format " + formatToString(format) + " is exists"); 1.144 + return; 1.145 + } 1.146 + } 1.147 + testFailed("supported format " + formatToString(format) + " does not exist"); 1.148 +} 1.149 + 1.150 +function formatToString(format) { 1.151 + for (var p in ext) { 1.152 + if (ext[p] == format) { 1.153 + return p; 1.154 + } 1.155 + } 1.156 + return "0x" + format.toString(16); 1.157 +} 1.158 + 1.159 +function runTestExtension() { 1.160 + debug("Testing WEBGL_compressed_texture_s3tc"); 1.161 + 1.162 + // check that all format enums exist. 1.163 + for (name in validFormats) { 1.164 + var expected = "0x" + validFormats[name].toString(16); 1.165 + var actual = "ext['" + name + "']"; 1.166 + shouldBe(actual, expected); 1.167 + } 1.168 + 1.169 + supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS); 1.170 + // There should be exactly 4 formats 1.171 + shouldBe("supportedFormats.length", "4"); 1.172 + 1.173 + // check that all 4 formats exist 1.174 + for (var name in validFormats.length) { 1.175 + formatExists(validFormats[name], supportedFormats); 1.176 + } 1.177 + 1.178 + // Test each format 1.179 + testDXT1_RGB(); 1.180 + testDXT1_RGBA(); 1.181 + testDXT3_RGBA(); 1.182 + testDXT5_RGBA(); 1.183 +} 1.184 + 1.185 +function testDXT1_RGB() { 1.186 + var tests = [ 1.187 + { width: 4, 1.188 + height: 4, 1.189 + channels: 3, 1.190 + data: img_4x4_rgb_dxt1, 1.191 + format: ext.COMPRESSED_RGB_S3TC_DXT1_EXT 1.192 + }, 1.193 + { width: 8, 1.194 + height: 8, 1.195 + channels: 3, 1.196 + data: img_8x8_rgb_dxt1, 1.197 + format: ext.COMPRESSED_RGB_S3TC_DXT1_EXT 1.198 + } 1.199 + ]; 1.200 + testDXTTextures(tests); 1.201 +} 1.202 + 1.203 +function testDXT1_RGBA() { 1.204 + var tests = [ 1.205 + { width: 4, 1.206 + height: 4, 1.207 + channels: 4, 1.208 + data: img_4x4_rgba_dxt1, 1.209 + format: ext.COMPRESSED_RGBA_S3TC_DXT1_EXT 1.210 + }, 1.211 + { width: 8, 1.212 + height: 8, 1.213 + channels: 4, 1.214 + data: img_8x8_rgba_dxt1, 1.215 + format: ext.COMPRESSED_RGBA_S3TC_DXT1_EXT 1.216 + } 1.217 + ]; 1.218 + testDXTTextures(tests); 1.219 +} 1.220 + 1.221 +function testDXT3_RGBA() { 1.222 + var tests = [ 1.223 + { width: 4, 1.224 + height: 4, 1.225 + channels: 4, 1.226 + data: img_4x4_rgba_dxt3, 1.227 + format: ext.COMPRESSED_RGBA_S3TC_DXT3_EXT 1.228 + }, 1.229 + { width: 8, 1.230 + height: 8, 1.231 + channels: 4, 1.232 + data: img_8x8_rgba_dxt3, 1.233 + format: ext.COMPRESSED_RGBA_S3TC_DXT3_EXT 1.234 + } 1.235 + ]; 1.236 + testDXTTextures(tests); 1.237 +} 1.238 + 1.239 +function testDXT5_RGBA() { 1.240 + var tests = [ 1.241 + { width: 4, 1.242 + height: 4, 1.243 + channels: 4, 1.244 + data: img_4x4_rgba_dxt5, 1.245 + format: ext.COMPRESSED_RGBA_S3TC_DXT5_EXT 1.246 + }, 1.247 + { width: 8, 1.248 + height: 8, 1.249 + channels: 4, 1.250 + data: img_8x8_rgba_dxt5, 1.251 + format: ext.COMPRESSED_RGBA_S3TC_DXT5_EXT 1.252 + } 1.253 + ]; 1.254 + testDXTTextures(tests); 1.255 +} 1.256 + 1.257 +function testDXTTextures(tests) { 1.258 + debug("<hr/>"); 1.259 + for (var ii = 0; ii < tests.length; ++ii) { 1.260 + testDXTTexture(tests[ii]); 1.261 + } 1.262 +} 1.263 + 1.264 +function uncompressDXTBlock( 1.265 + destBuffer, destX, destY, destWidth, src, srcOffset, format) { 1.266 + function make565(src, offset) { 1.267 + return src[offset + 0] + src[offset + 1] * 256; 1.268 + } 1.269 + function make8888From565(c) { 1.270 + return [ 1.271 + Math.floor(((c >> 11) & 0x1F) * 255 / 31), 1.272 + Math.floor(((c >> 5) & 0x3F) * 255 / 63), 1.273 + Math.floor(((c >> 0) & 0x1F) * 255 / 31), 1.274 + 255 1.275 + ]; 1.276 + } 1.277 + function mix(mult, c0, c1, div) { 1.278 + var r = []; 1.279 + for (var ii = 0; ii < c0.length; ++ii) { 1.280 + r[ii] = Math.floor((c0[ii] * mult + c1[ii]) / div); 1.281 + } 1.282 + return r; 1.283 + } 1.284 + var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT || 1.285 + format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT; 1.286 + var colorOffset = srcOffset + (isDXT1 ? 0 : 8); 1.287 + var color0 = make565(src, colorOffset + 0); 1.288 + var color1 = make565(src, colorOffset + 2); 1.289 + var c0gtc1 = color0 > color1 || !isDXT1; 1.290 + var rgba0 = make8888From565(color0); 1.291 + var rgba1 = make8888From565(color1); 1.292 + var colors = [ 1.293 + rgba0, 1.294 + rgba1, 1.295 + c0gtc1 ? mix(2, rgba0, rgba1, 3) : mix(1, rgba0, rgba1, 2), 1.296 + c0gtc1 ? mix(2, rgba1, rgba0, 3) : [0, 0, 0, 255] 1.297 + ]; 1.298 + 1.299 + // yea I know there is a lot of math in this inner loop. 1.300 + // so sue me. 1.301 + for (var yy = 0; yy < 4; ++yy) { 1.302 + var pixels = src[colorOffset + 4 + yy]; 1.303 + for (var xx = 0; xx < 4; ++xx) { 1.304 + var dstOff = ((destY + yy) * destWidth + destX + xx) * 4; 1.305 + var code = (pixels >> (xx * 2)) & 0x3; 1.306 + var srcColor = colors[code]; 1.307 + var alpha; 1.308 + switch (format) { 1.309 + case ext.COMPRESSED_RGB_S3TC_DXT1_EXT: 1.310 + alpha = 255; 1.311 + break; 1.312 + case ext.COMPRESSED_RGBA_S3TC_DXT1_EXT: 1.313 + alpha = (code == 3 && !c0gtc1) ? 0 : 255; 1.314 + break; 1.315 + case ext.COMPRESSED_RGBA_S3TC_DXT3_EXT: 1.316 + { 1.317 + var alpha0 = src[srcOffset + yy * 2 + Math.floor(xx / 2)]; 1.318 + var alpha1 = (alpha0 >> ((xx % 2) * 4)) & 0xF; 1.319 + alpha = alpha1 | (alpha1 << 4); 1.320 + } 1.321 + break; 1.322 + case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT: 1.323 + { 1.324 + var alpha0 = src[srcOffset + 0]; 1.325 + var alpha1 = src[srcOffset + 1]; 1.326 + var alphaOff = Math.floor(yy / 2) * 3 + 2; 1.327 + var alphaBits = 1.328 + src[srcOffset + alphaOff + 0] + 1.329 + src[srcOffset + alphaOff + 1] * 256 + 1.330 + src[srcOffset + alphaOff + 2] * 65536; 1.331 + var alphaShift = (yy % 2) * 12 + xx * 3; 1.332 + var alphaCode = (alphaBits >> alphaShift) & 0x7; 1.333 + if (alpha0 > alpha1) { 1.334 + switch (alphaCode) { 1.335 + case 0: 1.336 + alpha = alpha0; 1.337 + break; 1.338 + case 1: 1.339 + alpha = alpha1; 1.340 + break; 1.341 + default: 1.342 + alpha = ((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7; 1.343 + break; 1.344 + } 1.345 + } else { 1.346 + switch (alphaCode) { 1.347 + case 0: 1.348 + alpha = alpha0; 1.349 + break; 1.350 + case 1: 1.351 + alpha = alpha1; 1.352 + break; 1.353 + case 6: 1.354 + alpha = 0; 1.355 + break; 1.356 + case 7: 1.357 + alpha = 255; 1.358 + break; 1.359 + default: 1.360 + alpha = ((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5; 1.361 + break; 1.362 + } 1.363 + } 1.364 + } 1.365 + break; 1.366 + default: 1.367 + throw "bad format"; 1.368 + } 1.369 + destBuffer[dstOff + 0] = srcColor[0]; 1.370 + destBuffer[dstOff + 1] = srcColor[1]; 1.371 + destBuffer[dstOff + 2] = srcColor[2]; 1.372 + destBuffer[dstOff + 3] = alpha; 1.373 + } 1.374 + } 1.375 +} 1.376 + 1.377 +function getBlockSize(format) { 1.378 + var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT || 1.379 + format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT; 1.380 + return isDXT1 ? 8 : 16; 1.381 +} 1.382 + 1.383 +function uncompressDXT(width, height, data, format) { 1.384 + if (width % 4 || height % 4) throw "bad width or height"; 1.385 + 1.386 + var dest = new Uint8Array(width * height * 4); 1.387 + var blocksAcross = width / 4; 1.388 + var blocksDown = height / 4; 1.389 + var blockSize = getBlockSize(format); 1.390 + for (var yy = 0; yy < blocksDown; ++yy) { 1.391 + for (var xx = 0; xx < blocksAcross; ++xx) { 1.392 + uncompressDXTBlock( 1.393 + dest, xx * 4, yy * 4, width, data, 1.394 + (yy * blocksAcross + xx) * blockSize, format); 1.395 + } 1.396 + } 1.397 + return dest; 1.398 +} 1.399 + 1.400 +function copyRect(data, srcX, srcY, dstX, dstY, width, height, stride) { 1.401 + var bytesPerLine = width * 4; 1.402 + var srcOffset = srcX * 4 + srcY * stride; 1.403 + var dstOffset = dstX * 4 + dstY * stride; 1.404 + for (; height > 0; --height) { 1.405 + for (var ii = 0; ii < bytesPerLine; ++ii) { 1.406 + data[dstOffset + ii] = data[srcOffset + ii]; 1.407 + } 1.408 + srcOffset += stride; 1.409 + dstOffset += stride; 1.410 + } 1.411 +} 1.412 + 1.413 +function testDXTTexture(test) { 1.414 + var data = new Uint8Array(test.data); 1.415 + var width = test.width; 1.416 + var height = test.height; 1.417 + var format = test.format; 1.418 + 1.419 + var uncompressedData = uncompressDXT(width, height, data, format); 1.420 + 1.421 + canvas.width = width; 1.422 + canvas.height = height; 1.423 + gl.viewport(0, 0, width, height); 1.424 + debug("testing " + formatToString(format) + " " + width + "x" + height); 1.425 + var tex = gl.createTexture(); 1.426 + gl.bindTexture(gl.TEXTURE_2D, tex); 1.427 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 1.428 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 1.429 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 1.430 + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 1.431 + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data); 1.432 + glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture"); 1.433 + wtu.drawQuad(gl); 1.434 + compareRect(width, height, test.channels, width, height, uncompressedData, data, format); 1.435 + 1.436 + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 1, data); 1.437 + glErrorShouldBe(gl, gl.INVALID_VALUE, "non 0 border"); 1.438 + 1.439 + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width + 4, height, 0, data); 1.440 + glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); 1.441 + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height + 4, 0, data); 1.442 + glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); 1.443 + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 4, height, 0, data); 1.444 + glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); 1.445 + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 4, 0, data); 1.446 + glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); 1.447 + 1.448 + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 1, height, 0, data); 1.449 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); 1.450 + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 2, height, 0, data); 1.451 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); 1.452 + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 1, 0, data); 1.453 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); 1.454 + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 2, 0, data); 1.455 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); 1.456 + 1.457 + if (width == 4) { 1.458 + gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 1, height, 0, data); 1.459 + glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0"); 1.460 + gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 2, height, 0, data); 1.461 + glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0"); 1.462 + } 1.463 + if (height == 4) { 1.464 + gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 1, 0, data); 1.465 + glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0"); 1.466 + gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 2, 0, data); 1.467 + glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0"); 1.468 + } 1.469 + 1.470 + // pick a wrong format that uses the same amount of data. 1.471 + var wrongFormat; 1.472 + switch (format) { 1.473 + case ext.COMPRESSED_RGB_S3TC_DXT1_EXT: 1.474 + wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT1_EXT; 1.475 + break; 1.476 + case ext.COMPRESSED_RGBA_S3TC_DXT1_EXT: 1.477 + wrongFormat = ext.COMPRESSED_RGB_S3TC_DXT1_EXT; 1.478 + break; 1.479 + case ext.COMPRESSED_RGBA_S3TC_DXT3_EXT: 1.480 + wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT; 1.481 + break; 1.482 + case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT: 1.483 + wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT; 1.484 + break; 1.485 + } 1.486 + 1.487 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, wrongFormat, data); 1.488 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "format does not match"); 1.489 + 1.490 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width + 4, height, format, data); 1.491 + glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); 1.492 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height + 4, format, data); 1.493 + glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); 1.494 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 4, height, format, data); 1.495 + glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); 1.496 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 4, format, data); 1.497 + glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); 1.498 + 1.499 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 1, height, format, data); 1.500 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); 1.501 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 2, height, format, data); 1.502 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); 1.503 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 1, format, data); 1.504 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); 1.505 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 2, format, data); 1.506 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); 1.507 + 1.508 + var subData = new Uint8Array(data.buffer, 0, getBlockSize(format)); 1.509 + 1.510 + if (width == 8 && height == 8) { 1.511 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 1, 0, 4, 4, format, subData); 1.512 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset"); 1.513 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 1, 4, 4, format, subData); 1.514 + glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset"); 1.515 + } 1.516 + 1.517 + var stride = width * 4; 1.518 + for (var yoff = 0; yoff < height; yoff += 4) { 1.519 + for (var xoff = 0; xoff < width; xoff += 4) { 1.520 + copyRect(uncompressedData, 0, 0, xoff, yoff, 4, 4, stride); 1.521 + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, xoff, yoff, 4, 4, format, subData); 1.522 + glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture"); 1.523 + wtu.drawQuad(gl); 1.524 + compareRect(width, height, test.channels, width, height, uncompressedData, data, format); 1.525 + } 1.526 + } 1.527 +} 1.528 + 1.529 +function insertImg(element, caption, img) { 1.530 + var div = document.createElement("div"); 1.531 + div.appendChild(img); 1.532 + var label = document.createElement("div"); 1.533 + label.appendChild(document.createTextNode(caption)); 1.534 + div.appendChild(label); 1.535 + element.appendChild(div); 1.536 +} 1.537 + 1.538 +function makeImage(imageWidth, imageHeight, dataWidth, data, alpha) { 1.539 + var scale = 8; 1.540 + var c = document.createElement("canvas"); 1.541 + c.width = imageWidth * scale; 1.542 + c.height = imageHeight * scale; 1.543 + var ctx = c.getContext("2d"); 1.544 + for (var yy = 0; yy < imageWidth; ++yy) { 1.545 + for (var xx = 0; xx < imageHeight; ++xx) { 1.546 + var offset = (yy * dataWidth + xx) * 4; 1.547 + ctx.fillStyle = "rgba(" + 1.548 + data[offset + 0] + "," + 1.549 + data[offset + 1] + "," + 1.550 + data[offset + 2] + "," + 1.551 + (alpha ? data[offset + 3] / 255 : 1) + ")"; 1.552 + ctx.fillRect(xx * scale, yy * scale, scale, scale); 1.553 + } 1.554 + } 1.555 + var img = document.createElement("img"); 1.556 + img.src = c.toDataURL(); 1.557 + return img; 1.558 +} 1.559 +function compareRect( 1.560 + actualWidth, actualHeight, actualChannels, 1.561 + dataWidth, dataHeight, expectedData, 1.562 + testData, testFormat) { 1.563 + var actual = new Uint8Array(actualWidth * actualHeight * 4); 1.564 + gl.readPixels( 1.565 + 0, 0, actualWidth, actualHeight, gl.RGBA, gl.UNSIGNED_BYTE, actual); 1.566 + 1.567 + var div = document.createElement("div"); 1.568 + div.className = "testimages"; 1.569 + insertImg(div, "expected", makeImage( 1.570 + actualWidth, actualHeight, dataWidth, expectedData, 1.571 + actualChannels == 4)); 1.572 + insertImg(div, "actual", makeImage( 1.573 + actualWidth, actualHeight, actualWidth, actual, 1.574 + actualChannels == 4)); 1.575 + div.appendChild(document.createElement('br')); 1.576 + document.getElementById("console").appendChild(div); 1.577 + 1.578 + var failed = false; 1.579 + for (var yy = 0; yy < actualHeight; ++yy) { 1.580 + for (var xx = 0; xx < actualWidth; ++xx) { 1.581 + var actualOffset = (yy * actualWidth + xx) * 4; 1.582 + var expectedOffset = (yy * dataWidth + xx) * 4; 1.583 + var expected = [ 1.584 + expectedData[expectedOffset + 0], 1.585 + expectedData[expectedOffset + 1], 1.586 + expectedData[expectedOffset + 2], 1.587 + (actualChannels == 3 ? 255 : expectedData[expectedOffset + 3]) 1.588 + ]; 1.589 + for (var jj = 0; jj < 4; ++jj) { 1.590 + if (actual[actualOffset + jj] != expected[jj]) { 1.591 + failed = true; 1.592 + var was = actual[actualOffset + 0].toString(); 1.593 + for (j = 1; j < 4; ++j) { 1.594 + was += "," + actual[actualOffset + j]; 1.595 + } 1.596 + testFailed('at (' + xx + ', ' + yy + 1.597 + ') expected: ' + expected + ' was ' + was); 1.598 + } 1.599 + } 1.600 + } 1.601 + } 1.602 + if (!failed) { 1.603 + testPassed("texture rendered correctly"); 1.604 + } 1.605 +} 1.606 + 1.607 +function testPVRTCTextures() { 1.608 + testFailed("PVRTC test not yet implemented"); 1.609 +} 1.610 + 1.611 +debug(""); 1.612 +successfullyParsed = true; 1.613 +</script> 1.614 +<script>finishTest();</script> 1.615 + 1.616 +</body> 1.617 +</html>