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 mipmap 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="4" height="4" style="width: 16px; height: 16px;"></canvas>
<div id="description"></div>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec2 texCoord0;
varying vec2 texCoord;
void main()
{
gl_Position = vPosition;
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 wtu = WebGLTestUtils;
var canvas = document.getElementById("example");
var gl = wtu.create3DContext(canvas, undefined, 2);
description("Test srgb emulation for generateMipmap.");
function generateMipmap()
{
debug("Generate mipmaps for sRGB texture");
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 = {
blank: [0, 0, 0, 0],
srgba: [0, 63, 127, 255],
};
var texLoc = gl.getUniformLocation(program, "tex");
gl.uniform1i(texLoc, 0);
var width = 128;
var height = 128;
canvas.width = width;
canvas.height = height;
gl.viewport(0, 0, width, height);
var srgbTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, srgbTex);
// Set full texture as srgba color first.
wtu.fillTexture(gl, srgbTex, width, height, colors['srgba'], 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.SRGB8_ALPHA8);
// Set up-left region of the texture as red color.
// In order to make sure bi-linear interpolation operates on different colors, red region
// is 1 pixel smaller than a quarter of the full texture on each side.
var redWidth = width / 2 - 1;
var redHeight = height / 2 - 1;
var buf = new Uint8Array(redWidth * redHeight * 4);
for (var i = 0; i < redWidth * redHeight; i++) {
buf[4 * i + 0] = 255;
buf[4 * i + 1] = 0;
buf[4 * i + 2] = 0;
buf[4 * i + 3] = 255;
}
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, redWidth, redHeight, gl.RGBA, gl.UNSIGNED_BYTE, buf);
gl.generateMipmap(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);
// Decode the srgba texture to a linear texture which will be used as reference.
var linearTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, linearTex);
wtu.fillTexture(gl, linearTex, width, height, wtu.sRGBToLinear(colors['srgba']), 0, gl.RGBA, gl.UNSIGNED_BYTE);
// Set up-left region of the texture as red color.
// In order to make sure bi-linear interpolation operates on different colors, red region
// is 1 pixel smaller than a quarter of the full texture on each side.
for (var i = 0; i < redWidth * redHeight; i++) {
buf[4 * i + 0] = 255;
buf[4 * i + 1] = 0;
buf[4 * i + 2] = 0;
buf[4 * i + 3] = 255;
}
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, redWidth, redHeight, gl.RGBA, gl.UNSIGNED_BYTE, buf);
gl.generateMipmap(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);
// Change canvas to a small size.
width = 64;
height = 64;
canvas.width = width;
canvas.height = height;
gl.viewport(0, 0, width, height);
// Draw with srgb texture and linear texture respectively.
gl.bindTexture(gl.TEXTURE_2D, srgbTex);
wtu.clearAndDrawUnitQuad(gl);
var result = new Uint8Array(width * height * 4);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, result);
gl.bindTexture(gl.TEXTURE_2D, linearTex);
wtu.clearAndDrawUnitQuad(gl);
var reference = new Uint8Array(width * height * 4);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, reference);
gl.deleteTexture(srgbTex);
gl.deleteTexture(linearTex);
var tolerance = 7;
var diff = new Uint8Array(width * height * 4);
var failed = wtu.comparePixels(result, reference, tolerance, diff);
if (failed) {
testFailed("Generate wrong mipmaps for sRGB texture.");
wtu.displayImageDiff(result, reference, diff, width, height);
} else {
testPassed("Generate correct mipmaps for sRGB texture.");
}
}
function generateMipmap_immutableTexture()
{
debug("Generate mipmaps for immutable texture.");
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texStorage2D(gl.TEXTURE_2D, Math.log2(canvas.width), gl.SRGB8_ALPHA8, canvas.width, canvas.height);
gl.generateMipmap(gl.TEXTURE_2D);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "GenerateMipmap should succeed.");
gl.deleteTexture(tex);
}
function generateMipmap_widthHeightNotEqual()
{
debug("Generate mipmaps when width and height are not equal.");
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, 64, 32, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.generateMipmap(gl.TEXTURE_2D);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "GenerateMipmap should succeed.");
gl.deleteTexture(tex);
}
function generateMipmap_maxLevelLessThanFullMipmapLevel()
{
debug("Generate mipmaps when maxLevel is less than full mipmap level.");
wtu.setupUnitQuad(gl, 0, 1);
var program = wtu.setupProgram(
gl, ['vshader', 'fshader'], ['vPosition', 'texCoord0'], [0, 1]);
var colors = [0, 63, 127, 255];
var texLoc = gl.getUniformLocation(program, "tex");
gl.uniform1i(texLoc, 0);
var width = 16;
var height = 16;
canvas.width = width;
canvas.height = height;
gl.viewport(0, 0, width, height);
var srgbTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, srgbTex);
wtu.fillTexture(gl, srgbTex, width, height, colors, 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.SRGB8_ALPHA8);
// Set max level, check if the max level mipmap is generated.
var max_level = 3;
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, max_level);
gl.generateMipmap(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);
width >>= max_level;
height >>= max_level;
canvas.width = width;
canvas.height = height;
gl.viewport(0, 0, width, height);
gl.bindTexture(gl.TEXTURE_2D, srgbTex);
wtu.clearAndDrawUnitQuad(gl);
var reference = wtu.sRGBToLinear(colors);
var msg;
wtu.checkCanvasRect(gl, 0, 0, width, height, reference, msg, [1,1,1,1]);
gl.deleteTexture(srgbTex);
}
generateMipmap();
generateMipmap_immutableTexture();
generateMipmap_widthHeightNotEqual();
generateMipmap_maxLevelLessThanFullMipmapLevel();
var successfullyParsed = true;
</script>
<script src="../../../js/js-test-post.js"></script>
</body>
</html>