Skip to content

Commit

Permalink
Add conformance2/textures/misc/immutable-tex-render-feedback.html. (K…
Browse files Browse the repository at this point in the history
…hronosGroup#3221)

Combinatorial test for framebuffer attachment completeness of mipmaps,
and sampling from them with/without feedback.
  • Loading branch information
kdashg authored Mar 17, 2021
1 parent 1d8ca72 commit 4aad270
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 2 deletions.
1 change: 1 addition & 0 deletions sdk/tests/conformance2/textures/misc/00_test_list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,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
Expand Down
Original file line number Diff line number Diff line change
@@ -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>
4 changes: 2 additions & 2 deletions sdk/tests/js/webgl-test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3337,12 +3337,12 @@ function comparePixels(cmp, ref, tolerance, diff) {
}

function destroyContext(gl) {
gl.canvas.width = 1;
gl.canvas.height = 1;
const ext = gl.getExtension('WEBGL_lose_context');
if (ext) {
ext.loseContext();
}
gl.canvas.width = 1;
gl.canvas.height = 1;
}

function destroyAllContexts() {
Expand Down

0 comments on commit 4aad270

Please sign in to comment.