diff options
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc.html')
-rw-r--r-- | dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc.html | 736 |
1 files changed, 736 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc.html new file mode 100644 index 000000000..2f57e0a24 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-compressed-texture-s3tc.html @@ -0,0 +1,736 @@ +<!-- + +/* +** Copyright (c) 2012 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +--> + +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<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> +<title>WebGL WEBGL_compressed_texture_s3tc Conformance Tests</title> +<style> +img { + border: 1px solid black; + margin-right: 1em; +} +.testimages { +} + +.testimages br { + clear: both; +} + +.testimages > div { + float: left; + margin: 1em; +} +</style> +</head> +<body> +<div id="description"></div> +<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas> +<div id="console"></div> +<script> +"use strict"; +description("This test verifies the functionality of the WEBGL_compressed_texture_s3tc extension, if it is available."); + +debug(""); + +var img_4x4_rgba_raw = new Uint8Array([ + 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, +]); +var img_4x4_rgb_dxt1 = new Uint8Array([ + 0xe0,0x07,0x00,0xf8,0x11,0x10,0x15,0x00, +]); +var img_4x4_rgba_dxt1 = new Uint8Array([ + 0xe0,0x07,0x00,0xf8,0x13,0x10,0x15,0x00, +]); +var img_4x4_rgba_dxt3 = new Uint8Array([ + 0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0xe0,0x07,0x44,0x45,0x40,0x55, +]); +var img_4x4_rgba_dxt5 = new Uint8Array([ + 0xf6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0xe0,0x07,0x44,0x45,0x40,0x55, +]); +var img_8x8_rgba_raw = new Uint8Array([ + 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, +]); +var img_8x8_rgb_dxt1 = new Uint8Array([ + 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, +]); +var img_8x8_rgba_dxt1 = new Uint8Array([ + 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, +]); +var img_8x8_rgba_dxt3 = new Uint8Array([ + 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, +]); +var img_8x8_rgba_dxt5 = new Uint8Array([ + 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, +]); + +var wtu = WebGLTestUtils; +var contextVersion = wtu.getDefault3DContextVersion(); +var canvas = document.getElementById("canvas"); +var gl = wtu.create3DContext(canvas, {antialias: false}); +var program = wtu.setupTexturedQuad(gl); +var ext = null; +var vao = null; +var validFormats = { + COMPRESSED_RGB_S3TC_DXT1_EXT : 0x83F0, + COMPRESSED_RGBA_S3TC_DXT1_EXT : 0x83F1, + COMPRESSED_RGBA_S3TC_DXT3_EXT : 0x83F2, + COMPRESSED_RGBA_S3TC_DXT5_EXT : 0x83F3, +}; +var name; +var supportedFormats; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + // Run tests with extension disabled + runTestDisabled(); + + // Query the extension and store globally so shouldBe can access it + ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_s3tc"); + if (!ext) { + testPassed("No WEBGL_compressed_texture_s3tc support -- this is legal"); + runSupportedTest(false); + } else { + testPassed("Successfully enabled WEBGL_compressed_texture_s3tc extension"); + + runSupportedTest(true); + runTestExtension(); + } +} + +function runSupportedTest(extensionEnabled) { + var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_s3tc"); + if (name !== undefined) { + if (extensionEnabled) { + testPassed("WEBGL_compressed_texture_s3tc listed as supported and getExtension succeeded"); + } else { + testFailed("WEBGL_compressed_texture_s3tc listed as supported but getExtension failed"); + } + } else { + if (extensionEnabled) { + testFailed("WEBGL_compressed_texture_s3tc not listed as supported but getExtension succeeded"); + } else { + testPassed("WEBGL_compressed_texture_s3tc not listed as supported and getExtension failed -- this is legal"); + } + } +} + + +function runTestDisabled() { + debug("Testing binding enum with extension disabled"); + + supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS); + shouldBe("supportedFormats", "[]"); +} + +function formatExists(format, supportedFormats) { + for (var ii = 0; ii < supportedFormats.length; ++ii) { + if (format == supportedFormats[ii]) { + testPassed("supported format " + formatToString(format) + " is exists"); + return; + } + } + testFailed("supported format " + formatToString(format) + " does not exist"); +} + +function formatToString(format) { + for (var p in ext) { + if (ext[p] == format) { + return p; + } + } + return "0x" + format.toString(16); +} + +function runTestExtension() { + debug("Testing WEBGL_compressed_texture_s3tc"); + + // check that all format enums exist. + for (name in validFormats) { + var expected = "0x" + validFormats[name].toString(16); + var actual = "ext['" + name + "']"; + shouldBe(actual, expected); + } + + supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS); + // There should be exactly 4 formats for both WebGL 1.0 and WebGL 2.0. + shouldBe("supportedFormats.length", "4"); + + // check that all 4 formats exist + for (var name in validFormats.length) { + formatExists(validFormats[name], supportedFormats); + } + + // Test each format + testDXT1_RGB(); + testDXT1_RGBA(); + testDXT3_RGBA(); + testDXT5_RGBA(); +} + +function testDXT1_RGB() { + var tests = [ + { width: 4, + height: 4, + channels: 3, + data: img_4x4_rgb_dxt1, + format: ext.COMPRESSED_RGB_S3TC_DXT1_EXT, + hasAlpha: false, + }, + { width: 8, + height: 8, + channels: 3, + data: img_8x8_rgb_dxt1, + format: ext.COMPRESSED_RGB_S3TC_DXT1_EXT, + hasAlpha: false, + subX0: 0, + subY0: 0, + subWidth: 4, + subHeight: 4, + subData: img_4x4_rgb_dxt1 + } + ]; + testDXTTextures(tests); +} + +function testDXT1_RGBA() { + var tests = [ + { width: 4, + height: 4, + channels: 4, + data: img_4x4_rgba_dxt1, + format: ext.COMPRESSED_RGBA_S3TC_DXT1_EXT, + // This is a special case -- the texture is still opaque + // though it's RGBA. + hasAlpha: false, + }, + { width: 8, + height: 8, + channels: 4, + data: img_8x8_rgba_dxt1, + format: ext.COMPRESSED_RGBA_S3TC_DXT1_EXT, + // This is a special case -- the texture is still opaque + // though it's RGBA. + } + ]; + testDXTTextures(tests); +} + +function testDXT3_RGBA() { + var tests = [ + { width: 4, + height: 4, + channels: 4, + data: img_4x4_rgba_dxt3, + format: ext.COMPRESSED_RGBA_S3TC_DXT3_EXT, + hasAlpha: true, + }, + { width: 8, + height: 8, + channels: 4, + data: img_8x8_rgba_dxt3, + format: ext.COMPRESSED_RGBA_S3TC_DXT3_EXT, + hasAlpha: true, + subX0: 0, + subY0: 0, + subWidth: 4, + subHeight: 4, + subData: img_4x4_rgba_dxt3 + } + ]; + testDXTTextures(tests); +} + +function testDXT5_RGBA() { + var tests = [ + { width: 4, + height: 4, + channels: 4, + data: img_4x4_rgba_dxt5, + format: ext.COMPRESSED_RGBA_S3TC_DXT5_EXT, + hasAlpha: true, + }, + { width: 8, + height: 8, + channels: 4, + data: img_8x8_rgba_dxt5, + format: ext.COMPRESSED_RGBA_S3TC_DXT5_EXT, + hasAlpha: true, + subX0: 0, + subY0: 0, + subWidth: 4, + subHeight: 4, + subData: img_4x4_rgba_dxt5 + } + ]; + testDXTTextures(tests); +} + +function testDXTTextures(tests) { + debug("<hr/>"); + for (var ii = 0; ii < tests.length; ++ii) { + testDXTTexture(tests[ii], false); + if (contextVersion >= 2) { + debug("<br/>"); + testDXTTexture(tests[ii], true); + } + } +} + +function uncompressDXTBlock( + destBuffer, destX, destY, destWidth, src, srcOffset, format) { + function make565(src, offset) { + return src[offset + 0] + src[offset + 1] * 256; + } + function make8888From565(c) { + return [ + Math.floor(((c >> 11) & 0x1F) * 255 / 31), + Math.floor(((c >> 5) & 0x3F) * 255 / 63), + Math.floor(((c >> 0) & 0x1F) * 255 / 31), + 255 + ]; + } + function mix(mult, c0, c1, div) { + var r = []; + for (var ii = 0; ii < c0.length; ++ii) { + r[ii] = Math.floor((c0[ii] * mult + c1[ii]) / div); + } + return r; + } + var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT || + format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT; + var colorOffset = srcOffset + (isDXT1 ? 0 : 8); + var color0 = make565(src, colorOffset + 0); + var color1 = make565(src, colorOffset + 2); + var c0gtc1 = color0 > color1 || !isDXT1; + var rgba0 = make8888From565(color0); + var rgba1 = make8888From565(color1); + var colors = [ + rgba0, + rgba1, + c0gtc1 ? mix(2, rgba0, rgba1, 3) : mix(1, rgba0, rgba1, 2), + c0gtc1 ? mix(2, rgba1, rgba0, 3) : [0, 0, 0, 255] + ]; + + // yea I know there is a lot of math in this inner loop. + // so sue me. + for (var yy = 0; yy < 4; ++yy) { + var pixels = src[colorOffset + 4 + yy]; + for (var xx = 0; xx < 4; ++xx) { + var dstOff = ((destY + yy) * destWidth + destX + xx) * 4; + var code = (pixels >> (xx * 2)) & 0x3; + var srcColor = colors[code]; + var alpha; + switch (format) { + case ext.COMPRESSED_RGB_S3TC_DXT1_EXT: + alpha = 255; + break; + case ext.COMPRESSED_RGBA_S3TC_DXT1_EXT: + alpha = (code == 3 && !c0gtc1) ? 0 : 255; + break; + case ext.COMPRESSED_RGBA_S3TC_DXT3_EXT: + { + var alpha0 = src[srcOffset + yy * 2 + Math.floor(xx / 2)]; + var alpha1 = (alpha0 >> ((xx % 2) * 4)) & 0xF; + alpha = alpha1 | (alpha1 << 4); + } + break; + case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT: + { + var alpha0 = src[srcOffset + 0]; + var alpha1 = src[srcOffset + 1]; + var alphaOff = Math.floor(yy / 2) * 3 + 2; + var alphaBits = + src[srcOffset + alphaOff + 0] + + src[srcOffset + alphaOff + 1] * 256 + + src[srcOffset + alphaOff + 2] * 65536; + var alphaShift = (yy % 2) * 12 + xx * 3; + var alphaCode = (alphaBits >> alphaShift) & 0x7; + if (alpha0 > alpha1) { + switch (alphaCode) { + case 0: + alpha = alpha0; + break; + case 1: + alpha = alpha1; + break; + default: + alpha = ((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7; + break; + } + } else { + switch (alphaCode) { + case 0: + alpha = alpha0; + break; + case 1: + alpha = alpha1; + break; + case 6: + alpha = 0; + break; + case 7: + alpha = 255; + break; + default: + alpha = ((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5; + break; + } + } + } + break; + default: + throw "bad format"; + } + destBuffer[dstOff + 0] = srcColor[0]; + destBuffer[dstOff + 1] = srcColor[1]; + destBuffer[dstOff + 2] = srcColor[2]; + destBuffer[dstOff + 3] = alpha; + } + } +} + +function getBlockSize(format) { + var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT || + format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT; + return isDXT1 ? 8 : 16; +} + +function uncompressDXT(width, height, data, format) { + if (width % 4 || height % 4) throw "bad width or height"; + + var dest = new Uint8Array(width * height * 4); + var blocksAcross = width / 4; + var blocksDown = height / 4; + var blockSize = getBlockSize(format); + for (var yy = 0; yy < blocksDown; ++yy) { + for (var xx = 0; xx < blocksAcross; ++xx) { + uncompressDXTBlock( + dest, xx * 4, yy * 4, width, data, + (yy * blocksAcross + xx) * blockSize, format); + } + } + return dest; +} + +function uncompressDXTIntoSubRegion(width, height, subX0, subY0, subWidth, subHeight, data, format) +{ + if (width % 4 || height % 4 || subX0 % 4 || subY0 % 4 || subWidth % 4 || subHeight % 4) + throw "bad dimension"; + + var dest = new Uint8Array(width * height * 4); + var blocksAcross = subWidth / 4; + var blocksDown = subHeight / 4; + var blockSize = getBlockSize(format); + for (var yy = 0; yy < blocksDown; ++yy) { + for (var xx = 0; xx < blocksAcross; ++xx) { + uncompressDXTBlock( + dest, subX0 + xx * 4, subY0 + yy * 4, width, data, + (yy * blocksAcross + xx) * blockSize, format); + } + } + return dest; +} + +function copyRect(data, srcX, srcY, dstX, dstY, width, height, stride) { + var bytesPerLine = width * 4; + var srcOffset = srcX * 4 + srcY * stride; + var dstOffset = dstX * 4 + dstY * stride; + for (; height > 0; --height) { + for (var ii = 0; ii < bytesPerLine; ++ii) { + data[dstOffset + ii] = data[srcOffset + ii]; + } + srcOffset += stride; + dstOffset += stride; + } +} + +function testDXTTexture(test, useTexStorage) { + var data = new Uint8Array(test.data); + var width = test.width; + var height = test.height; + var format = test.format; + + var uncompressedData = uncompressDXT(width, height, data, format); + + canvas.width = width; + canvas.height = height; + gl.viewport(0, 0, width, height); + debug("testing " + formatToString(format) + " " + width + "x" + height + + (useTexStorage ? " via texStorage2D" : " via compressedTexImage2D")); + + var tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + if (useTexStorage) { + if (test.subData) { + var uncompressedDataSub = uncompressDXTIntoSubRegion( + width, height, test.subX0, test.subY0, test.subWidth, test.subHeight, test.subData, format); + var tex1 = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex1); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + + gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture via texStorage2D"); + gl.compressedTexSubImage2D( + gl.TEXTURE_2D, 0, test.subX0, test.subY0, test.subWidth, test.subHeight, format, test.subData); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture data via compressedTexSubImage2D"); + + wtu.clearAndDrawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 1"); + compareRect(width, height, test.channels, uncompressedDataSub, "NEAREST"); + + // Clean up and recover + gl.deleteTexture(tex1); + gl.bindTexture(gl.TEXTURE_2D, tex); + } + + gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture via texStorage2D"); + wtu.clearAndDrawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad"); + var clearColor = (test.hasAlpha ? [0, 0, 0, 0] : [0, 0, 0, 255]); + wtu.checkCanvas(gl, clearColor, "texture should be initialized to black"); + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture data via compressedTexSubImage2D"); + } else { + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture"); + } + gl.generateMipmap(gl.TEXTURE_2D); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after clearing generateMipmap error"); + wtu.clearAndDrawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 1"); + compareRect(width, height, test.channels, uncompressedData, "NEAREST"); + // Test again with linear filtering. + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + wtu.clearAndDrawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 2"); + compareRect(width, height, test.channels, uncompressedData, "LINEAR"); + + if (!useTexStorage) { + // It's not allowed to redefine textures defined via texStorage2D. + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 1, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "non 0 border"); + + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width + 4, height, 0, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height + 4, 0, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 4, height, 0, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 4, 0, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); + + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 1, height, 0, data); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 2, height, 0, data); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 1, 0, data); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); + gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 2, 0, data); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); + + if (width == 4) { + gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 1, height, 0, data); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0"); + gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 2, height, 0, data); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0"); + } + if (height == 4) { + gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 1, 0, data); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0"); + gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 2, 0, data); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0"); + } + } + + // pick a wrong format that uses the same amount of data. + var wrongFormat; + switch (format) { + case ext.COMPRESSED_RGB_S3TC_DXT1_EXT: + wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case ext.COMPRESSED_RGBA_S3TC_DXT1_EXT: + wrongFormat = ext.COMPRESSED_RGB_S3TC_DXT1_EXT; + break; + case ext.COMPRESSED_RGBA_S3TC_DXT3_EXT: + wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT: + wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + } + + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, wrongFormat, data); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "format does not match"); + + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 4, 0, width, height, format, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "dimension out of range"); + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 4, width, height, format, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "dimension out of range"); + + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width + 4, height, format, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height + 4, format, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 4, height, format, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 4, format, data); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions"); + + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 1, height, format, data); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 2, height, format, data); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 1, format, data); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 2, format, data); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions"); + + var subData = new Uint8Array(data.buffer, 0, getBlockSize(format)); + + if (width == 8 && height == 8) { + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 1, 0, 4, 4, format, subData); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset"); + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 1, 4, 4, format, subData); + wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset"); + } + + var stride = width * 4; + for (var yoff = 0; yoff < height; yoff += 4) { + for (var xoff = 0; xoff < width; xoff += 4) { + copyRect(uncompressedData, 0, 0, xoff, yoff, 4, 4, stride); + gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, xoff, yoff, 4, 4, format, subData); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture"); + // First test NEAREST filtering. + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + wtu.clearAndDrawUnitQuad(gl); + compareRect(width, height, test.channels, uncompressedData, "NEAREST"); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad"); + // Next test LINEAR filtering. + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + wtu.clearAndDrawUnitQuad(gl); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad"); + compareRect(width, height, test.channels, uncompressedData, "LINEAR"); + } + } +} + +function insertImg(element, caption, img) { + var div = document.createElement("div"); + div.appendChild(img); + var label = document.createElement("div"); + label.appendChild(document.createTextNode(caption)); + div.appendChild(label); + element.appendChild(div); +} + +function makeImage(imageWidth, imageHeight, data, alpha) { + var scale = 8; + var c = document.createElement("canvas"); + c.width = imageWidth * scale; + c.height = imageHeight * scale; + var ctx = c.getContext("2d"); + for (var yy = 0; yy < imageHeight; ++yy) { + for (var xx = 0; xx < imageWidth; ++xx) { + var offset = (yy * imageWidth + xx) * 4; + ctx.fillStyle = "rgba(" + + data[offset + 0] + "," + + data[offset + 1] + "," + + data[offset + 2] + "," + + (alpha ? data[offset + 3] / 255 : 1) + ")"; + ctx.fillRect(xx * scale, yy * scale, scale, scale); + } + } + return wtu.makeImageFromCanvas(c); +} + +function compareRect(width, height, channels, expectedData, filteringMode) { + var actual = new Uint8Array(width * height * 4); + gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, actual); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "reading back pixels"); + + var div = document.createElement("div"); + div.className = "testimages"; + insertImg(div, "expected", makeImage(width, height, expectedData, channels == 4)); + insertImg(div, "actual", makeImage(width, height, actual, channels == 4)); + div.appendChild(document.createElement('br')); + document.getElementById("console").appendChild(div); + + var failed = false; + for (var yy = 0; yy < height; ++yy) { + for (var xx = 0; xx < width; ++xx) { + var offset = (yy * width + xx) * 4; + var expected = [ + expectedData[offset + 0], + expectedData[offset + 1], + expectedData[offset + 2], + (channels == 3 ? 255 : expectedData[offset + 3]) + ]; + for (var jj = 0; jj < 4; ++jj) { + if (actual[offset + jj] != expected[jj]) { + failed = true; + var was = actual[offset + 0].toString(); + for (var j = 1; j < 4; ++j) { + was += "," + actual[offset + j]; + } + testFailed('at (' + xx + ', ' + yy + + ') expected: ' + expected + ' was ' + was); + } + } + } + } + if (!failed) { + testPassed("texture rendered correctly with " + filteringMode + " filtering"); + } +} + +debug(""); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> + +</body> +</html> |