Source code

Revision control

Copy as Markdown

Other Tools

<!--
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.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>texStorage3D and texSubImage3D conformance test</title>
<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>
</head>
<body>
<div id="description"></div>
<canvas id="canvas" width="64" height="64"> </canvas>
<div id="console"></div>
<script>
"use strict";
description("This test verifies the functionality of texStorage3D and texSubImage3D.");
debug("");
var wtu = WebGLTestUtils;
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas, null, 2);
var vao = null;
if (!gl) {
testFailed("WebGL context does not exist");
} else {
testPassed("WebGL context exists");
runTexStorageAndSubImage3DTest();
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors");
}
function enumToString(value) {
return wtu.glEnumToString(gl, value);
}
function runTexStorageAndSubImage3DTest()
{
var texStorage3DTestCases = [
{
target: gl.TEXTURE_3D,
mipmap: false,
sizedformat: gl.RGBA8,
unsizedformat: gl.RGBA,
type: gl.UNSIGNED_BYTE,
alpha: true,
redpixel: new Uint8Array([0xff, 0x00, 0x00, 0x00]),
},
{
target: gl.TEXTURE_3D,
mipmap: true,
sizedformat: gl.R11F_G11F_B10F,
unsizedformat: gl.RGB,
type: gl.UNSIGNED_INT_10F_11F_11F_REV,
alpha: false,
// Red is unsigned floating point with 5 exponent bits followed by 6 mantissa bits.
// The effective value is 2^(exponent - 15) * (1 + mantissa / 64)
// See OpenGL ES 3.0.3 spec, section 2.1.3
// Here we want to encode the value 1.0, which we achieve with a zero mantissa
// and an exponent of 15.
redpixel: new Uint32Array([15<<6]),
},
{
target: gl.TEXTURE_3D,
mipmap: true,
sizedformat: gl.RGBA32F,
unsizedformat: gl.RGBA,
type: gl.FLOAT,
alpha: true,
redpixel: new Float32Array([1, 0, 0, 0]),
},
];
texStorage3DTestCases.forEach(function(testcase){
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_3D, tex);
var texsize = 4;
var levels = testcase.mipmap
? Math.floor(Math.log(texsize) / Math.log(2)) + 1
: 1;
debug("");
debug("Testing texStorage3D with " +
(testcase.mipmap ? "mipmap" : "no mipmap") + ", " +
"internalformat: " + enumToString(testcase.sizedformat));
gl.texStorage3D(gl.TEXTURE_3D, levels, testcase.sizedformat,
0, texsize, texsize);
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texStorage3D should fail for zero width");
gl.texStorage3D(gl.TEXTURE_3D, levels, testcase.sizedformat,
texsize, 0, texsize);
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texStorage3D should fail for zero height");
gl.texStorage3D(gl.TEXTURE_3D, levels, testcase.sizedformat,
texsize, texsize, 0);
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texStorage3D should fail for zero depth");
gl.texStorage3D(gl.TEXTURE_3D, levels, testcase.sizedformat,
texsize, -texsize, texsize);
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texStorage3D should fail for negative height");
gl.texStorage3D(gl.TEXTURE_3D, 0, testcase.sizedformat,
texsize, texsize, texsize);
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texStorage3D should fail for zero levels");
if (testcase.mipmap) {
gl.texStorage3D(gl.TEXTURE_3D,
levels + 1,
testcase.sizedformat,
texsize, texsize, texsize);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "texStorage3D should fail for too many levels");
}
gl.texStorage3D(gl.TEXTURE_2D,
levels,
testcase.sizedformat,
texsize, texsize, texsize);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "texStorage3D should fail for target TEXTURE_2D");
gl.texStorage3D(gl.TEXTURE_CUBE_MAP,
levels,
testcase.sizedformat,
texsize, texsize, texsize);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "texStorage3D should fail for target TEXTURE_CUBE_MAP");
gl.bindTexture(gl.TEXTURE_3D, null);
gl.texStorage3D(gl.TEXTURE_3D, levels, testcase.sizedformat,
texsize, texsize, texsize);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "texStorage3D should fail when no texture is bound");
gl.bindTexture(gl.TEXTURE_3D, tex);
// texStorage3D should only accept sized internalformats
gl.texStorage3D(gl.TEXTURE_3D, levels, testcase.unsizedformat,
texsize, texsize, texsize);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "texStorage3D should fail for bad internalformat " + enumToString(testcase.unsizedformat));
var pixels;
var number_of_pixels = texsize * texsize * texsize;
if (testcase.redpixel instanceof Uint8Array) {
pixels = new Uint8Array(number_of_pixels * testcase.redpixel.length);
} else if (testcase.redpixel instanceof Uint16Array) {
pixels = new Uint16Array(number_of_pixels * testcase.redpixel.length);
} else if (testcase.redpixel instanceof Uint32Array) {
pixels = new Uint32Array(number_of_pixels * testcase.redpixel.length);
} else if (testcase.redpixel instanceof Float32Array) {
pixels = new Float32Array(number_of_pixels * testcase.redpixel.length);
}
for (var i = 0; i < number_of_pixels; i++) {
for (var j = 0; j < testcase.redpixel.length; j++) {
pixels[i * testcase.redpixel.length + j] = testcase.redpixel[j];
}
}
gl.texSubImage3D(gl.TEXTURE_2D,
0, 0, 0, 0,
texsize, texsize, texsize,
testcase.unsizedformat, testcase.type,
pixels);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
"texSubImage3D should generate INVALID_ENUM if passed TEXTURE_2D target");
gl.texSubImage3D(gl.TEXTURE_3D,
0, 0, 0, 0,
texsize, texsize, texsize,
testcase.unsizedformat, testcase.type,
pixels);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION,
"texSubImage3D should fail if texStorage3D has not succeeded");
// OK, now let's finally do the successfull texStorage3D call
gl.texStorage3D(gl.TEXTURE_3D, levels, testcase.sizedformat,
texsize, texsize, texsize);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texStorage3D should succeed with a good sized internalformat");
// Subsequent texStorage3D calls should fail, even identical ones.
gl.texStorage3D(gl.TEXTURE_3D, levels, testcase.sizedformat,
texsize, texsize, texsize);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "texStorage3D should fail on immutable-format texture");
var s = texsize;
for (var l = 0; l < levels; l++) {
gl.texSubImage3D(gl.TEXTURE_3D,
l, 0, 0, 0,
s, s, s,
testcase.unsizedformat, testcase.type,
pixels);
s /= 2;
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texSubImage3D should succeed on immutable texture as long as the format is compatible");
}
gl.texSubImage3D(gl.TEXTURE_3D,
levels, 0, 0, 0,
texsize, texsize, texsize,
testcase.unsizedformat, testcase.type,
pixels);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "texSubImage3D should fail for too-high level");
gl.texSubImage3D(gl.TEXTURE_3D,
0, 1, 0, 0,
texsize, texsize, texsize,
testcase.unsizedformat, testcase.type,
pixels);
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texSubImage3D should fail for dimension out of range");
});
debug("");
debug("Test non-square images:");
const levels = 4;
const maxSize = 1 << (levels-1);
function expectOk(target, x,y,z, err) {
debug("(target=" + target + ", size=[" + ([x,y,z].join(', ')) + "])");
const tex = gl.createTexture();
gl.bindTexture(gl[target], tex);
gl.texStorage3D(gl[target], levels+1, gl.RGBA8, x, y, z);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "levels=levels+1");
gl.texStorage3D(gl[target], levels, gl.RGBA8, x, y, z);
wtu.glErrorShouldBe(gl, gl[err], "levels=levels");
gl.deleteTexture(tex);
}
expectOk("TEXTURE_3D", maxSize, maxSize, maxSize, "NO_ERROR");
expectOk("TEXTURE_3D", maxSize, maxSize, 1, "NO_ERROR");
expectOk("TEXTURE_3D", maxSize, 1, maxSize, "NO_ERROR");
expectOk("TEXTURE_3D", maxSize, 1, 1, "NO_ERROR");
expectOk("TEXTURE_3D", 1, maxSize, maxSize, "NO_ERROR");
expectOk("TEXTURE_3D", 1, maxSize, 1, "NO_ERROR");
expectOk("TEXTURE_3D", 1, 1, maxSize, "NO_ERROR");
expectOk("TEXTURE_2D_ARRAY", maxSize, maxSize, 10, "NO_ERROR");
expectOk("TEXTURE_2D_ARRAY", maxSize, 1, 10, "NO_ERROR");
expectOk("TEXTURE_2D_ARRAY", 1, maxSize, 10, "NO_ERROR");
expectOk("TEXTURE_2D_ARRAY", 1, 1, 10, "INVALID_OPERATION");
}
debug("");
var successfullyParsed = true;
</script>
<script src="../../../js/js-test-post.js"></script>
</body>
</html>