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>WebGL texture mips 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>
<canvas id="example" width="2" height="2" style="width: 40px; height: 40px;"></canvas>
<div id="description"></div>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">
uniform vec4 uMult;
attribute vec4 vPosition;
attribute vec2 texCoord0;
varying vec2 texCoord;
void main()
{
gl_Position = vPosition * uMult;
texCoord = texCoord0;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D tex;
varying vec2 texCoord;
void main()
{
gl_FragColor = texture2D(tex, texCoord);
}
</script>
<script>
"use strict";
var canvas;
var wtu = WebGLTestUtils;
function init()
{
description("Checks mip issues");
canvas = document.getElementById("example");
shouldBe("canvas.width", "2");
shouldBe("canvas.height", "2");
var gl = wtu.create3DContext(canvas);
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.generateMipmap(gl.TEXTURE_2D);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "for generateMipmap with mip 0 is 0x0");
gl.texImage2D(
gl.TEXTURE_2D, 1, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array(4));
gl.generateMipmap(gl.TEXTURE_2D);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "for generateMipmap with mip 0 is 0x0");
tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "for generateMipmap with mip 0 is 0x0");
var faces = [
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
];
for (var ii = 0; ii < faces.length; ++ii) {
gl.texImage2D(
faces[ii], 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array(4 * 2 * 2));
gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
wtu.glErrorShouldBe(gl, ii == 5 ? gl.NO_ERROR : gl.INVALID_OPERATION, "for generateMipmap with " + (ii + 1) + " faces");
}
wtu.setupUnitQuad(gl, 0, 1);
var program = wtu.setupProgram(
gl, ['vshader', 'fshader'], ['vPosition', 'texCoord0'], [0, 1]);
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.BLEND);
var colors = {
blue: [0, 0, 255, 255],
red: [255, 0, 0, 255],
green: [0, 255, 0, 255],
cyan: [128, 255, 255, 255],
black: [0, 0, 0, 255],
blank: [0, 0, 0, 0]
};
var mips = [
];
var texLoc = gl.getUniformLocation(program, "tex");
gl.uniform1i(texLoc, 0);
var multLoc = gl.getUniformLocation(program, "uMult");
// ----------------------------------------------------
var clearTex = createTexture();
gl.uniform4f(multLoc, 1, 1, 1, 1);
gl.bindTexture(gl.TEXTURE_2D, clearTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
debug('gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);');
setMipData(0, 16, 'blank');
makeDivMipChain();
generateMipmap();
check('blank', "texture created with null that has all mips");
// ----------------------------------------------------
var tex = createTexture();
gl.uniform4f(multLoc, 1, 1, 1, 1);
gl.bindTexture(gl.TEXTURE_2D, tex);
// 16x16 texture no mips
fillLevel(tex, 0, 16, 'cyan');
check('black',
"texture that is missing mips when TEXTURE_MIN_FILTER not NEAREST or LINEAR");
generateMipmap();
check('cyan', "texture that has all mips");
// Fill in the bottom 2 mips with a different color.
fillLevel(tex, 4, 1, 'green');
fillLevel(tex, 3, 2, 'green');
// Choose the nearest mip
texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
check('green', "texture that is only using the smallest 2 mips");
gl.uniform4f(multLoc, 16, 16, 1, 1);
check('cyan', "texture that is using only the largest 2 mips");
// Set the top level
fillLevel(tex, 0, 1, 'red');
check('red',
"texture that is only using the top level even though other levels are defined");
// Set the top 2 levels using generateMipmap
fillLevel(tex, 0, 2, 'blue');
generateMipmap();
check('blue',
"texture that is only using the top 2 levels even though other levels are defined");
// Set the top 2 levels back to sizes that end up using levels 2, 3, and 4 again.
fillLevel(tex, 0, 16, 'blue');
fillLevel(tex, 1, 8, 'blue');
check('blue', "texture that is only using the largest 2 mips");
gl.uniform4f(multLoc, 1, 1, 1, 1);
check('green', "texture that is only using the smallest 2 mips");
// ----------------------------------------------------
var tex = createTexture();
gl.uniform4f(multLoc, 1, 1, 1, 1);
fillLevel(tex, 0, 8, 'cyan');
generateMipmap();
check('cyan', "texture that has 3 mips");
fillLevel(tex, 0, 16, 'blue');
texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
check('blue', "texture that is only using top mips");
fillLevel(tex, 0, 8, 'red');
texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
check('cyan', "texture that is only using smallest mips");
gl.uniform4f(multLoc, 16, 16, 1, 1);
check('red', "texture that is using only the largest mip");
// ----------------------------------------------------
var tex = createTexture();
gl.uniform4f(multLoc, 1, 1, 1, 1);
fillLevel(tex, 2, 1, 'green');
fillLevel(tex, 1, 2, 'green');
fillLevel(tex, 0, 4, 'green');
check('green', "texture that was built smallest mip first");
// ----------------------------------------------------
var tex = createTexture();
gl.uniform4f(multLoc, 1, 1, 1, 1);
fillLevel(tex, 0, 16, 'red');
generateMipmap();
check('red', "texture with 1 genmipmaps");
fillLevel(tex, 0, 16, 'blue');
generateMipmap();
fillLevel(tex, 0, 16, 'green');
generateMipmap();
check('green', "texture with 2 genmipmaps");
// ----------------------------------------------------
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors.");
function createTexture() {
debug("<hr/>gl.createTexture()");
mips = [];
makeDivMipChain();
return gl.createTexture();
}
function texParameteri(target, pname, value) {
debug("gl.texParameteri(" +
wtu.glEnumToString(gl, target) + ", " +
wtu.glEnumToString(gl, pname) + ", " +
wtu.glEnumToString(gl, value) + ")")
gl.texParameteri(target, pname, value);
}
function generateMipmap() {
debug("gl.generateMipmap(gl.TEXTURE_2D)");
gl.generateMipmap(gl.TEXTURE_2D);
var mip0 = mips[0];
var size = mip0.size;
var level = 1;
for(;;) {
size = Math.floor(size / 2);
if (!size) {
break;
}
setMipData(level, size, mip0.color);
++level;
}
makeDivMipChain();
}
function check(color, msg) {
wtu.clearAndDrawUnitQuad(gl);
wtu.checkCanvas(gl, colors[color], msg + " should draw with " + color);
}
function fillLevel(tex, level, size, color) {
setMipData(level, size, color);
debug("gl.texImage2D(gl.TEXTURE_2D, " + level + ", gl.RGBA, " + size + ", " + size +
", 0, gl.RGBA, gl.UNSIGNED_BYTE, " + color + ");");
wtu.fillTexture(gl, tex, size, size, colors[color], level);
makeDivMipChain();
}
function setMipData(level, size, color) {
mips[level] = {
size: size,
color: color
};
}
function makeDivMipChain(color) {
var html = [
'<div style="height: 68px; margin-top: 5px">',
'<div style="float:left;">mips: </div>'];
for (var ii = 0; ii < 5; ++ii) {
var mip = mips[ii];
if (mip) {
html.push(makeDivSquare(mip.size, mip.color));
} else {
html.push(makeDivSquare(16, undefined));
}
}
html.push("</div>");
debug(html.join(""));
}
function makeDivSquare(size, color) {
size *= 4;
var c = color ? colors[color] : [255,255,255];
var border = color ? 'solid' : 'dashed';
return '<div style="float:left; width: ' + size + 'px; height: ' + size +
'px; background-color: ' + rgb(c) +
'; border: 1px ' + border + ' black; margin-right: 3px;"></div>';
}
function rgb(c) {
return 'rgb(' + c[0] + ',' + c[1] + ',' + c[2] +')';
}
}
init();
var successfullyParsed = true;
</script>
<script src="../../../js/js-test-post.js"></script>
</body>
</html>