webgl-render-shared-exponent.html (8745B)
1 <!-- 2 Copyright (c) 2023 The Khronos Group Inc. 3 Use of this source code is governed by an MIT-style license that can be 4 found in the LICENSE.txt file. 5 --> 6 7 <!DOCTYPE html> 8 <html> 9 <head> 10 <meta charset="utf-8"> 11 <title>WebGL WEBGL_render_shared_exponent Conformance Tests</title> 12 <link rel="stylesheet" href="../../resources/js-test-style.css"/> 13 <script src="../../js/js-test-pre.js"></script> 14 <script src="../../js/webgl-test-utils.js"></script> 15 </head> 16 <body> 17 <div id="description"></div> 18 <div id="console"></div> 19 <script> 20 "use strict"; 21 description("This test verifies the functionality of the WEBGL_render_shared_exponent extension, if it is available."); 22 23 debug(""); 24 25 var wtu = WebGLTestUtils; 26 var gl = wtu.create3DContext(null, null, 2); 27 var ext; 28 const color = [64.0, 32.0, 16.0, 1.0]; 29 30 function drawTest() { 31 wtu.clearAndDrawUnitQuad(gl); 32 33 wtu.checkCanvasRect(gl, 0, 0, 1, 1, color, 34 "reading with the RGBA format and FLOAT type", 1, 35 new Float32Array(4), gl.FLOAT, gl.RGBA); 36 37 const implementationType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE); 38 const implementationFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT); 39 if (implementationFormat == gl.RGB && implementationType == gl.UNSIGNED_INT_5_9_9_9_REV) { 40 // Shared exponent value may be implementation 41 // specific, so compare decoded values. 42 const value = new Uint32Array(1); 43 gl.readPixels(0, 0, 1, 1, gl.RGB, gl.UNSIGNED_INT_5_9_9_9_REV, value); 44 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 45 46 let r = (value >> 0) & 0x1FF; 47 let g = (value >> 9) & 0x1FF; 48 let b = (value >> 18) & 0x1FF; 49 let e = (value >> 27) & 0x01F; 50 debug(`Raw value: 0x${value[0].toString(16).toUpperCase()}, ` + 51 `Raw components: R = ${r}, G = ${g}, B = ${b}, E = ${e}`); 52 53 e = Math.pow(2, e - 24); 54 r *= e; 55 g *= e; 56 b *= e; 57 debug(`Decoded color: (${r}, ${g}, ${b})`); 58 59 if (r == color[0] && g == color[1] && b == color[2]) { 60 testPassed("reading with the exact format/type"); 61 } else { 62 testFailed("reading with the exact format/type"); 63 } 64 } 65 } 66 67 function renderbufferTest(isSupported) { 68 debug(""); 69 debug(`RGB9_E5 renderbuffer: ` + 70 `${!isSupported ? "NOT " : ""}supported`); 71 72 const rbo = gl.createRenderbuffer(); 73 gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); 74 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB9_E5, 1, 1); 75 if (!isSupported) { 76 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "renderbuffer allocation failed"); 77 return; 78 } 79 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "renderbuffer allocation succeeded"); 80 81 const fbo = gl.createFramebuffer(); 82 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 83 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); 84 85 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); 86 87 drawTest(); 88 } 89 90 function textureTest(isRenderable) { 91 debug(""); 92 debug(`RGB9_E5 texture: ` + 93 `${!isRenderable ? "NOT " : ""}renderable`); 94 95 const tex = gl.createTexture(); 96 gl.bindTexture(gl.TEXTURE_2D, tex); 97 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB9_E5, 1, 1, 0, gl.RGB, gl.UNSIGNED_INT_5_9_9_9_REV, null); 98 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture allocation succeeded"); 99 100 const fbo = gl.createFramebuffer(); 101 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 102 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); 103 104 if (!isRenderable) { 105 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT); 106 return; 107 } 108 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); 109 110 drawTest(); 111 } 112 113 function formatTest(isEnabled) { 114 const program = wtu.setupProgram(gl, [wtu.simpleVertexShader, 115 wtu.simpleColorFragmentShader]); 116 gl.useProgram(program); 117 gl.uniform4fv(gl.getUniformLocation(program, "u_color"), color); 118 119 wtu.setupUnitQuad(gl); 120 121 renderbufferTest(isEnabled); 122 textureTest(isEnabled); 123 } 124 125 function colorMaskTest() { 126 debug(""); 127 debug("Test color write masks with shared exponent color buffers"); 128 129 const fs = `#version 300 es 130 precision highp float; 131 layout(location = 0) out vec4 color0; 132 layout(location = 1) out vec4 color1; 133 void main() { 134 color0 = vec4(1.0, 0.0, 0.0, 1.0); 135 color1 = vec4(0.0, 1.0, 0.0, 1.0); 136 }`; 137 const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, fs]); 138 gl.useProgram(program); 139 140 const fbo = gl.createFramebuffer(); 141 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 142 143 const rb0 = gl.createRenderbuffer(); 144 gl.bindRenderbuffer(gl.RENDERBUFFER, rb0); 145 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB9_E5, 4, 4); 146 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb0); 147 148 const rb1 = gl.createRenderbuffer(); 149 gl.bindRenderbuffer(gl.RENDERBUFFER, rb1); 150 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 4, 4); 151 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.RENDERBUFFER, rb1); 152 153 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 154 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); 155 156 const clearValue = new Float32Array(4); 157 const dbiExt = gl.getExtension("OES_draw_buffers_indexed"); 158 159 function expectError(enabled, effectiveMask, operation) { 160 if (!enabled || 161 effectiveMask == 0x0 /* 0000 */ || 162 effectiveMask == 0x8 /* 000A */ || 163 effectiveMask == 0x7 /* RGB0 */ || 164 effectiveMask == 0xF /* RGBA */ ) { 165 wtu.glErrorShouldBe(gl, gl.NO_ERROR, operation); 166 } else { 167 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, operation); 168 } 169 } 170 171 function runOps(enabled, mask0) { 172 wtu.drawUnitQuad(gl); 173 expectError(enabled, mask0, "draw"); 174 175 gl.clear(gl.COLOR_BUFFER_BIT); 176 expectError(enabled, mask0, "clear"); 177 178 gl.clearBufferfv(gl.COLOR, 0, clearValue); 179 expectError(enabled, mask0, "clearBufferfv(RGB9_E5)"); 180 gl.clearBufferfv(gl.COLOR, 1, clearValue); 181 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clearBufferfv(RGBA8)"); 182 } 183 184 for (let mask = 0; mask < 16; mask++) { 185 for (const enabled of [false, true]) { 186 debug(""); 187 debug(`Setting common color mask ` + 188 `${mask & 1 ? "R" : "0"}` + 189 `${mask & 2 ? "G" : "0"}` + 190 `${mask & 4 ? "B" : "0"}` + 191 `${mask & 8 ? "A" : "0"}` + 192 " with RGB9_E5 attachment " + 193 (enabled ? "enabled" : "disabled")); 194 gl.colorMask(mask & 1, mask & 2, mask & 4, mask & 8); 195 gl.drawBuffers([enabled ? gl.COLOR_ATTACHMENT0 : gl.NONE, 196 gl.COLOR_ATTACHMENT1]); 197 198 runOps(enabled, mask); 199 200 if (dbiExt) { 201 debug("Setting incompatible color mask on unused draw buffer") 202 dbiExt.colorMaskiOES(2, true, false, false, false); 203 runOps(enabled, mask); // common mask remains on draw buffer 0 204 205 debug("Setting incompatible color mask on RGBA8 draw buffer") 206 dbiExt.colorMaskiOES(1, true, false, false, false); 207 runOps(enabled, mask); // common mask remains on draw buffer 0 208 209 debug("Setting incompatible color mask on RGB9_E5 draw buffer") 210 dbiExt.colorMaskiOES(0, true, false, false, false); 211 runOps(enabled, 1); // overridden 212 213 debug("Setting compatible color mask on RGB9_E5 draw buffer") 214 dbiExt.colorMaskiOES(0, true, true, true, false); 215 runOps(enabled, 7); // overridden 216 } 217 } 218 } 219 } 220 221 function runTest() { 222 if (!gl) { 223 testFailed("context does not exist"); 224 return; 225 } 226 testPassed("context exists"); 227 228 debug(""); 229 debug("Testing shared exponent rendering with extension disabled"); 230 formatTest(false); 231 232 ext = gl.getExtension("WEBGL_render_shared_exponent"); 233 wtu.runExtensionSupportedTest(gl, "WEBGL_render_shared_exponent", ext !== null); 234 235 if (ext !== null) { 236 debug(""); 237 debug("Testing shared exponent rendering with extension enabled"); 238 formatTest(true); 239 colorMaskTest(); 240 } else { 241 testPassed("No WEBGL_render_shared_exponent support -- this is legal"); 242 } 243 } 244 245 runTest(); 246 247 var successfullyParsed = true; 248 </script> 249 <script src="../../js/js-test-post.js"></script> 250 </body> 251 </html>