Source code
Revision control
Copy as Markdown
Other Tools
<!--
Copyright (c) 2023 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 WEBGL_render_shared_exponent 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 WEBGL_render_shared_exponent extension, if it is available.");
debug("");
var wtu = WebGLTestUtils;
var gl = wtu.create3DContext(null, null, 2);
var ext;
const color = [64.0, 32.0, 16.0, 1.0];
function drawTest() {
wtu.clearAndDrawUnitQuad(gl);
wtu.checkCanvasRect(gl, 0, 0, 1, 1, color,
"reading with the RGBA format and FLOAT type", 1,
new Float32Array(4), gl.FLOAT, gl.RGBA);
const implementationType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
const implementationFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
if (implementationFormat == gl.RGB && implementationType == gl.UNSIGNED_INT_5_9_9_9_REV) {
// Shared exponent value may be implementation
// specific, so compare decoded values.
const value = new Uint32Array(1);
gl.readPixels(0, 0, 1, 1, gl.RGB, gl.UNSIGNED_INT_5_9_9_9_REV, value);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
let r = (value >> 0) & 0x1FF;
let g = (value >> 9) & 0x1FF;
let b = (value >> 18) & 0x1FF;
let e = (value >> 27) & 0x01F;
debug(`Raw value: 0x${value[0].toString(16).toUpperCase()}, ` +
`Raw components: R = ${r}, G = ${g}, B = ${b}, E = ${e}`);
e = Math.pow(2, e - 24);
r *= e;
g *= e;
b *= e;
debug(`Decoded color: (${r}, ${g}, ${b})`);
if (r == color[0] && g == color[1] && b == color[2]) {
testPassed("reading with the exact format/type");
} else {
testFailed("reading with the exact format/type");
}
}
}
function renderbufferTest(isSupported) {
debug("");
debug(`RGB9_E5 renderbuffer: ` +
`${!isSupported ? "NOT " : ""}supported`);
const rbo = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB9_E5, 1, 1);
if (!isSupported) {
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "renderbuffer allocation failed");
return;
}
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "renderbuffer allocation succeeded");
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
drawTest();
}
function textureTest(isRenderable) {
debug("");
debug(`RGB9_E5 texture: ` +
`${!isRenderable ? "NOT " : ""}renderable`);
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB9_E5, 1, 1, 0, gl.RGB, gl.UNSIGNED_INT_5_9_9_9_REV, null);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture allocation succeeded");
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
if (!isRenderable) {
wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
return;
}
wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
drawTest();
}
function formatTest(isEnabled) {
const program = wtu.setupProgram(gl, [wtu.simpleVertexShader,
wtu.simpleColorFragmentShader]);
gl.useProgram(program);
gl.uniform4fv(gl.getUniformLocation(program, "u_color"), color);
wtu.setupUnitQuad(gl);
renderbufferTest(isEnabled);
textureTest(isEnabled);
}
function colorMaskTest() {
debug("");
debug("Test color write masks with shared exponent color buffers");
const fs = `#version 300 es
precision highp float;
layout(location = 0) out vec4 color0;
layout(location = 1) out vec4 color1;
void main() {
color0 = vec4(1.0, 0.0, 0.0, 1.0);
color1 = vec4(0.0, 1.0, 0.0, 1.0);
}`;
const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, fs]);
gl.useProgram(program);
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
const rb0 = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rb0);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB9_E5, 4, 4);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0);
const rb1 = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rb1);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 4, 4);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, rb1);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
const clearValue = new Float32Array(4);
const dbiExt = gl.getExtension("OES_draw_buffers_indexed");
function expectError(enabled, effectiveMask, operation) {
if (!enabled ||
effectiveMask == 0x0 /* 0000 */ ||
effectiveMask == 0x8 /* 000A */ ||
effectiveMask == 0x7 /* RGB0 */ ||
effectiveMask == 0xF /* RGBA */ ) {
wtu.glErrorShouldBe(gl, gl.NO_ERROR, operation);
} else {
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, operation);
}
}
function runOps(enabled, mask0) {
wtu.drawUnitQuad(gl);
expectError(enabled, mask0, "draw");
gl.clear(gl.COLOR_BUFFER_BIT);
expectError(enabled, mask0, "clear");
gl.clearBufferfv(gl.COLOR, 0, clearValue);
expectError(enabled, mask0, "clearBufferfv(RGB9_E5)");
gl.clearBufferfv(gl.COLOR, 1, clearValue);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clearBufferfv(RGBA8)");
}
for (let mask = 0; mask < 16; mask++) {
for (const enabled of [false, true]) {
debug("");
debug(`Setting common color mask ` +
`${mask & 1 ? "R" : "0"}` +
`${mask & 2 ? "G" : "0"}` +
`${mask & 4 ? "B" : "0"}` +
`${mask & 8 ? "A" : "0"}` +
" with RGB9_E5 attachment " +
(enabled ? "enabled" : "disabled"));
gl.colorMask(mask & 1, mask & 2, mask & 4, mask & 8);
gl.drawBuffers([enabled ? gl.COLOR_ATTACHMENT0 : gl.NONE,
gl.COLOR_ATTACHMENT1]);
runOps(enabled, mask);
if (dbiExt) {
debug("Setting incompatible color mask on unused draw buffer")
dbiExt.colorMaskiOES(2, true, false, false, false);
runOps(enabled, mask); // common mask remains on draw buffer 0
debug("Setting incompatible color mask on RGBA8 draw buffer")
dbiExt.colorMaskiOES(1, true, false, false, false);
runOps(enabled, mask); // common mask remains on draw buffer 0
debug("Setting incompatible color mask on RGB9_E5 draw buffer")
dbiExt.colorMaskiOES(0, true, false, false, false);
runOps(enabled, 1); // overridden
debug("Setting compatible color mask on RGB9_E5 draw buffer")
dbiExt.colorMaskiOES(0, true, true, true, false);
runOps(enabled, 7); // overridden
}
}
}
}
function runTest() {
if (!gl) {
testFailed("context does not exist");
return;
}
testPassed("context exists");
debug("");
debug("Testing shared exponent rendering with extension disabled");
formatTest(false);
ext = gl.getExtension("WEBGL_render_shared_exponent");
wtu.runExtensionSupportedTest(gl, "WEBGL_render_shared_exponent", ext !== null);
if (ext !== null) {
debug("");
debug("Testing shared exponent rendering with extension enabled");
formatTest(true);
colorMaskTest();
} else {
testPassed("No WEBGL_render_shared_exponent support -- this is legal");
}
}
runTest();
var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>
</body>
</html>