diff options
Diffstat (limited to '')
-rw-r--r-- | dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js new file mode 100644 index 0000000000..6fad5520f2 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/js/tests/webgl-compressed-texture-size-limit.js @@ -0,0 +1,226 @@ +/* +Copyright (c) 2019 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +*/ + +'use strict'; + +var runCompressedTextureSizeLimitTest = function(maxArrayBufferSizeBytes, positiveCubeMapMaxSize) { + + function numLevelsFromSize(size) { + var levels = 0; + while ((size >> levels) > 0) { + ++levels; + } + return levels; + } + + // More formats can be added here when more texture compression extensions are enabled in WebGL. + 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, + }; + + // format specific restrictions for COMPRESSED_RGB_S3TC_DXT1_EXT and COMPRESSED_RGBA_S3TC_DXT1_EXT + // on the byteLength of the ArrayBufferView, pixels + function func1 (width, height) + { + return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8; + } + + // format specific restrictions for COMPRESSED_RGBA_S3TC_DXT3_EXT and COMPRESSED_RGBA_S3TC_DXT5_EXT + // on the byteLength of the ArrayBufferView, pixels + function func2 (width, height) + { + return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16; + } + + var wtu = WebGLTestUtils; + var gl = wtu.create3DContext("example"); + var tests = [ + // More tests can be added here when more texture compression extensions are enabled in WebGL. + // Level 0 image width and height must be a multiple of the sizeStep. + { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGB_S3TC_DXT1_EXT, dataType: Uint8Array, func: func1, sizeStep: 4}, + { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGBA_S3TC_DXT1_EXT, dataType: Uint8Array, func: func1, sizeStep: 4}, + { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGBA_S3TC_DXT3_EXT, dataType: Uint8Array, func: func2, sizeStep: 4}, + { extension: "WEBGL_compressed_texture_s3tc", format: validFormats.COMPRESSED_RGBA_S3TC_DXT5_EXT, dataType: Uint8Array, func: func2, sizeStep: 4}, + ]; + + // Note: We expressly only use 2 textures because first a texture will be defined + // using all mip levels of 1 format, then for a moment it will have mixed formats which + // may uncover bugs. + var targets = [ + { target: gl.TEXTURE_2D, + maxSize: gl.getParameter(gl.MAX_TEXTURE_SIZE), + tex: gl.createTexture(), + targets: [gl.TEXTURE_2D] + }, + { target: gl.TEXTURE_CUBE_MAP, + maxSize: gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE), + tex: gl.createTexture(), + targets: [ + gl.TEXTURE_CUBE_MAP_POSITIVE_X, + gl.TEXTURE_CUBE_MAP_NEGATIVE_X, + gl.TEXTURE_CUBE_MAP_POSITIVE_Y, + gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, + gl.TEXTURE_CUBE_MAP_POSITIVE_Z, + gl.TEXTURE_CUBE_MAP_NEGATIVE_Z + ] + } + ]; + + function getSharedArrayBufferSize() { + var sharedArrayBufferSize = 0; + for (var tt = 0; tt < tests.length; ++tt) { + var test = tests[tt]; + for (var trg = 0; trg < targets.length; ++trg) { + var t = targets[trg]; + var bufferSizeNeeded; + if (t.target === gl.TEXTURE_CUBE_MAP) { + var positiveTestSize = Math.min(2048, t.maxSize); + bufferSizeNeeded = test.func(positiveTestSize, positiveTestSize); + } else { + bufferSizeNeeded = test.func(t.maxSize, test.sizeStep); + } + if (bufferSizeNeeded > sharedArrayBufferSize) { + sharedArrayBufferSize = bufferSizeNeeded; + } + bufferSizeNeeded = test.func(t.maxSize + test.sizeStep, t.maxSize + test.sizeStep); + // ArrayBuffers can be at most 4GB (minus 1 byte). + if (bufferSizeNeeded > sharedArrayBufferSize && bufferSizeNeeded <= maxArrayBufferSizeBytes) { + sharedArrayBufferSize = bufferSizeNeeded; + } + } + } + return sharedArrayBufferSize; + } + + // Share an ArrayBuffer among tests to avoid too many large allocations + var sharedArrayBuffer = new ArrayBuffer(getSharedArrayBufferSize()); + + gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1); + + var trg = 0; + var tt = 0; + runNextTest(); + + function runNextTest() { + var t = targets[trg]; + + if (tt == 0) { + var tex = t.tex; + gl.bindTexture(t.target, tex); + + debug(""); + debug("max size for " + wtu.glEnumToString(gl, t.target) + ": " + t.maxSize); + } + + var test = tests[tt]; + testFormatType(t, test); + ++tt; + if (tt == tests.length) { + tt = 0; + ++trg; + if (trg == targets.length) { + finishTest(); + return; + } + } + wtu.dispatchPromise(runNextTest); + } + + function testFormatType(t, test) { + var positiveTestSize = t.maxSize; + var positiveTestOtherDimension = test.sizeStep; + if (t.target === gl.TEXTURE_CUBE_MAP) { + // Can't always test the maximum size since that can cause OOM: + positiveTestSize = Math.min(positiveCubeMapMaxSize, t.maxSize); + // Cube map textures need to be square: + positiveTestOtherDimension = positiveTestSize; + } + var positiveTestLevels = numLevelsFromSize(positiveTestSize); + var numLevels = numLevelsFromSize(t.maxSize); + debug(""); + debug("num levels: " + numLevels + ", levels used in positive test: " + positiveTestLevels); + + debug(""); + + // Query the extension and store globally so shouldBe can access it + var ext = wtu.getExtensionWithKnownPrefixes(gl, test.extension); + if (ext) { + + testPassed("Successfully enabled " + test.extension + " extension"); + + for (var j = 0; j < t.targets.length; ++j) { + var target = t.targets[j]; + debug(""); + debug(wtu.glEnumToString(gl, target) + " " + wtu.glEnumToString(ext, test.format)); + + // positive test + var size = positiveTestSize; + var otherDimension = positiveTestOtherDimension; + for (var i = 0; i < positiveTestLevels; i++) { + var pixels = new test.dataType(sharedArrayBuffer, 0, test.func(size, otherDimension)); + gl.compressedTexImage2D(target, i, test.format, size, otherDimension, 0, pixels); + wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture should generate NO_ERROR." + + "level is " + i + ", size is " + size + "x" + otherDimension); + size /= 2; + otherDimension /= 2; + if (otherDimension < 1) { + otherDimension = 1; + } + } + + var numLevels = numLevelsFromSize(t.maxSize); + + // out of bounds tests + + // width or height out of bounds + if (t.target != gl.TEXTURE_CUBE_MAP) { + // only width out of bounds + var wideAndShortDataSize = test.func(t.maxSize + test.sizeStep, test.sizeStep); + var pixelsNegativeTest1 = new test.dataType(sharedArrayBuffer, 0, wideAndShortDataSize); + gl.compressedTexImage2D(target, 0, test.format, t.maxSize + test.sizeStep, test.sizeStep, 0, pixelsNegativeTest1); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "width out of bounds: should generate INVALID_VALUE." + + " level is 0, size is " + (t.maxSize + test.sizeStep) + "x" + (test.sizeStep)); + + // only height out of bounds + var narrowAndTallDataSize = test.func(test.sizeStep, t.maxSize + test.sizeStep); + var pixelsNegativeTest1 = new test.dataType(sharedArrayBuffer, 0, narrowAndTallDataSize); + gl.compressedTexImage2D(target, 0, test.format, test.sizeStep, t.maxSize + test.sizeStep, 0, pixelsNegativeTest1); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "height out of bounds: should generate INVALID_VALUE." + + " level is 0, size is " + (test.sizeStep) + "x" + (t.maxSize + test.sizeStep)); + } + + // both width and height out of the maximum bounds simultaneously + var squareDataSize = test.func(t.maxSize + test.sizeStep, t.maxSize + test.sizeStep); + // this check assumes that each element is 1 byte + if (squareDataSize > sharedArrayBuffer.byteLength) { + testPassed("Unable to test square texture larger than maximum size due to ArrayBuffer size limitations -- this is legal"); + } else { + var pixelsNegativeTest1 = new test.dataType(sharedArrayBuffer, 0, squareDataSize); + gl.compressedTexImage2D(target, 0, test.format, t.maxSize + test.sizeStep, t.maxSize + test.sizeStep, 0, pixelsNegativeTest1); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "width and height out of bounds: should generate INVALID_VALUE." + + " level is 0, size is " + (t.maxSize + test.sizeStep) + "x" + (t.maxSize + test.sizeStep)); + } + + // level out of bounds + var pixelsNegativeTest2 = new test.dataType(sharedArrayBuffer, 0, test.func(256, 256)); + gl.compressedTexImage2D(target, numLevels, test.format, 256, 256, 0, pixelsNegativeTest2); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "level out of bounds: should generate INVALID_VALUE." + + " level is " + numLevels + ", size is 256x256"); + //width and height out of bounds for specified level + gl.compressedTexImage2D(target, numLevels - 1, test.format, 256, 256, 0, pixelsNegativeTest2); + wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "width or height out of bounds for specified level: should generate INVALID_VALUE." + + " level is " + (numLevels - 1) + ", size is 256x256"); + } + } + else { + testPassed("No " + test.extension + " extension support -- this is legal"); + } + } + +}; |