blob: 0b3f173247854706ee5852cc80d074a92825147e [file] [log] [blame]
/*
* Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
/**
* @description This test verifies the functionality of the WEBGL_depth_texture
* extension, if it is available.
*/
import "dart:html";
import "dart:web_gl" as wgl;
import 'dart:typed_data';
import "../../../testcommon.dart";
import "resources/webgl-test.dart";
import "resources/webgl-test-utils.dart" as wtu;
import "../../../../Utils/async_utils.dart";
main() {
document.body.setInnerHtml('''
<script id="vshader" type="x-shader/x-vertex">
attribute vec4 a_position;
void main()
{
gl_Position = a_position;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D u_texture;
uniform vec2 u_resolution;
void main()
{
vec2 texcoord = gl_FragCoord.xy / u_resolution;
gl_FragColor = texture2D(u_texture, texcoord);
}
</script>
<div id="console"></div>
<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
<div>PASS</div>
''', treeSanitizer: new NullTreeSanitizer());
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas, {'antialias': false});
var program = wtu.setupTexturedQuad(gl);
var ext = null;
var vao = null;
var tex;
var name;
var supportedFormats;
runSupportedTest(extensionEnabled) {
var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
if (name != null) {
if (extensionEnabled) {
testPassed("WEBGL_depth_texture listed as supported and getExtension succeeded");
} else {
testFailed("WEBGL_depth_texture listed as supported but getExtension failed");
}
} else {
if (extensionEnabled) {
testFailed("WEBGL_depth_texture not listed as supported but getExtension succeeded");
} else {
testPassed("WEBGL_depth_texture not listed as supported and getExtension failed -- this is legal");
}
}
}
runTestDisabled() {
debug("Testing binding enum with extension disabled");
var tex = gl.createTexture();
gl.bindTexture(wgl.TEXTURE_2D, tex);
shouldGenerateGLError(gl, wgl.INVALID_ENUM,
() => gl.texImage2D(wgl.TEXTURE_2D, 0, wgl.DEPTH_COMPONENT, 1, 1, 0,
wgl.DEPTH_COMPONENT, wgl.UNSIGNED_SHORT, null));
shouldGenerateGLError(gl, wgl.INVALID_ENUM,
() => gl.texImage2D(wgl.TEXTURE_2D, 0, wgl.DEPTH_COMPONENT, 1, 1, 0,
wgl.DEPTH_COMPONENT, wgl.UNSIGNED_INT, null));
}
dumpIt(gl, res, msg) {
//return; // comment out to debug
debug(msg);
var actualPixels = new Uint8List(res * res * 4);
gl.readPixels(0, 0, res, res, wgl.RGBA, wgl.UNSIGNED_BYTE, actualPixels);
for (var yy = 0; yy < res; ++yy) {
var strs = [];
for (var xx = 0; xx < res; ++xx) {
var actual = (yy * res + xx) * 4;
strs.add("(${actualPixels[actual]},${actualPixels[actual+1]},${actualPixels[actual+2]},${actualPixels[actual+3]})");
}
debug(strs.join(" "));
}
}
runTestExtension() {
debug("Testing WEBGL_depth_texture");
var res = 8;
// make canvas for testing.
var canvas2 = document.createElement("canvas");
canvas2.width = res;
canvas2.height = res;
var ctx = canvas2.getContext("2d");
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas2.width, canvas2.height);
var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['a_position']);
gl.useProgram(program);
gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), res, res);
var buffer = gl.createBuffer();
gl.bindBuffer(wgl.ARRAY_BUFFER, buffer);
gl.bufferData(
wgl.ARRAY_BUFFER,
new Float32List.fromList(
[1.0, 1.0, 1.0,
-1.0, 1.0, 0.0,
-1.0, -1.0, -1.0,
1.0, 1.0, 1.0,
-1.0, -1.0, -1.0,
1.0, -1.0, 0.0,
]),
wgl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, wgl.FLOAT, false, 0, 0);
var parameters = [
{'attachment': wgl.DEPTH_ATTACHMENT, 'format': wgl.DEPTH_COMPONENT, 'type': wgl.UNSIGNED_SHORT, 'data': new Uint16List(1)},
{'attachment': wgl.DEPTH_ATTACHMENT, 'format': wgl.DEPTH_COMPONENT, 'type': wgl.UNSIGNED_INT, 'data': new Uint32List(1)},
{'attachment': wgl.DEPTH_STENCIL_ATTACHMENT, 'format': wgl.DEPTH_STENCIL, 'type': wgl.DepthTexture.UNSIGNED_INT_24_8_WEBGL, 'data': new Uint32List(1)}
];
for (var ii = 0; ii < parameters.length; ++ii) {
var attachment = parameters[ii]['attachment'];
var format = parameters[ii]['format'];
var type = parameters[ii]['type'];
var data = parameters[ii]['data'];
debug("testing parameters $ii:");
// check that cubemaps are not allowed.
var cubeTex = gl.createTexture();
gl.bindTexture(wgl.TEXTURE_CUBE_MAP, cubeTex);
var targets = [
wgl.TEXTURE_CUBE_MAP_POSITIVE_X,
wgl.TEXTURE_CUBE_MAP_NEGATIVE_X,
wgl.TEXTURE_CUBE_MAP_POSITIVE_Y,
wgl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
wgl.TEXTURE_CUBE_MAP_POSITIVE_Z,
wgl.TEXTURE_CUBE_MAP_NEGATIVE_Z
];
for (var target in targets) {
shouldGenerateGLError(gl, wgl.INVALID_OPERATION, () {
gl.texImage2D(target, 1, format, 1, 1, 0, format, type, null);
});
}
// check 2d textures.
tex = gl.createTexture();
gl.bindTexture(wgl.TEXTURE_2D, tex);
gl.texParameteri(wgl.TEXTURE_2D, wgl.TEXTURE_WRAP_S, wgl.CLAMP_TO_EDGE);
gl.texParameteri(wgl.TEXTURE_2D, wgl.TEXTURE_WRAP_T, wgl.CLAMP_TO_EDGE);
gl.texParameteri(wgl.TEXTURE_2D, wgl.TEXTURE_MIN_FILTER, wgl.LINEAR);
gl.texParameteri(wgl.TEXTURE_2D, wgl.TEXTURE_MAG_FILTER, wgl.LINEAR);
// test level > 0
shouldGenerateGLError(gl, wgl.INVALID_OPERATION, () {
gl.texImage2D(wgl.TEXTURE_2D, 1, format, 1, 1, 0, format, type, null);
});
// test with data
shouldGenerateGLError(gl, wgl.INVALID_OPERATION, () {
gl.texImage2D(wgl.TEXTURE_2D, 0, format, 1, 1, 0, format, type, data);
});
// test with canvas
shouldGenerateGLError(gl, [wgl.INVALID_VALUE, wgl.INVALID_ENUM, wgl.INVALID_OPERATION], () {
gl.texImage2DCanvas(wgl.TEXTURE_2D, 0, format, format, type, canvas2);
});
// test copyTexImage2D
shouldGenerateGLError(gl, [wgl.INVALID_ENUM, wgl.INVALID_OPERATION], () {
gl.copyTexImage2D(wgl.TEXTURE_2D, 0, format, 0, 0, 1, 1, 0);
});
// test real thing
shouldGenerateGLError(gl, wgl.NO_ERROR, () {
gl.texImage2D(wgl.TEXTURE_2D, 0, format, res, res, 0, format, type, null);
});
// test texSubImage2D
shouldGenerateGLError(gl, wgl.INVALID_OPERATION, () {
gl.texSubImage2D(wgl.TEXTURE_2D, 0, 0, 0, 1, 1, format, type, data);
});
// test copyTexSubImage2D
shouldGenerateGLError(gl, wgl.INVALID_OPERATION, () {
gl.copyTexSubImage2D(wgl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
});
// test generateMipmap
shouldGenerateGLError(gl, wgl.INVALID_OPERATION, () {
gl.generateMipmap(wgl.TEXTURE_2D);
});
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(wgl.FRAMEBUFFER, attachment, wgl.TEXTURE_2D, tex, 0);
// TODO: remove this check if the spec is updated to require these combinations to work.
if (gl.checkFramebufferStatus(wgl.FRAMEBUFFER) != wgl.FRAMEBUFFER_COMPLETE)
{
// try adding a color buffer.
var colorTex = gl.createTexture();
gl.bindTexture(wgl.TEXTURE_2D, colorTex);
gl.texParameteri(wgl.TEXTURE_2D, wgl.TEXTURE_WRAP_S, wgl.CLAMP_TO_EDGE);
gl.texParameteri(wgl.TEXTURE_2D, wgl.TEXTURE_WRAP_T, wgl.CLAMP_TO_EDGE);
gl.texParameteri(wgl.TEXTURE_2D, wgl.TEXTURE_MIN_FILTER, wgl.LINEAR);
gl.texParameteri(wgl.TEXTURE_2D, wgl.TEXTURE_MAG_FILTER, wgl.LINEAR);
gl.texImage2D(wgl.TEXTURE_2D, 0, wgl.RGBA, res, res, 0, wgl.RGBA, wgl.UNSIGNED_BYTE, null);
gl.framebufferTexture2D(wgl.FRAMEBUFFER, wgl.COLOR_ATTACHMENT0, wgl.TEXTURE_2D, colorTex, 0);
}
shouldBe(gl.checkFramebufferStatus(wgl.FRAMEBUFFER), wgl.FRAMEBUFFER_COMPLETE);
// use the default texture to render with while we return to the depth texture.
gl.bindTexture(wgl.TEXTURE_2D, null);
// render the z-quad
gl.enable(wgl.DEPTH_TEST);
gl.clearColor(1, 0, 0, 1);
gl.clear(wgl.COLOR_BUFFER_BIT | wgl.DEPTH_BUFFER_BIT);
gl.drawArrays(wgl.TRIANGLES, 0, 6);
dumpIt(gl, res, "--first--");
// render the depth texture.
gl.bindFramebuffer(wgl.FRAMEBUFFER, null);
gl.bindTexture(wgl.TEXTURE_2D, tex);
gl.clearColor(0, 0, 1, 1);
gl.clear(wgl.COLOR_BUFFER_BIT | wgl.DEPTH_BUFFER_BIT);
gl.drawArrays(wgl.TRIANGLES, 0, 6);
var actualPixels = new Uint8List(res * res * 4);
gl.readPixels(0, 0, res, res, wgl.RGBA, wgl.UNSIGNED_BYTE, actualPixels);
dumpIt(gl, res, "--depth--");
// Check that each pixel's RGB are the same and that it's value is less
// than the previous pixel in either direction. Basically verify we have a
// gradient.
var success = true;
for (var yy = 0; yy < res; ++yy) {
for (var xx = 0; xx < res; ++xx) {
var actual = (yy * res + xx) * 4;
var left = actual - 4;
var down = actual - res * 4;
if (actualPixels[actual + 0] != actualPixels[actual + 1]) {
testFailed('R != G');
success = false;
}
if (actualPixels[actual + 0] != actualPixels[actual + 2]) {
testFailed('R != B');
success = false;
}
// ALPHA is implementation dependent
if (actualPixels[actual + 3] != 0xFF && actualPixels[actual + 3] != actualPixels[actual + 0]) {
testFailed('A != 255 && A != R');
success = false;
}
if (xx > 0) {
if (actualPixels[actual] <= actualPixels[left]) {
testFailed("actual(${actualPixels[actual]}) < left(${actualPixels[left]})");
success = false;
}
}
if (yy > 0) {
if (actualPixels[actual] <= actualPixels[down]) {
testFailed("actual(${actualPixels[actual]}) < down(${actualPixels[down]})");
success = false;
}
}
}
}
// Check that bottom left corner is vastly different thatn top right.
if (actualPixels[(res * res - 1) * 4] - actualPixels[0] < 0xC0) {
testFailed("corners are not different enough");
success = false;
}
if (success) {
testPassed("depth texture rendered correctly.");
}
// check limitations
gl.bindFramebuffer(wgl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(wgl.FRAMEBUFFER, attachment, wgl.TEXTURE_2D, null, 0);
var badAttachment = attachment == wgl.DEPTH_ATTACHMENT ? wgl.DEPTH_STENCIL_ATTACHMENT : wgl.DEPTH_ATTACHMENT;
shouldGenerateGLError(gl, wgl.NO_ERROR, () {
gl.framebufferTexture2D(wgl.FRAMEBUFFER, badAttachment, wgl.TEXTURE_2D, tex, 0);
});
shouldNotBe(gl.checkFramebufferStatus(wgl.FRAMEBUFFER), wgl.FRAMEBUFFER_COMPLETE);
shouldGenerateGLError(gl, wgl.INVALID_FRAMEBUFFER_OPERATION, () {
gl.clear(wgl.DEPTH_BUFFER_BIT);
});
gl.bindFramebuffer(wgl.FRAMEBUFFER, null);
shouldBe(gl.getError(), wgl.NO_ERROR);
}
}
if (gl == null) {
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 = gl.getExtension("WEBGL_depth_texture");
if (ext == null) {
testPassed("No WEBGL_depth_texture support -- this is legal");
runSupportedTest(false);
} else {
testPassed("Successfully enabled WEBGL_depth_texture extension");
runSupportedTest(true);
runTestExtension();
}
}
}