Bug 1724535 - Update WebGL CTS checkout. r=lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D122657
This commit is contained in:
Jeff Gilbert 2021-08-20 19:07:21 +00:00
parent 0d54d4b040
commit 360dba0b1c
199 changed files with 8202 additions and 1178 deletions

View File

@ -1 +1 @@
master
main

View File

@ -52,12 +52,7 @@ There is supposed to be an example drawing here, but it's not important.
componentSize: 4,
normalize: false,
},
{ data: new Float32Array([ 0, 1, 0, 1, 0, 0, 0, 0, 0 ]),
type: gl.FLOAT,
componentSize: 4,
normalize: false,
},
{ data: new Uint16Array([ 0, 32767, 0, 32767, 0, 0, 0, 0, 0 ]),
{ data: new Uint16Array([ 0, 32767, 0, 32767, 0, 0, 0, 0, 0]),
type: gl.SHORT,
componentSize: 2,
normalize: true,
@ -99,6 +94,41 @@ There is supposed to be an example drawing here, but it's not important.
}
];
if (wtu.getDefault3DContextVersion() >= 2) {
tests.push(...[
{ data: new Int32Array([ 0, 1, 0, 1, 0, 0, 0, 0, 0]),
type: gl.INT,
componentSize: 4,
normalize: false,
},
{ data: new Int32Array([ 0, 2147483647, 0, 2147483647, 0, 0, 0, 0, 0]),
type: gl.INT,
componentSize: 4,
normalize: true,
},
{ data: new Uint32Array([ 0, 1, 0, 1, 0, 0, 0, 0, 0]),
type: gl.UNSIGNED_INT,
componentSize: 4,
normalize: false,
},
{ data: new Uint32Array([ 0, 4294967295, 0, 4294967295, 0, 0, 0, 0, 0]),
type: gl.UNSIGNED_INT,
componentSize: 4,
normalize: true,
},
{ data: new Uint16Array([ 0, 0b11110000000000, 0, 0b11110000000000, 0, 0, 0, 0, 0]),
type: gl.HALF_FLOAT,
componentSize: 2,
normalize: false,
},
{ data: new Uint16Array([ 0, 0b11110000000000, 0, 0b11110000000000, 0, 0, 0, 0, 0]),
type: gl.HALF_FLOAT,
componentSize: 2,
normalize: false,
}
]);
}
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(gl.ARRAY_BUFFER, 1024, gl.STATIC_DRAW);

View File

@ -67,10 +67,10 @@ if (!gl) {
gl.vertexAttribPointer(0, 1, gl.UNSIGNED_INT, 0, 0, 0);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
"vertexAttribPointer should not support UNSIGNED_INT");
gl.vertexAttribPointer(0, 1, gl.FIXED, 0, 0, 0);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
"vertexAttribPointer should not support FIXED");
}
gl.vertexAttribPointer(0, 1, gl.FIXED, 0, 0, 0);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
"vertexAttribPointer should not support FIXED");
var checkVertexAttribPointer = function(
gl, err, reason, size, type, normalize, stride, offset) {
@ -100,6 +100,16 @@ if (!gl) {
{ type:gl.FLOAT, bytesPerComponent: 4 },
];
if (wtu.getDefault3DContextVersion() >= 2) {
types.push(...[
{ type:gl.INT, bytesPerComponent: 4 },
{ type:gl.UNSIGNED_INT, bytesPerComponent: 4 },
{ type:gl.HALF_FLOAT, bytesPerComponent: 2 },
{ type:gl.INT_2_10_10_10_REV, bytesPerComponent: 4, minSize: 4 },
{ type:gl.UNSIGNED_INT_2_10_10_10_REV, bytesPerComponent: 4, minSize: 4 },
]);
}
for (var ii = 0; ii < types.length; ++ii) {
var info = types[ii];
debug("");
@ -128,6 +138,10 @@ if (!gl) {
reason = "because stride is bad";
err = gl.INVALID_OPERATION;
}
if (size < info.minSize) {
reason = "because size < minSize";
err = gl.INVALID_OPERATION;
}
checkVertexAttribPointer(
gl, err, reason, size, info.type, false, stride, offset);
}
@ -135,10 +149,10 @@ if (!gl) {
if (offset == 0) {
checkVertexAttribPointer(
gl, gl.NO_ERROR, "at stride limit",
gl, size < info.minSize ? gl.INVALID_OPERATION : gl.NO_ERROR, "at stride limit",
size, info.type, false, stride, offset);
checkVertexAttribPointer(
gl, gl.INVALID_VALUE, "over stride limit",
gl, size < info.minSize ? [gl.INVALID_OPERATION, gl.INVALID_VALUE] : gl.INVALID_VALUE, "over stride limit",
size, info.type, false,
stride + info.bytesPerComponent, offset);
}

View File

@ -94,15 +94,24 @@ function bufferDataSizesTest() {
{ parameter: new ArrayBuffer(0), expectedBufferSize: 0 },
{ parameter: new ArrayBuffer(4), expectedBufferSize: 4 },
{ parameter: new Uint8Array(new ArrayBuffer(5)), expectedBufferSize: 5 },
{ parameter: new DataView(new ArrayBuffer(7)), expectedBufferSize: 7 },
{ parameter: "WebGL Rocks!", expectedBufferSize: 0 },
{ parameter: { mystring: "WebGL Rocks!" }, expectedBufferSize: 0 },
];
if (window.SharedArrayBuffer) {
bufferDataParams.push(
{ parameter: new SharedArrayBuffer(3), expectedBufferSize: 3 },
{ parameter: new Uint8Array(new SharedArrayBuffer(6)), expectedBufferSize: 6 },
{ parameter: new DataView(new SharedArrayBuffer(8)), expectedBufferSize: 8 }
);
}
bufferDataParams.forEach(function (bufferDataParam) {
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, bufferDataParam.parameter, gl.STATIC_DRAW);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Passing " + bufferDataParam.parameter + " to bufferData");
@ -154,6 +163,18 @@ function bufferSubDataTest() {
shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, { mynumber: 42});");
shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 10, null)");
shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 10, undefined)");
if (window.SharedArrayBuffer) {
const validDatas = [
'new SharedArrayBuffer(3)',
'new Uint8Array(new SharedArrayBuffer(3))',
'new DataView(new SharedArrayBuffer(3))',
];
for (const x of validDatas) {
shouldNotThrow(`gl.bufferSubData(gl.ARRAY_BUFFER, 0, ${x})`);
}
}
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should generate no GL error");
// -

View File

@ -13,6 +13,7 @@ drawingbuffer-test.html
--min-version 1.0.4 render-after-resize-test.html
--min-version 1.0.2 texture-bindings-unaffected-on-resize.html
--min-version 1.0.2 to-data-url-test.html
--min-version 1.0.4 to-data-url-after-composite.html
viewport-unchanged-upon-resize.html
--min-version 1.0.4 webgl-to-2d-canvas.html

View File

@ -36,10 +36,6 @@ const SMALL = 2;
// different results. Sometimes wrong, sometimes correct.
const LARGE = 1200;
function render() {
}
gl.uniform4fv(colorLocation, [0.0, 1.0, 0.0, 1.0]);
// -
@ -64,6 +60,19 @@ wtu.drawUnitQuad(gl);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, [ 0, 255, 0, 255 ]);
debug('\nCause a GL error, then resize and render.');
gl.depthFunc(0); // Causes INVALID_ENUM
gl.canvas.width = gl.canvas.height = LARGE;
gl.clear(gl.COLOR_BUFFER_BIT);
gl.canvas.width = gl.canvas.height = SMALL;
gl.clear(gl.COLOR_BUFFER_BIT);
wtu.drawUnitQuad(gl);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, [ 0, 255, 0, 255 ]);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
// -
debug('\nRender, no-op resize, then depth-fail render.');

View File

@ -0,0 +1,51 @@
<!--
Copyright (c) 2021 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 toDataURL after composite 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 width="20" height="20" style="border: 1px solid black; width: 128px; height: 128px" id="c3d"></canvas>
<canvas width="20" height="20" style="border: 1px solid black; width: 128px; height: 128px" id="c2d"></canvas>
<div id="description"></div>
<div id="console"></div>
<script type="application/javascript">
const wtu = WebGLTestUtils;
let gl;
let ctx;
function main() {
description();
const c2d = document.getElementById("c2d");
ctx = c2d.getContext("2d");
gl = wtu.create3DContext("c3d", { preserveDrawingBuffer: true });
// Clear to green
gl.clearColor(0.0, 1.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
wtu.waitForComposite(() => {
// Performs gl.canvas.toDataURL() internally
let img = wtu.makeImageFromCanvas(gl.canvas, function() {
ctx.drawImage(img, 0, 0);
wtu.checkCanvas(ctx, [0, 255, 0], "toDataURL loaded into image, drawn into 2D context, should be green", 5);
finishTest();
});
});
};
main();
var successfullyParsed = true;
</script>
</body>
</html>

View File

@ -26,13 +26,34 @@ var ctx;
var main = function() {
description();
ctx = document.getElementById("c2d").getContext("2d");
gl = wtu.create3DContext("c3d");
if (!gl) {
testFailed("can't create 3d context");
finishTest();
return;
}
var updateCanvas = function(width, height, attributes) {
var canvas = document.getElementById("c3d");
if (gl && (gl.attributes !== attributes)) {
// Attributes changed, recreate the canvas
var newCanvas = canvas.cloneNode();
canvas.parentNode.replaceChild(newCanvas, canvas);
canvas = newCanvas;
gl = undefined;
}
canvas.width = width;
canvas.height = height;
if (!gl) {
gl = wtu.create3DContext(canvas, attributes);
if (!gl) {
testFailed("can't create 3d context");
return;
}
gl.attributes = attributes;
}
return gl;
};
var clearRect = function(gl, x, y, width, height, color) {
gl.clearColor(color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255);
@ -40,10 +61,18 @@ var main = function() {
gl.clear(gl.COLOR_BUFFER_BIT);
};
var testSize = function(gl, width, height, callback) {
debug("testing " + width + " by " + height);
gl.canvas.width = width;
gl.canvas.height = height;
var testSize = function(width, height, attributes, callback) {
let attributesDebugMessage = "";
if (attributes) {
attributesDebugMessage = " attributes: " + JSON.stringify(attributes);
}
debug("testing " + width + " by " + height + attributesDebugMessage);
var gl = updateCanvas(width, height, attributes);
if (!gl) {
callback();
return;
}
gl.viewport(0, 0, width, height);
gl.enable(gl.SCISSOR_TEST);
@ -71,6 +100,9 @@ var main = function() {
});
};
const premultipliedAlphaAttributes = {
premultipliedAlpha: false,
};
var tests = [
{ width: 16 , height: 16 , },
{ width: 16 - 1, height: 16 , },
@ -87,6 +119,7 @@ var main = function() {
{ width: 512 - 1, height: 512 - 1, },
{ width: 512 + 1, height: 512 - 1, },
{ width: 512 - 1, height: 512 + 1, },
{ width: 16 , height: 16 , attributes: premultipliedAlphaAttributes},
];
var testIndex = 0;
var runNextTest = function() {
@ -95,7 +128,7 @@ var main = function() {
return;
}
var test = tests[testIndex++];
testSize(gl, test.width, test.height, function() {
testSize(test.width, test.height, test.attributes, function() {
setTimeout(runNextTest, 0);
})
};

View File

@ -12,6 +12,7 @@ context-attributes-alpha-depth-stencil-antialias.html
context-lost-restored.html
context-lost.html
--max-version 1.9.9 context-type-test.html
--min-version 1.0.4 deleted-object-behavior.html
incorrect-context-object-behaviour.html
--max-version 1.9.9 methods.html
premultiplyalpha-test.html

View File

@ -17,13 +17,13 @@ found in the LICENSE.txt file.
display: inline-block;
}
canvas {
width:50px;
height:50px;
width:10px;
height:10px;
}
.square {
display:inline-block;
width:50px;
height:50px;
width:10px;
height:10px;
background-color:red;
}
</style>

View File

@ -11,6 +11,7 @@ found in the LICENSE.txt file.
<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>
<script src="../../js/tests/context-methods.js"></script>
</head>
<body>
<div id="description"></div>
@ -20,7 +21,7 @@ found in the LICENSE.txt file.
"use strict";
description("This test ensures that the WebGL context has all the methods in the specification.");
var methods = [
const methods = [
"getContextAttributes",
"activeTexture",
"attachShader",
@ -159,55 +160,14 @@ var methods = [
"viewport"
];
// Properties to be ignored because they were added in versions of the
// spec that are backward-compatible with this version
var ignoredMethods = [
// There is no official spec for the commit API yet, the proposal link is:
// https://wiki.whatwg.org/wiki/OffscreenCanvas
"commit"
];
function assertFunction(v, f) {
try {
if (typeof v[f] != "function") {
testFailed("Property either does not exist or is not a function: " + f);
return false;
} else {
return true;
}
} catch(e) {
testFailed("Trying to access the property '" + f + "' threw an error: "+e.toString());
}
}
debug("");
debug("Canvas.getContext");
var wtu = WebGLTestUtils;
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas);
var passed = true;
for (var i=0; i<methods.length; i++) {
var r = assertFunction(gl, methods[i]);
passed = passed && r;
}
if (passed) {
testPassed("All WebGL methods found.");
}
var extended = false;
for (var i in gl) {
if (typeof gl[i] == "function" && methods.indexOf(i) == -1 && ignoredMethods.indexOf(i) == -1) {
if (!extended) {
extended = true;
testFailed("Also found the following extra methods:");
}
testFailed(i);
}
}
const wtu = WebGLTestUtils;
const canvas = document.getElementById("canvas");
const gl = wtu.create3DContext(canvas);
if (!extended) {
testPassed("No extra methods found on WebGL context.");
}
testContextMethods(gl, methods);
debug("");
var successfullyParsed = true;

View File

@ -1,6 +1,7 @@
--min-version 1.0.3 --max-version 1.9.9 angle-instanced-arrays.html
--min-version 1.0.3 --max-version 1.9.9 angle-instanced-arrays-out-of-bounds.html
--min-version 1.0.3 --max-version 1.9.9 ext-blend-minmax.html
--min-version 1.0.4 ext-color-buffer-half-float.html
--min-version 1.0.4 ext-float-blend.html
--min-version 1.0.4 ext-texture-compression-bptc.html
--min-version 1.0.4 ext-texture-compression-rgtc.html
@ -10,6 +11,7 @@
--min-version 1.0.3 --max-version 1.9.9 ext-sRGB.html
--min-version 1.0.2 ext-texture-filter-anisotropic.html
--min-version 1.0.2 get-extension.html
--min-version 1.0.4 khr-parallel-shader-compile.html
--max-version 1.9.9 oes-standard-derivatives.html
--max-version 1.9.9 oes-texture-float-with-canvas.html
--max-version 1.9.9 oes-texture-float-with-image-data.html
@ -33,7 +35,7 @@ webgl-debug-shaders.html
--min-version 1.0.4 webgl-compressed-texture-etc.html
--min-version 1.0.4 webgl-compressed-texture-etc1.html
--min-version 1.0.3 webgl-compressed-texture-pvrtc.html
--min-version 1.0.2 webgl-compressed-texture-s3tc.html
--min-version 1.0.4 s3tc-and-rgtc.html
--min-version 1.0.4 webgl-compressed-texture-s3tc-srgb.html
--min-version 1.0.3 webgl-compressed-texture-size-limit.html
--min-version 1.0.2 --max-version 1.9.9 webgl-depth-texture.html

View File

@ -196,6 +196,9 @@ function runOutputTests() {
0.0, 1.0, 0.0, 1.0, // Green
0.0, 0.0, 1.0, 1.0, // Blue
1.0, 1.0, 0.0, 1.0, // Yellow
// extra data when colorLoc divisor is set back to 0
1.0, 1.0, 0.0, 1.0, // Yellow
1.0, 1.0, 0.0, 1.0, // Yellow
]);
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
@ -277,6 +280,19 @@ function runOutputTests() {
wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0, w, h, [0, 0, 255, 255]);
wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0, w, h, [255, 255, 0, 255]);
debug("");
debug("Testing drawArraysInstancedANGLE with attributes 'divisor' reset to 0");
debug("Correct rendering output: 4 yellow triangles");
debug("Possible incorrect rendering output: missing triangles, or triangles with different color at each vertex");
ext.vertexAttribDivisorANGLE(colorLoc, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
ext.drawArraysInstancedANGLE(gl.TRIANGLES, 3, 3, instanceCount);
wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0.5*canvas.height, w, h, [255, 255, 0, 255]);
wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0.5*canvas.height, w, h, [255, 255, 0, 255]);
wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0, w, h, [255, 255, 0, 255]);
wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0, w, h, [255, 255, 0, 255]);
ext.vertexAttribDivisorANGLE(colorLoc, 1);
wtu.setupUnitQuad(gl, 0);
wtu.setupIndexedQuad(gl, 1, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);

View File

@ -0,0 +1,27 @@
<!--
Copyright (c) 2020 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 EXT_color_buffer_half_float Conformance 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>
<div id="description"></div>
<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
<div id="console"></div>
<script>
var version = 1;
</script>
<script src="../../js/tests/ext-color-buffer-half-float.js"></script>
<script src="../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -60,7 +60,7 @@ function runTestExtension() {
// * <height> is not a multiple of four, and <height> plus <yoffset> is
// not equal to TEXTURE_HEIGHT; or
// * <xoffset> or <yoffset> is not a multiple of four.
ctu.testTexSubImageDimensions(gl, validFormats, expectedByteLength, getBlockDimensions,
ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
16, 16, [
{ xoffset: 0, yoffset: 0, width: 4, height: 3,
expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
@ -73,6 +73,63 @@ function runTestExtension() {
{ xoffset: 12, yoffset: 12, width: 4, height: 4,
expectation: gl.NO_ERROR, message: "is valid" },
]);
// Test TexImage validation on level dimensions combinations.
// When level equals 0, width and height must be a multiple of 4.
// When level is larger than 0, this constraint doesn't apply.
let npotExpectation, npotMessage;
if (contextVersion >= 2) {
npotExpectation = gl.NO_ERROR;
npotMessage = "valid";
} else {
npotExpectation = gl.INVALID_VALUE;
npotMessage = "invalid";
}
ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
[
{ level: 0, width: 4, height: 3,
expectation: gl.INVALID_OPERATION, message: "level is 0, height is not a multiple of 4" },
{ level: 0, width: 3, height: 4,
expectation: gl.INVALID_OPERATION, message: "level is 0, width is not a multiple of 4" },
{ level: 0, width: 2, height: 2,
expectation: gl.INVALID_OPERATION, message: "level is 0, width is not a multiple of 4" },
{ level: 0, width: 4, height: 4,
expectation: gl.NO_ERROR, message: "is valid" },
{ level: 1, width: 1, height: 1,
expectation: gl.INVALID_OPERATION, message: "implied base mip 2x2 is invalid" },
{ level: 1, width: 1, height: 2,
expectation: gl.INVALID_OPERATION, message: "implied base mip 2x4 is invalid" },
{ level: 1, width: 2, height: 1,
expectation: gl.INVALID_OPERATION, message: "implied base mip 4x2 is invalid" },
{ level: 1, width: 2, height: 2,
expectation: gl.NO_ERROR, message: "implied base mip 4x4 is valid" },
{ level: 2, width: 1, height: 3,
expectation: npotExpectation, message: "implied base mip 4x12 is " + npotMessage },
]);
// Test that BPTC enums are not accepted by texImage2D
{
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RGBA_BPTC_UNORM_EXT, 4, 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RGBA_BPTC_UNORM_EXT fails with texImage2D");
gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT, 4, 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT fails with texImage2D");
if (contextVersion >= 2) {
gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, 4, 4, 0, gl.RGB, gl.FLOAT, null);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT fails with texImage2D");
gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT, 4, 4, 0, gl.RGB, gl.FLOAT, null);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT fails with texImage2D");
}
gl.deleteTexture(tex);
}
};
function runTest() {

View File

@ -65,7 +65,7 @@ function runTestExtension() {
// * <height> is not a multiple of four, and <height> plus <yoffset> is
// not equal to TEXTURE_HEIGHT; or
// * <xoffset> or <yoffset> is not a multiple of four.
ctu.testTexSubImageDimensions(gl, validFormats, expectedByteLength, getBlockDimensions,
ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
16, 16, [
{ xoffset: 0, yoffset: 0, width: 4, height: 3,
expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
@ -78,6 +78,61 @@ function runTestExtension() {
{ xoffset: 12, yoffset: 12, width: 4, height: 4,
expectation: gl.NO_ERROR, message: "is valid" },
]);
// Test TexImage validation on level dimensions combinations.
// When level equals 0, width and height must be a multiple of 4.
// When level is larger than 0, this constraint doesn't apply.
let npotExpectation, npotMessage;
if (contextVersion >= 2) {
npotExpectation = gl.NO_ERROR;
npotMessage = "valid";
} else {
npotExpectation = gl.INVALID_VALUE;
npotMessage = "invalid";
}
ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
[
{ level: 0, width: 4, height: 3,
expectation: gl.INVALID_OPERATION, message: "level is 0, height is not a multiple of 4" },
{ level: 0, width: 3, height: 4,
expectation: gl.INVALID_OPERATION, message: "level is 0, width is not a multiple of 4" },
{ level: 0, width: 2, height: 2,
expectation: gl.INVALID_OPERATION, message: "level is 0, width is not a multiple of 4" },
{ level: 0, width: 4, height: 4,
expectation: gl.NO_ERROR, message: "is valid" },
{ level: 1, width: 1, height: 1,
expectation: gl.INVALID_OPERATION, message: "implied base mip 2x2 is invalid" },
{ level: 1, width: 1, height: 2,
expectation: gl.INVALID_OPERATION, message: "implied base mip 2x4 is invalid" },
{ level: 1, width: 2, height: 1,
expectation: gl.INVALID_OPERATION, message: "implied base mip 4x2 is invalid" },
{ level: 1, width: 2, height: 2,
expectation: gl.NO_ERROR, message: "implied base mip 4x4 is valid" },
{ level: 2, width: 1, height: 3,
expectation: npotExpectation, message: "implied base mip 4x12 is " + npotMessage },
]);
// Test that RGTC enums are not accepted by texImage2D
if (contextVersion >= 2) {
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RED_RGTC1_EXT, 4, 4, 0, gl.RED, gl.UNSIGNED_BYTE, null);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RED_RGTC1_EXT fails with texImage2D");
gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_SIGNED_RED_RGTC1_EXT, 4, 4, 0, gl.RED, gl.BYTE, null);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_SIGNED_RED_RGTC1_EXT fails with texImage2D");
gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RED_GREEN_RGTC2_EXT, 4, 4, 0, gl.RG, gl.UNSIGNED_BYTE, null);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RED_GREEN_RGTC2_EXT fails with texImage2D");
gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, 4, 4, 0, gl.RG, gl.BYTE, null);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT fails with texImage2D");
gl.deleteTexture(tex);
}
};
function runTest() {

View File

@ -0,0 +1,220 @@
<!--
Copyright (c) 2020 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">
<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>
<style>
.spinner {
width: 100px;
height: 100px;
border: 20px solid transparent;
border-top: 20px solid black;
border-radius: 100%;
text-align: center;
padding: 10px;
}
@keyframes rotation {
from { transorm: rotate(0); }
to { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div id="description"></div>
<button onclick='compileShaders()'>The spinners below should not stutter when you click this button.</button>
<div class="spinner" style="animation: rotation 2s infinite linear;">CSS</div>
<div class="spinner" id=spinner>JS</div>
<div id="console"></div>
<canvas id=canvas></canvas>
<script>
"use strict";
description("Test KHR_parallel_shader_compile");
function spinSpinner() {
let degrees = (performance.now() / 1000 / 2 % 1.) * 360;
spinner.style.transform = `rotate(${degrees}deg)`;
requestAnimationFrame(spinSpinner);
}
spinSpinner();
const wtu = WebGLTestUtils;
const gl = wtu.create3DContext();
const loseContext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_lose_context");
let counter = 0;
const vertexSource = (extra) => `
void main() {
vec4 result = vec4(0.${counter++});
${extra || ''}
gl_Position = result;
}`;
const fragmentSource = (extra) => `
precision highp float;
void main() {
vec4 result = vec4(0.${counter++});
${extra || ''}
gl_FragColor = result;
}`;
let vs = gl.createShader(gl.VERTEX_SHADER);
let fs = gl.createShader(gl.FRAGMENT_SHADER);
let program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
const COMPLETION_STATUS_KHR = 0x91B1;
gl.shaderSource(vs, vertexSource());
gl.compileShader(vs);
let status = gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
if (status !== null) testFailed('Extension disabled, status should be null');
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "extension disabled");
gl.shaderSource(fs, fragmentSource());
gl.compileShader(fs);
gl.linkProgram(program);
status = gl.getProgramParameter(program, COMPLETION_STATUS_KHR);
if (status !== null) testFailed('Extension disabled, status should be null');
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "extension disabled");
const ext = wtu.getExtensionWithKnownPrefixes(gl, "KHR_parallel_shader_compile");
let successfullyParsed = false;
let extraCode = '';
(async () => {
if (!ext) {
testPassed("No KHR_parallel_shader_compile support -- this is legal");
} else {
testPassed("Successfully enabled KHR_parallel_shader_compile extension");
shouldBe("ext.COMPLETION_STATUS_KHR", "0x91B1");
debug("Checking that status is a boolean.");
gl.shaderSource(vs, vertexSource());
gl.compileShader(vs);
let status = gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
if (status !== true && status !== false) testFailed("status should be a boolean");
gl.linkProgram(program);
status = gl.getProgramParameter(program, COMPLETION_STATUS_KHR);
if (status !== true && status !== false) testFailed("status should be a boolean");
const minimumShaderCompileDurationMs = 500;
debug(`Constructing shader that takes > ${minimumShaderCompileDurationMs} ms to compile.`);
let measuredCompileDuration = 0;
extraCode = '\n if (true) { result += vec4(0.0000001); }';
for (let i = 0; measuredCompileDuration < minimumShaderCompileDurationMs; i++) {
extraCode += extraCode;
extraCode += extraCode;
if (i < 4) continue;
gl.shaderSource(vs, vertexSource(extraCode));
gl.shaderSource(fs, fragmentSource(extraCode));
gl.compileShader(vs);
gl.compileShader(fs);
gl.linkProgram(program);
const start = performance.now();
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
testFailed(`Shaders failed to compile.
program: ${gl.getProgramInfoLog(program)}
vs: ${gl.getShaderInfoLog(vs)}
fs: ${gl.getShaderInfoLog(fs)}`);
break;
}
measuredCompileDuration = performance.now() - start;
}
debug('');
gl.shaderSource(vs, vertexSource(extraCode));
gl.shaderSource(fs, fragmentSource(extraCode));
gl.compileShader(vs);
gl.compileShader(fs);
gl.linkProgram(program);
let start = performance.now();
gl.getShaderParameter(fs, COMPLETION_STATUS_KHR);
gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
let duration = performance.now() - start;
if (duration > 100)
testFailed(`Querying shader status should not wait for compilation. Took ${duration} ms`);
let frames = 0;
const maximumTimeToWait = measuredCompileDuration * 4;
while (!gl.getProgramParameter(program, COMPLETION_STATUS_KHR)
&& performance.now() - start < maximumTimeToWait) {
frames++;
await new Promise(requestAnimationFrame);
}
duration = performance.now() - start;
if (!gl.getProgramParameter(program, COMPLETION_STATUS_KHR)) {
testFailed(`Program took longer than ${maximumTimeToWait} ms to compile. Expected: ${measuredCompileDuration} ms, actual: ${duration} ms`);
} else if (!gl.getShaderParameter(vs, COMPLETION_STATUS_KHR) || !gl.getShaderParameter(fs, COMPLETION_STATUS_KHR)) {
testFailed('Program linked before shaders finished compiling.');
} else if (frames <= 6) {
testFailed(`Program should have taken many more than 6 frames to compile. Actual value: ${frames} frames, duration ${performance.now() - start} ms.`);
} else {
console.log(`COMPLETION_STATUS_KHR sucessfully transitioned from false to true in ${frames} frames and ${duration} ms.`);
testPassed(`COMPLETION_STATUS_KHR sucessfully transitioned from false to true`);
}
debug("Checking that status is true when context is lost.");
if (loseContext) {
gl.shaderSource(vs, vertexSource(extraCode));
gl.shaderSource(fs, fragmentSource(extraCode));
gl.compileShader(vs);
gl.compileShader(fs);
gl.linkProgram(program);
loseContext.loseContext();
status = gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
if (status !== true) testFailed("shader status should be true when context is lost");
status = gl.getProgramParameter(program, COMPLETION_STATUS_KHR);
if (status !== true) testFailed("program status should be true when context is lost");
loseContext.restoreContext();
vs = gl.createShader(gl.VERTEX_SHADER);
fs = gl.createShader(gl.FRAGMENT_SHADER);
program = gl.createProgram();
}
}
finishTest();
})();
async function compileShaders() {
console.log('Compiling shaders');
const gl = canvas.getContext('webgl');
const vs = gl.createShader(gl.VERTEX_SHADER);
const fs = gl.createShader(gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.getExtension(wtu.getExtensionWithKnownPrefixes(gl, "KHR_parallel_shader_compile"));
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.shaderSource(vs, vertexSource(extraCode));
gl.shaderSource(fs, fragmentSource(extraCode));
gl.compileShader(vs);
gl.compileShader(fs);
gl.linkProgram(program);
while (!gl.getProgramParameter(program, COMPLETION_STATUS_KHR)) {
gl.getShaderParameter(vs, COMPLETION_STATUS_KHR);
gl.getShaderParameter(fs, COMPLETION_STATUS_KHR);
await new Promise(requestAnimationFrame);
}
gl.getProgramParameter(program, gl.LINK_STATUS);
console.log('Compilation finished.');
}
</script>
</body>
</html>

View File

@ -25,7 +25,7 @@ const wtu = WebGLTestUtils;
const gl = wtu.create3DContext();
(function() {
if (!(gl instanceof WebGL2RenderingContext)) {
if (!wtu.isWebGL2(gl)) {
if (!gl.getExtension("OES_texture_float")) {
testPassed("No OES_texture_float support -- this is legal");
return;

View File

@ -25,7 +25,7 @@ const wtu = WebGLTestUtils;
const gl = wtu.create3DContext();
(function() {
if (gl instanceof WebGL2RenderingContext)
if (wtu.isWebGL2(gl))
throw new Error("OES_texture_half_float_linear is core in WebGL 2.");
const ext = gl.getExtension("OES_texture_half_float");

View File

@ -12,7 +12,7 @@ found in the LICENSE.txt file.
<script src="../../js/js-test-pre.js"></script>
<script src="../../js/webgl-test-utils.js"></script>
<script src="../../js/tests/compressed-texture-utils.js"></script>
<title>WebGL WEBGL_compressed_texture_s3tc Conformance Tests</title>
<title>WebGL WEBGL_compressed_texture_s3tc and EXT_texture_compression_rgtc Conformance Tests</title>
<style>
img {
border: 1px solid black;
@ -35,7 +35,7 @@ img {
<div id="console"></div>
<script>
"use strict";
description("This test verifies the functionality of the WEBGL_compressed_texture_s3tc extension, if it is available.");
description("This test verifies the functionality of the WEBGL_compressed_texture_s3tc extension, if it is available. It also tests the related formats from the EXT_texture_compression_rgtc extension.");
debug("");
@ -130,6 +130,31 @@ var img_4x4_rgba_dxt5 = new Uint8Array([
0x00, 0xF8, 0xE0, 0x07, 0x1B, 0x5B, 0xAB, 0xFF
]);
// BC4 - just the alpha block from BC3 above, interpreted as the red channel.
// See http://www.reedbeta.com/blog/understanding-bcn-texture-compression-formats/#bc4
// for format details.
var img_4x4_r_bc4 = new Uint8Array([
0xFF, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
]);
// BC5 - Two BC3 alpha blocks, interpreted as the red and green channels.
var img_4x4_rg_bc5 = new Uint8Array([
0xFF, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
0x00, 0xFF, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
]);
// Signed BC4 - change endpoints to use full -1 to 1 range.
var img_4x4_signed_r_bc4 = new Uint8Array([
0x7F, 0x80, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
]);
// Signed BC5 - Two BC3 alpha blocks, interpreted as the red and green channels.
var img_4x4_signed_rg_bc5 = new Uint8Array([
0x7F, 0x80, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
0x80, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
]);
/*
8x8 block endpoints use half-intensity values (appear darker than 4x4)
*/
@ -151,6 +176,18 @@ var img_8x8_rgba_dxt5 = new Uint8Array([
0xff,0x69,0x00,0x00,0x00,0x01,0x10,0x00,0x0f,0x78,0xe0,0x03,0x11,0x10,0x15,0x00,
0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x03,0xef,0x00,0x11,0x10,0x15,0x00
]);
var img_8x8_r_bc4 = new Uint8Array([
0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
]);
var img_8x8_rg_bc5 = new Uint8Array([
0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
]);
var wtu = WebGLTestUtils;
var ctu = CompressedTextureUtils;
@ -159,6 +196,7 @@ var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas, {antialias: false});
var program = wtu.setupTexturedQuad(gl);
var ext = null;
var ext_rgtc = {};
var vao = null;
var validFormats = {
COMPRESSED_RGB_S3TC_DXT1_EXT : 0x83F0,
@ -188,6 +226,14 @@ if (!gl) {
wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_s3tc", true);
runTestExtension();
}
ext_rgtc = wtu.getExtensionWithKnownPrefixes(gl, "EXT_texture_compression_rgtc");
if (ext_rgtc) {
ext = ext || {};
// Make ctu.formatToString work for rgtc enums.
for (const name in ext_rgtc)
ext[name] = ext_rgtc[name];
runTestRGTC();
}
}
function expectedByteLength(width, height, format) {
@ -221,6 +267,145 @@ function runTestExtension() {
if (contextVersion >= 2) {
testDXT5_RGBA_PBO();
}
// Test TexImage validation on level dimensions combinations.
debug("");
debug("When level equals 0, width and height must be a multiple of 4.");
debug("When level is larger than 0, this constraint doesn't apply.");
ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
[
{ level: 0, width: 4, height: 3, expectation: gl.INVALID_OPERATION, message: "0: 4x3" },
{ level: 0, width: 3, height: 4, expectation: gl.INVALID_OPERATION, message: "0: 3x4" },
{ level: 0, width: 2, height: 2, expectation: gl.INVALID_OPERATION, message: "0: 2x2" },
{ level: 0, width: 4, height: 4, expectation: gl.NO_ERROR, message: "0: 4x4" },
{ level: 1, width: 2, height: 2, expectation: gl.NO_ERROR, message: "1: 2x2" },
{ level: 2, width: 1, height: 1, expectation: gl.NO_ERROR, message: "2: 1x1" },
]);
ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions, 16, 16,
[
{ xoffset: 0, yoffset: 0, width: 4, height: 3,
expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
{ xoffset: 0, yoffset: 0, width: 3, height: 4,
expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
{ xoffset: 1, yoffset: 0, width: 4, height: 4,
expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
{ xoffset: 0, yoffset: 1, width: 4, height: 4,
expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
{ xoffset: 12, yoffset: 12, width: 4, height: 4,
expectation: gl.NO_ERROR, message: "is valid" },
]);
if (contextVersion >= 2) {
debug("");
debug("Testing NPOT textures");
ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
[
{ level: 0, width: 0, height: 0, expectation: gl.NO_ERROR, message: "0: 0x0 is valid" },
{ level: 0, width: 1, height: 1, expectation: gl.INVALID_OPERATION, message: "0: 1x1 is invalid" },
{ level: 0, width: 2, height: 2, expectation: gl.INVALID_OPERATION, message: "0: 2x2 is invalid" },
{ level: 0, width: 3, height: 3, expectation: gl.INVALID_OPERATION, message: "0: 3x3 is invalid" },
{ level: 0, width: 10, height: 10, expectation: gl.INVALID_OPERATION, message: "0: 10x10 is invalid" },
{ level: 0, width: 11, height: 11, expectation: gl.INVALID_OPERATION, message: "0: 11x11 is invalid" },
{ level: 0, width: 11, height: 12, expectation: gl.INVALID_OPERATION, message: "0: 11x12 is invalid" },
{ level: 0, width: 12, height: 11, expectation: gl.INVALID_OPERATION, message: "0: 12x11 is invalid" },
{ level: 0, width: 12, height: 12, expectation: gl.NO_ERROR, message: "0: 12x12 is valid" },
{ level: 1, width: 0, height: 0, expectation: gl.NO_ERROR, message: "1: 0x0, is valid" },
{ level: 1, width: 3, height: 3, expectation: gl.INVALID_OPERATION, message: "1: 3x3, is invalid" },
{ level: 1, width: 5, height: 5, expectation: gl.INVALID_OPERATION, message: "1: 5x5, is invalid" },
{ level: 1, width: 5, height: 6, expectation: gl.INVALID_OPERATION, message: "1: 5x6, is invalid" },
{ level: 1, width: 6, height: 5, expectation: gl.INVALID_OPERATION, message: "1: 6x5, is invalid" },
{ level: 1, width: 6, height: 6, expectation: gl.NO_ERROR, message: "1: 6x6, is valid" },
{ level: 2, width: 0, height: 0, expectation: gl.NO_ERROR, message: "2: 0x0, is valid" },
{ level: 2, width: 3, height: 3, expectation: gl.NO_ERROR, message: "2: 3x3, is valid" },
{ level: 3, width: 1, height: 3, expectation: gl.NO_ERROR, message: "3: 1x3, is valid" },
{ level: 3, width: 1, height: 1, expectation: gl.NO_ERROR, message: "3: 1x1, is valid" },
]);
debug("");
debug("Testing partial updates");
ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions, 12, 12,
[
{ xoffset: 0, yoffset: 0, width: 4, height: 3,
expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
{ xoffset: 0, yoffset: 0, width: 3, height: 4,
expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
{ xoffset: 1, yoffset: 0, width: 4, height: 4,
expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
{ xoffset: 0, yoffset: 1, width: 4, height: 4,
expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
{ xoffset: 8, yoffset: 8, width: 4, height: 4,
expectation: gl.NO_ERROR, message: "is valid" },
]);
debug("");
debug("Testing immutable NPOT textures");
ctu.testTexStorageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
[
{ width: 12, height: 12, expectation: gl.NO_ERROR, message: "0: 12x12 is valid" },
{ width: 6, height: 6, expectation: gl.NO_ERROR, message: "1: 6x6, is valid" },
{ width: 3, height: 3, expectation: gl.NO_ERROR, message: "2: 3x3, is valid" },
{ width: 1, height: 1, expectation: gl.NO_ERROR, message: "3: 1x1, is valid" },
]);
}
}
function runTestRGTC() {
var tests = [
{ width: 4,
height: 4,
channels: 1,
data: img_4x4_r_bc4,
format: ext_rgtc.COMPRESSED_RED_RGTC1_EXT,
hasAlpha: false,
},
{ width: 4,
height: 4,
channels: 1,
data: img_4x4_signed_r_bc4,
format: ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT,
hasAlpha: false,
},
{ width: 4,
height: 4,
channels: 2,
data: img_4x4_rg_bc5,
format: ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT,
hasAlpha: false,
},
{ width: 4,
height: 4,
channels: 2,
data: img_4x4_signed_rg_bc5,
format: ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT,
hasAlpha: false,
},
{ width: 8,
height: 8,
channels: 2,
data: img_8x8_r_bc4,
format: ext_rgtc.COMPRESSED_RED_RGTC1_EXT,
hasAlpha: false,
subX0: 0,
subY0: 0,
subWidth: 4,
subHeight: 4,
subData: img_4x4_r_bc4,
},
{ width: 8,
height: 8,
channels: 2,
data: img_8x8_rg_bc5,
format: ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT,
hasAlpha: false,
subX0: 0,
subY0: 0,
subWidth: 4,
subHeight: 4,
subData: img_4x4_rg_bc5,
},
];
testDXTTextures(tests);
}
function testDXT1_RGB() {
@ -365,20 +550,29 @@ function uncompressDXTBlock(
}
return r;
}
var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT ||
format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
var colorOffset = srcOffset + (isDXT1 ? 0 : 8);
var color0 = make565(src, colorOffset + 0);
var color1 = make565(src, colorOffset + 2);
var c0gtc1 = color0 > color1 || !isDXT1;
var rgba0 = make8888From565(color0);
var rgba1 = make8888From565(color1);
var colors = [
rgba0,
rgba1,
c0gtc1 ? mix(2, rgba0, rgba1, 3) : mix(1, rgba0, rgba1, 2),
c0gtc1 ? mix(2, rgba1, rgba0, 3) : [0, 0, 0, 255]
];
var isBC45 = ext_rgtc &&
(format == ext_rgtc.COMPRESSED_RED_RGTC1_EXT ||
format == ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT ||
format == ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT ||
format == ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT);
if (!isBC45) {
var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT ||
format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
var colorOffset = srcOffset + (isDXT1 ? 0 : 8);
var color0 = make565(src, colorOffset + 0);
var color1 = make565(src, colorOffset + 2);
var c0gtc1 = color0 > color1 || !isDXT1;
var rgba0 = make8888From565(color0);
var rgba1 = make8888From565(color1);
var colors = [
rgba0,
rgba1,
c0gtc1 ? mix(2, rgba0, rgba1, 3) : mix(1, rgba0, rgba1, 2),
c0gtc1 ? mix(2, rgba1, rgba0, 3) : [0, 0, 0, 255]
];
}
const isSigned = ext_rgtc && (format == ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT || format == ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT);
const signedSrc = new Int8Array(src);
// yea I know there is a lot of math in this inner loop.
// so sue me.
@ -386,9 +580,57 @@ function uncompressDXTBlock(
var pixels = src[colorOffset + 4 + yy];
for (var xx = 0; xx < 4; ++xx) {
var dstOff = ((destY + yy) * destWidth + destX + xx) * 4;
var code = (pixels >> (xx * 2)) & 0x3;
var srcColor = colors[code];
if (!isBC45) {
var code = (pixels >> (xx * 2)) & 0x3;
var srcColor = colors[code];
}
var alpha;
var rgChannel2 = 0;
let decodeAlpha = (offset) => {
let alpha;
var alpha0 = (isSigned ? signedSrc : src)[offset + 0];
var alpha1 = (isSigned ? signedSrc : src)[offset + 1];
var alphaOff = (yy >> 1) * 3 + 2;
var alphaBits =
src[offset + alphaOff + 0] +
src[offset + alphaOff + 1] * 256 +
src[offset + alphaOff + 2] * 65536;
var alphaShift = (yy % 2) * 12 + xx * 3;
var alphaCode = (alphaBits >> alphaShift) & 0x7;
if (alpha0 > alpha1) {
switch (alphaCode) {
case 0:
alpha = alpha0;
break;
case 1:
alpha = alpha1;
break;
default:
alpha = Math.floor(((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7.0 + 0.5);
break;
}
} else {
switch (alphaCode) {
case 0:
alpha = alpha0;
break;
case 1:
alpha = alpha1;
break;
case 6:
alpha = 0;
break;
case 7:
alpha = 255;
break;
default:
alpha = Math.floor(((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5.0 + 0.5);
break;
}
}
return alpha;
}
switch (format) {
case ext.COMPRESSED_RGB_S3TC_DXT1_EXT:
alpha = 255;
@ -403,57 +645,33 @@ function uncompressDXTBlock(
alpha = alpha1 | (alpha1 << 4);
}
break;
case ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT:
case ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
rgChannel2 = decodeAlpha(srcOffset + 8);
// FALLTHROUGH
case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT:
{
var alpha0 = src[srcOffset + 0];
var alpha1 = src[srcOffset + 1];
var alphaOff = (yy >> 1) * 3 + 2;
var alphaBits =
src[srcOffset + alphaOff + 0] +
src[srcOffset + alphaOff + 1] * 256 +
src[srcOffset + alphaOff + 2] * 65536;
var alphaShift = (yy % 2) * 12 + xx * 3;
var alphaCode = (alphaBits >> alphaShift) & 0x7;
if (alpha0 > alpha1) {
switch (alphaCode) {
case 0:
alpha = alpha0;
break;
case 1:
alpha = alpha1;
break;
default:
alpha = Math.floor(((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7.0 + 0.5);
break;
}
} else {
switch (alphaCode) {
case 0:
alpha = alpha0;
break;
case 1:
alpha = alpha1;
break;
case 6:
alpha = 0;
break;
case 7:
alpha = 255;
break;
default:
alpha = Math.floor(((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5.0 + 0.5);
break;
}
}
}
case ext_rgtc.COMPRESSED_RED_RGTC1_EXT:
case ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT:
alpha = decodeAlpha(srcOffset);
break;
default:
throw "bad format";
}
destBuffer[dstOff + 0] = srcColor[0];
destBuffer[dstOff + 1] = srcColor[1];
destBuffer[dstOff + 2] = srcColor[2];
destBuffer[dstOff + 3] = alpha;
if (isBC45) {
destBuffer[dstOff + 0] = alpha;
destBuffer[dstOff + 1] = rgChannel2;
destBuffer[dstOff + 2] = 0;
destBuffer[dstOff + 3] = 255;
if (isSigned) {
destBuffer[dstOff + 0] = Math.max(0, alpha) * 2;
destBuffer[dstOff + 1] = Math.max(0, rgChannel2) * 2;
}
} else {
destBuffer[dstOff + 0] = srcColor[0];
destBuffer[dstOff + 1] = srcColor[1];
destBuffer[dstOff + 2] = srcColor[2];
destBuffer[dstOff + 3] = alpha;
}
}
}
}
@ -461,7 +679,8 @@ function uncompressDXTBlock(
function getBlockSize(format) {
var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT ||
format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
return isDXT1 ? 8 : 16;
var isBC4 = ext_rgtc && (format == ext_rgtc.COMPRESSED_RED_RGTC1_EXT || format == ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT);
return isDXT1 || isBC4 ? 8 : 16;
}
function uncompressDXT(width, height, data, format) {
@ -487,8 +706,10 @@ function uncompressDXTIntoSubRegion(width, height, subX0, subY0, subWidth, subHe
throw "bad dimension";
var dest = new Uint8Array(width * height * 4);
// Zero-filled DXT1 texture represents [0, 0, 0, 255]
if (format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT || format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT) {
// Zero-filled DXT1 or BC4/5 texture represents [0, 0, 0, 255]
if (format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT || format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT ||
format == ext.COMPRESSED_RED_RGTC1_EXT || format == ext.COMPRESSED_SIGNED_RED_RGTC1_EXT ||
format == ext.COMPRESSED_RED_GREEN_RGTC2_EXT || format == ext.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT) {
for (var i = 3; i < dest.length; i += 4) dest[i] = 255;
}
var blocksAcross = subWidth / 4;
@ -612,14 +833,16 @@ function testDXTTexture(test, useTexStorage) {
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
if (width == 4) {
// The width/height of the implied base level must be a multiple of the block size.
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 1, height, 0, data);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level 1");
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level > 0");
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 2, height, 0, data);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
}
if (height == 4) {
// The width/height of the implied base level must be a multiple of the block size.
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 1, 0, data);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level 1");
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level > 0");
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 2, 0, data);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
}
@ -640,6 +863,14 @@ function testDXTTexture(test, useTexStorage) {
case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT:
wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT;
break;
case ext_rgtc.COMPRESSED_RED_RGTC1_EXT:
case ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT:
wrongFormat = ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT;
break;
case ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT:
case ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
wrongFormat = ext_rgtc.COMPRESSED_RED_RGTC1_EXT;
break;
}
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, wrongFormat, data);

View File

@ -252,7 +252,7 @@ function testPVRTCTexture(test) {
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
gl.generateMipmap(gl.TEXTURE_2D);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture");
wtu.drawQuad(gl);
wtu.clearAndDrawUnitQuad(gl);
compareRect(width, height, test.channels, width, height, uncompressedData, data, format, undefined, "NEAREST");
// Test again with linear filtering.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

View File

@ -226,6 +226,72 @@ function runTestExtension() {
if (contextVersion >= 2) {
testDXT5_SRGB_ALPHA_PBO();
}
// Test TexImage validation on level dimensions combinations.
debug("");
debug("When level equals 0, width and height must be a multiple of 4.");
debug("When level is larger than 0, this constraint doesn't apply.");
ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
[
{ level: 0, width: 4, height: 3, expectation: gl.INVALID_OPERATION, message: "0: 4x3" },
{ level: 0, width: 3, height: 4, expectation: gl.INVALID_OPERATION, message: "0: 3x4" },
{ level: 0, width: 2, height: 2, expectation: gl.INVALID_OPERATION, message: "0: 2x2" },
{ level: 0, width: 4, height: 4, expectation: gl.NO_ERROR, message: "0: 4x4" },
{ level: 1, width: 2, height: 2, expectation: gl.NO_ERROR, message: "1: 2x2" },
{ level: 2, width: 1, height: 1, expectation: gl.NO_ERROR, message: "2: 1x1" },
]);
ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions, 16, 16,
[
{ xoffset: 0, yoffset: 0, width: 4, height: 3,
expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
{ xoffset: 0, yoffset: 0, width: 3, height: 4,
expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
{ xoffset: 1, yoffset: 0, width: 4, height: 4,
expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
{ xoffset: 0, yoffset: 1, width: 4, height: 4,
expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
{ xoffset: 12, yoffset: 12, width: 4, height: 4,
expectation: gl.NO_ERROR, message: "is valid" },
]);
if (contextVersion >= 2) {
debug("");
debug("Testing NPOT textures");
ctu.testTexImageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
[
{ level: 0, width: 12, height: 12, expectation: gl.NO_ERROR, message: "0: 12x12 is valid" },
{ level: 1, width: 6, height: 6, expectation: gl.NO_ERROR, message: "1: 6x6, is valid" },
{ level: 2, width: 3, height: 3, expectation: gl.NO_ERROR, message: "2: 3x3, is valid" },
{ level: 3, width: 1, height: 1, expectation: gl.NO_ERROR, message: "3: 1x1, is valid" },
]);
debug("");
debug("Testing partial updates");
ctu.testTexSubImageDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions, 12, 12,
[
{ xoffset: 0, yoffset: 0, width: 4, height: 3,
expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
{ xoffset: 0, yoffset: 0, width: 3, height: 4,
expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
{ xoffset: 1, yoffset: 0, width: 4, height: 4,
expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
{ xoffset: 0, yoffset: 1, width: 4, height: 4,
expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
{ xoffset: 8, yoffset: 8, width: 4, height: 4,
expectation: gl.NO_ERROR, message: "is valid" },
]);
debug("");
debug("Testing immutable NPOT textures");
ctu.testTexStorageLevelDimensions(gl, ext, validFormats, expectedByteLength, getBlockDimensions,
[
{ width: 12, height: 12, expectation: gl.NO_ERROR, message: "0: 12x12 is valid" },
{ width: 6, height: 6, expectation: gl.NO_ERROR, message: "1: 6x6, is valid" },
{ width: 3, height: 3, expectation: gl.NO_ERROR, message: "2: 3x3, is valid" },
{ width: 1, height: 1, expectation: gl.NO_ERROR, message: "3: 1x1, is valid" },
]);
}
}
function testDXT1_SRGB() {
@ -617,14 +683,16 @@ function testDXTTexture(test, useTexStorage) {
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
if (width == 4) {
// The width/height of the implied base level must be a multiple of the block size.
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 1, height, 0, data);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level 1");
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level > 0");
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 2, height, 0, data);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
}
if (height == 4) {
// The width/height of the implied base level must be a multiple of the block size.
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 1, 0, data);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level 1");
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions for level > 0");
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 2, 0, data);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
}

View File

@ -146,6 +146,7 @@ const wtu = WebGLTestUtils;
const canvas = document.getElementById("canvas");
const gl = wtu.create3DContext(canvas);
const instancedExt = gl && gl.getExtension('ANGLE_instanced_arrays');
const bufferUsageSet = [ gl.STATIC_DRAW, gl.DYNAMIC_DRAW ];
// Check if the extension is either both enabled and supported or
// not enabled and not supported.
@ -187,18 +188,18 @@ function runTest() {
function doTest(ext, instanced) {
function runValidationTests() {
function runValidationTests(bufferUsage) {
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0.2,0.2, 0.8,0.2, 0.5,0.8 ]), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0.2,0.2, 0.8,0.2, 0.5,0.8 ]), bufferUsage);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([ 0, 1, 2, 0]), gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([ 0, 1, 2, 0]), bufferUsage);
const instanceBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0, 1, 2, 3 ]), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0, 1, 2, 3 ]), bufferUsage);
const program = wtu.setupProgram(gl, ["vshaderNoDrawID", "fshader"], ["vPosition", "vInstance"], [0, 1]);
expectTrue(program != null, "can compile simple program");
@ -354,7 +355,7 @@ function doTest(ext, instanced) {
}
}
function runShaderTests() {
function runShaderTests(bufferUsage) {
const illegalProgram = wtu.setupProgram(gl, ["vshaderIllegalDrawID", "fshader"], ["vPosition"], [0]);
expectTrue(illegalProgram == null, "cannot compile program with gl_DrawID but no extension directive");
@ -363,14 +364,14 @@ function doTest(ext, instanced) {
expectTrue(drawIDProgram !== null, "can compile program with gl_DrawID");
gl.useProgram(drawIDProgram);
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0,1, 0,1, 1,0, 1,1 ]), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0,1, 0,1, 1,0, 1,1 ]), bufferUsage);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
wtu.checkCanvas(gl, [0, 255, 0, 255], "gl_DrawID is 0 for non-Multi* draw calls", 0);
}
function runPixelTests() {
function runPixelTests(bufferUsage, useSharedArrayBuffer) {
// An array of quads is tiled across the screen.
// gl_DrawID is checked by using it to select the color of the draw.
// Instanced entrypoints are tested here scaling and then instancing the
@ -438,16 +439,16 @@ function doTest(ext, instanced) {
const instanceBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, nonIndexedVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, nonIndexedVertices, gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, nonIndexedVertices, bufferUsage);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, vertices, bufferUsage);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, bufferUsage);
gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 2, 3, 4]), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 2, 3, 4]), bufferUsage);
function checkResult(config, msg) {
const rects = [];
@ -505,10 +506,18 @@ function doTest(ext, instanced) {
wtu.checkCanvasRects(gl, rects);
}
const firsts = new Uint32Array(tri_count);
const counts = new Uint32Array(tri_count);
const offsets = new Uint32Array(tri_count);
const instances = new Uint32Array(tri_count);
function newIntArray(count) {
if (!useSharedArrayBuffer) {
return new Int32Array(count);
}
let sab = new SharedArrayBuffer(count * Int32Array.BYTES_PER_ELEMENT);
return new Int32Array(sab);
}
const firsts = newIntArray(tri_count);
const counts = newIntArray(tri_count);
const offsets = newIntArray(tri_count);
const instances = newIntArray(tri_count);
for (let i = 0; i < firsts.length; ++i) firsts[i] = i * 3;
counts.fill(3);
@ -520,7 +529,7 @@ function doTest(ext, instanced) {
const offsetsOffset = countsOffset + counts.length;
const instancesOffset = offsetsOffset + instances.length;
const buffer = new Uint32Array(firstsOffset + firsts.length + counts.length + offsets.length + instances.length);
const buffer = newIntArray(firstsOffset + firsts.length + counts.length + offsets.length + instances.length);
buffer.set(firsts, firstsOffset);
buffer.set(counts, countsOffset);
buffer.set(offsets, offsetsOffset);
@ -663,6 +672,8 @@ function doTest(ext, instanced) {
config.instanced ? ' instanced' : ''
) + (
config.drawID ? ' with gl_DrawID' : ''
) + (
useSharedArrayBuffer ? ' and SharedArrayBuffer' : ''
));
gl.disableVertexAttribArray(0);
@ -821,9 +832,18 @@ function doTest(ext, instanced) {
}
}
runValidationTests();
runShaderTests();
runPixelTests();
for (let i = 0; i < bufferUsageSet.length; i++) {
let bufferUsage = bufferUsageSet[i];
debug("Testing with BufferUsage = " + bufferUsage);
runValidationTests(bufferUsage);
runShaderTests(bufferUsage);
runPixelTests(bufferUsage, false);
}
// Run a subset of the pixel tests with SharedArrayBuffer if supported.
if (window.SharedArrayBuffer) {
runPixelTests(bufferUsageSet[0], true);
}
}
runTest();

View File

@ -0,0 +1,211 @@
<!--
Copyright (c) 2021 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">
<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>
<script src="../../js/tests/out-of-bounds-test.js"></script>
<script src="../../../../extensions/proposals/WEBGL_webcodecs_video_frame/webgl_webcodecs_video_frame.js"></script>
<style>
canvas {
padding: 10px;
background: gold;
}
button {
background-color: #555555;
border: none;
color: white;
padding: 15px 32px;
width: 150px;
text-align: center;
display: block;
font-size: 16px;
}
</style>
</head>
<body>
<canvas id="src" width="640" height="480"></canvas>
<canvas id="dst" width="640" height="480"></canvas>
<p id="info"></p>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
description("Test of importing Videoframe from Webcodecs to Webgl");
const kIsRunningTest = true;
const kMaxFrame = 10;
const kTestPixel = [255, 128, 0, 255];
// Sum of pixel difference of R/G/B channel. Use to decide whether a
// pixel is matched with another.
const codec_string = "vp09.00.51.08.00";
let wtu = WebGLTestUtils;
let cnv = document.getElementById("src");
let src_width = cnv.width;
let src_height = cnv.height;
let src_color = "rgba(" + kTestPixel[0].toString() + "," + kTestPixel[1].toString() + ","
+ kTestPixel[2].toString() + "," + kTestPixel[3].toString() + ")";
let frame_counter = 0;
let pixelCompareTolerance = 5;
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) { return pair[1]; }
}
return false;
}
let th = parseInt(getQueryVariable('threshold'));
if (!isNaN(th))
pixelCompareTolerance = th;
async function startDrawing() {
let cnv = document.getElementById("src");
var ctx = cnv.getContext('2d', { alpha: false });
ctx.fillStyle = src_color;
let drawOneFrame = function (time) {
ctx.fillStyle = src_color;
ctx.fillRect(0, 0, src_width, src_height);
window.requestAnimationFrame(drawOneFrame);
}
window.requestAnimationFrame(drawOneFrame);
}
function captureAndEncode(processChunk) {
let cnv = document.getElementById("src");
let fps = 60;
let pending_outputs = 0;
let stream = cnv.captureStream(fps);
let processor = new MediaStreamTrackProcessor(stream.getVideoTracks()[0]);
const init = {
output: (chunk) => {
testPassed("Encode frame successfully.");
pending_outputs--;
processChunk(chunk);
},
error: (e) => {
testFailed("Failed to encode frame.");
finishTest();
vtr.stop();
}
};
const config = {
codec: codec_string,
width: cnv.width,
height: cnv.height,
bitrate: 10e6,
framerate: fps,
};
let encoder = new VideoEncoder(init);
encoder.configure(config);
const frame_reader = processor.readable.getReader();
frame_reader.read().then(function processFrame({done, value}) {
if (done)
return;
if (pending_outputs > 30) {
console.log("drop this frame");
// Too many frames in flight, encoder is overwhelmed
// let's drop this frame.
value.close();
frame_reader.read().then(processFrame);
return;
}
if(frame_counter == kMaxFrame) {
frame_reader.releaseLock();
processor.readable.cancel();
value.close();
return;
}
frame_counter++;
pending_outputs++;
const insert_keyframe = (frame_counter % 150) == 0;
encoder.encode(value, { keyFrame: insert_keyframe });
frame_reader.read().then(processFrame);
});
}
function startDecodingAndRendering(cnv, handleFrame) {
const init = {
output: handleFrame,
error: (e) => {
testFailed("Failed to decode frame.");
finishTest();
}
};
const config = {
codec: codec_string,
codedWidth: cnv.width,
codedHeight: cnv.height,
acceleration: "deny",
};
let decoder = new VideoDecoder(init);
decoder.configure(config);
return decoder;
}
function isFramePixelMatched(gl, th_per_pixel = pixelCompareTolerance) {
WebGLTestUtils.checkCanvasRect(gl, 0, 0, src_width, src_width, kTestPixel, "should be orange", pixelCompareTolerance)
}
function main() {
if (!("VideoEncoder" in window)) {
testPassed("WebCodecs API is not supported.");
finishTest();
return;
}
let cnv = document.getElementById("dst");
let webgl_webcodecs_test_context = {
maxFrameTested: kMaxFrame,
displayed_frame: 0,
isFramePixelMatched: isFramePixelMatched,
testFailed: testFailed,
testPassed: testPassed,
finishTest: finishTest
};
setTestMode(webgl_webcodecs_test_context);
let handleFrame = requestWebGLVideoFrameHandler(cnv);
if (handleFrame === null) {
finishTest();
return;
}
startDrawing();
let decoder = startDecodingAndRendering(cnv, handleFrame);
captureAndEncode((chunk) => {
decoder.decode(chunk);
});
}
document.body.onload = main;
</script>
</body>
</html>

View File

@ -5,6 +5,7 @@
--min-version 1.0.3 array-of-struct-with-int-first-position.html
--min-version 1.0.4 assign-to-swizzled-twice-in-function.html
--min-version 1.0.4 bool-type-cast-bug-int-float.html
--min-version 1.0.4 character-set.html
--min-version 1.0.3 compare-loop-index-to-uniform.html
--min-version 1.0.3 complex-glsl-does-not-crash.html
--min-version 1.0.4 compound-assignment-type-combination.html
@ -46,5 +47,6 @@
--min-version 1.0.4 undefined-index-should-not-crash.html
--min-version 1.0.3 uniforms-should-not-lose-values.html
--min-version 1.0.4 varying-arrays-should-not-be-reversed.html
--min-version 1.0.4 vector-matrix-constructor-scalarization.html
--min-version 1.0.4 vector-scalar-arithmetic-inside-loop.html
--min-version 1.0.4 vector-scalar-arithmetic-inside-loop-complex.html
--min-version 1.0.4 vector-scalar-arithmetic-inside-loop-complex.html

View File

@ -54,7 +54,7 @@ if (!gl) {
debug("");
debug("Checking shader compilation and linking.");
checkCompilation()
checkCompilation();
}
function checkCompilation() {

View File

@ -0,0 +1,115 @@
<!--
Copyright (c) 2020 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>Character Set</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>
<script src="../../../js/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="canvas" width="2" height="2"> </canvas>
<script>
"use strict";
// See http://crbug.com/1108588 for original failing case.
// Check "OpenGL Registry The OpenGL ES Shading Language"
// Section 3.2 Character Sets For more info
description("This test checks character set validation for glsl.");
debug("");
debug("Canvas.getContext");
let wtu = WebGLTestUtils;
let gl = wtu.create3DContext("canvas");
let consoleDiv = document.getElementById("console");
if (!gl) {
testFailed("context does not exist");
} else {
testPassed("context exists");
debug("");
debug("Checking shader character set validation and compilation");
runTest();
}
function testShaderSource(shaderSource, msg) {
if (!quietMode()) {
wtu.addShaderSource(consoleDiv, "test fragment shader", shaderSource);
}
let shader = gl.createShader(gl.FRAGMENT_SHADER);
if (shader == null) {
testFailed("*** Error: unable to create shader '" + shaderSource + "'");
return;
}
gl.shaderSource(shader, shaderSource);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, msg);
}
function MUST(ifTruthy) {
return ifTruthy ? 'MUST' : 'MUST NOT';
}
function runTest() {
const BAD_STRINGS = [
'$',
'"',
'一些注释',
'#line 42 "foo.glsl"',
];
const TESTS = [
['in identifier', s => s, false],
['in comment', s => `// ${s}`, true, true],
['in ifdef-out', s => `#if 0 \n${s} \n#endif`, true],
['in ifdef-out #preproc', s => `#if 0 \n#${s} \n#endif`, true],
['in #preproc', s => `#${s}`, false],
['in comment after #define', s => `#define TEST // ${s}`, true], // Regression test for crbug.com/940865
];
const glsl_tests = [];
for (const s of BAD_STRINGS) {
for (const [where, template, validCompile] of TESTS) {
const st = template(s);
const src = `
precision mediump float;
${st}
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}`.trim();
testShaderSource(src, `shaderSource allows Out-of-charset string '${s}' ${where} until compilation.`);
glsl_tests.push(
{
fShaderSource: src,
fShaderSuccess: validCompile,
linkSuccess: validCompile,
passMsg: `Out-of-charset string '${s}' ${where} ${MUST(validCompile)} compile.`
}
);
}
}
GLSLConformanceTester.runTests(glsl_tests);
}
debug("");
var successfullyParsed = true;
</script>
</body>
</html>

View File

@ -0,0 +1,181 @@
<!--
Copyright (c) 2021 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></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>
<!--
Original Shadertoy:
https://www.shadertoy.com/view/ttGyzh
float a = 0.; // bug
#define A 0. // ok
//#define A min(0.,iTime) // bug
#define r(a) mat2( cos( a + vec4(0,-1.5708,1.5708,0) ) ) // bug
//#define r(a) mat2( cos(a), -sin(a), sin(a), cos(a) ) // no bug
//#define r(a) cos(a),sin(a)) // no bug ( vec instead of mat )
//#define r(a) cos(a+vec2(0,-1.5708)) // no bug ( vec instead of mat )
vec2 c;
#define f(U,a) ( c = (U) * r(a) , sin(10.*c.x) )
void mainImage( out vec4 O, vec2 U )
{
U /= iResolution.xy;
O = U.y > .5
? vec4( f(U,a) , f(U*4.,a) , 0,0) // top
: vec4( f(U,A) , f(U*4.,A) , 0,0); // bottom
}
-->
<script id="vshader" type="x-shader/x-vertex">
attribute vec2 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main(void) {
gl_Position = vec4(aPosition, 0.0, 1.0);
vTexCoord = aTexCoord;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTexCoord;
float a = 0.;
#define A 0.
#define r(a) mat2( cos( a + vec4(0,-1.5708,1.5708,0) ) )
vec2 c;
#define f(U,a) ( c = (U) * r(a) , sin(10.*c.x) )
void main() {
vec2 U = vTexCoord;
gl_FragColor = U.y > .5
? vec4( f(U,a) , f(U*4.,a) , 0,1.0) // top
: vec4( f(U,A) , f(U*4.,A) , 0,1.0); // bottom
}
</script>
<script id="compileVShader" type="x-shader/x-vertex">
varying vec2 v_texcoord;
void main() {
v_texcoord = vec2(0.0, 0.0);
gl_Position = vec4(1.0, 0.0, 0.0, 1.0);
}
</script>
<script id="compileFShader" type="x-shader/x-fragment">
// From http://crbug.com/398694
precision mediump float;
uniform sampler2D s_texture;
uniform vec4 color_weights;
varying vec2 v_texcoord;
void main() {
gl_FragColor = color_weights * mat4(
vec4(texture2D(s_texture, v_texcoord).rgb, 1.0),
vec4(texture2D(s_texture, v_texcoord).rgb, 1.0),
vec4(texture2D(s_texture, v_texcoord).rgb, 1.0),
vec4(texture2D(s_texture, v_texcoord).rgb, 1.0));
}
</script>
</head>
<body>
<canvas id="example"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
debug("");
description("Vector and matrix constructor scalarization workaround (SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS) caused bugs");
debug('Regression test for <a href="http://crbug.com/1165751">crbug.com/1165751</a>');
// Note: Firefox reports that without this workaround, there are
// failures on at least Windows / Intel GPU / OpenGL on:
// conformance/glsl/constructors/glsl-construct-mat2.html
// https://searchfox.org/mozilla-central/source/dom/canvas/WebGLShaderValidator.cpp#63
// Chromium reported that
// conformance/glsl/misc/shader-struct-scope.html failed on macOS and
// on Linux AMD without this workaround enabled:
// http://crbug.com/angleproject/701
const wtu = WebGLTestUtils;
const canvas = document.getElementById("example");
const sz = canvas.width = canvas.height = 256;
const gl = wtu.create3DContext(canvas, undefined);
if (!gl) {
testFailed("WebGL context creation failed");
finishTest();
} else {
testPassed("WebGL context creation succeeded");
runDrawTest();
runCompileTest();
finishTest();
}
function runDrawTest() {
debug("Ensure that shader translation isn't broken by the vector and matrix constructor scalarization workaround");
let positionLocation = 0;
let texCoordLocation = 1;
wtu.setupUnitQuad(gl, positionLocation, texCoordLocation);
let program = wtu.setupProgram(gl, ["vshader", "fshader"],
["aPosition", "aTexCoord"],
[positionLocation, texCoordLocation], true);
if (!program) {
testFailed("Error compiling shaders");
return;
}
gl.useProgram(program);
// Buffers returned from setupQuad above, and ignored, are already bound.
wtu.drawUnitQuad(gl);
// Top and bottom halves should be roughly equal. Go through one
// horizontal scanline in the middle.
const compareHeight = sz / 4;
let pixelValue = new Uint8Array(4);
let allEqual = true;
// Empirically found that tolerance between the top and bottom
// needs to be up to roughly 8 on some platforms.
const tolerance = 8;
let tempBuf = new Uint8Array(4);
// Step over some pixels to spew slightly fewer comparison messages.
for (let x = 0; x < sz; x += 4) {
gl.readPixels(x, compareHeight, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixelValue);
wtu.checkCanvasRect(gl, x, sz - compareHeight, 1, 1, pixelValue, undefined, tolerance, tempBuf);
}
}
function runCompileTest() {
debug("Running compilation test");
let program = wtu.setupProgram(gl, ["compileVShader", "compileFShader"], [], [], true);
if (program) {
testPassed("Shader previously requiring SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS compiled successfully");
} else {
testFailed("Shader previously requiring SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS failed to compile");
}
}
</script>
</body>
</html>

View File

@ -49,6 +49,5 @@ void main()
GLSLConformanceTester.runRenderTest();
var successfullyParsed = true;
</script>
<script src="../../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -38,7 +38,6 @@ shader-with-clipvertex.vert.html
--min-version 1.0.2 shader-with-conditional-scoping-negative.html
shader-with-default-precision.frag.html
shader-with-default-precision.vert.html
--max-version 1.9.9 shader-with-define-line-continuation.frag.html
shader-with-dfdx-no-ext.frag.html
shader-with-dfdx.frag.html
--min-version 1.0.2 shader-with-do-loop.html

View File

@ -18,20 +18,35 @@ found in the LICENSE.txt file.
<body>
<div id="description"></div>
<div id="console"></div>
<script id="vertexShader" type="text/something-not-javascript">
// Non ascii comments in source should succeed
// これはASCIIではないです。
//    
/*
*    
*/
#define TEST 1 // <20>スs<EFBDBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ス@<40>スh<EFBDBD><EFBFBD><EFBFBD>ス@<40>スm<EFBDBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ス@<40>ス`<60>スr<EFBDBD>スb<EFBDBD>スh<EFBDBD>スh
void main() {
gl_Position = vec4(1,1,1,1); // <20>スs<EFBDBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ス@<40>スh<EFBDBD><EFBFBD><EFBFBD>ス@<40>スm<EFBDBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ス@<40>ス`<60>スr<EFBDBD>スb<EFBDBD>スh<EFBDBD>スh
} // <20>スs<EFBDBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ス@<40>スh<EFBDBD><EFBFBD><EFBFBD>ス@<40>スm<EFBDBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ス@<40>ス`<60>スr<EFBDBD>スb<EFBDBD>スh<EFBDBD>スh
<script id="vertexShader" type="text/plain">
Loading...
</script>
<script>
"use strict";
// Via `[].map.call(str, x => x.codePointAt(0));`
let a = [12371,12428,12399,65313,65331,65315,65321,65321,12391,12399,12394,12356,12391,12377,12290];
let b = [65332,65352,65353,65363,12288,65321,65363,12288,65326,65359,65364,12288,65313,65331,65315,65321,65321];
a = String.fromCodePoint(...a);
b = String.fromCodePoint(...b);
// -
vertexShader.textContent = `
// Non ascii comments in source should succeed
// ${a}
// ${b}
/*
* ${b}
*/
#define TEST 1 // ${b}
void main() {
gl_Position = vec4(1,1,1,1); // ${b}
} // ${b}
`;
// -
GLSLConformanceTester.runTest();
var successfullyParsed = true;
</script>

View File

@ -18,18 +18,35 @@ found in the LICENSE.txt file.
<body>
<div id="description"></div>
<div id="console"></div>
<script id="vertexShader" type="text/something-not-javascript">
// Non ascii data in source should fail
// See GLSL ES Spec 1.0.17 section 3.1 and 3.2
// これはASCIIではないです。
//    
uniform mat4 ;
void main() {
gl_Position = vec4(1,1,1,1);
}
<script id="vertexShader" type="text/plain">
Loading...
</script>
<script>
"use strict";
// Via `[].map.call(str, x => x.codePointAt(0));`
let a = [12371,12428,12399,65313,65331,65315,65321,65321,12391,12399,12394,12356,12391,12377,12290];
let b = [65332,65352,65353,65363,12288,65321,65363,12288,65326,65359,65364,12288,65313,65331,65315,65321,65321];
let c = [65326,65359,65364,65313,65331,65315,65321,65321];
a = String.fromCodePoint(...a);
b = String.fromCodePoint(...b);
c = String.fromCodePoint(...c);
// -
vertexShader.textContent = `
// Non ascii data in source should fail
// See GLSL ES Spec 1.0.17 section 3.1 and 3.2
// ${a}
// ${b}
uniform mat4 ${c};
void main() {
gl_Position = vec4(1,1,1,1);
}
`;
// -
GLSLConformanceTester.runTest();
var successfullyParsed = true;
</script>

View File

@ -1,37 +0,0 @@
<!--
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 GLSL Conformance Tests</title>
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<link rel="stylesheet" href="../../../resources/glsl-feature-tests.css"/>
<script src="../../../js/js-test-pre.js"></script>
<script src="../../../js/webgl-test-utils.js"></script>
<script src="../../../js/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="fragmentShader" type="text/something-not-javascript">
// fragment shader that uses line continuation macro should fail
#define foo this \
is a test
precision mediump float;
void main()
{
gl_FragColor = vec4(0.0,0.0,0.0,1.0);
}
</script>
<script>
"use strict";
GLSLConformanceTester.runTest();
var successfullyParsed = true;
</script>
</body>
</html>

View File

@ -39,7 +39,13 @@ void main()
"use strict";
/*
GLSL 1.017 section 4.2.6
This test previously concluded that an attribute in a vertex shader
would conflict across shaders with a uniform of the same name in the
fragment shader, based on the following sections of the GLSL ES 1.0.17
specification:
---
Section 4.2.6
...
@ -56,16 +62,15 @@ Attribute variables are required to have global scope
Section 4.3.4
The uniform qualifier is used to declare global variables
---
QED: If both uniforms and attributes are in the global namespace they
conflict across shaders
GLSL ES 3.00 later confirmed that pipeline stages have distinct
namespaces. The OpenGL ES working group confirmed in discussions
https://github.com/KhronosGroup/WebGL/issues/3201 that this was the
intended behavior for GLSL ES 1.00.
Note: This was brought up on the OpenGL ES working group and confirmed
that the spec required these conflicts to fail to link.
Though most drivers allow this to work, some drivers to do no therefore
WebGL implementation must enforce this restriction to provide consistent
behavior.
For this reason, this test asserts that such usage does not generate a
conflict.
*/
GLSLConformanceTester.runTests([
@ -73,8 +78,8 @@ GLSLConformanceTester.runTests([
vShaderSuccess: true,
fShaderId: 'fragmentShader',
fShaderSuccess: true,
linkSuccess: false,
passMsg: 'shaders with conflicting uniform/attribute names should fail'
linkSuccess: true,
passMsg: 'using the same name for a vertex shader attribute and fragment shader uniform should succeed'
},
]);
var successfullyParsed = true;

View File

@ -126,12 +126,15 @@ for (var i = 0; i < invalidSet.length; ++i) {
// Backslash as line-continuation is allowed in WebGL 2.0.
if (contextVersion > 1 && invalidSet[i] == '\\')
continue;
// With recent specification changes from
// https://github.com/KhronosGroup/WebGL/pull/3206 , shaderSource no
// longer generates INVALID_VALUE.
var validShaderSource = generateShaderSource(undefined, invalidSet[i]);
context.shaderSource(vShader, validShaderSource);
shouldBe("context.getError()", "context.NO_ERROR");
var invalidShaderSource = generateShaderSource(invalidSet[i], undefined);
context.shaderSource(vShader, invalidShaderSource);
shouldBe("context.getError()", "context.INVALID_VALUE");
shouldBe("context.getError()", "context.NO_ERROR");
}
debug("");

View File

@ -128,6 +128,209 @@ shouldBeTrue('shaderPrecisionFormat.rangeMin == shaderPrecisionFormat2.rangeMin'
shouldBeTrue('shaderPrecisionFormat.rangeMax == shaderPrecisionFormat2.rangeMax');
shouldBeTrue('shaderPrecisionFormat.precision == shaderPrecisionFormat2.precision');
debug("");
debug("Test that specified precision matches rendering results");
debug("");
function testRenderPrecisionSetup(gl, shaderPair) {
const program = wtu.setupProgram(gl, shaderPair);
// Create a buffer and setup an attribute.
// We wouldn't need this except for a bug in Safari and arguably
// this should be removed from the test but we can't test the test itself
// without until the bug is fixed.
// see https://bugs.webkit.org/show_bug.cgi?id=197592
{
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, 1, gl.STATIC_DRAW);
const loc = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(loc, 1, gl.UNSIGNED_BYTE, false, 0, 0);
}
gl.useProgram(program);
return program;
}
function testRenderPrecision(gl, shaderType, type, precision, expected, msg) {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, 1);
const pixel = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, expected, msg, 5);
}
function testRenderPrecisionFloat(gl, precisionEnum, precision) {
function test(gl, shaderPair, shaderType) {
const format = gl.getShaderPrecisionFormat(shaderType, precisionEnum);
const value = 2 ** format.precision - 1;
const length = v => Math.sqrt(v.reduce((sum, v) => sum + v * v, 0));
const normalize = (v) => {
const l = length(v);
return v.map(v => v / l);
};
const input = [Math.sqrt(value), Math.sqrt(value), Math.sqrt(value)];
const expected = [...normalize(input).map(v => (v * 0.5 + 0.5) * 255 | 0), 255];
const msg = `${wtu.glEnumToString(gl, shaderType)}: ${precision} float precision: ${format.precision}, rangeMin: ${format.rangeMin}, rangeMax: ${format.rangeMax}`;
const program = testRenderPrecisionSetup(gl, shaderPair);
const vLocation = gl.getUniformLocation(program, 'v');
gl.uniform3fv(vLocation, input);
testRenderPrecision(gl, shaderType, 'float', precision, expected, msg);
}
{
const vs = `
attribute vec4 position;
uniform ${precision} vec3 v;
varying ${precision} vec4 v_result;
void main() {
gl_Position = position;
gl_PointSize = 1.0;
v_result = vec4(normalize(v) * 0.5 + 0.5, 1);
}
`;
const fs = `
precision ${precision} float;
varying ${precision} vec4 v_result;
void main() {
gl_FragColor = v_result;
}
`;
test(gl, [vs, fs], gl.VERTEX_SHADER);
}
{
const vs = `
attribute vec4 position;
void main() {
gl_Position = position;
gl_PointSize = 1.0;
}
`;
const fs = `
precision ${precision} float;
uniform ${precision} vec3 v;
void main() {
gl_FragColor = vec4(normalize(v) * 0.5 + 0.5, 1);
}
`;
test(gl, [vs, fs], gl.FRAGMENT_SHADER);
}
}
function testRenderPrecisionInt(gl, precisionEnum, precision) {
function test(gl, shaderPair, shaderType) {
const format = gl.getShaderPrecisionFormat(shaderType, precisionEnum);
const value = 1 << (format.rangeMax - 1);
const input = [value, value, value, value];
const expected = [255, 255, 255, 255];
const msg = `${wtu.glEnumToString(gl, shaderType)}: ${precision} int precision: ${format.precision}, rangeMin: ${format.rangeMin}, rangeMax: ${format.rangeMax}`;
const program = testRenderPrecisionSetup(gl, shaderPair);
gl.uniform1i(gl.getUniformLocation(program, 'v'), value);
gl.uniform1f(gl.getUniformLocation(program, 'f'), value);
testRenderPrecision(gl, shaderType, 'int', precision, expected, msg);
}
{
const vs = `
attribute vec4 position;
uniform ${precision} int v;
uniform highp float f;
varying vec4 v_result;
void main() {
gl_Position = position;
gl_PointSize = 1.0;
float diff = abs(float(v) - f);
bool pass = diff < 1.0;
v_result = vec4(pass);
}
`;
const fs = `
precision mediump float;
varying vec4 v_result;
void main() {
gl_FragColor = v_result;
}
`;
test(gl, [vs, fs], gl.VERTEX_SHADER);
}
{
const vs = `
attribute vec4 position;
void main() {
gl_Position = position;
gl_PointSize = 1.0;
}
`;
const fs = `
precision ${precision} float;
uniform ${precision} int v;
uniform mediump float f;
void main() {
mediump float diff = abs(float(v) - f);
bool pass = diff < 1.0;
gl_FragColor = vec4(pass);
}
`;
test(gl, [vs, fs], gl.FRAGMENT_SHADER);
}
}
// because the canvas can be 16 bit IIRC
const fb = gl.createFramebuffer(gl.FRAMEBUFFER);
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
tex,
0);
gl.viewport(0, 0, 1, 1);
{
testRenderPrecisionFloat(gl, gl.LOW_FLOAT, 'lowp');
testRenderPrecisionFloat(gl, gl.MEDIUM_FLOAT, 'mediump');
const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
if (format.precision !== 0) {
testRenderPrecisionFloat(gl, gl.HIGH_FLOAT, 'highp');
}
}
{
testRenderPrecisionInt(gl, gl.LOW_INT, 'lowp');
testRenderPrecisionInt(gl, gl.MEDIUM_INT, 'mediump');
const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_INT);
if (format.rangeMax !== 0) {
testRenderPrecisionInt(gl, gl.HIGH_INT, 'highp');
}
}
finishTest();
</script>

View File

@ -178,6 +178,75 @@ gl.deleteTexture(tex);
gl.finish();
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
debug("");
debug("Reading an uninitialized portion of a texture (copyTexSubImage2D) should succeed with all bytes set to 0.");
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
var rbo = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
var fboWidth = 16;
var fboHeight = 16;
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, fboWidth, fboHeight);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
gl.clearColor(1.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, width, height);
checkNonZeroPixels(tex, width, height, 0, 0, fboWidth, fboHeight, 255, 0, 0, 255);
gl.deleteTexture(tex);
gl.finish();
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
debug("");
debug("Reading an uninitialized portion of a texture (copyTexSubImage2D with negative x and y) should succeed with all bytes set to 0.");
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
var rbo = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
var fboWidth = 16;
var fboHeight = 16;
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, fboWidth, fboHeight);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
gl.clearColor(1.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
var x = -8;
var y = -8;
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, x, y, width, height);
checkNonZeroPixels(tex, width, height, -x, -y, fboWidth, fboHeight, 255, 0, 0, 255);
gl.deleteTexture(tex);
gl.finish();
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
debug("");
debug("Reading an uninitialized portion of a texture (copyTexSubImage2D from WebGL internal fbo) should succeed with all bytes set to 0.");
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.clearColor(0.0, 1.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, width, height);
checkNonZeroPixels(tex, width, height, 0, 0, canvas.width, canvas.height, 0, 255, 0, 0);
gl.deleteTexture(tex);
gl.finish();
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
//TODO: uninitialized vertex array buffer
//TODO: uninitialized vertex elements buffer
//TODO: uninitialized framebuffer? (implementations would need to do a GL clear at first binding?)

View File

@ -11,6 +11,10 @@ found in the LICENSE.txt file.
<script type="application/javascript" src="../unit.js"></script>
<script type="application/javascript" src="../util.js"></script>
<script type="application/javascript" src="../../../js/webgl-test-utils.js"></script>
</head><body>
<canvas id="gl" width="16" height="16"></canvas>
<canvas id="c" width="128" height="128"></canvas>
<img id="i">
<script type="application/javascript">
var wtu = WebGLTestUtils;
var defaultImgUrl = "https://get.webgl.org/conformance-resources/opengl_logo.jpg";
@ -92,12 +96,18 @@ Tests.testReadPixelsSOPCanvas = function(gl) {
}
Tests.endUnit = function(gl) {
}
};
wtu.setupImageForCrossOriginTest("#i", defaultImgUrl, localImgUrl, initTests);
(async function() {
const img = document.getElementById('i');
try {
await wtu.awaitOrTimeout(wtu.loadCrossOriginImage(img, defaultImgUrl, localImgUrl));
} catch (e) {
testFailed(`Image setup failed (${e}).`);
finishTest();
return;
}
initTests();
})();
</script>
</head><body>
<canvas id="gl" width="16" height="16"></canvas>
<canvas id="c" width="128" height="128"></canvas>
<img id="i">
</body></html>

View File

@ -133,23 +133,14 @@ Tests.testTexImage2DNonSOP = function(gl) {
Tests.endUnit = function(gl) {
};
async function setupNonSOPImage() {
const img = document.getElementById('i2');
const url = wtu.chooseUrlForCrossOriginImage(defaultImgUrl, localImgUrl);
img.src = url;
await img.decode();
}
async function throwOnTimeout(ms) {
await wtu.awaitTimeout(ms);
throw 'timeout';
}
(async function() {
const img = document.getElementById('i2');
try {
await Promise.race([setupNonSOPImage(), throwOnTimeout(1000)]);
await wtu.awaitOrTimeout(wtu.loadCrossOriginImage(img, defaultImgUrl, localImgUrl));
} catch (e) {
console.log(`Image setup failed (${e}), running tests anyway.`);
testFailed(`Image setup failed (${e}).`);
finishTest();
return;
}
initTests();
})();

View File

@ -143,25 +143,16 @@ Tests.testTexImage2DNonSOP = function(gl) {
}
Tests.endUnit = function(gl) {
}
async function setupNonSOPImage() {
const img = document.getElementById('i2');
const url = wtu.chooseUrlForCrossOriginImage(defaultImgUrl, localImgUrl);
img.src = url;
await img.decode();
}
async function throwOnTimeout(ms) {
await wtu.awaitTimeout(ms);
throw 'timeout';
}
};
(async function() {
const img = document.getElementById('i2');
try {
await Promise.race([setupNonSOPImage(), throwOnTimeout(1000)]);
await wtu.awaitOrTimeout(wtu.loadCrossOriginImage(img, defaultImgUrl, localImgUrl));
} catch (e) {
console.log(`Image setup failed (${e}), running tests anyway.`);
testFailed(`Image setup failed (${e}).`);
finishTest();
return;
}
initTests();
})();

View File

@ -33,7 +33,7 @@ function compareImages(refData, tstData, width, height, diff) {
return true;
}
// TODO: Implement check that's used in OpenGL ES 2.0 conformance tests.
// TODO: Implement crazy check that's used in OpenGL ES 2.0 conformance tests.
// NOTE: on Desktop things seem to be working. Maybe the more complex check
// is needed for embedded systems?
return false;

View File

@ -24,6 +24,7 @@ found in the LICENSE.txt file.
description("Checks that ReadPixels works as expected.");
var wtu = WebGLTestUtils;
let gl;
debug("<h1>antialias = false</h1>")
runTest(document.getElementById("example"), false);
@ -35,7 +36,7 @@ var actual;
var expected;
function runTest(canvas, antialias) {
var gl = wtu.create3DContext(canvas, {antialias: antialias});
gl = wtu.create3DContext(canvas, {antialias: antialias});
var contextVersion = wtu.getDefault3DContextVersion();
var width = 2;
@ -179,17 +180,10 @@ function runTest(canvas, antialias) {
wtu.glErrorShouldBe(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "Should not be able to read as " + wtu.glEnumToString(gl, type));
}
var combinations = [
{
format: gl.RGBA,
type: gl.UNSIGNED_BYTE,
dest: new Uint8Array(4),
},
{
format: gl.RGB,
type: gl.UNSIGNED_BYTE,
dest: new Uint8Array(3),
},
// -
const combinations = [
{
format: gl.RGB,
type: gl.UNSIGNED_SHORT_5_6_5,
@ -205,37 +199,113 @@ function runTest(canvas, antialias) {
type: gl.UNSIGNED_SHORT_4_4_4_4,
dest: new Uint16Array(1),
},
{
format: gl.ALPHA,
type: gl.UNSIGNED_BYTE,
dest: new Uint8Array(1),
}
];
if (contextVersion > 1) {
combinations = combinations.concat([
const FORMATS = [
{
format: gl.RGBA,
channels: 4,
}, {
format: gl.RGB,
channels: 3,
}, {
format: gl.LUMINANCE_ALPHA,
channels: 2,
}, {
format: gl.ALPHA,
channels: 1,
}, {
format: gl.LUMINANCE,
channels: 3,
},
];
if (contextVersion >= 2) {
FORMATS.push(
{
format: gl.RED,
type: gl.UNSIGNED_BYTE,
dest: new Uint8Array(1),
},
{
channels: 1,
}, {
format: gl.RG,
channels: 1,
}, {
format: gl.RGBA_INTEGER,
type: gl.UNSIGNED_INT,
dest: new Uint32Array(4),
},
{
format: gl.RGBA_INTEGER,
type: gl.INT,
dest: new Int32Array(4),
channels: 4,
}, {
format: gl.RGB_INTEGER,
channels: 3,
}, {
format: gl.RG_INTEGER,
channels: 2,
}, {
format: gl.RED_INTEGER,
channels: 1,
}
]);
);
}
// -
const TYPES = [
{
type: gl.UNSIGNED_BYTE,
ctor: Uint8Array,
}, {
type: gl.BYTE,
ctor: Int8Array,
}, {
type: gl.UNSIGNED_SHORT,
ctor: Uint16Array,
}, {
type: gl.SHORT,
ctor: Int16Array,
}, {
type: gl.UNSIGNED_INT,
ctor: Uint32Array,
}, {
type: gl.INT,
ctor: Int32Array,
}, {
type: gl.FLOAT,
ctor: Float32Array,
}
];
if (contextVersion >= 2) {
TYPES.push(
{
type: gl.HALF_FLOAT,
ctor: Uint16Array,
}
);
}
const ext = gl.getExtension('OES_texture_half_float');
if (ext) {
TYPES.push(
{
type: ext.HALF_FLOAT_OES,
ctor: Uint16Array,
}
);
}
for (const t of TYPES) {
for (const f of FORMATS) {
const desc = Object.assign({}, f, t);
desc.dest = new desc.ctor(desc.channels);
combinations.push(desc);
}
}
// -
debug("");
debug("check invalid combinations of format/type");
var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
debug("IMPLEMENTATION_COLOR_READ_FORMAT: " + wtu.glEnumToString(gl, implFormat));
debug("IMPLEMENTATION_COLOR_READ_TYPE: " + wtu.glEnumToString(gl, implType));
for (var tt = 0; tt < combinations.length; ++ tt) {
var info = combinations[tt];
@ -253,7 +323,7 @@ function runTest(canvas, antialias) {
" / " + wtu.glEnumToString(gl, type));
} else {
wtu.glErrorShouldBe(
gl, gl.INVALID_OPERATION,
gl, [gl.INVALID_OPERATION, gl.INVALID_ENUM],
"Should not be able to read as " + wtu.glEnumToString(gl, format) +
" / " + wtu.glEnumToString(gl, type));
}
@ -335,6 +405,22 @@ function runTest(canvas, antialias) {
"color pixel at 0, 0 should be [0, 255, 0, 255], was " +
[buf[0], buf[1], buf[2], buf[3]]);
}
const validDatas = [
`new Uint8Array(4)`,
`new Uint8Array(new ArrayBuffer(4))`,
`new Uint8ClampedArray(4)`,
`new Uint8ClampedArray(new ArrayBuffer(4))`,
];
if (window.SharedArrayBuffer) {
validDatas.push(
`new Uint8Array(new SharedArrayBuffer(4))`,
`new Uint8ClampedArray(new SharedArrayBuffer(4))`
);
}
for (const x of validDatas) {
shouldNotThrow(`gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, ${x});`);
}
}
}
</script>

View File

@ -4,12 +4,12 @@ Use of this source code is governed by an MIT-style license that can be
found in the LICENSE.txt file.
-->
<!--
This bug would occur after the app would render several times with the
same vertex attributes and buffers, but using a different start offset.
One of the buffers would likely have to be DYNAMIC.
See http://anglebug.com/1327 and http://crbug.com/594509
-->
<!DOCTYPE html>

View File

@ -126,6 +126,7 @@ function runTest()
debug('Polygon offset factor of 0.1 should alter order of slanted polygons');
clear(gl, red, 1.0);
gl.polygonOffset(0, 0);
draw(gl, slantedSquare, colLoc, green);
gl.polygonOffset(0.1, 0);
draw(gl, slantedSquare, colLoc, blue);
@ -133,6 +134,7 @@ function runTest()
debug('Polygon offset factor of 0.1 should not alter order of flat polygons');
clear(gl, red, 1.0);
gl.polygonOffset(0, 0);
draw(gl, flatSquare, colLoc, blue);
gl.polygonOffset(0.1, 0);
draw(gl, flatSquare, colLoc, green);

View File

@ -1,3 +1,4 @@
--min-version 1.0.4 fb-attach-implicit-target-assignment.html
gl-enable-enum-test.html
--max-version 1.9.9 gl-enum-tests.html
gl-get-calls.html

View File

@ -0,0 +1,94 @@
<!--
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 gl calls Conformance 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>
<div id='description'></div>
<div id='console'></div>
<canvas id='canvas' width='2' height='2'> </canvas>
<script>
'use strict';
description('Test implicit target assignment during FB attachment');
const wtu = WebGLTestUtils;
const gl = wtu.create3DContext('canvas');
let fb, rb, tex;
(() => {
if (!gl) {
testFailed('context does not exist');
return;
}
fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
wtu.glErrorShouldBe(gl, 0, 'No errors');
// -
debug('');
debug('framebufferRenderbuffer');
rb = gl.createRenderbuffer();
shouldBe('gl.isRenderbuffer(rb)', 'false');
gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
shouldBe('gl.isRenderbuffer(rb)', 'true');
rb = gl.createRenderbuffer();
shouldBe('gl.isRenderbuffer(rb)', 'false');
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, 'framebufferRenderbuffer must be preceeded by some bindRenderbuffer');
shouldBe('gl.isRenderbuffer(rb)', 'false');
wtu.glErrorShouldBe(gl, 0, 'No errors');
// -
debug('');
debug('framebufferTexture2D');
tex = gl.createTexture();
shouldBe('gl.isTexture(tex)', 'false');
gl.bindTexture(gl.TEXTURE_2D, tex);
shouldBe('gl.isTexture(tex)', 'true');
tex = gl.createTexture();
shouldBe('gl.isTexture(tex)', 'false');
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
// https://bugzilla.mozilla.org/show_bug.cgi?id=1636524 :
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, 'framebufferTexture2D must be preceeded by some bindTexture');
shouldBe('gl.isTexture(tex)', 'false');
gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
wtu.glErrorShouldBe(gl, 0, 'No errors after bindTexture');
tex = gl.createTexture();
shouldBe('gl.isTexture(tex)', 'false');
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X, tex, 0);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, 'framebufferTexture2D must be preceeded by some bindTexture');
shouldBe('gl.isTexture(tex)', 'false');
gl.bindTexture(gl.TEXTURE_2D, tex);
wtu.glErrorShouldBe(gl, 0, 'No errors after bindTexture');
})();
debug('');
var successfullyParsed = true;
</script>
<script src='../../js/js-test-post.js'></script>
</body>
</html>

View File

@ -1,5 +1,5 @@
--min-version 1.0.4 canvas-teximage-after-multiple-drawimages.html
compressed-tex-image.html
--max-version 1.9.9 compressed-tex-image.html
copy-tex-image-and-sub-image-2d.html
--min-version 1.0.2 copy-tex-image-2d-formats.html
--min-version 1.0.4 copy-tex-image-crash.html
@ -8,9 +8,11 @@ copy-tex-image-and-sub-image-2d.html
--min-version 1.0.4 cube-incomplete-fbo.html
--min-version 1.0.4 cube-map-uploads-out-of-order.html
--min-version 1.0.3 default-texture.html
--min-version 1.0.4 exif-orientation.html
--min-version 1.0.2 --max-version 1.9.9 gl-get-tex-parameter.html
gl-pixelstorei.html
gl-teximage.html
--min-version 1.0.2 mipmap-fbo.html
origin-clean-conformance.html
--min-version 1.0.4 origin-clean-conformance-offscreencanvas.html
tex-image-and-sub-image-2d-with-array-buffer-view.html
@ -29,11 +31,14 @@ texture-active-bind.html
--min-version 1.0.2 texture-attachment-formats.html
--min-version 1.0.2 texture-clear.html
texture-complete.html
--min-version 1.0.4 texture-copying-and-deletion.html
--min-version 1.0.3 texture-copying-feedback-loops.html
--min-version 1.0.4 texture-corner-case-videos.html
--min-version 1.0.4 texture-cube-as-fbo-attachment.html
--min-version 1.0.2 texture-hd-dpi.html
--min-version 1.0.3 texture-draw-with-2d-and-cube.html
--min-version 1.0.3 --max-version 1.9.9 texture-fakeblack.html
--min-version 1.0.2 --max-version 1.9.9 texture-formats-test.html
--min-version 1.0.2 texture-hd-dpi.html
texture-mips.html
--max-version 1.9.9 texture-npot-video.html
--max-version 1.9.9 texture-npot.html
@ -44,8 +49,8 @@ texture-size-cube-maps.html
texture-transparent-pixels-initialized.html
--min-version 1.0.2 texture-upload-cube-maps.html
--min-version 1.0.3 texture-upload-size.html
--min-version 1.0.2 mipmap-fbo.html
--min-version 1.0.3 --max-version 1.9.9 texture-fakeblack.html
--min-version 1.0.3 texture-draw-with-2d-and-cube.html
--min-version 1.0.4 texture-video-transparent.html
--min-version 1.0.4 texture-with-flip-y-and-premultiply-alpha.html
--min-version 1.0.4 upload-from-srcset-with-empty-data.html
--min-version 1.0.4 video-rotation.html
--min-version 1.0.4 png-image-types.html

View File

@ -1,5 +1,5 @@
<!--
Copyright (c) 2019 The Khronos Group Inc.
Copyright (c) 2020 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.
-->
@ -8,8 +8,7 @@ found in the LICENSE.txt file.
<html>
<head>
<meta charset="utf-8">
<title>WebGL compressed texture test</title>
<LINK rel="stylesheet" href="../../../resources/js-test-style.css"/>
<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>
@ -17,100 +16,9 @@ found in the LICENSE.txt file.
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
description("This test ensures WebGL implementations correctly implement querying for compressed textures when extensions are disabled.");
debug("");
const wtu = WebGLTestUtils;
const gl = wtu.create3DContext();
const COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
const COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
let formats = null;
let ext;
if (!gl) {
testFailed("context does not exist");
} else {
testPassed("context exists");
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION],
"gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 10, 10, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, new Uint8Array(8));");
wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 8, 8, 0, new Uint8Array(8))");
wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 8, 8, 0, new Uint8Array(8))");
wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "formats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS)");
shouldBeNonNull("formats");
shouldBe("formats.length", "0");
wtu.shouldGenerateGLError(gl, gl.NO_ERROR, "gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 4, 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4*4*4));");
wtu.shouldGenerateGLError(gl, gl.INVALID_ENUM,
"gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 4, 4, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, new Uint8Array(8));");
// Check too-many and too-few args.
wtu.shouldThrow(gl, false, "too many args", function() {
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 4, 4, 0, new Uint8Array(8), null);
});
wtu.shouldThrow(gl, TypeError, "too few args", function() {
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 4, 4, 0);
});
wtu.shouldThrow(gl, false, "too many args", function() {
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 4, 4, COMPRESSED_RGB_PVRTC_4BPPV1_IMG, new Uint8Array(8), null);
});
wtu.shouldThrow(gl, TypeError, "too few args", function() {
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 4, 4, COMPRESSED_RGB_PVRTC_4BPPV1_IMG);
});
if (gl.PIXEL_UNPACK_BUFFER) {
const buf = gl.createBuffer();
gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, buf);
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
function validateExt(extName, enumName, blockSize, blockByteSize) {
ext = gl.getExtension(extName);
if (!ext) {
testPassed(`Optional ext ${extName} MAY be unsupported.`);
return;
}
testPassed(`Optional ext ${extName} is supported.`);
gl.bufferData(gl.PIXEL_UNPACK_BUFFER, blockByteSize*2, gl.STATIC_DRAW);
wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
`gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, 0)`);
wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
`gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, 1)`);
wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
`gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, ${blockByteSize})`);
wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION,
`gl.compressedTexImage2D(gl.TEXTURE_2D, 0, ext.${enumName}, ${blockSize},${blockSize}, 0, ${blockByteSize}, ${blockByteSize+1})`);
wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
`gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, 0)`);
wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
`gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, 1)`);
wtu.shouldGenerateGLError(gl, gl.NO_ERROR,
`gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, ${blockByteSize})`);
wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION,
`gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0,0, ${blockSize},${blockSize}, ext.${enumName}, ${blockByteSize}, ${blockByteSize+1})`);
}
validateExt('WEBGL_compressed_texture_s3tc', 'COMPRESSED_RGBA_S3TC_DXT5_EXT', 4, 16);
validateExt('WEBGL_compressed_texture_etc1', 'COMPRESSED_RGB_ETC1_WEBGL', 4, 8);
validateExt('WEBGL_compressed_texture_etc', 'COMPRESSED_RGBA8_ETC2_EAC', 4, 16);
validateExt('WEBGL_compressed_texture_astc', 'COMPRESSED_RGBA_ASTC_4x4_KHR', 4, 16);
}
}
var successfullyParsed = true;
const contextVersion = 1;
</script>
<script src="../../../js/tests/compressed-tex-image.js"></script>
<script src="../../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -0,0 +1,167 @@
<!--
Copyright (c) 2020 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>Verifies EXIF orientation is respected when uploading images to WebGL textures</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>
<script src="../../../js/tests/tex-image-and-sub-image-utils.js"></script>
</head>
<body onload="run()">
<canvas id="c" width="256" height="256"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
description();
let wtu = WebGLTestUtils;
let tiu = TexImageUtils;
let canvas = document.getElementById("c");
let gl = wtu.create3DContext(canvas);
let program = tiu.setupTexturedQuad(gl, gl.RGBA);
const resourcePath = "../../../resources/";
const tolerance = 5;
// The locations are written assuming flipY = false. For flipY = true, y = 1.0-y.
const expectedColors = {
top: { location: [ 0.5, 0.25 ], color: [ 255, 0, 0 ] },
left: { location: [ 0.4, 0.5 ], color: [ 0, 0, 255 ] },
right: { location: [ 0.6, 0.5 ], color: [ 255, 255, 0 ] },
bottom: { location: [ 0.5, 0.75 ], color: [ 0, 255, 0 ] },
}
function output(str)
{
debug(str);
bufferedLogToConsole(str);
}
function checkPixels(flipY)
{
for (let place in expectedColors) {
let color = expectedColors[place];
let loc = color.location;
let x = loc[0];
let y = (flipY ? 1.0 - loc[1] : loc[1]);
output(" Checking " + place);
wtu.checkCanvasRect(gl, Math.floor(canvas.width * x), Math.floor(canvas.height * y), 1, 1,
color.color, "shouldBe " + color.color + " +/-" + tolerance, tolerance);
}
}
async function testImageBitmapFromBlobWithFlipY(blob, flipY)
{
let bitmap;
// As a concession to Firefox, which doesn't yet implement
// createImageBitmap with creation options, skip the tests
// involving flipY=true if ImageBitmap creation throws an
// exception, and use the single-argument constructor for the
// flipY=false case.
if (flipY) {
try {
bitmap = await createImageBitmap(blob, {imageOrientation: flipY});
} catch (e) {
output(" (createImageBitmap options not supported - skipping flipY=true case)");
return;
}
} else {
bitmap = await createImageBitmap(blob);
}
output(" Testing texImage2D, flipY = " + flipY);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap);
wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
checkPixels(flipY);
output(" Testing texSubImage2D, flipY = " + flipY);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, bitmap.width, bitmap.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, bitmap);
wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
checkPixels(flipY);
}
async function testImageBitmapFromBlob(filename)
{
let response = await fetch(resourcePath + filename);
let blob = await response.blob();
output("----------------------------------------------------------------");
output("Testing " + filename + " via ImageBitmap from Blob");
await testImageBitmapFromBlobWithFlipY(blob, true);
await testImageBitmapFromBlobWithFlipY(blob, false);
}
async function testImageElementWithFlipY(image, flipY)
{
output(" Testing texImage2D, flipY = " + flipY);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
checkPixels(flipY);
output(" Testing texSubImage2D, flipY = " + flipY);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, image);
wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
checkPixels(flipY);
}
async function testImageElement(filename)
{
let image = new Image();
image.src = resourcePath + filename;
await image.decode();
output("----------------------------------------------------------------");
output("Testing " + filename + " via HTMLImageElement");
await testImageElementWithFlipY(image, true);
await testImageElementWithFlipY(image, false);
}
async function testSingleImage(filename)
{
await testImageBitmapFromBlob(filename);
await testImageElement(filename);
}
async function run()
{
let tex = gl.createTexture();
// Bind the texture to the default texture unit 0
gl.bindTexture(gl.TEXTURE_2D, tex);
// Set up texture parameters
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
const filenames = [
"exif-orientation-test-1-normal.jpg",
"exif-orientation-test-2-mirror-horizontal.jpg",
"exif-orientation-test-3-rotate-180.jpg",
"exif-orientation-test-4-mirror-vertical.jpg",
"exif-orientation-test-5-mirror-horizontal-90-ccw.jpg",
"exif-orientation-test-6-90-ccw.jpg",
"exif-orientation-test-7-mirror-horizontal-90-cw.jpg",
"exif-orientation-test-8-90-cw.jpg",
];
for (let fn of filenames) {
await testSingleImage(fn);
}
finishTest();
}
var successfullyParsed = true;
</script>
</body>
</html>

View File

@ -12,6 +12,12 @@ found in the LICENSE.txt file.
<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>
<div id="console"></div>
<canvas id="canvas"></canvas>
<img id="img" style="display:none;">
<script>
"use strict";
var wtu = WebGLTestUtils;
@ -33,7 +39,7 @@ var localImgUrl = "../../../resources/opengl_logo.jpg";
var imgDomain;
var pageDomain;
function imageLoaded() {
function imageLoaded(img) {
description("This test ensures WebGL implementations for OffscreenCanvas follow proper same-origin restrictions.");
if (!window.OffscreenCanvas) {
@ -42,8 +48,6 @@ function imageLoaded() {
return;
}
var img = this;
assertMsg(img.width > 0 && img.height > 0, "img was loaded");
imgDomain = wtu.getBaseDomain(wtu.getHost(img.src));
pageDomain = wtu.getBaseDomain(window.location.host);
@ -105,13 +109,17 @@ function imageLoaded() {
finishTest();
}
wtu.setupImageForCrossOriginTest("#img", defaultImgUrl, localImgUrl, imageLoaded);
(async function() {
const img = document.getElementById('img');
try {
await wtu.awaitOrTimeout(wtu.loadCrossOriginImage(img, defaultImgUrl, localImgUrl));
} catch (e) {
testFailed(`Image setup failed (${e}).`);
finishTest();
return;
}
imageLoaded(img);
})();
</script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="canvas"></canvas>
<img id="img" style="display:none;">
</body>
</html>

View File

@ -12,6 +12,13 @@ found in the LICENSE.txt file.
<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>
<div id="console"></div>
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
<img id="img" style="display:none;">
<script>
"use strict";
var wtu = WebGLTestUtils;
@ -34,9 +41,8 @@ var imgDomain;
var pageDomain;
var successfullyParsed;
function imageLoaded() {
function imageLoaded(img) {
description("This test ensures WebGL implementations follow proper same-origin restrictions.");
var img = this;
assertMsg(img.width > 0 && img.height > 0, "img was loaded");
imgDomain = wtu.getBaseDomain(wtu.getHost(img.src));
@ -115,14 +121,17 @@ function imageLoaded() {
notifyFinishedToHarness();
}
wtu.setupImageForCrossOriginTest("#img", defaultImgUrl, localImgUrl, imageLoaded);
(async function() {
const img = document.getElementById('img');
try {
await wtu.awaitOrTimeout(wtu.loadCrossOriginImage(img, defaultImgUrl, localImgUrl));
} catch (e) {
testFailed(`Image setup failed (${e}).`);
finishTest();
return;
}
imageLoaded(img);
})();
</script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
<img id="img" style="display:none;">
</body>
</html>

View File

@ -0,0 +1,164 @@
<!--
Copyright (c) 2021 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">
<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>
<div id="console"></div>
<script>
"use strict";
description("This test verifies correct channel mapping of different PNG image types.");
const testData = {
"Grayscale": {
src: [
// [0x40]
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQI12NwAAAAQgBBg7nsrQAAAABJRU5ErkJggg==",
// [0x4040]
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABEAAAAABq7kcWAAAAC0lEQVQI12NwcAAAAMMAgUenLEIAAAAASUVORK5CYII="
],
expectations: [
{ color: [0x00, 0x00, 0x00, 0xFF], format: "ALPHA" },
{ color: [0x40, 0x40, 0x40, 0xFF], format: "RGB" },
{ color: [0x40, 0x40, 0x40, 0xFF], format: "RGBA" },
{ color: [0x40, 0x40, 0x40, 0xFF], format: "LUMINANCE" },
{ color: [0x40, 0x40, 0x40, 0xFF], format: "LUMINANCE_ALPHA" },
{ color: [0x40, 0x00, 0x00, 0xFF], format: "RED", internalformat: "R8" },
{ color: [0x40, 0x40, 0x00, 0xFF], format: "RG", internalformat: "RG8" }
]
},
"Grayscale Alpha": {
src: [
// [0x40, 0x80]
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQI12NwaAAAAQMAwUxZTl4AAAAASUVORK5CYII=",
// [0x4040, 0x8080]
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABEAQAAADljNBBAAAADUlEQVQI12NwcGhoAAADRQGBoxssPgAAAABJRU5ErkJggg=="
],
expectations: [
{ color: [0x00, 0x00, 0x00, 0x80], format: "ALPHA" },
{ color: [0x40, 0x40, 0x40, 0xFF], format: "RGB" },
{ color: [0x40, 0x40, 0x40, 0x80], format: "RGBA" },
{ color: [0x40, 0x40, 0x40, 0xFF], format: "LUMINANCE" },
{ color: [0x40, 0x40, 0x40, 0x80], format: "LUMINANCE_ALPHA" },
{ color: [0x40, 0x00, 0x00, 0xFF], format: "RED", internalformat: "R8" },
{ color: [0x40, 0x40, 0x00, 0xFF], format: "RG", internalformat: "RG8" }
]
},
"Color": {
src: [
// [0xBF, 0x7F, 0xFF]
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12PYX/8fAAQ+Aj5BqwprAAAAAElFTkSuQmCC",
// [0xBFBF, 0x7F7F, 0xFFFF]
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABEAIAAADA54+dAAAAD0lEQVQI12PYv7++/v9/AA6yBHvtbgBNAAAAAElFTkSuQmCC"
],
expectations: [
{ color: [0x00, 0x00, 0x00, 0xFF], format: "ALPHA" },
{ color: [0xBF, 0x7F, 0xFF, 0xFF], format: "RGB" },
{ color: [0xBF, 0x7F, 0xFF, 0xFF], format: "RGBA" },
{ color: [0xBF, 0xBF, 0xBF, 0xFF], format: "LUMINANCE" },
{ color: [0xBF, 0xBF, 0xBF, 0xFF], format: "LUMINANCE_ALPHA" },
{ color: [0xBF, 0x00, 0x00, 0xFF], format: "RED", internalformat: "R8" },
{ color: [0xBF, 0x7F, 0x00, 0xFF], format: "RG", internalformat: "RG8" }
]
},
"Color Alpha": {
src: [
// [0xBF, 0x7F, 0xFF, 0x40]
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQI12PYX//fAQAGvAJ+xPMwKQAAAABJRU5ErkJggg==",
// [0xBFBF, 0x7F7F, 0xFFFF, 0x4040]
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABEAYAAABPhRjKAAAAEUlEQVQI12PYv7++/v9/BwcAGGgE+8YN4XUAAAAASUVORK5CYII="
],
expectations: [
{ color: [0x00, 0x00, 0x00, 0x40], format: "ALPHA" },
{ color: [0xBF, 0x7F, 0xFF, 0xFF], format: "RGB" },
{ color: [0xBF, 0x7F, 0xFF, 0x40], format: "RGBA" },
{ color: [0xBF, 0xBF, 0xBF, 0xFF], format: "LUMINANCE" },
{ color: [0xBF, 0xBF, 0xBF, 0x40], format: "LUMINANCE_ALPHA" },
{ color: [0xBF, 0x00, 0x00, 0xFF], format: "RED", internalformat: "R8" },
{ color: [0xBF, 0x7F, 0x00, 0xFF], format: "RG", internalformat: "RG8" }
]
}
};
const wtu = WebGLTestUtils;
const gl = wtu.create3DContext();
wtu.setupTexturedQuad(gl);
gl.bindTexture(gl.TEXTURE_2D, gl.createTexture());
(async () => {
for (const [type, testCase] of Object.entries(testData)) {
if (testCase.src.length != 2) throw new Error('testCase.src.length != 2');
let images = testCase.src.map(src => loadImage(src));
images = await Promise.all(images);
debug("");
debug("");
debug(`PNG image type ${type} with RGBA values of ${testCase.expectations[2].color}`);
let formats = testCase.expectations;
if (!wtu.isWebGL2(gl)) {
formats = formats.filter((f) => !f.internalformat);
}
for (const f of formats) {
debug("");
debug(`GL format: ${f.format}`);
function check(data, description) {
debug(`Upload ${description}`);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl[f.internalformat || f.format],
gl[f.format],
gl.UNSIGNED_BYTE,
data
);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
wtu.clearAndDrawUnitQuad(gl);
wtu.checkCanvas(gl, f.color, undefined, 1);
}
check(images[0].image, "8-bit PNG from Image");
check(images[1].image, "16-bit PNG from Image");
if (images[0].bitmap) {
check(images[0].bitmap, "8-bit PNG from ImageBitmap");
check(images[1].bitmap, "16-bit PNG from ImageBitmap");
}
}
}
finishTest();
})();
async function loadImage(src) {
const img = new Image();
img.src = src;
await img.decode();
const ret = { image: img };
if (self.createImageBitmap) {
try {
ret.bitmap = await createImageBitmap(img, {
premultiplyAlpha: "none",
});
} catch {}
}
return ret;
}
var successfullyParsed = true;
</script>
</body>
</html>

View File

@ -264,7 +264,6 @@ function runTest(bindingTarget, program)
}
}
}
}
var gl = wtu.create3DContext("example");
@ -275,6 +274,29 @@ program = wtu.setupTexturedQuadWithCubeMap(gl);
runTest(gl.TEXTURE_CUBE_MAP, program);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
const validDatas = [
`new Uint8Array(4)`,
`new Uint8Array(new ArrayBuffer(4))`,
`new Uint8ClampedArray(4)`,
`new Uint8ClampedArray(new ArrayBuffer(4))`,
];
if (window.SharedArrayBuffer) {
validDatas.push(
`new Uint8Array(new SharedArrayBuffer(4))`,
`new Uint8ClampedArray(new SharedArrayBuffer(4))`
);
}
for (const x of validDatas) {
shouldNotThrow(`gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1, 0, gl.RGBA, gl.UNSIGNED_BYTE, ${x});`);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
shouldNotThrow(`gl.texSubImage2D(gl.TEXTURE_2D, 0, 0,0, 1,1, gl.RGBA, gl.UNSIGNED_BYTE, ${x});`);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
}
var successfullyParsed = true;
</script>
<script src="../../../js/js-test-post.js"></script>

View File

@ -0,0 +1,91 @@
<!--
Copyright (c) 2020 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 Copying and Deletion 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="1" height="1" style="width: 40px; height: 40px;"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
description('Checks that texture copying and deletion work correctly together.');
debug('Regression test for <a href="http://anglebug.com/4267">http://anglebug.com/4267</a>');
const wtu = WebGLTestUtils;
const canvas = document.getElementById("example");
canvas.addEventListener('webglcontextlost', contextLost, false);
let contextWasLost = false;
function contextLost(e) {
e.preventDefault();
contextWasLost = true;
debug("***context lost -- should not happen***");
}
const gl = wtu.create3DContext(canvas);
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
const texture2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture2);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
assertMsg(gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE,
"framebuffer should be FRAMEBUFFER_COMPLETE.");
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after setup");
// This test does not call getError, because doing so seems to cause
// an implicit flush which intermittently masks the bug.
debug("");
debug("testing copyTexImage2D");
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.copyTexImage2D(gl.TEXTURE_2D, 1, gl.RGBA, 0, 0, 2, 2, 0);
// Not necessary to do any CopyTexImage2D operations to texture2.
debug("");
debug("testing copyTexSubImage2D");
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.copyTexSubImage2D(gl.TEXTURE_2D, 1, 0, 0, 0, 0, 1, 1);
gl.bindTexture(gl.TEXTURE_2D, texture2);
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
debug('deleting framebuffer');
gl.deleteFramebuffer(framebuffer);
debug('deleting texture');
gl.deleteTexture(texture);
debug('deleting texture2');
// On buggy driver, crashes during this deleteTexture call.
gl.deleteTexture(texture2);
setTimeout(function() {
shouldBe("contextWasLost", "false");
finishTest();
}, 1000);
</script>
</body>
</html>

View File

@ -99,31 +99,33 @@ function runOneIteration(videoElement, useTexSubImage2D)
// - Left is green and right is transparent-blended-with-red
let leftIsGreen = false, leftIsRed = false, rightIsBlue = false, rightIsRed = false;
let greenRedError = "", redBlueError = "";
let leftGreenError = "", rightBlueError = "";
let bufLeft, bufRight;
wtu.checkCanvasRectColor(gl, 4, 4, 8, 24, green, tolerance,
/* sameFn */ () => { leftIsGreen = true; }, /* differentFn */ m => {}, debug);
/* sameFn */ () => { leftIsGreen = true; }, /* differentFn */ (m, b) => { leftGreenError = m; bufLeft = b;}, debug);
wtu.checkCanvasRectColor(gl, 20, 4, 8, 24, red, tolerance,
/* sameFn */ () => { rightIsRed = true; }, /* differentFn */ m => { greenRedError = m; }, debug);
/* sameFn */ () => { rightIsRed = true; }, /* differentFn */ (m, b) => { greenRedError = m; bufRight = b;}, debug);
// - Right is blue and left is transparent-blended-with-red
wtu.checkCanvasRectColor(gl, 20, 4, 8, 24, blue, tolerance,
/* sameFn */ () => { rightIsBlue = true; }, /* differentFn */ m => {}, debug);
/* sameFn */ () => { rightIsBlue = true; }, /* differentFn */ (m, b) => { rightBlueError = m; bufRight = b;}, debug);
wtu.checkCanvasRectColor(gl, 4, 4, 8, 24, red, tolerance,
/* sameFn */ () => { leftIsRed = true; }, /* differentFn */ m => { redBlueError = m; }, debug);
/* sameFn */ () => { leftIsRed = true; }, /* differentFn */ (m, b) => { redBlueError = m; bufLeft = b;}, debug);
if (leftIsGreen) {
if (rightIsRed) {
testPassed("left is green, right is transparent-blended-with-red")
testPassed("left is green, right is transparent-blended-with-red");
} else {
testFailed("left is green, but: " + greenRedError);
testFailed("left is green, but: " + greenRedError + "\n" + bufRight);
}
} else if (rightIsBlue) {
if (leftIsRed) {
testPassed("right is blue, left is transparent-blended-with-red");
} else {
testFailed("right is blue, but: " + redBlueError);
testFailed("right is blue, but: " + redBlueError + "\n" + bufLeft);
}
} else {
testFailed("neither left is green nor right is blue")
testFailed("neither left is green nor right is blue \n" + leftGreenError + "\n" + rightBlueError + "\n" + bufLeft + "\n" + bufRight);
}
}
</script>

View File

@ -0,0 +1,44 @@
<!--
Copyright (c) 2020 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">
<link rel="stylesheet" href="../../../resources/js-test-style.css"/>
<title>Upload From Srcset With Empty Data</title>
<script src="../../../js/js-test-pre.js"></script>
<script src="../../../js/webgl-test-utils.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<img srcset="data:,a 1x, data:,b 1w" id="i">
<script>
"use strict";
var wtu = WebGLTestUtils;
var successfullyParsed;
description("This test ensures WebGL implementations handle srcsets with empty data.");
debug("Regression test for <a href='http://crbug.com/1085044'>http://crbug.com/1085044</a>");
let gl = wtu.create3DContext();
// Note we run this test synchronously, rather than running it in an async
// function called after "wtu.awaitOrTimeout(img.decode());". This reproduces
// the bug more reliably.
let img = document.getElementById("i");
let tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
// Implementations can decide how to respond to these kinds of bad
// inputs, as long as they don't crash.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
finishTest();
</script>
</body>
</html>

View File

@ -0,0 +1,167 @@
<!--
Copyright (c) 2021 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>Verifies rotation metadata tag is respected when uploading videos to WebGL textures.</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>
<script src="../../../js/tests/tex-image-and-sub-image-utils.js"></script>
</head>
<body onload="run()">
<canvas id="c" width="256" height="256"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
description();
let wtu = WebGLTestUtils;
let tiu = TexImageUtils;
let canvas = document.getElementById("c");
let gl = wtu.create3DContext(canvas);
let program = tiu.setupTexturedQuad(gl, gl.RGBA);
const resourcePath = "../../../resources/";
const mp4Tolerance = 10;
// Significantly higher tolerance needed for VP9 tests. http://crbug.com/1219015 .
const vp9Tolerance = 45;
const expectedColors = {
top: { location: [0.5, 0.25], color: [255, 0, 0] },
left: { location: [0.4, 0.5], color: [0, 0, 255] },
right: { location: [0.6, 0.5], color: [255, 255, 0] },
bottom: { location: [0.5, 0.75], color: [0, 255, 0] },
}
function output(str) {
debug(str);
bufferedLogToConsole(str);
}
function checkPixels(tolerance) {
for (let place in expectedColors) {
let color = expectedColors[place];
let loc = color.location;
let x = loc[0];
let y = loc[1];
output(" Checking " + place);
wtu.checkCanvasRect(gl, Math.floor(canvas.width * x), Math.floor(canvas.height * y), 1, 1,
color.color, "shouldBe " + color.color + " +/-" + tolerance, tolerance);
}
}
function loadVideoElement(filename) {
return new Promise((resolve) => {
const video = document.createElement('video');
video.crossOrigin = 'anonymous';
video.src = resourcePath + filename;
wtu.startPlayingAndWaitForVideo(video, resolve);
});
}
async function testVideoElement(filename, isVP9) {
const video = await loadVideoElement(filename);
output("----------------------------------------------------------------");
output("Testing " + filename + " via HTMLVideoElement");
output(" Testing texImage2D");
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);
wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
const localTolerance = isVP9 ? vp9Tolerance : mp4Tolerance;
checkPixels(localTolerance);
output(" Testing texSubImage2D");
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, video.videoWidth, video.videoHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, video);
wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]);
checkPixels(localTolerance);
}
async function run() {
await (async () => {
const video = document.createElement('video');
if (!video.canPlayType) {
testFailed("video.canPlayType required method missing");
return;
}
let supports_h264 = !!video.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/no/, '');
let supports_vp9 = !!video.canPlayType('video/mp4; codecs="vp09.00.10.08"').replace(/no/, '');
if (!supports_h264 && !supports_vp9) {
testFailed("No supported video types.");
return;
}
let tex = gl.createTexture();
// Bind the texture to the default texture unit 0
gl.bindTexture(gl.TEXTURE_2D, tex);
// Set up texture parameters
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// These files were created by converting exif-orientation-test.psd to mp4
// files, rotating them using the transpose filter, and adding rotate metadata, all
// using the ffmpeg command-line tool.
//
// From sdk/tests/resources/ directory:
//
// 0:
// ffmpeg -noautorotate -i exif-orientation-originals\exif-orientation-test.psd -vf scale=128x96 -pix_fmt yuv420p -y temp.mp4
// ffmpeg -i temp.mp4 -c copy -metadata:s:v:0 rotate=0 video-rotation-0.mp4
// ffmpeg -noautorotate -i exif-orientation-originals\exif-orientation-test.psd -vf scale=128x96 -pix_fmt yuv420p -crf 0 -vcodec libvpx-vp9 -y temp.mp4
// ffmpeg -i temp.mp4 -c copy -metadata:s:v:0 rotate=0 video-rotation-0.vp9.mp4
//
// 90:
// ffmpeg -noautorotate -i exif-orientation-originals\exif-orientation-test.psd -vf scale=128x96,transpose=2 -pix_fmt yuv420p -y temp.mp4
// ffmpeg -i temp.mp4 -c copy -metadata:s:v:0 rotate=270 video-rotation-90.mp4
// ffmpeg -noautorotate -i exif-orientation-originals\exif-orientation-test.psd -vf scale=128x96,transpose=2 -pix_fmt yuv420p -crf 0 -vcodec libvpx-vp9 -y temp.mp4
// ffmpeg -i temp.mp4 -c copy -metadata:s:v:0 rotate=270 video-rotation-90.vp9.mp4
//
// 180:
// ffmpeg -noautorotate -i exif-orientation-originals\exif-orientation-test.psd -vf scale=128x96,transpose=2,transpose=2 -pix_fmt yuv420p -y temp.mp4
// ffmpeg -i temp.mp4 -c copy -metadata:s:v:0 rotate=180 video-rotation-180.mp4
// ffmpeg -noautorotate -i exif-orientation-originals\exif-orientation-test.psd -vf scale=128x96,transpose=2,transpose=2 -pix_fmt yuv420p -crf 0 -vcodec libvpx-vp9 -y temp.mp4
// ffmpeg -i temp.mp4 -c copy -metadata:s:v:0 rotate=180 video-rotation-180.vp9.mp4
//
// 270:
// ffmpeg -noautorotate -i exif-orientation-originals\exif-orientation-test.psd -vf scale=128x96,transpose=1 -pix_fmt yuv420p -y temp.mp4
// ffmpeg -i temp.mp4 -c copy -metadata:s:v:0 rotate=90 video-rotation-270.mp4
// ffmpeg -noautorotate -i exif-orientation-originals\exif-orientation-test.psd -vf scale=128x96,transpose=1 -pix_fmt yuv420p -crf 0 -vcodec libvpx-vp9 -y temp.mp4
// ffmpeg -i temp.mp4 -c copy -metadata:s:v:0 rotate=90 video-rotation-270.vp9.mp4
const filenames = [
"video-rotation-0",
"video-rotation-90",
"video-rotation-180",
"video-rotation-270",
];
if (supports_h264) {
for (let fn of filenames)
await testVideoElement(fn + ".mp4", false);
}
if (supports_vp9) {
for (let fn of filenames)
await testVideoElement(fn + ".vp9.mp4", true);
}
})();
finishTest();
}
var successfullyParsed = true;
</script>
</body>
</html>

View File

@ -164,9 +164,9 @@ function testInheritanceHierarchy() {
try {
var foo = ArrayBufferView;
testFailed('ArrayBufferView has [NoInterfaceObject] extended attribute and should not be defined');
testFailed('ArrayBufferView is a typedef and should not be defined');
} catch (e) {
testPassed('ArrayBufferView has [NoInterfaceObject] extended attribute and was (correctly) not defined');
testPassed('ArrayBufferView is a typedef and was (correctly) not defined');
}
// Uint8ClampedArray inherited from Uint8Array in earlier versions

View File

@ -33,6 +33,25 @@ found in the LICENSE.txt file.
gl_FragColor = vec4(color[0]$(elem), color[1]$(elem), color[2]$(elem), 1);
}
</script>
<script id="vshader300" type="x-shader/x-vertex">
#version 300 es
in vec4 a_position;
void main()
{
gl_Position = a_position;
}
</script>
<script id="fshader300" type="x-shader/x-fragment">
#version 300 es
precision mediump float;
uniform $(type) color[3];
out vec4 o_FragColor;
void main()
{
o_FragColor = vec4(color[0]$(elem), color[1]$(elem), color[2]$(elem), 1);
}
</script>
<script>
"use strict";
description();
@ -42,10 +61,17 @@ var MaxInt32PlusOne = 4294967296;
var wtu = WebGLTestUtils;
var gl = wtu.create3DContext("example");
var vSrc = wtu.getScript("vshader");
var fTemplate = wtu.getScript("fshader");
const contextVersion = wtu.getDefault3DContextVersion();
var typeInfos = [
let [vElemId, fElemId] = ["vshader", "fshader"];
if (contextVersion >= 2) {
[vElemId, fElemId] = ["vshader300", "fshader300"];
}
var vSrc = wtu.getScript(vElemId).trim();
var fTemplate = wtu.getScript(fElemId).trim();
const typeInfos = [
{ type: 'float',
jsTypeOf: 'number',
setter: 'uniform1fv',
@ -185,6 +211,428 @@ var typeInfos = [
}
];
if (contextVersion >= 2) {
const more = [
{ type: 'int',
jsTypeOf: 'number',
setter: 'uniform1iv',
elem: '',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform2iv(loc, [1, 2]);
},
srcValueAsString: function(index, srcValues) {
return srcValues[index].toString();
},
returnValueAsString: function(value) {
return value === null ? 'null' : value.toString();
},
checkType: function(value) {
return typeof value === 'number';
},
checkValue: function(typeInfo, index, value) {
return typeInfo.srcValues[index] == value;
},
srcValues: [16, 15, 14],
srcValuesLess: [],
srcValuesLessMultiple: [16],
srcValuesMoreMultiple: [16, 15, 14, 13],
srcValuesNonMultiple: null,
},
{ type: 'ivec2',
jsTypeOf: 'Int32Array',
setter: 'uniform2iv',
elem: '[1]',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform1iv(loc, [2]);
},
illegalSet: function(loc) {
gl.uniform1iv(loc, 2);
},
srcValueAsString: function(index, srcValues) {
return "[" + srcValues[index * 2 + 0].toString() + ", " +
srcValues[index * 2 + 1].toString() + "]";
},
returnValueAsString: function(value) {
return value === null ? 'null' : ("[" + value[0] + ", " + value[1] + "]");
},
checkType: function(value) {
return value &&
typeof value.length === 'number' &&
value.length == 2;
},
checkValue: function(typeInfo, index, value) {
return value !== null &&
typeInfo.srcValues[index * 2 + 0] == value[0] &&
typeInfo.srcValues[index * 2 + 1] == value[1];
},
srcValues: [16, 15, 14, 13, 12, 11],
srcValuesLess: [16],
srcValuesLessMultiple: [16, 15, 14, 13],
srcValuesMoreMultiple: [16, 15, 14, 13, 12, 11, 10, 9],
srcValuesNonMultiple: [16, 15, 14, 13, 12, 11, 10],
},
{ type: 'ivec3',
jsTypeOf: 'Int32Array',
setter: 'uniform3iv',
elem: '[2]',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform1iv(loc, [2]);
},
illegalSet: function(loc) {
gl.uniform1iv(loc, 2);
},
srcValueAsString: function(index, srcValues) {
return "[" + srcValues[index * 3 + 0].toString() + ", " +
srcValues[index * 3 + 1].toString() + ", " +
srcValues[index * 3 + 2].toString() + "]";
},
returnValueAsString: function(value) {
return value === null ? 'null' :
("[" + value[0] + ", " + value[1] + ", " + value[2] + "]");
},
checkType: function(value) {
return value &&
typeof value.length === 'number' &&
value.length == 3;
},
checkValue: function(typeInfo, index, value) {
return value !== null &&
typeInfo.srcValues[index * 3 + 0] == value[0] &&
typeInfo.srcValues[index * 3 + 1] == value[1] &&
typeInfo.srcValues[index * 3 + 2] == value[2];
},
srcValues: [16, 15, 14, 13, 12, 11, 10, 9, 8],
srcValuesLess: [16, 15],
srcValuesLessMultiple: [16, 15, 14, 13, 12, 11],
srcValuesMoreMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2],
srcValuesNonMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7],
},
{ type: 'ivec4',
jsTypeOf: 'Int32Array',
setter: 'uniform4iv',
elem: '[3]',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform1iv(loc, [2]);
},
illegalSet: function(loc) {
gl.uniform1iv(loc, 2);
},
srcValueAsString: function(index, srcValues) {
return "[" + srcValues[index * 4 + 0].toString() + ", " +
srcValues[index * 4 + 1].toString() + ", " +
srcValues[index * 4 + 2].toString() + ", " +
srcValues[index * 4 + 3].toString() + "]";
},
returnValueAsString: function(value) {
return value === null ? 'null' :
("[" + value[0] + ", " + value[1] +
", " + value[2] + ", " + value[3] + "]");
},
checkType: function(value) {
return value &&
typeof value.length === 'number' &&
value.length == 4;
},
checkValue: function(typeInfo, index, value) {
return value !== null &&
typeInfo.srcValues[index * 4 + 0] == value[0] &&
typeInfo.srcValues[index * 4 + 1] == value[1] &&
typeInfo.srcValues[index * 4 + 2] == value[2] &&
typeInfo.srcValues[index * 4 + 3] == value[3];
},
srcValues: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5],
srcValuesLess: [16, 15, 14],
srcValuesLessMultiple: [16, 15, 14, 13, 12, 11, 10, 9],
srcValuesMoreMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
srcValuesNonMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4],
},
{ type: 'uint',
jsTypeOf: 'number',
setter: 'uniform1uiv',
elem: '',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform2uiv(loc, [1, 2]);
},
srcValueAsString: function(index, srcValues) {
return srcValues[index].toString();
},
returnValueAsString: function(value) {
return value === null ? 'null' : value.toString();
},
checkType: function(value) {
return typeof value === 'number';
},
checkValue: function(typeInfo, index, value) {
return typeInfo.srcValues[index] == value;
},
srcValues: [16, 15, 14],
srcValuesLess: [],
srcValuesLessMultiple: [16],
srcValuesMoreMultiple: [16, 15, 14, 13],
srcValuesNonMultiple: null,
},
{ type: 'uvec2',
jsTypeOf: 'Uint32Array',
setter: 'uniform2uiv',
elem: '[1]',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform1uiv(loc, [2]);
},
illegalSet: function(loc) {
gl.uniform1uiv(loc, 2);
},
srcValueAsString: function(index, srcValues) {
return "[" + srcValues[index * 2 + 0].toString() + ", " +
srcValues[index * 2 + 1].toString() + "]";
},
returnValueAsString: function(value) {
return value === null ? 'null' : ("[" + value[0] + ", " + value[1] + "]");
},
checkType: function(value) {
return value &&
typeof value.length === 'number' &&
value.length == 2;
},
checkValue: function(typeInfo, index, value) {
return value !== null &&
typeInfo.srcValues[index * 2 + 0] == value[0] &&
typeInfo.srcValues[index * 2 + 1] == value[1];
},
srcValues: [16, 15, 14, 13, 12, 11],
srcValuesLess: [16],
srcValuesLessMultiple: [16, 15, 14, 13],
srcValuesMoreMultiple: [16, 15, 14, 13, 12, 11, 10, 9],
srcValuesNonMultiple: [16, 15, 14, 13, 12, 11, 10],
},
{ type: 'uvec3',
jsTypeOf: 'Uint32Array',
setter: 'uniform3uiv',
elem: '[2]',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform1uiv(loc, [2]);
},
illegalSet: function(loc) {
gl.uniform1uiv(loc, 2);
},
srcValueAsString: function(index, srcValues) {
return "[" + srcValues[index * 3 + 0].toString() + ", " +
srcValues[index * 3 + 1].toString() + ", " +
srcValues[index * 3 + 2].toString() + "]";
},
returnValueAsString: function(value) {
return value === null ? 'null' :
("[" + value[0] + ", " + value[1] + ", " + value[2] + "]");
},
checkType: function(value) {
return value &&
typeof value.length === 'number' &&
value.length == 3;
},
checkValue: function(typeInfo, index, value) {
return value !== null &&
typeInfo.srcValues[index * 3 + 0] == value[0] &&
typeInfo.srcValues[index * 3 + 1] == value[1] &&
typeInfo.srcValues[index * 3 + 2] == value[2];
},
srcValues: [16, 15, 14, 13, 12, 11, 10, 9, 8],
srcValuesLess: [16, 15],
srcValuesLessMultiple: [16, 15, 14, 13, 12, 11],
srcValuesMoreMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2],
srcValuesNonMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7],
},
{ type: 'uvec4',
jsTypeOf: 'Uint32Array',
setter: 'uniform4uiv',
elem: '[3]',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform1uiv(loc, [2]);
},
illegalSet: function(loc) {
gl.uniform1uiv(loc, 2);
},
srcValueAsString: function(index, srcValues) {
return "[" + srcValues[index * 4 + 0].toString() + ", " +
srcValues[index * 4 + 1].toString() + ", " +
srcValues[index * 4 + 2].toString() + ", " +
srcValues[index * 4 + 3].toString() + "]";
},
returnValueAsString: function(value) {
return value === null ? 'null' :
("[" + value[0] + ", " + value[1] +
", " + value[2] + ", " + value[3] + "]");
},
checkType: function(value) {
return value &&
typeof value.length === 'number' &&
value.length == 4;
},
checkValue: function(typeInfo, index, value) {
return value !== null &&
typeInfo.srcValues[index * 4 + 0] == value[0] &&
typeInfo.srcValues[index * 4 + 1] == value[1] &&
typeInfo.srcValues[index * 4 + 2] == value[2] &&
typeInfo.srcValues[index * 4 + 3] == value[3];
},
srcValues: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5],
srcValuesLess: [16, 15, 14],
srcValuesLessMultiple: [16, 15, 14, 13, 12, 11, 10, 9],
srcValuesMoreMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
srcValuesNonMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4],
},
{ type: 'bool',
jsTypeOf: 'boolean',
setter: 'uniform1iv',
elem: '',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform2iv(loc, [1, 2]);
},
srcValueAsString: function(index, srcValues) {
return srcValues[index].toString();
},
returnValueAsString: function(value) {
return value === null ? 'null' : value.toString();
},
checkType: function(value) {
return typeof value === 'boolean';
},
checkValue: function(typeInfo, index, value) {
return typeInfo.srcValues[index] == value;
},
srcValues: [true, true, true],
srcValuesLess: [],
srcValuesLessMultiple: [16],
srcValuesMoreMultiple: [16, 15, 14, 13],
srcValuesNonMultiple: null,
},
{ type: 'bvec2',
jsTypeOf: 'Float32Array',
setter: 'uniform2fv',
elem: '[1]',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform1iv(loc, [2]);
},
illegalSet: function(loc) {
gl.uniform1iv(loc, 2);
},
srcValueAsString: function(index, srcValues) {
return "[" + srcValues[index * 2 + 0].toString() + ", " +
srcValues[index * 2 + 1].toString() + "]";
},
returnValueAsString: function(value) {
return value === null ? 'null' : ("[" + value[0] + ", " + value[1] + "]");
},
checkType: function(value) {
return value &&
typeof value.length === 'number' &&
value.length == 2;
},
checkValue: function(typeInfo, index, value) {
return value !== null &&
typeInfo.srcValues[index * 2 + 0] == value[0] &&
typeInfo.srcValues[index * 2 + 1] == value[1];
},
srcValues: [true, true, true, true, true, true],
srcValuesLess: [16],
srcValuesLessMultiple: [16, 15, 14, 13],
srcValuesMoreMultiple: [16, 15, 14, 13, 12, 11, 10, 9],
srcValuesNonMultiple: [16, 15, 14, 13, 12, 11, 10],
},
{ type: 'bvec3',
jsTypeOf: 'Int32Array',
setter: 'uniform3iv',
elem: '[2]',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform1iv(loc, [2]);
},
illegalSet: function(loc) {
gl.uniform1iv(loc, 2);
},
srcValueAsString: function(index, srcValues) {
return "[" + srcValues[index * 3 + 0].toString() + ", " +
srcValues[index * 3 + 1].toString() + ", " +
srcValues[index * 3 + 2].toString() + "]";
},
returnValueAsString: function(value) {
return value === null ? 'null' :
("[" + value[0] + ", " + value[1] + ", " + value[2] + "]");
},
checkType: function(value) {
return value &&
typeof value.length === 'number' &&
value.length == 3;
},
checkValue: function(typeInfo, index, value) {
return value !== null &&
typeInfo.srcValues[index * 3 + 0] == value[0] &&
typeInfo.srcValues[index * 3 + 1] == value[1] &&
typeInfo.srcValues[index * 3 + 2] == value[2];
},
srcValues: [true, true, true, true, true, true, true, true, true],
srcValuesLess: [16, 15],
srcValuesLessMultiple: [16, 15, 14, 13, 12, 11],
srcValuesMoreMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2],
srcValuesNonMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7],
},
{ type: 'bvec4',
jsTypeOf: 'Uint32Array',
setter: 'uniform4uiv',
elem: '[3]',
numSrcValues: 3,
invalidSet: function(loc) {
gl.uniform1iv(loc, [2]);
},
illegalSet: function(loc) {
gl.uniform1iv(loc, 2);
},
srcValueAsString: function(index, srcValues) {
return "[" + srcValues[index * 4 + 0].toString() + ", " +
srcValues[index * 4 + 1].toString() + ", " +
srcValues[index * 4 + 2].toString() + ", " +
srcValues[index * 4 + 3].toString() + "]";
},
returnValueAsString: function(value) {
return value === null ? 'null' :
("[" + value[0] + ", " + value[1] +
", " + value[2] + ", " + value[3] + "]");
},
checkType: function(value) {
return value &&
typeof value.length === 'number' &&
value.length == 4;
},
checkValue: function(typeInfo, index, value) {
return value !== null &&
typeInfo.srcValues[index * 4 + 0] == value[0] &&
typeInfo.srcValues[index * 4 + 1] == value[1] &&
typeInfo.srcValues[index * 4 + 2] == value[2] &&
typeInfo.srcValues[index * 4 + 3] == value[3];
},
srcValues: [true, true, true, true, true, true, true, true, true, true, true, true],
srcValuesLess: [16, 15, 14],
srcValuesLessMultiple: [16, 15, 14, 13, 12, 11, 10, 9],
srcValuesMoreMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
srcValuesNonMultiple: [16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4],
}
];
typeInfos.push(...more);
}
let loc;
for (var tt = 0; tt < typeInfos.length; ++tt) {
var typeInfo = typeInfos[tt];
debug("");
@ -199,7 +647,8 @@ for (var tt = 0; tt < typeInfos.length; ++tt) {
assertMsg(info.name == "color[0]",
"uniform name is 'color[0]' not 'color' as per OpenGL ES 2.0.24 section 2.10");
shouldBeNull("gl.getUniformLocation(program, 'color[" + MaxInt32PlusOne + "]');");
var loc = gl.getUniformLocation(program, "color[0]");
loc = gl.getUniformLocation(program, "color[0]");
if (!loc) throw 'Missing loc';
var srcValues = typeInfo.srcValues;
var srcValuesLess = typeInfo.srcValuesLess;
var srcValuesLessMultiple = typeInfo.srcValuesLessMultiple;
@ -220,6 +669,20 @@ for (var tt = 0; tt < typeInfos.length; ++tt) {
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
"should fail with non-multiple array size with gl." + typeInfo.setter);
}
const validDatas = [
`new Float32Array(${srcValues.length})`,
`new Float32Array(new ArrayBuffer(4*${srcValues.length}))`,
];
if (window.SharedArrayBuffer) {
validDatas.push(
`new Float32Array(new SharedArrayBuffer(4*${srcValues.length}))`
);
}
for (const x of validDatas) {
shouldNotThrow(`gl.${typeInfo.setter}(loc, ${x});`);
}
gl[typeInfo.setter](loc, srcValues);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
"can set an array of uniforms with gl." + typeInfo.setter);
@ -234,7 +697,7 @@ for (var tt = 0; tt < typeInfos.length; ++tt) {
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
"can call gl.getUniform");
assertMsg(typeInfo.checkType(values),
"gl.getUniform returns the correct type.");
"gl.getUniform returns the correct type. " + `(was ${values.constructor.name})`);
for (var ii = 0; ii < typeInfo.numSrcValues; ++ii) {
shouldBeNull("gl.getUniformLocation(program, 'color[" + (MaxInt32PlusOne + ii) + "]')");
var elemLoc = gl.getUniformLocation(program, "color[" + ii + "]");

View File

@ -19,23 +19,49 @@ found in the LICENSE.txt file.
<canvas id="example" width="2" height="2"> </canvas>
<script id="vshader" type="x-shader/x-vertex">
attribute vec4 vPosition;
uniform mat4 world4;
uniform mat3 world3;
uniform mat2 world2;
void main()
{
gl_Position = vec4(vPosition.xyz, world3[0].x + world2[0].x) * world4;
uniform mat2 world2x2;
uniform mat3 world3x3;
uniform mat4 world4x4;
void main() {
gl_Position.x += world2x2[0][0];
gl_Position.x += world3x3[0][0];
gl_Position.x += world4x4[0][0];
}
</script>
<script id="fshader" type="x-shader/x-fragment">
void main()
{
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
void main() {}
</script>
<script id="vshader300" type="x-shader/x-vertex">
#version 300 es
uniform mat2 world2x2;
uniform mat2x3 world2x3;
uniform mat2x4 world2x4;
uniform mat3x2 world3x2;
uniform mat3 world3x3;
uniform mat3x4 world3x4;
uniform mat4x2 world4x2;
uniform mat4x3 world4x3;
uniform mat4 world4x4;
void main() {
gl_Position.x += world2x2[0][0];
gl_Position.x += world2x3[0][0];
gl_Position.x += world2x4[0][0];
gl_Position.x += world3x2[0][0];
gl_Position.x += world3x3[0][0];
gl_Position.x += world3x4[0][0];
gl_Position.x += world4x2[0][0];
gl_Position.x += world4x3[0][0];
gl_Position.x += world4x4[0][0];
}
</script>
<script id="fshader300" type="x-shader/x-fragment">
#version 300 es
void main() {}
</script>
<script>
"use strict";
description("This test ensures WebGL implementations handle uniformMatrix in a OpenGL ES 2.0 spec compliant way");
@ -46,20 +72,42 @@ debug("Checking gl.uniformMatrix.");
var wtu = WebGLTestUtils;
var gl = wtu.create3DContext("example");
var contextVersion = wtu.getDefault3DContextVersion();
var program = wtu.setupProgram(gl, ["vshader", "fshader"], ["vPosition"]);
for (var ii = 2; ii <= 4; ++ii) {
var loc = gl.getUniformLocation(program, "world" + ii);
var matLess = [];
for (var jj = 0; jj < ii; ++jj) {
for (var ll = 0; ll < ii; ++ll) {
if (jj == ii - 1 && ll == ii - 1)
continue;
matLess[jj * ii + ll] = (jj == ll) ? 1 : 0;
let shaders = ["vshader", "fshader"];
const dims = [
[2, 2, 'uniformMatrix2fv'],
[3, 3, 'uniformMatrix3fv'],
[4, 4, 'uniformMatrix4fv'],
];
if (contextVersion >= 2) {
shaders = ["vshader300", "fshader300"];
dims.push(
[2, 3, 'uniformMatrix2x3fv'],
[2, 4, 'uniformMatrix2x4fv'],
[3, 2, 'uniformMatrix3x2fv'],
[3, 4, 'uniformMatrix3x4fv'],
[4, 2, 'uniformMatrix4x2fv'],
[4, 3, 'uniformMatrix4x3fv']
);
}
const program = wtu.setupProgram(gl, shaders);
let loc;
for (const [A, B, name] of dims) {
loc = gl.getUniformLocation(program, `world${A}x${B}`);
if (!loc) throw 'missing loc';
const mat = [];
for (let a = 0; a < A; ++a) {
for (let b = 0; b < B; ++b) {
mat.push((a == b) ? 1 : 0);
}
}
var mat = matLess.concat([1]);
var matMore = mat.concat([1]);
name = "uniformMatrix" + ii + "fv";
const matLess = mat.slice(0, mat.length-2);
const matMore = mat.concat([1]);
gl[name](loc, false, matLess);
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "should fail with insufficient array size for " + name);
gl[name](loc, false, mat);
@ -67,7 +115,19 @@ for (var ii = 2; ii <= 4; ++ii) {
gl[name](loc, false, matMore);
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "should fail with more than 1 array size for " + name);
mat[ii * ii - 1] = 1;
const validDatas = [
`new Float32Array(${mat.length})`,
`new Float32Array(new ArrayBuffer(4*${mat.length}))`,
];
if (window.SharedArrayBuffer) {
validDatas.push(
`new Float32Array(new SharedArrayBuffer(4*${mat.length}))`
);
}
for (const x of validDatas) {
shouldNotThrow(`gl.${name}(loc, false, ${x});`);
}
gl[name](loc, false, mat);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "can call " + name + "with transpose = false");
if (contextVersion <= 1) {

View File

@ -16,8 +16,8 @@ found in the LICENSE.txt file.
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
<canvas id="canvas2d" width="40" height="40"> </canvas>
<canvas id="canvas1" style="width: 50px; height: 50px;"> </canvas>
<canvas id="canvas2" style="width: 50px; height: 50px;"> </canvas>
<script>
"use strict";
description("This test ensures WebGL2 implementations interact correctly with the canvas tag.");
@ -25,24 +25,53 @@ description("This test ensures WebGL2 implementations interact correctly with th
debug("");
debug("Canvas.getContext");
assertMsg(window.WebGLRenderingContext,
"WebGL2RenderingContext should be a member of window");
assertMsg('WebGL2RenderingContext' in window,
"WebGL2RenderingContext should be 'in' window");
function runTest() {
assertMsg(window.WebGL2RenderingContext,
"WebGL2RenderingContext should be a member of window");
assertMsg('WebGL2RenderingContext' in window,
"WebGL2RenderingContext should be 'in' window");
var wtu = WebGLTestUtils;
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas, null, 2);
if (!gl) {
testFailed("context does not exist");
} else {
testPassed("context exists");
const wtu = WebGLTestUtils;
let canvas2 = document.getElementById("canvas2");
let gl2 = wtu.create3DContext(canvas2, null, 2);
if (!gl2) {
testFailed("Could not fetch WebGL 2.0 context");
return;
}
testPassed("Fetched WebGL2 context successfully");
debug("Checking context type");
assertMsg(gl instanceof WebGL2RenderingContext,
debug("Checking WebGL2 context type");
assertMsg(gl2 instanceof WebGL2RenderingContext,
"context type should be WebGL2RenderingContext");
// WebGL1 contexts do not respond to the WebGL2 context type, and vice versa.
let canvas1 = document.getElementById("canvas1");
let gl1 = wtu.create3DContext(canvas1, null, 1);
if (!gl1) {
testFailed("Could not fetch WebGL 1.0 context");
return;
}
debug("Checking WebGL1 context type");
assertMsg(gl1 instanceof WebGLRenderingContext,
"context type should be WebGLRenderingContext");
let msg1 = "A canvas which has created a WebGL 1.0 context should not return it for a 'webgl2' context request";
if (canvas1.getContext("webgl2"))
testFailed(msg1);
else
testPassed(msg1);
let msg2 = "A canvas which has created a WebGL 2.0 context should not return it for a 'webgl' context request";
if (canvas2.getContext("webgl"))
testFailed(msg2);
else
testPassed(msg2);
}
runTest();
debug("");
var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>

View File

@ -11,6 +11,7 @@ found in the LICENSE.txt file.
<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>
<script src="../../js/tests/context-methods.js"></script>
</head>
<body>
<div id="description"></div>
@ -20,7 +21,7 @@ found in the LICENSE.txt file.
"use strict";
description("This test ensures that the WebGL context has all the methods in the specification.");
var methods = [
const methods = [
"getContextAttributes",
"activeTexture",
"attachShader",
@ -249,55 +250,14 @@ var methods = [
"bindVertexArray",
];
// Properties to be ignored because they were added in versions of the
// spec that are backward-compatible with this version
var ignoredMethods = [
// There is no official spec for the commit API yet, the proposal link is:
// https://wiki.whatwg.org/wiki/OffscreenCanvas
"commit"
];
function assertFunction(v, f) {
try {
if (typeof v[f] != "function") {
testFailed("Property either does not exist or is not a function: " + f);
return false;
} else {
return true;
}
} catch(e) {
testFailed("Trying to access the property '" + f + "' threw an error: "+e.toString());
}
}
debug("");
debug("Canvas.getContext");
var wtu = WebGLTestUtils;
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas, null, 2);
var passed = true;
for (var i=0; i<methods.length; i++) {
var r = assertFunction(gl, methods[i]);
passed = passed && r;
}
if (passed) {
testPassed("All WebGL methods found.");
}
var extended = false;
for (var i in gl) {
if (typeof gl[i] == "function" && methods.indexOf(i) == -1 && ignoredMethods.indexOf(i) == -1) {
if (!extended) {
extended = true;
testFailed("Also found the following extra methods:");
}
testFailed(i);
}
}
const wtu = WebGLTestUtils;
const canvas = document.getElementById("canvas");
const gl = wtu.create3DContext(canvas, null, 2);
if (!extended) {
testPassed("No extra methods found on WebGL context.");
}
testContextMethods(gl, methods);
debug("");
var successfullyParsed = true;

View File

@ -1,9 +1,11 @@
ext-color-buffer-float.html
--min-version 2.0.1 ext-color-buffer-half-float.html
ext-disjoint-timer-query-webgl2.html
--min-version 2.0.1 ext-texture-filter-anisotropic.html
--min-version 2.0.1 ext-texture-norm16.html
promoted-extensions.html
promoted-extensions-in-shaders.html
--min-version 2.0.1 oes-draw-buffers-indexed.html
--min-version 2.0.1 ovr_multiview2.html
--min-version 2.0.1 ovr_multiview2_depth.html
--min-version 2.0.1 ovr_multiview2_draw_buffers.html

View File

@ -284,7 +284,7 @@ function runInternalFormatQueryTest()
debug("testing the internal format query");
var maxSamples = gl.getParameter(gl.MAX_SAMPLES);
var formats = new Array(gl.RGBA16F, gl.R32F, gl.RG32F, gl.RGBA32F, gl.R16F, gl.RG16F, gl.R11F_G11F_B10F);
const formats = [gl.RGBA16F, gl.R32F, gl.RG32F, gl.RGBA32F, gl.R16F, gl.RG16F, gl.R11F_G11F_B10F];
var firstMultiOnlyFormat = 4;
for (var fmt = 0; fmt < formats.length; ++fmt) {
var samples = gl.getInternalformatParameter(gl.RENDERBUFFER, formats[fmt], gl.SAMPLES);

View File

@ -0,0 +1,27 @@
<!--
Copyright (c) 2020 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 2 EXT_color_buffer_half_float Conformance 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>
<div id="description"></div>
<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
<div id="console"></div>
<script>
var version = 2;
</script>
<script src="../../js/tests/ext-color-buffer-half-float.js"></script>
<script src="../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -23,7 +23,7 @@ description("This test verifies the functionality of the EXT_texture_norm16 exte
debug("");
var wtu = WebGLTestUtils;
var gl = wtu.create3DContext();
var gl = wtu.create3DContext(null, null, 2);
var ext;
var formats = null;
@ -138,6 +138,38 @@ function testNorm16Render(interalFormat, format, type, tolerance) {
gl.bindTexture(gl.TEXTURE_2D, null);
}
function testSnorm16Unrenderable(internalFormat, format, type) {
gl.bindTexture(gl.TEXTURE_2D, textures[1]);
gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, 1, 1, 0, format, type, null);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture definition succeeded");
gl.bindFramebuffer(gl.FRAMEBUFFER, fbos[0]);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures[1], 0);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "fbo binding succeeded");
wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, [ gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT, gl.FRAMEBUFFER_UNSUPPORTED ],
"framebuffer should not be complete with SNORM16 texture attached");
}
function runInternalFormatQueryTest()
{
debug("");
debug("testing the internal format query");
var maxSamples = gl.getParameter(gl.MAX_SAMPLES);
const formats = [ext.R16_EXT, ext.RG16_EXT, ext.RGBA16_EXT];
for (const format of formats) {
var samples = gl.getInternalformatParameter(gl.RENDERBUFFER, format, gl.SAMPLES);
if (samples == null || samples.length == 0 || samples[0] < maxSamples) {
testFailed("the maximum value in SAMPLES should be at least " + maxSamples);
return;
}
}
testPassed("Internal format query succeeded");
}
function runTestExtension() {
textures = [gl.createTexture(), gl.createTexture()];
fbos = [gl.createFramebuffer(), gl.createFramebuffer()];
@ -174,6 +206,11 @@ function runTestExtension() {
testNorm16Render(ext.R16_EXT, gl.RED, gl.UNSIGNED_SHORT, 0);
testNorm16Render(ext.RG16_EXT, gl.RG, gl.UNSIGNED_SHORT, 0);
testNorm16Render(ext.RGBA16_EXT, gl.RGBA, gl.UNSIGNED_SHORT, 0);
testSnorm16Unrenderable(ext.R16_SNORM_EXT, gl.RED, gl.SHORT);
testSnorm16Unrenderable(ext.RG16_SNORM_EXT, gl.RG, gl.SHORT);
testSnorm16Unrenderable(ext.RGB16_SNORM_EXT, gl.RGB, gl.SHORT);
testSnorm16Unrenderable(ext.RGBA16_SNORM_EXT, gl.RGBA, gl.SHORT);
};
function runTest() {
@ -187,6 +224,7 @@ function runTest() {
wtu.runExtensionSupportedTest(gl, "EXT_texture_norm16", ext !== null);
if (ext !== null) {
runInternalFormatQueryTest();
runTestExtension();
} else {
testPassed("No EXT_texture_norm16 support -- this is legal");

View File

@ -0,0 +1,545 @@
<!--
Copyright (c) 2020 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 OES_draw_buffers_indexed Conformance 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>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
description("This test verifies the functionality of the OES_draw_buffers_indexed extension, if it is available.");
debug("");
var wtu = WebGLTestUtils;
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(null, null, 2);
var ext;
const vs = `#version 300 es
layout(location=0) in vec4 vPosition;
void main()
{
gl_Position = vPosition;
}
`;
const fs = `#version 300 es
precision lowp float;
layout(location = 0) out vec4 o_color0;
layout(location = 1) out vec4 o_color1;
void main()
{
o_color0 = vec4(1, 0, 0, 0);
o_color1 = vec4(1, 0, 0, 0);
}
`;
function setup() {
const program = wtu.setupProgram(gl, [vs, fs]);
gl.useProgram(program);
wtu.setupUnitQuad(gl, 0);
wtu.glErrorShouldBe(gl, 0, 'No errors from program');
const tex1 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
wtu.glErrorShouldBe(gl, 0, 'Create texture 1 successfully');
const tex2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex2);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
wtu.glErrorShouldBe(gl, 0, 'Create texture 2 successfully');
const attachments = [gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1];
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[0], gl.TEXTURE_2D, tex1, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, attachments[1], gl.TEXTURE_2D, tex2, 0);
shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
gl.drawBuffers(attachments);
wtu.glErrorShouldBe(gl, 0, 'Set draw buffers without errors');
}
function enableDisableTest() {
debug("Testing enableiOES/disableiOES");
// Invalid input
ext.enableiOES(gl.DEPTH_TEST, 0);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'target could only be gl.BLEND');
ext.disableiOES(gl.DEPTH_TEST, 0);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'target could only be gl.BLEND');
gl.disable(gl.BLEND);
// Valid input
ext.enableiOES(gl.BLEND, 0);
shouldBe('gl.isEnabled(gl.BLEND)', 'true');
ext.disableiOES(gl.BLEND, 0);
ext.enableiOES(gl.BLEND, 1);
shouldBe('gl.isEnabled(gl.BLEND)', 'false');
gl.enable(gl.BLEND);
shouldBe('gl.isEnabled(gl.BLEND)', 'true');
wtu.glErrorShouldBe(gl, 0, 'No errors from enable and disable draw buffers blend state');
}
function constantAlphaBlendColorValidationTest() {
debug("Testing CONSTANT_COLOR/ALPHA blend functions limit validation");
function isConstantColorAndAlphaBlendFunctions(first, second)
{
return (first == gl.CONSTANT_COLOR || first == gl.ONE_MINUS_CONSTANT_COLOR) &&
(second == gl.CONSTANT_ALPHA || second == gl.ONE_MINUS_CONSTANT_ALPHA);
}
function checkBlendFunctions(src, dst)
{
if (isConstantColorAndAlphaBlendFunctions(src, dst) ||
isConstantColorAndAlphaBlendFunctions(dst, src))
{
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, 'invalid combinations');
return false;
}
else
{
wtu.glErrorShouldBe(gl, 0, 'No error');
return true;
}
}
const srcFunc = [
gl.ZERO,
gl.ONE,
gl.SRC_COLOR,
gl.ONE_MINUS_SRC_COLOR,
gl.DST_COLOR,
gl.ONE_MINUS_DST_COLOR,
gl.SRC_ALPHA,
gl.ONE_MINUS_SRC_ALPHA,
gl.DST_ALPHA,
gl.ONE_MINUS_DST_ALPHA,
gl.CONSTANT_COLOR,
gl.ONE_MINUS_CONSTANT_COLOR,
gl.CONSTANT_ALPHA,
gl.ONE_MINUS_CONSTANT_ALPHA,
gl.SRC_ALPHA_SATURATE,
];
const dstFunc = [
gl.ZERO, gl.ONE,
gl.SRC_COLOR, gl.ONE_MINUS_SRC_COLOR,
gl.DST_COLOR, gl.ONE_MINUS_DST_COLOR,
gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA,
gl.DST_ALPHA, gl.ONE_MINUS_DST_ALPHA,
gl.CONSTANT_COLOR, gl.ONE_MINUS_CONSTANT_COLOR,
gl.CONSTANT_ALPHA, gl.ONE_MINUS_CONSTANT_ALPHA,
];
let src, dst;
// CONSTANT_COLOR/ALPHA invalid combination check
for (let i = 0, leni = srcFunc.length; i < leni; i++)
{
src = srcFunc[i];
for (let j = 0, lenj = dstFunc.length; j < lenj; j++)
{
dst = dstFunc[j];
ext.blendFunciOES(0, src, dst);
checkBlendFunctions(src, dst);
ext.blendFuncSeparateiOES(0, src, dst, gl.ONE, gl.ONE);
checkBlendFunctions(src, dst);
}
}
}
function indexedBlendColorTest() {
debug('');
debug("Testing blendEquationiOES and blendFunciOES");
wtu.glErrorShouldBe(gl, 0, 'top of indexedBlendColorTest');
gl.clearColor(0, 0, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
ext.blendEquationiOES(0, gl.FUNC_ADD);
ext.blendFunciOES(0, gl.ONE, gl.ONE);
ext.blendEquationiOES(1, gl.FUNC_ADD);
ext.blendFunciOES(1, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.drawArrays(gl.TRIANGLES, 0, 6);
wtu.glErrorShouldBe(gl, 0, 'Draw quad without errors');
gl.readBuffer(gl.COLOR_ATTACHMENT0);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, [255, 0, 255, 255]);
gl.readBuffer(gl.COLOR_ATTACHMENT1);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 255, 255]);
debug("Testing blendEquationSeparateiOES and blendFuncSeparateiOES");
gl.clear(gl.COLOR_BUFFER_BIT);
ext.blendEquationSeparateiOES(0, gl.FUNC_ADD, gl.FUNC_SUBTRACT);
ext.blendFuncSeparateiOES(0, gl.ONE, gl.ONE, gl.ZERO, gl.ZERO);
ext.blendEquationSeparateiOES(1, gl.FUNC_ADD, gl.FUNC_SUBTRACT);
ext.blendFuncSeparateiOES(1, gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ZERO);
gl.drawArrays(gl.TRIANGLES, 0, 6);
wtu.glErrorShouldBe(gl, 0, 'Draw quad without errors');
gl.readBuffer(gl.COLOR_ATTACHMENT0);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, [255, 0, 255, 0]);
gl.readBuffer(gl.COLOR_ATTACHMENT1);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 255, 0]);
debug("Testing colorMaskiOES");
gl.clear(gl.COLOR_BUFFER_BIT);
ext.colorMaskiOES(0, false, false, false, false);
ext.colorMaskiOES(1, true, true, true, true);
gl.drawArrays(gl.TRIANGLES, 0, 6);
wtu.glErrorShouldBe(gl, 0, 'Draw quad without errors');
gl.readBuffer(gl.COLOR_ATTACHMENT0);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 255, 255]);
gl.readBuffer(gl.COLOR_ATTACHMENT1);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 255, 0]);
debug('');
debug(`Testing that new tokens aren't on the extension.`);
shouldBe('ext.BLEND_EQUATION_RGB', 'undefined');
shouldBe('ext.BLEND_EQUATION_ALPHA', 'undefined');
shouldBe('ext.BLEND_SRC_RGB', 'undefined');
shouldBe('ext.BLEND_SRC_ALPHA', 'undefined');
shouldBe('ext.BLEND_DST_RGB', 'undefined');
shouldBe('ext.BLEND_DST_ALPHA', 'undefined');
shouldBe('ext.COLOR_WRITEMASK', 'undefined');
debug("Testing new tokens for getIndexedParameterTest");
shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 0)', 'gl.FUNC_ADD');
shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_ALPHA, 0)', 'gl.FUNC_SUBTRACT');
shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)', 'gl.ONE');
shouldBe('gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)', 'gl.ONE');
shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)', 'gl.ZERO');
shouldBe('gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)', 'gl.ZERO');
shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 1)', 'gl.FUNC_ADD');
shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_ALPHA, 1)', 'gl.FUNC_SUBTRACT');
shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_RGB, 1)', 'gl.SRC_ALPHA');
shouldBe('gl.getIndexedParameter(gl.BLEND_DST_RGB, 1)', 'gl.ONE_MINUS_SRC_ALPHA');
shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 1)', 'gl.ZERO');
shouldBe('gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 1)', 'gl.ZERO');
shouldBe('gl.getIndexedParameter(gl.COLOR_WRITEMASK, 0)', '[false, false, false, false]');
shouldBe('gl.getIndexedParameter(gl.COLOR_WRITEMASK, 1)', '[true, true, true, true]');
debug("Testing non-indexed getParamter get state from draw buffer 0");
shouldBe('gl.getParameter(gl.BLEND_SRC_RGB)', 'gl.ONE');
shouldBe('gl.getParameter(gl.BLEND_DST_RGB)', 'gl.ONE');
shouldBe('gl.getParameter(gl.BLEND_SRC_ALPHA)', 'gl.ZERO');
shouldBe('gl.getParameter(gl.BLEND_DST_ALPHA)', 'gl.ZERO');
shouldBe('gl.getParameter(gl.BLEND_EQUATION_RGB)', 'gl.FUNC_ADD');
shouldBe('gl.getParameter(gl.BLEND_EQUATION_ALPHA)', 'gl.FUNC_SUBTRACT');
shouldBe('gl.getParameter(gl.COLOR_WRITEMASK)', '[false, false, false, false]');
debug("Testing non-indexed calls modify all draw buffers state");
gl.blendEquationSeparate(gl.FUNC_SUBTRACT, gl.FUNC_ADD);
gl.blendFuncSeparate(gl.ONE_MINUS_DST_ALPHA, gl.DST_ALPHA, gl.ONE, gl.ONE);
gl.colorMask(true, false, true, false);
wtu.glErrorShouldBe(gl, 0, 'Non-indexed state set without errors');
shouldBe('gl.getParameter(gl.BLEND_EQUATION_RGB)', 'gl.FUNC_SUBTRACT');
shouldBe('gl.getParameter(gl.BLEND_EQUATION_ALPHA)', 'gl.FUNC_ADD');
shouldBe('gl.getParameter(gl.BLEND_SRC_RGB)', 'gl.ONE_MINUS_DST_ALPHA');
shouldBe('gl.getParameter(gl.BLEND_DST_RGB)', 'gl.DST_ALPHA');
shouldBe('gl.getParameter(gl.BLEND_SRC_ALPHA)', 'gl.ONE');
shouldBe('gl.getParameter(gl.BLEND_DST_ALPHA)', 'gl.ONE');
shouldBe('gl.getParameter(gl.COLOR_WRITEMASK)', '[true, false, true, false]');
shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 0)', 'gl.FUNC_SUBTRACT');
shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_ALPHA, 0)', 'gl.FUNC_ADD');
shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_RGB, 0)', 'gl.ONE_MINUS_DST_ALPHA');
shouldBe('gl.getIndexedParameter(gl.BLEND_DST_RGB, 0)', 'gl.DST_ALPHA');
shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 0)', 'gl.ONE');
shouldBe('gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 0)', 'gl.ONE');
shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_RGB, 1)', 'gl.FUNC_SUBTRACT');
shouldBe('gl.getIndexedParameter(gl.BLEND_EQUATION_ALPHA, 1)', 'gl.FUNC_ADD');
shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_RGB, 1)', 'gl.ONE_MINUS_DST_ALPHA');
shouldBe('gl.getIndexedParameter(gl.BLEND_DST_RGB, 1)', 'gl.DST_ALPHA');
shouldBe('gl.getIndexedParameter(gl.BLEND_SRC_ALPHA, 1)', 'gl.ONE');
shouldBe('gl.getIndexedParameter(gl.BLEND_DST_ALPHA, 1)', 'gl.ONE');
shouldBe('gl.getIndexedParameter(gl.COLOR_WRITEMASK, 0)', '[true, false, true, false]');
shouldBe('gl.getIndexedParameter(gl.COLOR_WRITEMASK, 1)', '[true, false, true, false]');
}
function runTestExtension() {
setup();
testInvalidValues();
enableDisableTest();
// blending should be enabled for drawBuffers 0 and 1 at this point
constantAlphaBlendColorValidationTest();
indexedBlendColorTest();
testColorMaskDrawNoOp();
}
function runInvalidEnumsTest() {
debug("Testing new enums for getIndexedParameterTest being invalid before requesting the extension");
gl.getIndexedParameter(0x8009, 0); // BLEND_EQUATION_RGB
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_EQUATION_RGB');
gl.getIndexedParameter(0x883D, 0); // BLEND_EQUATION_ALPHA
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_EQUATION_ALPHA');
gl.getIndexedParameter(0x80C9, 0); // BLEND_SRC_RGB
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_SRC_RGB');
gl.getIndexedParameter(0x80CB, 0); // BLEND_SRC_ALPHA
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_SRC_ALPHA');
gl.getIndexedParameter(0x80C8, 0); // BLEND_DST_RGB
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_DST_RGB');
gl.getIndexedParameter(0x80CA, 0); // BLEND_DST_ALPHA
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, 'BLEND_DST_ALPHA');
gl.getIndexedParameter(0x0C23, 0); // COLOR_WRITEMASK
wtu.glErrorShouldBe(gl, [gl.INVALID_OPERATION, gl.INVALID_ENUM], 'invalid operations or invalid enums for COLOR_WRITEMASK');
}
function testInvalidValues() {
const numDrawBuffers = gl.getParameter(gl.MAX_DRAW_BUFFERS);
if (!numDrawBuffers) throw new Error('!numDrawBuffers');
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.enableiOES(gl.BLEND, -1)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.enableiOES(gl.BLEND, ${numDrawBuffers})`);
wtu.shouldGenerateGLError(gl, 0, `ext.enableiOES(gl.BLEND, ${numDrawBuffers-1})`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.disableiOES(gl.BLEND, -1)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.disableiOES(gl.BLEND, ${numDrawBuffers})`);
wtu.shouldGenerateGLError(gl, 0, `ext.disableiOES(gl.BLEND, ${numDrawBuffers-1})`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendEquationiOES(-1, gl.FUNC_ADD)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendEquationiOES(${numDrawBuffers}, gl.FUNC_ADD)`);
wtu.shouldGenerateGLError(gl, 0, `ext.blendEquationiOES(${numDrawBuffers-1}, gl.FUNC_ADD)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendEquationSeparateiOES(-1, gl.FUNC_ADD, gl.FUNC_ADD)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendEquationSeparateiOES(${numDrawBuffers}, gl.FUNC_ADD, gl.FUNC_ADD)`);
wtu.shouldGenerateGLError(gl, 0, `ext.blendEquationSeparateiOES(${numDrawBuffers-1}, gl.FUNC_ADD, gl.FUNC_ADD)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendFunciOES(-1, gl.ONE, gl.ONE)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendFunciOES(${numDrawBuffers}, gl.ONE, gl.ONE)`);
wtu.shouldGenerateGLError(gl, 0, `ext.blendFunciOES(${numDrawBuffers-1}, gl.ONE, gl.ONE)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendFuncSeparateiOES(-1, gl.ONE, gl.ZERO, gl.ONE, gl.ZERO)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.blendFuncSeparateiOES(${numDrawBuffers}, gl.ONE, gl.ZERO, gl.ONE, gl.ZERO)`);
wtu.shouldGenerateGLError(gl, 0, `ext.blendFuncSeparateiOES(${numDrawBuffers-1}, gl.ONE, gl.ZERO, gl.ONE, gl.ZERO)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.colorMaskiOES(-1, 1,1,1,1)`);
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, `ext.colorMaskiOES(${numDrawBuffers}, 1,1,1,1)`);
wtu.shouldGenerateGLError(gl, 0, `ext.colorMaskiOES(${numDrawBuffers-1}, 1,1,1,1)`);
}
function* range(n) {
for (let i = 0; i < n; i++) {
yield i;
}
}
function testColorMaskDrawNoOp() {
debug('');
debug('testColorMaskDrawNoOp')
// > If any draw buffer with an attachment does not have a defined
// fragment shader output, draws generate INVALID_OPERATION,
// unless all 4 channels of colorMask are set to false.
const NUM_OUTPUTS = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
shouldBeTrue(`${NUM_OUTPUTS} > 1`);
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.viewport(0,0,1,1);
const DRAW_BUFFERS = [];
for (const i of range(NUM_OUTPUTS)) {
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1);
const ca = gl.COLOR_ATTACHMENT0+i;
DRAW_BUFFERS.push(ca)
gl.framebufferTexture2D(gl.FRAMEBUFFER, ca,
gl.TEXTURE_2D, tex, 0);
}
shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
gl.drawBuffers(DRAW_BUFFERS);
console.log('DRAW_BUFFERS', DRAW_BUFFERS);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
for (const i of range(NUM_OUTPUTS)) {
gl.readBuffer(gl.COLOR_ATTACHMENT0+i);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 0, 0], 'initially black');
}
for (const validOutput of range(NUM_OUTPUTS)) {
const invalidOutput = validOutput ^ 0b11;
debug(`validOutput: ${validOutput}, invalidOutput: ${invalidOutput}`);
const prog = wtu.setupProgram(gl, [
`\
#version 300 es
void main() {
gl_Position = vec4(0,0,0,1);
gl_PointSize = 1.0f;
}
`,
`\
#version 300 es
precision mediump float;
layout(location=${validOutput}) out vec4 o_color;
void main() {
o_color = vec4(1,1,1,1);
}
`
]);
gl.useProgram(prog);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
'After init.');
gl.colorMask(1,1,1,1);
gl.drawBuffers(DRAW_BUFFERS);
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION,
'Drawing with unmasked undefined color outputs.');
gl.colorMask(0,0,0,0);
gl.drawBuffers(DRAW_BUFFERS);
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
'Drawing with colorMask-masked-out undefined color outputs.');
gl.colorMask(1,1,1,1);
gl.drawBuffers(DRAW_BUFFERS.map((x,i) => (i == invalidOutput) ? x : 0));
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION,
'Drawing with wrong-id drawBuffer-masked-out undefined color outputs.');
gl.drawBuffers(DRAW_BUFFERS.map((x,i) => (i == validOutput) ? x : 0));
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
'Drawing with drawBuffer-masked-out undefined color outputs.');
gl.colorMask(0,0,0,0);
gl.drawBuffers([]);
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
'Drawing with colorMask+drawBuffer-masked-out undefined color outputs.');
const testMask = (r,g,b,a) => {
debug(`testMask(${[r,g,b,a]})`);
gl.drawBuffers(DRAW_BUFFERS);
gl.colorMask(1,1,1,1);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.colorMask(0,0,0,0);
ext.colorMaskiOES(validOutput, r,g,b,a);
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
`Drawing with sole defined color${validOutput} output writemask: ${[r,g,b,a]}.`);
for (const i of range(NUM_OUTPUTS)) {
gl.readBuffer(gl.COLOR_ATTACHMENT0+i);
let expect = [0,0,0,0];
if (i == validOutput) {
expect = [r,g,b,a].map(x => 0xff*x);
}
wtu.checkCanvasRect(gl, 0, 0, 1, 1, expect, `COLOR_ATTACHMENT${i}: [${expect}]`);
}
gl.colorMask(1,1,1,1);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.colorMask(r,g,b,a);
for (const i of range(NUM_OUTPUTS)) {
if (i == validOutput) continue;
ext.colorMaskiOES(i, 0,0,0,0);
}
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
`Drawing with sole remaining defined color${validOutput} output writemask: ${[r,g,b,a]}.`);
for (const i of range(NUM_OUTPUTS)) {
gl.readBuffer(gl.COLOR_ATTACHMENT0+i);
let expect = [0,0,0,0];
if (i == validOutput) {
expect = [r,g,b,a].map(x => 0xff*x);
}
wtu.checkCanvasRect(gl, 0, 0, 1, 1, expect, `COLOR_ATTACHMENT${i}: [${expect}]`);
}
if (r || g || b || a) {
gl.colorMask(0,0,0,0);
ext.colorMaskiOES(invalidOutput, r,g,b,a);
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION,
`Drawing with wrong-id undefined color output color masked: ${[r,g,b,a]}.`);
gl.drawBuffers([]);
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
'Drawing with wrong-id colorMask, but all-off drawBuffers.');
gl.drawBuffers(DRAW_BUFFERS.map((x,i) => (i == validOutput) ? x : 0));
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
'Drawing with wrong-id colorMask, but right-id drawBuffers masked.');
}
};
testMask(0,0,0,0);
testMask(1,0,0,0);
testMask(0,1,0,0);
testMask(0,0,1,0);
testMask(0,0,0,1);
testMask(1,1,1,1);
}
}
function runTest() {
if (!gl) {
testFailed("context does not exist");
} else {
testPassed("context exists");
runInvalidEnumsTest();
ext = gl.getExtension("OES_draw_buffers_indexed");
wtu.runExtensionSupportedTest(gl, "OES_draw_buffers_indexed", ext !== null);
if (ext !== null) {
runTestExtension();
} else {
testPassed("No OES_draw_buffers_indexed support -- this is legal");
}
}
}
runTest();
var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -38,7 +38,6 @@ var exts = gl.getSupportedExtensions();
var promotedExtensions = [
"ANGLE_instanced_arrays",
"EXT_blend_minmax",
"EXT_color_buffer_half_float",
"EXT_frag_depth",
"EXT_shader_texture_lod",
"EXT_sRGB",

View File

@ -9,7 +9,7 @@
<script src="../../js/webgl-test-utils.js"></script>
</head>
<body>
<script id="vshaderIllegalBaseInstance" type="x-shader/x-vertex">#version 300 es
<script id="vshaderBaseInstanceWithoutExt" type="x-shader/x-vertex">#version 300 es
layout(location = 0) in vec2 vPosition;
out vec4 color;
void main()
@ -18,20 +18,6 @@ void main()
gl_Position = vec4(vPosition * 2.0 - 1.0, gl_BaseInstance, 1);
}
</script>
<script id="vshaderBaseInstanceZero" type="x-shader/x-vertex">#version 300 es
#extension GL_ANGLE_base_vertex_base_instance : require
layout(location = 0) in vec2 vPosition;
out vec4 color;
void main()
{
if (gl_BaseInstance == 0) {
color = vec4(0, 1, 0, 1);
} else {
color = vec4(1, 0, 0, 1);
}
gl_Position = vec4(vPosition * 2.0 - 1.0, 0, 1);
}
</script>
<!-- Check gl_InstanceID starts at 0 regardless of gl_BaseInstance -->
<script id="vshaderInstanceIDCheck" type="x-shader/x-vertex">#version 300 es
layout(location = 0) in vec2 vPosition;
@ -46,7 +32,7 @@ void main()
gl_Position = vec4(vPosition * 2.0 - 1.0, 0, 1);
}
</script>
<script id="vshaderIllegalBaseVertex" type="x-shader/x-vertex">#version 300 es
<script id="vshaderBaseVertexWithoutExt" type="x-shader/x-vertex">#version 300 es
layout(location = 0) in vec2 vPosition;
out vec4 color;
void main()
@ -55,17 +41,13 @@ void main()
gl_Position = vec4(vPosition * 2.0 - 1.0, gl_BaseVertex, 1);
}
</script>
<script id="vshaderBaseVertexZero" type="x-shader/x-vertex">#version 300 es
<script id="vshaderWithExt" type="x-shader/x-vertex">#version 300 es
#extension GL_ANGLE_base_vertex_base_instance : require
layout(location = 0) in vec2 vPosition;
out vec4 color;
void main()
{
if (gl_BaseVertex == 0) {
color = vec4(0, 1, 0, 1);
} else {
color = vec4(1, 0, 0, 1);
}
color = vec4(0, 1, 0, 1);
gl_Position = vec4(vPosition * 2.0 - 1.0, 0, 1);
}
</script>
@ -84,7 +66,6 @@ void main()
}
</script>
<script id="vshaderSimple" type="x-shader/x-vertex">#version 300 es
#extension GL_ANGLE_base_vertex_base_instance : require
layout(location = 0) in vec2 vPosition;
layout(location = 1) in float vInstance;
out vec4 color;
@ -121,7 +102,13 @@ description("This test verifies the functionality of the WEBGL_[multi]_draw_base
const wtu = WebGLTestUtils;
const canvas = document.getElementById("canvas");
const gl = wtu.create3DContext(canvas, null, 2);
canvas.style.backgroundColor = '#000';
canvas.style.imageRendering = 'pixelated'; // Because Chrome doesn't support crisp-edges.
canvas.style.imageRendering = 'crisp-edges';
const attribs = {
antialias: false,
};
const gl = wtu.create3DContext(canvas, attribs, 2);
const width = gl.canvas.width;
const height = gl.canvas.height;
@ -133,6 +120,7 @@ const tileSize = [ 1/x_count, 1/y_count ];
const tilePixelSize = [ Math.floor(width / x_count), Math.floor(height / y_count) ];
const quadRadius = [ 0.25 * tileSize[0], 0.25 * tileSize[1] ];
const pixelCheckSize = [ Math.floor(quadRadius[0] * width), Math.floor(quadRadius[1] * height) ];
const bufferUsageSet = [ gl.STATIC_DRAW, gl.DYNAMIC_DRAW ];
function getTileCenter(x, y) {
return [ tileSize[0] * (0.5 + x), tileSize[1] * (0.5 + y) ];
@ -193,18 +181,6 @@ const vertexBuffer = gl.createBuffer();
const nonIndexedVertexBuffer = gl.createBuffer();
const instanceIDBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, nonIndexedVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, nonIndexedVertices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, instanceIDBuffer);
gl.bufferData(gl.ARRAY_BUFFER, instanceIDs, gl.STATIC_DRAW);
const drawArraysDrawCount = x_count / 2;
let drawArraysParams = {
drawCount: drawArraysDrawCount,
@ -237,6 +213,20 @@ for (let v = 0; v < y_count; ++v) {
}
}
function setupGeneralBuffers(bufferUsage) {
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, bufferUsage);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, bufferUsage);
gl.bindBuffer(gl.ARRAY_BUFFER, nonIndexedVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, nonIndexedVertices, bufferUsage);
gl.bindBuffer(gl.ARRAY_BUFFER, instanceIDBuffer);
gl.bufferData(gl.ARRAY_BUFFER, instanceIDs, bufferUsage);
}
// Check if the extension is either both enabled and supported or
// not enabled and not supported.
function runSupportedTest(extensionName, extensionEnabled) {
@ -267,8 +257,245 @@ function runTest() {
doTest('WEBGL_draw_instanced_base_vertex_base_instance', false);
doTest('WEBGL_multi_draw_instanced_base_vertex_base_instance', true);
testGlslBuiltins();
}
// -
function* range(n) {
for (let i = 0; i < n; i++) {
yield i;
}
}
function crossCombine(...args) {
function crossCombine2(listA, listB) {
const listC = [];
for (const a of listA) {
for (const b of listB) {
const c = Object.assign({}, a, b);
listC.push(c);
}
}
return listC;
}
let res = [{}];
while (args.length) {
const next = args.shift();
next[0].defined;
res = crossCombine2(res, next);
}
return res;
}
// -
const PASSTHROUGH_FRAG_SRC = `\
#version 300 es
precision mediump float;
in vec4 v_color;
out vec4 o_color;
void main() {
o_color = v_color;
}
`;
function testGlslBuiltins() {
const EXT = gl.getExtension('WEBGL_draw_instanced_base_vertex_base_instance');
const vertid_prog = (() => {
const vert_src = `\
#version 300 es
#line 405
layout(location = 0) in int a_vertex_id; // Same as first_vert+gl_VertexID
out vec4 v_color;
void main() {
gl_Position = vec4(0,0,0,1);
gl_PointSize = 1.0;
v_color = vec4(float(gl_VertexID), float(a_vertex_id),0,0);
v_color /= 255.0;
}
`;
const prog = wtu.setupProgram(gl, [vert_src, PASSTHROUGH_FRAG_SRC],
undefined, undefined, /*logShaders*/ true);
expectTrue(!!prog, `make_vertid_prog failed`);
return prog;
})();
const instid_prog = (() => {
const vert_src = `\
#version 300 es
#line 425
layout(location = 0) in int a_vertex_id; // Same as first_vert+gl_VertexID
layout(location = 1) in int a_instance_div1; // Same as base_instance+gl_InstanceID
layout(location = 2) in int a_instance_div2; // Same as base_instance+floor(gl_InstanceID/2)
layout(location = 3) in int a_instance_div3; // Same as base_instance+floor(gl_InstanceID/3)
out vec4 v_color;
void main() {
gl_Position = vec4(0,0,0,1);
gl_PointSize = 1.0;
v_color = vec4(float(gl_InstanceID), float(a_instance_div1),
float(a_instance_div2), float(a_instance_div3));
v_color /= 255.0;
}
`;
const prog = wtu.setupProgram(gl, [vert_src, PASSTHROUGH_FRAG_SRC],
undefined, undefined, /*logShaders*/ true);
expectTrue(!!prog, `make_instid_prog failed`);
return prog;
})();
const COUNT_UP_DATA = new Int32Array(1000);
for (const i in COUNT_UP_DATA) {
COUNT_UP_DATA[i] = i;
}
const vertex_id_buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_id_buf);
gl.bufferData(gl.ARRAY_BUFFER, COUNT_UP_DATA, gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribIPointer(0, 1, gl.INT, 0, 0);
gl.enableVertexAttribArray(1);
gl.vertexAttribIPointer(1, 1, gl.INT, 0, 0);
gl.vertexAttribDivisor(1, 1);
gl.enableVertexAttribArray(2);
gl.vertexAttribIPointer(2, 1, gl.INT, 0, 0);
gl.vertexAttribDivisor(2, 2);
gl.enableVertexAttribArray(3);
gl.vertexAttribIPointer(3, 1, gl.INT, 0, 0);
gl.vertexAttribDivisor(3, 3);
const index_buf = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buf);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, COUNT_UP_DATA, gl.STATIC_DRAW);
gl.canvas.width = gl.canvas.height = 1;
gl.canvas.style.width = gl.canvas.style.height = '1em';
gl.viewport(0, 0, 1, 1);
const expect_pixel = (() => {
const was = new Uint8Array(4);
return (desc, subtest, expected) => {
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, was);
if (!areArraysEqual(was, expected)) {
testFailed(`${subtest}: Expected [${expected}], was [${was}]. desc: ${JSON.stringify(desc)}`);
} else {
debug(`${subtest}: Was [${was}] as expected.`);
}
};
})();
// Common setup complete
// -
// Create testcases
const DRAW_FUNC_COMBINER = [{
name: 'drawArraysInstanced',
draw: desc => {
if (desc.base_vert) return false;
if (desc.base_inst) return false;
gl.drawArraysInstanced(gl[desc.mode], desc.first_vert,
desc.vert_count, desc.inst_count);
return true;
},
}, {
name: 'drawElementsInstanced',
draw: desc => {
if (desc.base_vert) return false;
if (desc.base_inst) return false;
gl.drawElementsInstanced(gl[desc.mode], desc.vert_count,
gl.UNSIGNED_INT, 4*desc.first_vert, desc.inst_count);
return true;
},
}, {
name: 'drawArraysInstancedBaseInstanceWEBGL',
draw: desc => {
if (desc.base_vert) return false;
if (!EXT) return false;
EXT.drawArraysInstancedBaseInstanceWEBGL(gl[desc.mode],
desc.first_vert, desc.vert_count, desc.inst_count,
desc.base_inst);
return true;
},
}, {
name: 'drawElementsInstancedBaseVertexBaseInstanceWEBGL',
draw: desc => {
if (!EXT) return false;
EXT.drawElementsInstancedBaseVertexBaseInstanceWEBGL(
gl[desc.mode], desc.vert_count, gl.UNSIGNED_INT, 4*desc.first_vert,
desc.inst_count, desc.base_vert, desc.base_inst);
return true;
},
}];
// -
function make_key_combiner(key, vals) {
const ret = [];
for (const v of vals) {
const cur = {};
cur[key] = v;
ret.push(cur);
}
return ret;
}
const TEST_DESCS = crossCombine(
DRAW_FUNC_COMBINER,
make_key_combiner('base_vert', [0,1,2]),
make_key_combiner('vert_count', [0,1,2]),
make_key_combiner('base_inst', [0,1,2]),
make_key_combiner('inst_count', range(10)),
make_key_combiner('first_vert', [0,1,2]),
);
console.log('TEST_DESCS', TEST_DESCS);
// -
// Run testcases
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.STENCIL_TEST);
gl.disable(gl.BLEND);
for (const desc of TEST_DESCS) {
gl.disable(gl.SCISSOR_TEST);
gl.clearBufferfv(gl.COLOR, 0, [1,0,0,1]);
const last_gl_vert_id = desc.base_vert + desc.vert_count - 1;
const last_vert_id = desc.first_vert + last_gl_vert_id;
const last_inst_id = desc.inst_count - 1;
const last_inst_div1 = desc.base_inst + last_inst_id;
const last_inst_div2 = desc.base_inst + Math.floor(last_inst_id / 2);
const last_inst_div3 = desc.base_inst + Math.floor(last_inst_id / 3);
gl.useProgram(vertid_prog);
if (!desc.draw(desc)) continue;
debug('\ndesc: ' + JSON.stringify(desc));
wtu.glErrorAssert(gl, 0);
if (!desc.vert_count || !desc.inst_count) {
expect_pixel(desc, 'vertid_prog', [255, 0, 0, 255]);
continue;
}
expect_pixel(desc, 'vertid_prog', [last_gl_vert_id, last_vert_id, 0, 0]);
gl.useProgram(instid_prog);
desc.draw(desc);
expect_pixel(desc, 'instid_prog', [last_inst_id, last_inst_div1, last_inst_div2, last_inst_div3]);
}
}
// -
function doTest(extensionName, multiDraw) {
const ext = gl.getExtension(extensionName);
if (!runSupportedTest(extensionName, ext)) {
@ -279,21 +506,20 @@ function doTest(extensionName, multiDraw) {
const vs = [
'#version 300 es',
config.isMultiDraw ? '#extension GL_ANGLE_multi_draw : require' : '',
'#extension GL_ANGLE_base_vertex_base_instance : require',
//'#extension GL_ANGLE_base_vertex_base_instance : require',
'#define kCountX ' + countX.toString(),
'#define kCountY ' + countY.toString(),
'layout(location = 0) in vec2 vPosition;',
config.useBaseInstanceBuiltin ? '' : 'layout(location = 1) in float vInstanceID;',
'layout(location = 1) in float vInstanceID;',
'out vec4 color;',
'void main()',
'{',
' const float xStep = 1.0 / float(kCountX);',
' const float yStep = 1.0 / float(kCountY);',
' float xID = ' + (config.useBaseInstanceBuiltin ? 'float(gl_InstanceID + gl_BaseInstance)' : 'vInstanceID') + ';',
' float xID = vInstanceID;',
' float xColor = 1.0 - xStep * xID;',
' float yID = floor(float(gl_VertexID) / ' + (config.isDrawArrays ? '6.0' : '4.0') + ' + 0.01);',
' color = vec4(xColor, 1.0 - yStep * yID, ',
config.useBaseVertexBuiltin ? '1.0 - yStep * float(gl_BaseVertex) / 4.0' : '1.0',
' color = vec4(xColor, 1.0 - yStep * yID, 1.0',
' , 1.0);',
' mat3 transform = mat3(1.0);',
' transform[2][0] = xID * xStep;',
@ -306,20 +532,20 @@ function doTest(extensionName, multiDraw) {
return [vs, fs];
}
function runValidationTests() {
function runValidationTests(bufferUsage) {
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0.2,0.2, 0.8,0.2, 0.5,0.8 ]), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0.2,0.2, 0.8,0.2, 0.5,0.8 ]), bufferUsage);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([ 0, 1, 2 ]), gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([ 0, 1, 2 ]), bufferUsage);
const instanceBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, instanceBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0, 1, 2 ]), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0, 1, 2 ]), bufferUsage);
const program = wtu.setupProgram(gl, ['vshaderSimple', 'fshader'], ['vPosition, vInstanceID'], [0, 1]);
const program = wtu.setupProgram(gl, ['vshaderSimple', 'fshader'], ['vPosition, vInstanceID'], [0, 1], true);
expectTrue(program != null, "can compile simple program");
function setupInstanced() {
@ -486,39 +712,28 @@ function doTest(extensionName, multiDraw) {
}
}
function runShaderTests() {
const illegalBaseInstanceProgram = wtu.setupProgram(gl, ["vshaderIllegalBaseInstance", "fshader"]);
expectTrue(illegalBaseInstanceProgram == null, "cannot compile program with gl_BaseInstance but no extension directive");
const illegalBaseVertexProgram = wtu.setupProgram(gl, ["vshaderIllegalBaseVertex", "fshader"]);
expectTrue(illegalBaseVertexProgram == null, "cannot compile program with gl_BaseVertex but no extension directive");
function runShaderTests(bufferUsage) {
let badProgram;
badProgram = wtu.setupProgram(gl, ["vshaderBaseInstanceWithoutExt", "fshader"]);
expectTrue(!badProgram, "cannot compile program with gl_BaseInstance but no extension directive");
badProgram = wtu.setupProgram(gl, ["vshaderBaseVertexWithoutExt", "fshader"]);
expectTrue(!badProgram, "cannot compile program with gl_BaseVertex but no extension directive");
badProgram = wtu.setupProgram(gl, ["vshaderWithExt", "fshader"]);
expectTrue(!badProgram, "cannot compile program with #extension GL_ANGLE_base_vertex_base_instance");
const x = Math.floor(width * 0.4);
const y = Math.floor(height * 0.4);
const xSize = Math.floor(width * 0.2);
const ySize = Math.floor(height * 0.2);
// gl_BaseInstance and gl_InstanceID
// gl_InstanceID
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0.5,1, 0,1, 0.5,0, 1,1 ]), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0.5,1, 0,1, 0.5,0, 1,1 ]), bufferUsage);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
const baseInstanceZeroProgram = wtu.setupProgram(gl, ["vshaderBaseInstanceZero", "fshader"], ["vPosition"], [0]);
expectTrue(baseInstanceZeroProgram !== null, "can compile program with gl_BaseInstance");
gl.useProgram(baseInstanceZeroProgram);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
if (!multiDraw) {
ext.drawArraysInstancedBaseInstanceWEBGL(gl.TRIANGLES, 0, 6, 1, 5);
} else {
ext.multiDrawArraysInstancedBaseInstanceWEBGL(gl.TRIANGLES, [0], 0, [6], 0, [1], 0, [5], 0, 1);
}
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
wtu.checkCanvasRect(gl, x, y, xSize, ySize, [0, 255, 0, 255], "gl_BaseInstance is 0 for non-BaseInstance draw calls");
const instanceIDProgram = wtu.setupProgram(gl, ["vshaderInstanceIDCheck", "fshader"], ["vPosition"], [0]);
expectTrue(instanceIDProgram !== null, "can compile program with gl_InstanceID");
gl.useProgram(instanceIDProgram);
@ -532,30 +747,14 @@ function doTest(extensionName, multiDraw) {
wtu.checkCanvasRect(gl, x, y, xSize, ySize, [0, 255, 0, 255], "gl_InstanceID should always starts from 0");
// gl_BaseVertex and gl_VertexID
// gl_VertexID
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0.5,1, 0,1, 0.5,0, 1,1, 0,0, 1,0, 0.5,1, 0,1 ]), gl.STATIC_DRAW);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0, 1,0, 0.5,1, 0,1, 0.5,0, 1,1, 0,0, 1,0, 0.5,1, 0,1 ]), bufferUsage);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([0, 1, 2, 3, 4, 5]), gl.STATIC_DRAW);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array([0, 1, 2, 3, 4, 5]), bufferUsage);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
const baseVertexZeroProgram = wtu.setupProgram(gl, ["vshaderBaseVertexZero", "fshader"], ["vPosition"], [0]);
expectTrue(baseVertexZeroProgram !== null, "can compile program with gl_BaseVertex");
gl.useProgram(baseVertexZeroProgram);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
if (!multiDraw) {
ext.drawElementsInstancedBaseVertexBaseInstanceWEBGL(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, 1, 3, 0);
} else {
ext.multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(gl.TRIANGLES, [6], 0, gl.UNSIGNED_BYTE, [0], 0, [1], 0, [3], 0, [0], 0, 1);
}
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
wtu.checkCanvasRect(gl, x, y, xSize, ySize, [0, 255, 0, 255], "gl_BaseVertex is 0 for non-BaseVertex draw calls");
const vertexIDProgram = wtu.setupProgram(gl, ["vshaderVertexIDCheck", "fshader"], ["vPosition"], [0]);
expectTrue(vertexIDProgram !== null, "can compile program with gl_VertexID");
gl.useProgram(vertexIDProgram);
@ -674,30 +873,6 @@ function doTest(extensionName, multiDraw) {
useBaseInstanceBuiltin: false
});
checkDraw({
drawFunc: multiDraw ? multiDrawArraysInstancedBaseInstance : drawArraysInstancedBaseInstance,
isDrawArrays: true,
isMultiDraw: multiDraw,
useBaseVertexBuiltin: true,
useBaseInstanceBuiltin: false
});
checkDraw({
drawFunc: multiDraw ? multiDrawArraysInstancedBaseInstance : drawArraysInstancedBaseInstance,
isDrawArrays: true,
isMultiDraw: multiDraw,
useBaseVertexBuiltin: false,
useBaseInstanceBuiltin: true
});
checkDraw({
drawFunc: multiDraw ? multiDrawArraysInstancedBaseInstance : drawArraysInstancedBaseInstance,
isDrawArrays: true,
isMultiDraw: multiDraw,
useBaseVertexBuiltin: true,
useBaseInstanceBuiltin: true
});
checkDraw({
drawFunc: multiDraw ? multiDrawElementsInstancedBaseVertexBaseInstance : drawElementsInstancedBaseVertexBaseInstance,
isDrawArrays: false,
@ -705,35 +880,16 @@ function doTest(extensionName, multiDraw) {
useBaseVertexBuiltin: false,
useBaseInstanceBuiltin: false
});
checkDraw({
drawFunc: multiDraw ? multiDrawElementsInstancedBaseVertexBaseInstance : drawElementsInstancedBaseVertexBaseInstance,
isDrawArrays: false,
isMultiDraw: multiDraw,
useBaseVertexBuiltin: true,
useBaseInstanceBuiltin: false
});
checkDraw({
drawFunc: multiDraw ? multiDrawElementsInstancedBaseVertexBaseInstance : drawElementsInstancedBaseVertexBaseInstance,
isDrawArrays: false,
isMultiDraw: multiDraw,
useBaseVertexBuiltin: false,
useBaseInstanceBuiltin: true
});
checkDraw({
drawFunc: multiDraw ? multiDrawElementsInstancedBaseVertexBaseInstance : drawElementsInstancedBaseVertexBaseInstance,
isDrawArrays: false,
isMultiDraw: multiDraw,
useBaseVertexBuiltin: true,
useBaseInstanceBuiltin: true
});
}
runValidationTests();
runShaderTests();
runPixelTests();
for (let i = 0; i < bufferUsageSet.length; i++) {
let bufferUsage = bufferUsageSet[i];
debug("Testing with BufferUsage = " + bufferUsage);
setupGeneralBuffers(bufferUsage);
runValidationTests(bufferUsage);
runShaderTests(bufferUsage);
runPixelTests();
}
}
runTest();

View File

@ -17,6 +17,7 @@ const-array-init.html
forbidden-operators.html
--min-version 2.0.1 forward-declaration.html
frag-depth.html
--min-version 2.0.1 fragment-shader-loop-crash.html
--min-version 2.0.1 gradient-in-discontinuous-loop.html
--min-version 2.0.1 input-with-interpotaion-as-lvalue.html
invalid-default-precision.html
@ -26,6 +27,8 @@ loops-with-side-effects.html
--min-version 2.0.1 matrix-row-major-dynamic-indexing.html
misplaced-version-directive.html
--min-version 2.0.1 no-attribute-vertex-shader.html
--min-version 2.0.1 precision-side-effects-bug.html
--min-version 2.0.1 reciprocal-sqrt-of-sum-of-squares-crash.html
sampler-no-precision.html
--min-version 2.0.1 sampler-array-indexing.html
sequence-operator-returns-non-constant.html
@ -42,6 +45,7 @@ short-circuiting-in-loop-condition.html
texture-offset-out-of-range.html
--min-version 2.0.1 texture-offset-uniform-texture-coordinate.html
--min-version 2.0.1 tricky-loop-conditions.html
--min-version 2.0.1 uint-int-shift-bug.html
--min-version 2.0.1 unary-minus-operator-in-dynamic-loop.html
uniform-block-layouts.html
uniform-block-layout-match.html

View File

@ -0,0 +1,72 @@
<!--
Copyright (c) 2021 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>Fragment shader containing loop should not crash</title>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<link rel="stylesheet" href="../../resources/glsl-feature-tests.css"/>
<script src="../../js/js-test-pre.js"></script>
<script src="../../js/webgl-test-utils.js"></script>
<script src="../../js/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">#version 300 es
precision highp float;
out vec2 v_tex_coord;
uniform mat4 matrix;
void main() {
v_tex_coord = vec2(0.0, 0.0);
gl_Position = vec4(0.0, 0.0, 0.0, 0.0);
}
</script>
<script id="fshader" type="x-shader/x-fragment">#version 300 es
precision highp float;
in vec2 v_tex_coord;
out vec4 out_color;
uniform sampler2D texture_1;
uniform vec2 resolution;
vec4 do_loops(vec4 z)
{
vec4 v[16];
for (int i = 0; i < 16; i++)
{
v[i] = z;
}
return v[1];
}
void main() {
out_color = do_loops(vec4(0.2, 0.4, 0.6, 1.0)) - texture(texture_1, v_tex_coord);
}
</script>
<script type="application/javascript">
"use strict";
description();
const wtu = WebGLTestUtils;
const tests = [
{
vShaderSource: wtu.getScript('vshader'),
fShaderSource: wtu.getScript('fshader'),
vShaderSuccess: true,
fShaderSuccess: true,
linkSuccess: true,
passMsg: 'Fragment shader containing a simple loop should compile and link'
}
];
GLSLConformanceTester.runTests(tests, 2);
</script>
</body>
</html>

View File

@ -0,0 +1,125 @@
<!--
Copyright (c) 2020 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>Verify precision side effects (Adreno driver bug)</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="canvas" width="2" height="2"> </canvas>
<div id="description"></div>
<div id="console"></div>
<script id="vshader-simple" type="x-shader/x-vertex">#version 300 es
in vec3 aPosition;
void main() {
gl_Position = vec4(aPosition, 1.0);
}
</script>
<script id="fshader-int" type="x-shader/x-fragment">#version 300 es
out highp vec4 myFragColor;
void main() {
highp int t;
t = 0 | (int(t == t) * 0x8000);
if (t == 0x8000)
myFragColor = vec4(1.0, 0.0, 0.0, 1.0);
else
myFragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
</script>
<script id="fshader-ivec2" type="x-shader/x-fragment">#version 300 es
out highp vec4 myFragColor;
void main() {
highp ivec2 t;
t = 0 | (ivec2(t == t) * 0x8000);
if (t == ivec2(0x8000))
myFragColor = vec4(1.0, 0.0, 0.0, 1.0);
else
myFragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
</script>
<script id="fshader-ivec3" type="x-shader/x-fragment">#version 300 es
out highp vec4 myFragColor;
void main() {
highp ivec3 t;
t = 0 | (ivec3(t == t) * 0x8000);
if (t == ivec3(0x8000))
myFragColor = vec4(1.0, 0.0, 0.0, 1.0);
else
myFragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
</script>
<script id="fshader-ivec4" type="x-shader/x-fragment">#version 300 es
out highp vec4 myFragColor;
void main() {
highp ivec4 t;
t = 0 | (ivec4(t == t) * 0x8000);
if (t == ivec4(0x8000))
myFragColor = vec4(1.0, 0.0, 0.0, 1.0);
else
myFragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
</script>
<script type="application/javascript">
"use strict";
description("Verify precision side effects");
debug("");
debug("When this test is run on Adreno (no repros on other vendors so far):");
debug(" - the result of the expression 0 | (int(e0 == e0) * 0x8000) somehow returns -32768 instead of 32768 despite the variable using highp precision;");
debug(" - splitting the expression along | fixes the issue (could also be observed with other operators).");
debug('For additional reference see this <a href="https://github.com/KhronosGroup/WebGL/pull/3192">pull request</a> and <a href="http://crbug.com/1155942">Chromium bug</a>');
debug("");
var wtu = WebGLTestUtils;
function test() {
var gl = wtu.create3DContext("canvas", undefined, 2);
if (!gl) {
testFailed("context does not exist");
return;
}
wtu.setupUnitQuad(gl);
var testCases = [
{ vshader: "vshader-simple", fshader: "fshader-int", desc: "fragment shader int" },
{ vshader: "vshader-simple", fshader: "fshader-ivec2", desc: "fragment shader ivec2" },
{ vshader: "vshader-simple", fshader: "fshader-ivec3", desc: "fragment shader ivec3" },
{ vshader: "vshader-simple", fshader: "fshader-ivec4", desc: "fragment shader ivec4" },
];
for (var idx = 0; idx < testCases.length; ++idx) {
var test = testCases[idx];
debug("");
var program = wtu.setupProgram(gl, [test.vshader, test.fshader], ["aPosition"]);
if (!program) {
testFailed("Fail to set up program");
} else {
debug("Testing " + test.desc);
wtu.drawUnitQuad(gl);
wtu.checkCanvas(gl, [255, 0, 0, 255]);
gl.deleteProgram(program);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from testing");
}
}
};
test();
debug("");
var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -0,0 +1,66 @@
<!--
Copyright (c) 2021 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>Shader identified as containing reciprocal square root of sum of squares should not crash</title>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<link rel="stylesheet" href="../../resources/glsl-feature-tests.css"/>
<script src="../../js/js-test-pre.js"></script>
<script src="../../js/webgl-test-utils.js"></script>
<script src="../../js/glsl-conformance-test.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">#version 300 es
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 0.0);
}
</script>
<script id="fshader" type="x-shader/x-fragment">#version 300 es
precision highp float;
#define CRASH 1
out vec4 fragmentColor;
void main()
{
vec2 p = gl_FragCoord.xy;
// This expression meets the requirement of being the reciprocal
// square root of a sum of squares.
float d = 1.0 / length(p);
#if CRASH
if (p.x > 0.0)
{
d *= 2.0;
}
#endif
fragmentColor = vec4(d);
}
</script>
<script type="application/javascript">
"use strict";
description();
debug('Regression test for <a href="https://crbug.com/1079309">crbug.com/1079309</a>');
const wtu = WebGLTestUtils;
const tests = [
{
vShaderSource: wtu.getScript('vshader'),
fShaderSource: wtu.getScript('fshader'),
vShaderSuccess: true,
fShaderSuccess: true,
linkSuccess: true,
passMsg: 'Shader containing expression that driver recognizes as reciprocal square root of sum of squares should compile and link'
}
];
GLSLConformanceTester.runTests(tests, 2);
</script>
</body>
</html>

View File

@ -36,6 +36,59 @@ void main()
}
}
</script>
<script id="fshaderDeclarationInsideSwitchDefault" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 my_FragColor;
uniform int u_zero;
void main()
{
my_FragColor = vec4(1, 0, 0, 1);
switch (u_zero)
{
default:
ivec2 i;
i = ivec2(1, 0);
my_FragColor = vec4(0, i[0], 0, 1);
}
}
</script>
<script id="fshaderDeclarationInsideSwitchLiteral" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 my_FragColor;
void main()
{
my_FragColor = vec4(1, 0, 0, 1);
switch (0)
{
case 0:
ivec2 i;
i = ivec2(1, 0);
my_FragColor = vec4(0, i[0], 0, 1);
}
}
</script>
<script id="fshaderDeclarationInsideSwitchLiteralDefault" type="x-shader/x-fragment">#version 300 es
precision highp float;
out vec4 my_FragColor;
void main()
{
my_FragColor = vec4(1, 0, 0, 1);
switch (0)
{
default:
ivec2 i;
i = ivec2(1, 0);
my_FragColor = vec4(0, i[0], 0, 1);
}
}
</script>
<script id="fshaderDeclarationInsideSwitchScope" type="x-shader/x-fragment">#version 300 es
precision highp float;
@ -221,6 +274,27 @@ GLSLConformanceTester.runTests([
passMsg: 'Declaration inside switch should work.',
render: true
},
{
fShaderId: 'fshaderDeclarationInsideSwitchDefault',
fShaderSuccess: true,
linkSuccess: true,
passMsg: 'Declaration inside switch default case should work.',
render: true
},
{
fShaderId: 'fshaderDeclarationInsideSwitchLiteral',
fShaderSuccess: true,
linkSuccess: true,
passMsg: 'Declaration inside switch with literal value should work.',
render: true
},
{
fShaderId: 'fshaderDeclarationInsideSwitchLiteralDefault',
fShaderSuccess: true,
linkSuccess: true,
passMsg: 'Declaration inside switch with literal value and default case should work.',
render: true
},
{
fShaderId: 'fshaderDeclarationInsideSwitchScope',
fShaderSuccess: true,

View File

@ -0,0 +1,106 @@
<!--
Copyright (c) 2020 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>Verify (uint(int) >> 31) works correctly (Adreno driver bug)</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="canvas" width="2" height="2"> </canvas>
<div id="description"></div>
<div id="console"></div>
<script id="vshader-uint-1" type="x-shader/x-vertex">#version 300 es
in vec3 aPosition;
flat out highp uint uvalue;
uniform highp int ivalue;
void main() {
gl_Position = vec4(aPosition, 1);
uvalue = uint(ivalue) >> 31u;
}
</script>
<script id="fshader-uint-1" type="x-shader/x-fragment">#version 300 es
flat in highp uint uvalue;
out highp vec4 myFragColor;
void main() {
if (uvalue == 1u)
myFragColor = vec4(1.0, 0.0, 0.0, 1.0);
else
myFragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
</script>
<script id="vshader-simple" type="x-shader/x-vertex">#version 300 es
in vec3 aPosition;
void main() {
gl_Position = vec4(aPosition, 1);
}
</script>
<script id="fshader-uint-2" type="x-shader/x-fragment">#version 300 es
uniform highp int ivalue;
out highp vec4 myFragColor;
void main() {
uint uvalue = uint(ivalue) >> 31u;
if (uvalue == 1u)
myFragColor = vec4(1.0, 0.0, 0.0, 1.0);
else
myFragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
</script>
<script type="application/javascript">
"use strict";
description("Verify (uint(int) >> 31) works correctly");
debug("");
var wtu = WebGLTestUtils;
function test() {
var gl = wtu.create3DContext("canvas", undefined, 2);
if (!gl) {
testFailed("context does not exist");
return;
}
wtu.setupUnitQuad(gl);
var testCases = [
{ vshader: "vshader-uint-1", fshader: "fshader-uint-1", desc: "vertex shader uint" },
{ vshader: "vshader-simple", fshader: "fshader-uint-2", desc: "fragment shader uint" },
];
for (var idx = 0; idx < testCases.length; ++idx) {
var test = testCases[idx];
debug("");
var program = wtu.setupProgram(gl, [test.vshader, test.fshader], ["aPosition"]);
if (!program) {
testFailed("Fail to set up program");
} else {
var uniformLoc = gl.getUniformLocation(program, 'ivalue');
gl.uniform1i(uniformLoc, -1);
wtu.drawUnitQuad(gl);
wtu.checkCanvas(gl, [255, 0, 0, 255]);
gl.deleteProgram(program);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from testing");
}
}
};
test();
debug("");
var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -1,6 +1,7 @@
expando-loss-2.html
getextension-while-pbo-bound-stability.html
instanceof-test.html
--min-version 2.0.1 null-object-behaviour-2.html
object-deletion-behaviour-2.html
uninitialized-test-2.html
views-with-offsets.html

View File

@ -0,0 +1,61 @@
<!--
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">
<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>
<div id="console"></div>
<script>
"use strict";
var wtu = WebGLTestUtils;
description("Tests calling WebGL 2 APIs without providing the necessary objects");
var gl = wtu.create3DContext(undefined, undefined, 2);
var shouldGenerateGLError = wtu.shouldGenerateGLError;
for (let nullOrUndefined of [null, undefined]) {
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.deleteQuery(${nullOrUndefined})`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.isQuery(${nullOrUndefined})`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.deleteSync(${nullOrUndefined})`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.isSync(${nullOrUndefined})`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.deleteTransformFeedback(${nullOrUndefined})`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.isTransformFeedback(${nullOrUndefined})`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.deleteSampler(${nullOrUndefined})`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.isSampler(${nullOrUndefined})`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.deleteVertexArray(${nullOrUndefined})`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.isVertexArray(${nullOrUndefined})`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.bindSampler(0, ${nullOrUndefined})`);
shouldThrow(`gl.samplerParameteri(${nullOrUndefined}, gl.TEXTURE_MAG_FILTER, gl.NEAREST)`);
shouldThrow(`gl.samplerParameterf(${nullOrUndefined}, gl.TEXTURE_MAX_LOD, 1)`);
shouldThrow(`gl.getSamplerParameter(${nullOrUndefined}, gl.TEXTURE_MAX_LOD)`);
shouldThrow(`gl.waitSync(${nullOrUndefined}, 0, 0)`);
shouldThrow(`gl.clientWaitSync(${nullOrUndefined}, 0, 0)`);
shouldThrow(`gl.getSyncParameter(${nullOrUndefined}, gl.OBJECT_TYPE)`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, ${nullOrUndefined})`);
shouldThrow(`gl.transformFeedbackVaryings(${nullOrUndefined}, [], gl.SEPARATE_ATTRIBS)`);
shouldGenerateGLError(gl, gl.NO_ERROR, `gl.bindVertexArray(${nullOrUndefined})`);
}
var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -122,6 +122,16 @@ function runCurrentQueryTest() {
gl.beginQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, q1);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "beginning a deleted query object");
shouldBeNull("gl.getQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, gl.CURRENT_QUERY)");
debug("");
debug("Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1636525");
q1 = gl.createQuery();
gl.deleteQuery(q1);
wtu.glErrorShouldBe(gl, 0, "DeleteQuery after CreateQuery");
gl.beginQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, q1);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "Begining a deleted query");
shouldBeNull("gl.getQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, gl.CURRENT_QUERY)");
}
function runObjectTest() {

View File

@ -322,6 +322,7 @@ function testPackParameters(usePixelPackBuffer)
runTestIteration(0, 0, 2, 3, {alignment:8, skipPixels:2}, usePixelPackBuffer, false);
runTestIteration(0, 0, 2, 3, {alignment:8, skipPixels:1, skipRows:3}, usePixelPackBuffer, false);
runTestIteration(0, 0, 2, 3, {alignment:8, skipRows:3}, usePixelPackBuffer, true);
runTestIteration(0, 0, 2, 3, {skipPixels:1, rowLength:4}, usePixelPackBuffer, true);
}
debug("");

View File

@ -412,6 +412,29 @@ testFramebufferWithImagesOfDifferentSizes();
testUsingIncompleteFramebuffer();
testReadingFromMissingAttachment();
// -
debug("");
debug("Test calling framebufferTexture2D with impossible mip levels.");
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 1000);
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "Mip level attachment impossibly high.");
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 10);
wtu.glErrorShouldBe(gl, 0, "Mip level attachment within acceptable range.");
// Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1636517 :
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 1000);
wtu.glErrorShouldBe(gl, 0, "Mip level detachment can be impossibly high.");
shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "0");
// -
debug("")
var successfullyParsed = true;
</script>

View File

@ -78,8 +78,8 @@ var testReadBufferOnFBO = function() {
var maxColorAttachments = gl.getParameter(gl.MAX_COLOR_ATTACHMENTS);
gl.readBuffer(gl.COLOR_ATTACHMENT0 + maxColorAttachments);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
"calling readBuffer with GL_COLOR_ATTACHMENTi that exceeds MAX_COLOR_ATTACHMENT on fbo should generate INVALID_ENUM.");
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION,
"calling readBuffer with GL_COLOR_ATTACHMENTi that exceeds MAX_COLOR_ATTACHMENT on fbo should generate INVALID_OPERATION.");
gl.readBuffer(gl.COLOR_ATTACHMENT1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
"calling readBuffer with GL_COLOR_ATTACHMENT1 on the fbo should succeed.");

View File

@ -20,10 +20,12 @@ clear-func-buffer-type-match.html
draw-buffers.html
--min-version 2.0.1 draw-buffers-dirty-state-bug.html
--min-version 2.0.1 draw-buffers-driver-hang.html
--min-version 2.0.1 draw-buffers-sparse-output-locations.html
--min-version 2.0.1 draw-with-integer-texture-base-level.html
element-index-uint.html
--min-version 2.0.1 framebuffer-completeness-draw-framebuffer.html
framebuffer-completeness-unaffected.html
--min-version 2.0.1 framebuffer-mismatched-attachment-targets.html
--min-version 2.0.1 framebuffer-render-to-layer.html
--min-version 2.0.1 framebuffer-render-to-layer-angle-issue.html
--min-version 2.0.1 framebuffer-texture-changing-base-level.html
@ -36,6 +38,7 @@ instanced-arrays.html
--min-version 2.0.1 line-rendering-quality.html
--min-version 2.0.1 multisampling-fragment-evaluation.html
out-of-bounds-index-buffers-after-copying.html
--min-version 2.0.1 rasterizer-discard-and-implicit-clear.html
--min-version 2.0.1 read-draw-when-missing-image.html
rgb-format-support.html
uniform-block-buffer-size.html

View File

@ -72,57 +72,51 @@ function blitframebuffer_filter_outofbounds(readbufferFormat, drawbufferFormat,
if (gl.checkFramebufferStatus(gl.READ_FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
// Blit read framebuffer to the image in draw framebuffer.
var test = [
var tests = [
// [srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1]
[-2, -2, 4, 4, 1, 1, 4, 4], // only src region is out-of-bounds, dst region has different width/height as src region.
[-2, -2, 4, 4, 1, 1, 7, 7], // only src region is out-of-bounds, dst region has the same width/height as src region.
[0, 0, 6, 6, 7, 7, 10, 10], // only dst region is out-of-bounds, dst region has different width/height as src region after dst region is clipped to the bounds of draw buffer.
[0, 0, 6, 6, 4, 4, 10, 10], // only dst region is out-of-bounds, dst region has the same width/height as src region after dst region is clipped to the bounds of draw buffer.
[-2, -2, 4, 4, 7, 7, 10, 10], // both src and dst region are out-of-bounds, dst region has different width/height as src region after dst region is clipped to the bounds of draw buffer.
[-2, -2, 4, 4, 4, 4, 10, 10], // both src and dst region are out-of-bounds, dst region has the same width/height as src region after dst region is clipped to the bounds of draw buffer.
[-2, -2, 4, 4, 2, 2, 10, 10], // both src and dst region are out-of-bounds. There are some dst pixels (x and y are within [4, 8] , and x or y equals to 4) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying outside the real sampling area.
[-2, -2, 4, 4, 3, 3, 10, 10], // both src and dst region are out-of-bounds. There are some dst pixels (x and y are within [4, 7] , and x or y equals to 5) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying inside the real sampling area.
[-2, -2, 4, 4, 10, 10, 2, 2], // both src and dst region are out-of-bounds, and the dst coordinates are reversed. There are some dst pixels (x and y are within [2, 7] , and x or y equals to 7) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying outside the real sampling area.
[-2, -2, 4, 4, 10, 10, 3, 3], // both src and dst region are out-of-bounds, and the dst coordinates are reversed. There are some dst pixels (x and y are within [3, 7] , and x or y equals to 7) whose corresponding src pixels are partially inside and partially outside the read sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying inside the real sampling area.
{ args: [-2, -2, 4, 4, 1, 1, 4, 4], changedDstRect: [2, 2, 4, 4], desc: 'only src region is out-of-bounds, dst region has different width/height as src region.'},
{ args: [-2, -2, 4, 4, 1, 1, 7, 7], changedDstRect: [3, 3, 7, 7], desc: 'only src region is out-of-bounds, dst region has the same width/height as src region.'},
{ args: [0, 0, 6, 6, 7, 7, 10, 10], changedDstRect: [7, 7, 8, 8], desc: 'only dst region is out-of-bounds, dst region has different width/height as src region after dst region is clipped to the bounds of draw buffer.'},
{ args: [0, 0, 6, 6, 4, 4, 10, 10], changedDstRect: [4, 4, 8, 8], desc: 'only dst region is out-of-bounds, dst region has the same width/height as src region after dst region is clipped to the bounds of draw buffer.'},
{ args: [-2, -2, 4, 4, 7, 7, 10, 10], changedDstRect: [8, 8, 8, 8], desc: 'both src and dst region are out-of-bounds, dst region has different width/height as src region after dst region is clipped to the bounds of draw buffer.'},
{ args: [-2, -2, 4, 4, 4, 4, 10, 10], changedDstRect: [6, 6, 8, 8], desc: 'both src and dst region are out-of-bounds, dst region has the same width/height as src region after dst region is clipped to the bounds of draw buffer.'},
{ args: [-2, -2, 4, 4, 2, 2, 10, 10], changedDstRect: [2 + 2/6*8, 2 + 2/6*8, 8, 8], desc: 'both src and dst region are out-of-bounds. There are some dst pixels (x and y are within [4, 8] , and x or y equals to 4) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying outside the real sampling area.'},
{ args: [-2, -2, 4, 4, 3, 3, 10, 10], changedDstRect: [5, 5, 8, 8], desc: 'both src and dst region are out-of-bounds. There are some dst pixels (x and y are within [4, 7] , and x or y equals to 5) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying inside the real sampling area.'},
{ args: [-2, -2, 4, 4, 10, 10, 2, 2], changedDstRect: [2, 2, 7, 7], desc: 'both src and dst region are out-of-bounds, and the dst coordinates are reversed. There are some dst pixels (x and y are within [2, 7] , and x or y equals to 7) whose corresponding src pixels are partially inside and partially outside the real sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying outside the real sampling area.'},
{ args: [-2, -2, 4, 4, 10, 10, 3, 3], changedDstRect: [3, 3, 8, 8], desc: 'both src and dst region are out-of-bounds, and the dst coordinates are reversed. There are some dst pixels (x and y are within [3, 7] , and x or y equals to 7) whose corresponding src pixels are partially inside and partially outside the read sampling area of the src region (the real sampling area is [0, 0, 4, 4]). But the centers of such src pixels are lying inside the real sampling area.'},
];
var realBlittedDstRegion = [
[2, 2, 4, 4],
[3, 3, 7, 7],
[7, 7, 8, 8],
[4, 4, 8, 8],
[8, 8, 8, 8],
[6, 6, 8, 8],
[5, 5, 8, 8],
[5, 5, 8, 8],
[2, 2, 7, 7],
[3, 3, 8, 8],
]
var readbufferHasSRGBImage = (readbufferFormat == gl.SRGB8_ALPHA8);
var drawbufferHasSRGBImage = (drawbufferFormat == gl.SRGB8_ALPHA8);
for (var i = 0; i < test.length; ++i) {
for (const test of tests) {
const args = test.args;
const changedDstRect = test.changedDstRect;
debug("");
debug("both the read framebuffer and draw framebuffer bounds are [0, 0, 8, 8]");
debug("blitting from src region [" + test[i][0] + ", " + test[i][1] + ", " + test[i][2] + ", " + test[i][3] + "] to dst region [" + test[i][4] + ", " + test[i][5] + ", " + test[i][6] + ", " + test[i][7] + "]");
debug("Both the read framebuffer and draw framebuffer bounds are [0, 0, 8, 8]");
debug(`Blitting from src region [${args.slice(0, 4)}] to dst region [${args.slice(4, 8)}]`);
debug(`Expects changed dst region of [${changedDstRect}]`);
debug(`Explaination: ${test.desc}`);
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_read);
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo_draw);
gl.bindTexture(gl.TEXTURE_2D, tex_draw);
gl.texImage2D(gl.TEXTURE_2D, 0, drawbufferFormat, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.blitFramebuffer(test[i][0], test[i][1], test[i][2], test[i][3], test[i][4], test[i][5], test[i][6], test[i][7], gl.COLOR_BUFFER_BIT, filter);
gl.blitFramebuffer(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], gl.COLOR_BUFFER_BIT, filter);
// Read pixels and check the correctness.
var pixels = new Uint8Array(size * size * 4);
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo_draw);
gl.readPixels(0, 0, size, size, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
for (var ii = 0; ii < size; ++ii) {
for (var jj = 0; jj < size; ++jj) {
var loc = ii * size + jj;
var color = [pixels[loc * 4], pixels[loc * 4 + 1], pixels[loc * 4 + 2], pixels[loc * 4 + 3]];
var expectedColor = [0, 0, 0, 0];
if (ii >= realBlittedDstRegion[i][0] && ii < realBlittedDstRegion[i][2] && jj >= realBlittedDstRegion[i][1] && jj < realBlittedDstRegion[i][3]) {
if (ii >= changedDstRect[0] && ii < changedDstRect[2] && jj >= changedDstRect[1] && jj < changedDstRect[3]) {
expectedColor = [0x20, 0x20, 0x20, 0xff];
// We may need to covert the color space for pixels in blit region
@ -163,6 +157,7 @@ if (!gl) {
var filters = [gl.LINEAR, gl.NEAREST];
for (var ii = 0; ii < filters.length; ++ii) {
blitframebuffer_filter_outofbounds(gl.RGBA8, gl.RGBA8, filters[ii]);
break;
blitframebuffer_filter_outofbounds(gl.RGBA8, gl.SRGB8_ALPHA8, filters[ii]);
blitframebuffer_filter_outofbounds(gl.SRGB8_ALPHA8, gl.RGBA8, filters[ii]);
blitframebuffer_filter_outofbounds(gl.SRGB8_ALPHA8, gl.SRGB8_ALPHA8, filters[ii]);

View File

@ -71,7 +71,7 @@ function clear_srgb_color_buffer(iter) {
}
var color_ref = wtu.linearToSRGB(color);
var tolerance = 1;
var tolerance = 3;
var msg = "";
wtu.checkCanvasRect(gl, 0, 0, size, size, color_ref, msg, tolerance);
}

View File

@ -0,0 +1,108 @@
<!--
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 Conformance Tests: Verify drawBuffers sparse output locations</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="1" height="1" style="width: 4px; height: 4px;"> </canvas>
<div id="console"></div>
<script id="vs" type="x-shader/x-vertex">#version 300 es
void main() {
gl_PointSize = 100.0;
gl_Position = vec4(0, 0, 0, 1);
}
</script>
<script id="fs" type="x-shader/x-fragment">#version 300 es
// fragment shader only outputs to attachments 1 and 3
precision highp float;
layout(location = 1) out vec4 output1;
layout(location = 3) out vec4 output2;
void main()
{
output1 = vec4(0.0, 1.0, 0.0, 1.0);
output2 = vec4(0.0, 0.0, 1.0, 1.0);
}
</script>
<script>
"use strict";
description("This test verifies sparse output locations of fragment shaders render correctly");
debug("");
var wtu = WebGLTestUtils;
var canvas = document.getElementById("canvas");
var gl = wtu.create3DContext(canvas, null, 2);
if (!gl) {
testFailed("WebGL context does not exist");
} else {
testPassed("WebGL context exists");
runTests();
}
function testAttachment(attachment, expected) {
gl.readBuffer(gl.COLOR_ATTACHMENT0 + attachment);
wtu.checkCanvas(gl, expected, `check COLOR_ATTACHMENT${attachment}`, 1);
}
function runTests() {
var program = wtu.setupProgram(gl, ["vs", "fs"]);
if (!program) {
testFailed("Set up program failed");
return;
}
gl.useProgram(program);
// create a framebuffer with 4 1x1 pixel color attachments
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
for (let i = 0; i < 4; ++i) {
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, tex, 0);
}
// draw only to the 1st and 3rd attachments
gl.drawBuffers([
gl.NONE,
gl.COLOR_ATTACHMENT1,
gl.NONE,
gl.COLOR_ATTACHMENT3,
]);
// draw
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No GL error from set up");
// check we got the correct values
testAttachment(0, [0, 0, 0, 0]);
testAttachment(1, [0, 255, 0, 255]);
testAttachment(2, [0, 0, 0, 0]);
testAttachment(3, [0, 0, 255, 255]);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "No GL error from testing");
}
var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -0,0 +1,162 @@
<!--
Copyright (c) 2020 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>WebGL2 can render to framebuffer attachments with different targets</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>
<script id="vshader" type="x-shader/x-vertex">#version 300 es
void main(void) {
gl_Position = vec4(-0.5, -0.5, 0, 1);
gl_PointSize = 1.0;
}
</script>
<script id="fshader" type="x-shader/x-fragment">#version 300 es
precision mediump float;
out vec4 outColor;
void main() {
outColor = vec4(0, 1, 0, 1);
}
</script>
</head>
<body>
<canvas id="example" width="1", height="1"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
debug("");
description("Test framebuffer attachments with different targets");
const wtu = WebGLTestUtils;
const gl = wtu.create3DContext("example", undefined, 2);
if (!gl) {
testFailed("WebGL context creation failed");
} else {
testPassed("WebGL context creation succeeded");
runTest();
}
function newResource(target, mipLevels, format, size) {
let ret;
switch (target) {
case gl.RENDERBUFFER: {
ret = gl.createRenderbuffer();
ret.mips = [ ret ];
for (let i = 1; i < mipLevels; i++) {
ret.mips.push(gl.createRenderbuffer());
}
for (const i in ret.mips) {
const rb = ret.mips[i];
gl.bindRenderbuffer(target, rb);
gl.renderbufferStorage(target, format, size>>i, size>>i);
}
ret.attach = (attachEnum, mipLevel) => {
const rb = ret.mips[mipLevel];
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachEnum, gl.RENDERBUFFER, rb);
};
break;
}
case gl.TEXTURE_2D:
case gl.TEXTURE_CUBE_MAP: {
ret = gl.createTexture();
gl.bindTexture(target, ret);
gl.texStorage2D(target, mipLevels, format, size, size);
let imageTarget = target;
if (imageTarget == gl.TEXTURE_CUBE_MAP) {
imageTarget = gl.TEXTURE_CUBE_MAP_POSITIVE_X+2; // Deliberately don't choose the first image.
}
ret.attach = (attachEnum, mipLevel) => {
gl.framebufferTexture2D(gl.FRAMEBUFFER, attachEnum, imageTarget, ret, mipLevel);
};
break;
}
case gl.TEXTURE_3D:
case gl.TEXTURE_2D_ARRAY: {
ret = gl.createTexture();
gl.bindTexture(target, ret);
gl.texStorage3D(target, mipLevels, format, size, size, 1);
ret.attach = (attachEnum, mipLevel) => {
gl.framebufferTextureLayer(gl.FRAMEBUFFER, attachEnum, ret, mipLevel, 0);
};
break;
}
default:
throw new Error();
}
ret.target = wtu.glEnumToString(gl, target);
ret.format = wtu.glEnumToString(gl, format);
return ret;
}
function runTest() {
const MIP_LEVELS = 2;
const SIZE = 2;
gl.clearColor(1, 0, 0, 1);
const program = wtu.setupProgram(gl, ['vshader','fshader'], [], console.log.bind(console));
gl.useProgram(program);
const colorResList = [
newResource(gl.RENDERBUFFER, MIP_LEVELS, gl.RGBA8, SIZE),
newResource(gl.TEXTURE_2D, MIP_LEVELS, gl.RGBA8, SIZE),
newResource(gl.TEXTURE_CUBE_MAP, MIP_LEVELS, gl.RGBA8, SIZE),
newResource(gl.TEXTURE_3D, MIP_LEVELS, gl.RGBA8, SIZE),
newResource(gl.TEXTURE_2D_ARRAY, MIP_LEVELS, gl.RGBA8, SIZE),
];
const depthResList = [
newResource(gl.RENDERBUFFER, MIP_LEVELS, gl.DEPTH_COMPONENT16, SIZE),
newResource(gl.TEXTURE_2D, MIP_LEVELS, gl.DEPTH_COMPONENT16, SIZE),
newResource(gl.TEXTURE_CUBE_MAP, MIP_LEVELS, gl.DEPTH_COMPONENT16, SIZE),
//newResource(gl.TEXTURE_3D, MIP_LEVELS, gl.DEPTH_COMPONENT16, SIZE), // Depth formats forbidden for TEXTURE_3D.
newResource(gl.TEXTURE_2D_ARRAY, MIP_LEVELS, gl.DEPTH_COMPONENT16, SIZE),
];
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
for (const color of colorResList) {
for (const depth of depthResList) {
debug(`\ncolor: ${color.target}; depth: ${depth.target}`);
for (let mipLevel = 0; mipLevel < MIP_LEVELS; mipLevel++) {
debug(`mipLevel: ${mipLevel}`);
color.attach(gl.COLOR_ATTACHMENT0, mipLevel);
depth.attach(gl.DEPTH_ATTACHMENT, mipLevel);
const maybeStatus = wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, [gl.FRAMEBUFFER_COMPLETE, gl.FRAMEBUFFER_UNSUPPORTED]);
if (!maybeStatus || maybeStatus[0] != gl.FRAMEBUFFER_COMPLETE) {
continue;
}
gl.clear(gl.COLOR_BUFFER_BIT);
wtu.checkCanvas(gl, [255, 0, 0, 255], `framebuffer layer ${mipLevel} should be cleared red`);
gl.drawArrays(gl.POINTS, 0, 1);
wtu.checkCanvas(gl, [0, 255, 0, 255], `framebuffer layer ${mipLevel} should be drawn green`);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, `No errors`);
}
}
}
// make sure we were not rendering to the canvas.
gl.bindFramebuffer(gl.FRAMEBUFFER, null)
wtu.checkCanvas(gl, [0, 0, 0, 0], "canvas should be zero");
}
debug("");
var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -123,6 +123,9 @@ function runOutputTests() {
0.0, 1.0, 0.0, 1.0, // Green
0.0, 0.0, 1.0, 1.0, // Blue
1.0, 1.0, 0.0, 1.0, // Yellow
// extra data when colorLoc divisor is set back to 0
1.0, 1.0, 0.0, 1.0, // Yellow
1.0, 1.0, 0.0, 1.0, // Yellow
]);
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
@ -174,6 +177,45 @@ function runOutputTests() {
gl.drawArraysInstanced(desktopGL['POLYGON'], 0, 6, instanceCount);
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "drawArraysInstanced with POLYGON should return INVALID_ENUM");
debug("Testing drawArraysInstanced with param 'first' > 0");
gl.clear(gl.COLOR_BUFFER_BIT);
wtu.setupQuad(gl, {
positionLocation: 0,
scale: 0.5
});
var offsetsHalf = new Float32Array([
-0.5, 0.5,
0.5, 0.5,
-0.5, -0.5,
0.5, -0.5
]);
gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
gl.bufferData(gl.ARRAY_BUFFER, offsetsHalf, gl.STATIC_DRAW);
gl.drawArraysInstanced(gl.TRIANGLES, 3, 3, instanceCount);
var w = Math.floor(0.25*canvas.width),
h = Math.floor(0.25*canvas.height);
wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0.5*canvas.height, w, h, [255, 0, 0, 255]);
wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0.5*canvas.height, w, h, [0, 255, 0, 255]);
wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0, w, h, [0, 0, 255, 255]);
wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0, w, h, [255, 255, 0, 255]);
debug("Testing drawArraysInstanced with attributes 'divisor' reset to 0");
debug("Correct rendering output: 4 yellow triangles");
debug("Possible incorrect rendering output: missing triangles, or triangles with different color at each vertex");
gl.vertexAttribDivisor(colorLoc, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArraysInstanced(gl.TRIANGLES, 3, 3, instanceCount);
wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0.5*canvas.height, w, h, [255, 255, 0, 255]);
wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0.5*canvas.height, w, h, [255, 255, 0, 255]);
wtu.checkCanvasRect(gl, Math.ceil(0.25*canvas.width), 0, w, h, [255, 255, 0, 255]);
wtu.checkCanvasRect(gl, Math.ceil(0.75*canvas.width), 0, w, h, [255, 255, 0, 255]);
gl.vertexAttribDivisor(colorLoc, 1);
wtu.setupUnitQuad(gl, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer);
gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW);
// Draw 2: Draw indexed instances
debug("Testing drawElementsInstanced");
gl.clear(gl.COLOR_BUFFER_BIT);

View File

@ -0,0 +1,149 @@
<!--
Copyright (c) 2020 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>RASTERIZER_DISCARD doesn't affect implicit clears</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>
<script id="vshader" type="x-shader/x-vertex">#version 300 es
layout(location=0) in vec2 vPosition;
uniform float xTranslation;
void main(void) {
gl_Position = vec4(vPosition[0] + xTranslation, vPosition[1], 0.0, 1.0);
}
</script>
<script id="fshader" type="x-shader/x-fragment">#version 300 es
precision mediump float;
uniform vec4 color;
out vec4 outColor;
void main() {
outColor = color;
}
</script>
</head>
<body>
<canvas id="example"></canvas>
<div id="description"></div>
<div id="console"></div>
<script>
"use strict";
debug("");
description("Enabling RASTERIZER_DISCARD should not affect implicit clears");
const wtu = WebGLTestUtils;
const canvas = document.getElementById("example");
const sz = canvas.width = canvas.height = 256;
const gl = wtu.create3DContext(canvas, undefined, 2);
const NUM_FRAMES = 15;
let framesToGo = NUM_FRAMES;
let xTranslationLoc;
let colorLoc;
const positionLocation = 0;
const red = [ 1.0, 0.0, 0.0, 1.0 ];
const green = [ 0.0, 1.0, 0.0, 1.0 ];
const transparentBlackRender = [ 0, 0, 0, 0 ];
const greenRender = [ 0, 255, 0, 255 ];
if (!gl) {
testFailed("WebGL context creation failed");
finishTest();
} else {
testPassed("WebGL context creation succeeded");
runDrawTest();
}
function runDrawTest() {
debug("Verify that draws with rasterizer discard enabled do not interfere with implicit clears");
let prog = wtu.loadProgramFromScript(gl, "vshader", "fshader");
gl.useProgram(prog);
xTranslationLoc = gl.getUniformLocation(prog, "xTranslation");
colorLoc = gl.getUniformLocation(prog, "color");
let leftRectBuffer = gl.createBuffer();
gl.enableVertexAttribArray(positionLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, leftRectBuffer);
// Create a rectangle covering the left half of the viewport, in
// normalized device coordinates.
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0.0, 1.0,
-1.0, 1.0,
-1.0, -1.0,
0.0, 1.0,
-1.0, -1.0,
0.0, -1.0]), gl.STATIC_DRAW);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
requestAnimationFrame(renderDrawTestFrame);
}
function renderDrawTestFrame() {
// Animation is required in order to expose this bug. When it
// occurs, the rectangle leaves trails behind it.
gl.uniform1f(xTranslationLoc, 0.0);
gl.enable(gl.RASTERIZER_DISCARD);
gl.uniform4fv(colorLoc, red);
gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.disable(gl.RASTERIZER_DISCARD);
// Animate the rectangle from the left to the right half of the viewport.
gl.uniform1f(xTranslationLoc, (NUM_FRAMES - framesToGo) / NUM_FRAMES);
// Draw the last frame with green so any (incorrect) trails are visibly red.
if (framesToGo == 0)
gl.uniform4fv(colorLoc, green);
gl.drawArrays(gl.TRIANGLES, 0, 6);
if (framesToGo-- == 0) {
// The left half of the canvas should be transparent black,
// which comes from the implicit clear just before drawing the
// rectangle without rasterizer discard enabled.
wtu.checkCanvasRect(gl, 0, 0, sz / 2, sz, transparentBlackRender, "left half of canvas should be clear", 3);
// The right half of the canvas should be solid green, from
// the last render of the translated rectangle.
wtu.checkCanvasRect(gl, sz / 2, 0, sz / 2, sz, greenRender, "right half of canvas should be green", 3);
runReadPixelsTest();
} else {
requestAnimationFrame(renderDrawTestFrame);
}
}
function runReadPixelsTest() {
debug("Verify that readPixels with rasterizer discard enabled receives implicitly cleared data");
framesToGo = NUM_FRAMES; // Reset state.
// Clear to transparent black.
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// Start with rasterizer discard enabled.
gl.enable(gl.RASTERIZER_DISCARD);
requestAnimationFrame(renderReadPixelsTestFrame);
}
function renderReadPixelsTestFrame() {
// Rasterizer discard is enabled at the beginning of this test.
// The canvas should always contain transparent black at the beginning of the frame.
wtu.checkCanvasRect(gl, 0, 0, sz, sz, transparentBlackRender, undefined, 3);
gl.disable(gl.RASTERIZER_DISCARD);
// Clear to red.
gl.clearColor(1.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// Enable rasterizer discard again.
gl.enable(gl.RASTERIZER_DISCARD);
if (--framesToGo == 0) {
finishTest();
} else {
requestAnimationFrame(renderReadPixelsTestFrame);
}
}
</script>
</body>
</html>

View File

@ -2,6 +2,7 @@
--min-version 2.0.1 angle-stuck-depth-textures.html
canvas-remains-unchanged-after-used-in-webgl-texture.html
--min-version 2.0.1 compressed-tex-from-pbo-crash.html
--min-version 2.0.1 compressed-tex-image.html
--min-version 2.0.1 copy-texture-cube-map-AMD-bug.html
--min-version 2.0.1 copy-texture-cube-map-bug.html
copy-texture-image.html
@ -10,6 +11,7 @@ copy-texture-image-luma-format.html
copy-texture-image-webgl-specific.html
--min-version 2.0.1 generate-mipmap-with-large-base-level.html
gl-get-tex-parameter.html
--min-version 2.0.1 immutable-tex-render-feedback.html
--min-version 2.0.1 integer-cubemap-texture-sampling.html
--min-version 2.0.1 integer-cubemap-specification-order-bug.html
mipmap-fbo.html

View File

@ -0,0 +1,24 @@
<!--
Copyright (c) 2020 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">
<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>
<div id="console"></div>
<script>
const contextVersion = 2;
</script>
<script src="../../../js/tests/compressed-tex-image.js"></script>
<script src="../../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -0,0 +1,221 @@
<!--
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>Ensure sampling-feedback detection can allow certain immutable texture uses</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>
<div id="console"></div>
<script>
"use strict";
const wtu = WebGLTestUtils;
description();
const gl = wtu.create3DContext(undefined, undefined, 2);
function* range(a, b) {
a.required;
if (b === undefined) {
b = a;
a = 0;
}
for (let i = a; i < b; i += 1) {
yield i;
}
}
const VS = `\
void main() {
gl_PointSize = 1.0;
}
`;
const FS = `\
uniform sampler2D u_tex0;
void main() {
gl_FragColor = texture2D(u_tex0, vec2(0));
}
`;
const prog = wtu.loadProgram(gl, VS, FS);
gl.useProgram(prog);
(() => {
const MIPS = 3;
const SIZE = 10;
const immutTex = gl.createTexture();
immutTex.name = "immutTex";
immutTex.immutable = true;
gl.bindTexture(gl.TEXTURE_2D, immutTex);
gl.texStorage2D(gl.TEXTURE_2D, MIPS, gl.RGBA8, SIZE, SIZE);
const mutTex = gl.createTexture();
mutTex.name = "mutTex";
mutTex.immutable = false;
gl.bindTexture(gl.TEXTURE_2D, mutTex);
for (const mip of range(MIPS)) {
const size = SIZE >> mip;
gl.texImage2D(gl.TEXTURE_2D, mip, gl.RGBA8, size, size, 0,
gl.RGBA, gl.UNSIGNED_BYTE, null);
}
const MAG_FILTERS = [
'LINEAR',
'NEAREST',
];
const MIN_FILTERS = [
['LINEAR',false],
['LINEAR_MIPMAP_LINEAR',true],
['LINEAR_MIPMAP_NEAREST',true],
['NEAREST',false],
['NEAREST_MIPMAP_LINEAR',true],
['NEAREST_MIPMAP_NEAREST',true],
];
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
debug(`
mips: ${MIPS}: [0,${MIPS-1}] (inclusive)
size: ${SIZE}`);
const texs = [
immutTex,
mutTex,
];
for (const tex of texs) {
debug(`\
immutable: ${tex.immutable}`);
gl.bindTexture(gl.TEXTURE_2D, tex);
for (const level_prime_base of range(MIPS+1)) { // `level_base` in GLES
// ES 3.0.6 p150
let _level_base = level_prime_base;
if (tex.immutable) {
_level_base = Math.min(_level_base, MIPS-1);
}
const level_base = _level_base;
for (let _level_prime_max of range(level_prime_base-1, MIPS+2)) { // `q` in GLES
if (_level_prime_max < 0) continue;
if (_level_prime_max == MIPS+1) {
_level_prime_max = 10000; // This is the default, after all!
}
const level_prime_max = _level_prime_max;
// ES 3.0.6 p150
let _level_max = level_prime_max;
if (tex.immutable) {
_level_max = Math.min(Math.max(level_base, level_prime_max), MIPS-1);
}
const level_max = _level_max;
const p = Math.floor(Math.log2(SIZE)) + level_base;
const q = Math.min(p, level_max);
debug(`\
level_prime_base/max: [${level_prime_base}, ${level_prime_max}] (inclusive)
level_base/max: [${level_base}, ${level_max}] (inclusive)
q: ${q}`);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL,
level_prime_base);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL,
level_prime_max);
const mipComplete = (q <= MIPS-1);
for (const [minFilter,useMips] of MIN_FILTERS) {
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
gl[minFilter]);
// ES3.0 p211
const srcMaxSampledMip = (useMips ? q : level_base);
// ES3.0 p160-161
const textureComplete = (srcMaxSampledMip <= MIPS-1) &&
(level_base <= level_max);
for (const magFilter of MAG_FILTERS) {
debug(`\
min: ${minFilter}, mag: ${magFilter}`);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,
gl[magFilter]);
for (const dstMip of range(0,MIPS+1)) {
debug(`
mip: ${dstMip}`);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D, tex, dstMip);
// -
// ES3.0 p213-214
let fbComplete = true;
// * "The width and height of `image` are non-zero"
fbComplete &= (0 <= dstMip && dstMip <= MIPS-1);
if (!tex.immutable) { // "...does not name an immutable-format texture..."
// * "...the value of [level] must be in the range `[level_base, q]`"
fbComplete &= (level_base <= dstMip && dstMip <= q);
// * "...the value of [level] is not `level_base`, then the texture must be mipmap complete"
if (dstMip != level_base) {
fbComplete &= mipComplete;
}
}
// -
let expectError = 0;
let expectStatus = gl.FRAMEBUFFER_COMPLETE;
// ES3.0 p211
let samplingFeedback = (level_base <= dstMip && dstMip <= srcMaxSampledMip);
if (!textureComplete) {
// Incomplete textures are safe
samplingFeedback = false;
}
if (samplingFeedback) {
expectError = gl.INVALID_OPERATION;
}
if (!fbComplete) {
expectStatus = gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
expectError = gl.INVALID_FRAMEBUFFER_OPERATION;
}
// -
wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER,
expectStatus, `{immutable: ${tex.immutable}, level_prime_base/max: [${level_prime_base}, ${level_prime_max}], minFilter: ${minFilter}, dest: ${dstMip}}`);
gl.drawArrays(gl.POINTS, 0, 1);
wtu.glErrorShouldBe(gl, expectError, "after draw with texture");
}
}
}
}
}
}
})();
var successfullyParsed = true;
</script>
<script src="../../../js/js-test-post.js"></script>
</body>
</html>

View File

@ -12,6 +12,12 @@ found in the LICENSE.txt file.
<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>
<div id="console"></div>
<canvas id="canvas"></canvas>
<img id="img" style="display:none;">
<script>
"use strict";
var wtu = WebGLTestUtils;
@ -33,7 +39,7 @@ var localImgUrl = "../../../resources/opengl_logo.jpg";
var imgDomain;
var pageDomain;
function imageLoaded() {
function imageLoaded(img) {
description("This test ensures WebGL2 implementations for OffscreenCanvas follow proper same-origin restrictions.");
if (!window.OffscreenCanvas) {
@ -42,8 +48,6 @@ function imageLoaded() {
return;
}
var img = this;
assertMsg(img.width > 0 && img.height > 0, "img was loaded");
imgDomain = wtu.getBaseDomain(wtu.getHost(img.src));
pageDomain = wtu.getBaseDomain(window.location.host);
@ -126,13 +130,17 @@ function imageLoaded() {
finishTest();
}
wtu.setupImageForCrossOriginTest("#img", defaultImgUrl, localImgUrl, imageLoaded);
(async function() {
const img = document.getElementById('img');
try {
await wtu.awaitOrTimeout(wtu.loadCrossOriginImage(img, defaultImgUrl, localImgUrl), 1000);
} catch (e) {
testFailed(`Image setup failed (${e}).`);
finishTest();
return;
}
imageLoaded(img);
})();
</script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="canvas"></canvas>
<img id="img" style="display:none;">
</body>
</html>

View File

@ -41,7 +41,7 @@ gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB10_A2UI, 16, 16, 0, gl.RGBA_INTEGER, gl.UNSIGNED_INT_2_10_10_10_REV, null);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Teximage2D taking a null array buffer should succeed");
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB10_A2UI, gl.RGBA_INTEGER, gl.UNSIGNED_INT_2_10_10_10_REV, c);
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "TexImage2D taking RGB10_A2UI internalformat and a canvas source should fail");
wtu.glErrorShouldBe(gl, [gl.INVALID_VALUE, gl.INVALID_ENUM], "TexImage2D taking RGB10_A2UI internalformat and a canvas source should fail");
gl.deleteTexture(tex);
var successfullyParsed = true;

View File

@ -98,7 +98,7 @@ function runTexCompressedFormatsTest(texCompressedFormats)
// Test a 2D texture.
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texStorage2D(gl.TEXTURE_2D, 1, internalformat, 1, 1);
gl.texStorage2D(gl.TEXTURE_2D, 1, internalformat, 4, 4);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
"texStorage2D should succeed for " + enumToString(internalformat));
gl.deleteTexture(tex);
@ -111,14 +111,14 @@ function runTexCompressedFormatsTest(texCompressedFormats)
// Test the 3D texture targets.
var tex3d = gl.createTexture();
gl.bindTexture(gl.TEXTURE_3D, tex3d);
gl.texStorage3D(gl.TEXTURE_3D, 1, internalformat, 1, 1, 1);
gl.texStorage3D(gl.TEXTURE_3D, 1, internalformat, 4, 4, 1);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION,
"texStorage3D(TEXTURE_3D) should fail for " + enumToString(internalformat));
gl.deleteTexture(tex3d);
var tex2dArr = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D_ARRAY, tex2dArr);
gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, internalformat, 1, 1, 1);
gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, internalformat, 4, 4, 1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
"texStorage3D(TEXTURE_2D_ARRAY) should succeed for " + enumToString(internalformat));
wtu.clearAndDrawUnitQuad(gl);

View File

@ -9,6 +9,7 @@ fboinvalidate/00_test_list.txt
fborender/00_test_list.txt
fragmentoutput/00_test_list.txt
framebufferblit/00_test_list.txt
multisample/00_test_list.txt
primitiverestart/00_test_list.txt
shaderindexing/00_test_list.txt
shadermatrix/00_test_list.txt
@ -43,7 +44,6 @@ instancedrendering.html
integerstatequery.html
internalformatquery.html
lifetime.html
multisample.html
negativebufferapi.html
negativefragmentapi.html
negativeshaderapi.html

View File

@ -1713,7 +1713,7 @@ goog.scope(function() {
* Run test
* @param {WebGL2RenderingContext} context
*/
es3fMultisampleTests.run = function(context) {
es3fMultisampleTests.run = function(context, range) {
gl = context;
//Set up Test Root parameters
var testName = 'multisample';
@ -1730,6 +1730,8 @@ goog.scope(function() {
try {
//Create test cases
es3fMultisampleTests.init();
if (range)
state.setRange(range);
//Run test cases
tcuTestCase.runTestCases();
}

View File

@ -1,24 +0,0 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebGL Multisample Conformance 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>
<script src="../../../closure-library/closure/goog/base.js"></script>
<script src="../../deqp-deps.js"></script>
<script>goog.require('functional.gles3.es3fMultisampleTests');</script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="canvas" width="256" height="256"> </canvas>
<script>
var wtu = WebGLTestUtils;
var gl = wtu.create3DContext('canvas', null, 2);
functional.gles3.es3fMultisampleTests.run(gl);
</script>
</body>
</html>

View File

@ -0,0 +1,6 @@
# This file is auto-generated from multisample_test_generator.py
# DO NOT EDIT!
default_fbo.html
fbo_4_samples.html
fbo_8_samples.html
fbo_max_samples.html

View File

@ -0,0 +1,31 @@
<!--
This file is auto-generated from multisample_test_generator.py
DO NOT EDIT!
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebGL Multisample Conformance 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>
<script src="../../../../closure-library/closure/goog/base.js"></script>
<script src="../../../deqp-deps.js"></script>
<script>goog.require('functional.gles3.es3fMultisampleTests');</script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="canvas" width="256" height="256"> </canvas>
<script>
var wtu = WebGLTestUtils;
var gl = wtu.create3DContext('canvas', null, 2);
functional.gles3.es3fMultisampleTests.run(gl, [0, 1]);
</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More