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 CopyTexImage Tests</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"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
var wtu = WebGLTestUtils;
description("This test verifies the functionality of copyTexImage.");
var gl = wtu.create3DContext("example", undefined, 2);
function copytexsubimage3d_invalid_operation_feedbackloops() {
debug("");
debug("Testing copytexsubimage3d_invalid_operation_feedbackloops");
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_3D, texture);
var uint8 = new Uint8Array(32);
var layer = 0;
var width = 2;
var height = 2;
var depth = 2;
gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, width, height, depth, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint8);
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture, 0, layer);
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
gl.copyTexSubImage3D(gl.TEXTURE_3D, 0, 0, 0, layer, 0, 0, width, height);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "gl.INVALID_OPERATION is generated");
} else {
testFailed("framebuffer not complete");
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.deleteFramebuffer(fbo);
gl.deleteTexture(texture);
};
function copytexsubimage3d_valid_operation_diff_level() {
debug("");
debug("Testing copytexsubimage3d_valid_operation_diff_level");
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_3D, texture);
var uint8 = new Uint8Array(32);
var level1 = 0;
var level2 = 1;
var width = 2;
var height = 2;
var depth = 2;
gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, width, height, depth, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint8);
gl.generateMipmap(gl.TEXTURE_3D);
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture, level1, 0);
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
gl.copyTexSubImage3D(gl.TEXTURE_3D, level2, 0, 0, 0, 0, 0, width/2, height/2);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texImage3D should succeed.");
} else {
testFailed("framebuffer not complete");
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.deleteFramebuffer(fbo);
gl.deleteTexture(texture);
};
function copytexsubimage3d_valid_operation_diff_layer() {
debug("");
debug("Testing copytexsubimage3d_valid_operation_diff_layer");
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_3D, texture);
var uint8 = new Uint8Array(32);
var layer1 = 0;
var layer2 = 1;
var width = 2;
var height = 2;
var depth = 2;
gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, width, height, depth, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint8);
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture, 0, layer1);
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
gl.copyTexSubImage3D(gl.TEXTURE_3D, 0, 0, 0, layer2, 0, 0, width, height);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texImage3D should succeed.");
} else {
testFailed("framebuffer not complete");
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.deleteFramebuffer(fbo);
gl.deleteTexture(texture);
}
function copytexsubimage3d_texture_wrongly_initialized() {
debug("");
debug("Testing copytexsubimage3d_texture_wrongly_initialized");
var texture = [];
texture[0] = gl.createTexture();
texture[1] = gl.createTexture();
var layer = 0;
var width = 2;
var height = 2;
var depth = 2;
gl.bindTexture(gl.TEXTURE_2D, texture[0]);
var uint = new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint);
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture[0], 0);
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
gl.bindTexture(gl.TEXTURE_3D, texture[1]);
gl.texStorage3D(gl.TEXTURE_3D, 1, gl.RGBA8, width, height, depth);
gl.copyTexSubImage3D(gl.TEXTURE_3D, 0, 0, 0, layer, 0, 0, width, height);
gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture[1], 0, layer);
var bytes = new Uint8Array(width * height * 4);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, bytes);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readpixel should succeed.");
for (var x = 0; x < width * height * 4; x++) {
if (bytes[x] != uint[x]) {
testFailed("byte comparison failure, byte at "+ x + " was " + bytes[x] +
", should be " + uint[x]);
break;
}
}
} else {
testFailed("framebuffer not complete");
}
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindTexture(gl.TEXTURE_3D, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.deleteFramebuffer(fbo);
gl.deleteTexture(texture[0]);
gl.deleteTexture(texture[1]);
};
function copytexsubimage3d_out_of_bounds_test_helper(xx, yy, copyWidth, copyHeight) {
var texture = [];
texture[0] = gl.createTexture();
texture[1] = gl.createTexture();
var layer = 0;
var width = 2;
var height = 2;
var depth = 2;
var width2 = 4;
var height2 = 4;
var xoffset = 0;
var yoffset = 0;
var uint = new Uint8Array(width * height * 4);
for (var i = 0; i < uint.length; i++) {
uint[i] = 0x01;
}
var uint2 = new Uint8Array(width2 * height2 * depth * 4);
for (var i = 0; i < uint2.length; i++) {
uint2[i] = 0xFF;
}
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.bindTexture(gl.TEXTURE_2D, texture[0]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture[0], 0);
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
gl.bindTexture(gl.TEXTURE_3D, texture[1]);
gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, width2, height2, depth, 0, gl.RGBA, gl.UNSIGNED_BYTE, uint2);
gl.copyTexSubImage3D(gl.TEXTURE_3D, 0, xoffset, yoffset, layer, xx, yy, copyWidth, copyHeight);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "using copyTexSubImage3D: x = " + xx + ", y = " + yy + " width = " + copyWidth + ", height = " + copyHeight);
gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture[1], 0, layer);
var bytes = new Uint8Array(width2 * height2 * 4);
gl.readPixels(0, 0, width2, height2, gl.RGBA, gl.UNSIGNED_BYTE, bytes);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "readpixel should succeed.");
var sourceX = new Object();
var sourceY = new Object();
Clip(xx, copyWidth, width, sourceX);
Clip(yy, copyHeight, height, sourceY);
var destX = sourceX.start - xx + xoffset;
var rangeX = sourceX.range;
var destY = sourceY.start - yy + yoffset;
var rangeY = sourceY.range;
for (var y = 0; y < height2; y++) {
for (var x = 0; x < width2 * 4; x++) {
var current = y * height2 * 4 + x;
// pixels copied from read framebuffer should be 0x01
if (x >= destX * 4 && x < (destX + rangeX) * 4 && y >= destY && y < destY + rangeY) {
if (bytes[current] != 0x01) {
testFailed("byte comparison failure, byte at "+ (current) + " was " +
bytes[current] +", should be 1");
break;
}
// pixels out-of-bounds should be untouched
} else {
if (bytes[current] != 0xFF) {
testFailed("byte comparison failure, byte at "+ (current) + " was " +
bytes[current] + ", should be 255");
break;
}
}
}
// Test failed; abort
if (x < width2 * 4) {
break;
}
}
} else {
testFailed("framebuffer not complete");
}
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindTexture(gl.TEXTURE_3D, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.deleteFramebuffer(fbo);
gl.deleteTexture(texture[0]);
gl.deleteTexture(texture[1]);
}
function copytexsubimage3d_out_of_bounds() {
debug("");
debug("Test pixels outside of read framebuffer for CopyTexSubImage3D");
for(var i=0; i < testlist.length; i++) {
copytexsubimage3d_out_of_bounds_test_helper(testlist[i][0], testlist[i][1], testlist[i][2], testlist[i][3]);
}
};
/**
* This array defines some copy areas for CopyTexSubImage3D.
* A copy area is defined by x coordinate, y coordinate, copyWidth and copyHeight.
* the source read framebuffer is (0, 0, 2, 2).
*/
var testlist = [
[-1, -1, 4, 4],
[0, 0, 3, 3],
[-1, -1, 3, 3],
[-1, 0, 3, 3],
[0, -1, 3, 3],
[0, 0, 2, 3],
[0, 0, 3, 2],
[-1, 0, 3, 2],
[0, -1, 2, 3],
[-2, -2, 3, 3],
[-2, 1, 3, 3],
[1, -2, 3, 3],
[1, 1, 3, 3],
[2 , 2 ,3, 3]
];
function Clip(start, range, sourceRange, target) {
if (start < 0) {
range += start;
start = 0;
}
var end = start + range;
if(end > sourceRange) {
range -= end - sourceRange;
}
target.start = start;
target.range = range;
}
if (!gl) {
testFailed("WebGL context does not exist");
} else {
testPassed("WebGL context exists");
copytexsubimage3d_invalid_operation_feedbackloops();
copytexsubimage3d_valid_operation_diff_level();
copytexsubimage3d_valid_operation_diff_layer();
copytexsubimage3d_texture_wrongly_initialized();
copytexsubimage3d_out_of_bounds();
}
var successfullyParsed = true;
</script>
<script src="../../../js/js-test-post.js"></script>
</body>
</html>