framebuffer-render-to-layer.html (25246B)
1 <!-- 2 Copyright (c) 2020 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>WebGL2 can render to layers in 3D and 2D_ARRAY textures</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 <script id="vshader" type="x-shader/x-vertex">#version 300 es 16 void main(void) { 17 gl_Position = vec4(0, 0, 0, 1); 18 gl_PointSize = 1.0; 19 } 20 </script> 21 </head> 22 <body> 23 <canvas id="example" width="100", height="100"></canvas> 24 <div id="description"></div> 25 <div id="console"></div> 26 <script> 27 "use strict"; 28 debug(""); 29 30 description("Test that WebGL2 can render to layers in 3D and 2D_ARRAY textures"); 31 32 var wtu = WebGLTestUtils; 33 var gl = wtu.create3DContext("example", undefined, 2); 34 35 if (!gl) { 36 testFailed("WebGL context creation failed"); 37 } else { 38 testPassed("WebGL context creation succeeded"); 39 runTest(); 40 } 41 42 function runTest() { 43 const texWidth = 1; 44 const texHeight = 1; 45 const texDepth = 2; 46 47 function makeFragmentShader(typeInfo) { 48 const src = `#version 300 es 49 precision mediump float; 50 out ${typeInfo.outType} color; 51 void main() { 52 color = ${typeInfo.outValue}; 53 } 54 `; 55 return src; 56 } 57 58 const textureInternalFormatInfo = {}; 59 { 60 const t = textureInternalFormatInfo; 61 // unsized formats 62 // If understand correctly these 3 unsized formats are not required to be color renderable 63 t[gl.ALPHA] = { textureFormat: gl.ALPHA, colorRenderable: false, textureFilterable: true, bytesPerElement: [1, 2, 2, 4], type: [gl.UNSIGNED_BYTE, gl.HALF_FLOAT, gl.HALF_FLOAT_OES, gl.FLOAT], }; 64 t[gl.LUMINANCE] = { textureFormat: gl.LUMINANCE, colorRenderable: false, textureFilterable: true, bytesPerElement: [1, 2, 2, 4], type: [gl.UNSIGNED_BYTE, gl.HALF_FLOAT, gl.HALF_FLOAT_OES, gl.FLOAT], }; 65 t[gl.LUMINANCE_ALPHA] = { textureFormat: gl.LUMINANCE_ALPHA, colorRenderable: false, textureFilterable: true, bytesPerElement: [2, 4, 4, 8], type: [gl.UNSIGNED_BYTE, gl.HALF_FLOAT, gl.HALF_FLOAT_OES, gl.FLOAT], }; 66 67 t[gl.RGB] = { textureFormat: gl.RGB, colorRenderable: true, textureFilterable: true, bytesPerElement: [3, 6, 6, 12, 2], type: [gl.UNSIGNED_BYTE, gl.HALF_FLOAT, gl.HALF_FLOAT_OES, gl.FLOAT, gl.UNSIGNED_SHORT_5_6_5], }; 68 t[gl.RGBA] = { textureFormat: gl.RGBA, colorRenderable: true, textureFilterable: true, bytesPerElement: [4, 8, 8, 16, 2, 2], type: [gl.UNSIGNED_BYTE, gl.HALF_FLOAT, gl.HALF_FLOAT_OES, gl.FLOAT, gl.UNSIGNED_SHORT_4_4_4_4, gl.UNSIGNED_SHORT_5_5_5_1], }; 69 70 // sized formats 71 t[gl.R8] = { textureFormat: gl.RED, colorRenderable: true, textureFilterable: true, bytesPerElement: [1], type: [gl.UNSIGNED_BYTE], }; 72 t[gl.R8_SNORM] = { textureFormat: gl.RED, colorRenderable: false, textureFilterable: true, bytesPerElement: [1], type: [gl.BYTE], }; 73 t[gl.R16F] = { textureFormat: gl.RED, colorRenderable: false, textureFilterable: true, bytesPerElement: [4, 2], type: [gl.FLOAT, gl.HALF_FLOAT], }; 74 t[gl.R32F] = { textureFormat: gl.RED, colorRenderable: false, textureFilterable: false, bytesPerElement: [4], type: [gl.FLOAT], }; 75 t[gl.R8UI] = { textureFormat: gl.RED_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [1], type: [gl.UNSIGNED_BYTE], }; 76 t[gl.R8I] = { textureFormat: gl.RED_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [1], type: [gl.BYTE], }; 77 t[gl.R16UI] = { textureFormat: gl.RED_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [2], type: [gl.UNSIGNED_SHORT], }; 78 t[gl.R16I] = { textureFormat: gl.RED_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [2], type: [gl.SHORT], }; 79 t[gl.R32UI] = { textureFormat: gl.RED_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.UNSIGNED_INT], }; 80 t[gl.R32I] = { textureFormat: gl.RED_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.INT], }; 81 t[gl.RG8] = { textureFormat: gl.RG, colorRenderable: true, textureFilterable: true, bytesPerElement: [2], type: [gl.UNSIGNED_BYTE], }; 82 t[gl.RG8_SNORM] = { textureFormat: gl.RG, colorRenderable: false, textureFilterable: true, bytesPerElement: [2], type: [gl.BYTE], }; 83 t[gl.RG16F] = { textureFormat: gl.RG, colorRenderable: false, textureFilterable: true, bytesPerElement: [8, 4], type: [gl.FLOAT, gl.HALF_FLOAT], }; 84 t[gl.RG32F] = { textureFormat: gl.RG, colorRenderable: false, textureFilterable: false, bytesPerElement: [8], type: [gl.FLOAT], }; 85 t[gl.RG8UI] = { textureFormat: gl.RG_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [2], type: [gl.UNSIGNED_BYTE], }; 86 t[gl.RG8I] = { textureFormat: gl.RG_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [2], type: [gl.BYTE], }; 87 t[gl.RG16UI] = { textureFormat: gl.RG_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.UNSIGNED_SHORT], }; 88 t[gl.RG16I] = { textureFormat: gl.RG_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.SHORT], }; 89 t[gl.RG32UI] = { textureFormat: gl.RG_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [gl.UNSIGNED_INT], }; 90 t[gl.RG32I] = { textureFormat: gl.RG_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [gl.INT], }; 91 t[gl.RGB8] = { textureFormat: gl.RGB, colorRenderable: true, textureFilterable: true, bytesPerElement: [3], type: [gl.UNSIGNED_BYTE], }; 92 t[gl.SRGB8] = { textureFormat: gl.RGB, colorRenderable: false, textureFilterable: true, bytesPerElement: [3], type: [gl.UNSIGNED_BYTE], }; 93 t[gl.RGB565] = { textureFormat: gl.RGB, colorRenderable: true, textureFilterable: true, bytesPerElement: [3, 2], type: [gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT_5_6_5], }; 94 t[gl.RGB8_SNORM] = { textureFormat: gl.RGB, colorRenderable: false, textureFilterable: true, bytesPerElement: [3], type: [gl.BYTE], }; 95 t[gl.R11F_G11F_B10F] = { textureFormat: gl.RGB, colorRenderable: false, textureFilterable: true, bytesPerElement: [12, 6, 4], type: [gl.FLOAT, gl.HALF_FLOAT, gl.UNSIGNED_INT_10F_11F_11F_REV], }; 96 t[gl.RGB9_E5] = { textureFormat: gl.RGB, colorRenderable: false, textureFilterable: true, bytesPerElement: [12, 6, 4], type: [gl.FLOAT, gl.HALF_FLOAT, gl.UNSIGNED_INT_5_9_9_9_REV], }; 97 t[gl.RGB16F] = { textureFormat: gl.RGB, colorRenderable: false, textureFilterable: true, bytesPerElement: [12, 6], type: [gl.FLOAT, gl.HALF_FLOAT], }; 98 t[gl.RGB32F] = { textureFormat: gl.RGB, colorRenderable: false, textureFilterable: false, bytesPerElement: [12], type: [gl.FLOAT], }; 99 t[gl.RGB8UI] = { textureFormat: gl.RGB_INTEGER, colorRenderable: false, textureFilterable: false, bytesPerElement: [3], type: [gl.UNSIGNED_BYTE], }; 100 t[gl.RGB8I] = { textureFormat: gl.RGB_INTEGER, colorRenderable: false, textureFilterable: false, bytesPerElement: [3], type: [gl.BYTE], }; 101 t[gl.RGB16UI] = { textureFormat: gl.RGB_INTEGER, colorRenderable: false, textureFilterable: false, bytesPerElement: [6], type: [gl.UNSIGNED_SHORT], }; 102 t[gl.RGB16I] = { textureFormat: gl.RGB_INTEGER, colorRenderable: false, textureFilterable: false, bytesPerElement: [6], type: [gl.SHORT], }; 103 t[gl.RGB32UI] = { textureFormat: gl.RGB_INTEGER, colorRenderable: false, textureFilterable: false, bytesPerElement: [12], type: [gl.UNSIGNED_INT], }; 104 t[gl.RGB32I] = { textureFormat: gl.RGB_INTEGER, colorRenderable: false, textureFilterable: false, bytesPerElement: [12], type: [gl.INT], }; 105 t[gl.RGBA8] = { textureFormat: gl.RGBA, colorRenderable: true, textureFilterable: true, bytesPerElement: [4], type: [gl.UNSIGNED_BYTE], }; 106 t[gl.SRGB8_ALPHA8] = { textureFormat: gl.RGBA, colorRenderable: true, textureFilterable: true, bytesPerElement: [4], type: [gl.UNSIGNED_BYTE], }; 107 t[gl.RGBA8_SNORM] = { textureFormat: gl.RGBA, colorRenderable: false, textureFilterable: true, bytesPerElement: [4], type: [gl.BYTE], }; 108 t[gl.RGB5_A1] = { textureFormat: gl.RGBA, colorRenderable: true, textureFilterable: true, bytesPerElement: [4, 2, 4], type: [gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT_5_5_5_1, gl.UNSIGNED_INT_2_10_10_10_REV], }; 109 t[gl.RGBA4] = { textureFormat: gl.RGBA, colorRenderable: true, textureFilterable: true, bytesPerElement: [4, 2], type: [gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT_4_4_4_4], }; 110 t[gl.RGB10_A2] = { textureFormat: gl.RGBA, colorRenderable: true, textureFilterable: true, bytesPerElement: [4], type: [gl.UNSIGNED_INT_2_10_10_10_REV], }; 111 t[gl.RGBA16F] = { textureFormat: gl.RGBA, colorRenderable: false, textureFilterable: true, bytesPerElement: [16, 8], type: [gl.FLOAT, gl.HALF_FLOAT], }; 112 t[gl.RGBA32F] = { textureFormat: gl.RGBA, colorRenderable: false, textureFilterable: false, bytesPerElement: [16], type: [gl.FLOAT], }; 113 t[gl.RGBA8UI] = { textureFormat: gl.RGBA_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.UNSIGNED_BYTE], }; 114 t[gl.RGBA8I] = { textureFormat: gl.RGBA_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.BYTE], }; 115 t[gl.RGB10_A2UI] = { textureFormat: gl.RGBA_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.UNSIGNED_INT_2_10_10_10_REV], }; 116 t[gl.RGBA16UI] = { textureFormat: gl.RGBA_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [gl.UNSIGNED_SHORT], }; 117 t[gl.RGBA16I] = { textureFormat: gl.RGBA_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [8], type: [gl.SHORT], }; 118 t[gl.RGBA32I] = { textureFormat: gl.RGBA_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [16], type: [gl.INT], }; 119 t[gl.RGBA32UI] = { textureFormat: gl.RGBA_INTEGER, colorRenderable: true, textureFilterable: false, bytesPerElement: [16], type: [gl.UNSIGNED_INT], }; 120 121 // Sized Internal 122 t[gl.DEPTH_COMPONENT16] = { textureFormat: gl.DEPTH_COMPONENT, colorRenderable: true, textureFilterable: false, bytesPerElement: [2, 4], type: [gl.UNSIGNED_SHORT, gl.UNSIGNED_INT], }; 123 t[gl.DEPTH_COMPONENT24] = { textureFormat: gl.DEPTH_COMPONENT, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.UNSIGNED_INT], }; 124 t[gl.DEPTH_COMPONENT32F] = { textureFormat: gl.DEPTH_COMPONENT, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.FLOAT], }; 125 t[gl.DEPTH24_STENCIL8] = { textureFormat: gl.DEPTH_STENCIL, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.UNSIGNED_INT_24_8], }; 126 t[gl.DEPTH32F_STENCIL8] = { textureFormat: gl.DEPTH_STENCIL, colorRenderable: true, textureFilterable: false, bytesPerElement: [4], type: [gl.FLOAT_32_UNSIGNED_INT_24_8_REV], }; 127 128 Object.keys(t).forEach(function(internalFormat) { 129 const info = t[internalFormat]; 130 info.bytesPerElementMap = {}; 131 info.bytesPerElement.forEach(function(bytesPerElement, ndx) { 132 const type = info.type[ndx]; 133 info.bytesPerElementMap[type] = bytesPerElement; 134 }); 135 }); 136 } 137 138 const validChannelsByTextureFormat = {}; 139 { 140 const v = validChannelsByTextureFormat; 141 v[gl.RED] = [1, 0, 0, 0]; 142 v[gl.RG] = [1, 1, 0, 0]; 143 v[gl.RGB] = [1, 1, 1, 0]; 144 v[gl.RGBA] = [1, 1, 1, 1]; 145 v[gl.RED_INTEGER] = [1, 0, 0, 0]; 146 v[gl.RG_INTEGER] = [1, 1, 0, 0]; 147 v[gl.RGB_INTEGER] = [1, 1, 1, 0]; 148 v[gl.RGBA_INTEGER] = [1, 1, 1, 1]; 149 } 150 151 const depthTextureFormats = [ 152 gl.DEPTH_COMPONENT16, 153 gl.DEPTH_COMPONENT24, 154 gl.DEPTH_COMPONENT32F, 155 gl.DEPTH24_STENCIL8, 156 gl.DEPTH32F_STENCIL8, 157 ]; 158 159 const intTextureFormats = [ 160 gl.R8I, 161 gl.R16I, 162 gl.R32I, 163 gl.RG8I, 164 gl.RG16I, 165 gl.RG32I, 166 gl.RGB8I, 167 gl.RGB16I, 168 gl.RGB32I, 169 gl.RGBA8I, 170 gl.RGBA16I, 171 gl.RGBA32I, 172 ]; 173 174 const unsignedIntTextureFormats = [ 175 gl.R8UI, 176 gl.R16UI, 177 gl.R32UI, 178 gl.RG8UI, 179 gl.RG16UI, 180 gl.RG32UI, 181 gl.RGB8UI, 182 gl.RGB16UI, 183 gl.RGB32UI, 184 gl.RGBA8UI, 185 gl.RGB10_A2UI, 186 gl.RGBA16UI, 187 gl.RGBA32UI, 188 ]; 189 190 const floatTextureFormats = Object.keys(textureInternalFormatInfo).map(function(v) { 191 return parseInt(v); 192 }).filter(function(format) { 193 return intTextureFormats.indexOf(format) < 0 && 194 unsignedIntTextureFormats.indexOf(format) < 0 && 195 depthTextureFormats.indexOf(format); 196 }); 197 198 const expectedColorByInternalFormat = {}; 199 expectedColorByInternalFormat[gl.SRGB8_ALPHA8] = [225, 188, 137, 255]; 200 201 function clearFloat(gl) { 202 gl.clearBufferfv(gl.COLOR, 0, [0, 0, 0, 0]); 203 } 204 205 function clearInt(gl) { 206 gl.clearBufferiv(gl.COLOR, 0, [0, 0, 0, 0]); 207 } 208 209 function clearUint(gl) { 210 gl.clearBufferuiv(gl.COLOR, 0, [0, 0, 0, 0]); 211 } 212 213 214 function checkData(data, expected, internalFormat, tolerance) { 215 const internalFormatInfo = textureInternalFormatInfo[internalFormat]; 216 const validChannels = validChannelsByTextureFormat[internalFormatInfo.textureFormat]; 217 if (!validChannels) { 218 testFailed('oops'); 219 return; 220 } 221 for (let y = 0; y < texHeight; ++y) { 222 for (let x = 0; x < texWidth; ++x) { 223 for (let c = 0; c < validChannels.length; ++c) { 224 if (validChannels[c]) { 225 const offset = (y * texWidth + x) * 4 + c; 226 const pixel = data[offset]; 227 const diff = Math.abs(pixel - expected[c]); 228 if (diff > tolerance) { 229 testFailed(`pixel ${x},${y} channel ${c} was ${pixel} expected ${expected[c]} +/- ${tolerance}`); 230 return; 231 } 232 } 233 } 234 } 235 } 236 testPassed(`data was ${expected.join(',')}`); 237 } 238 239 function checkFloat(gl, textureInfo, expected) { 240 const data = new Uint8Array(texWidth * texHeight * 4); 241 gl.readPixels(0, 0, texWidth, texHeight, gl.RGBA, gl.UNSIGNED_BYTE, data); 242 const internalFormat = textureInfo.internalFormat; 243 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `No errors from readPixels with ${wtu.glEnumToString(gl, internalFormat)}`); 244 checkData(data, expected, internalFormat, 9); 245 } 246 247 function checkInt(gl, textureInfo, expected) { 248 const data = new Int32Array(texWidth * texHeight * 4); 249 gl.readPixels(0, 0, texWidth, texHeight, gl.RGBA_INTEGER, gl.INT, data); 250 const internalFormat = textureInfo.internalFormat; 251 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `No errors from readPixels with ${wtu.glEnumToString(gl, internalFormat)}`); 252 checkData(data, expected, internalFormat, 0); 253 } 254 255 function checkUint(gl, textureInfo, expected) { 256 const data = new Uint32Array(texWidth * texHeight * 4); 257 gl.readPixels(0, 0, texWidth, texHeight, gl.RGBA_INTEGER, gl.UNSIGNED_INT, data); 258 const internalFormat = textureInfo.internalFormat; 259 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `No errors from readPixels with ${wtu.glEnumToString(gl, internalFormat)}`); 260 checkData(data, expected, internalFormat, 0); 261 } 262 263 const expectedFloatColor = [.75 * 255 | 0, .5 * 255 | 0, .25 * 255 | 0, 1 * 255 | 0]; 264 const floatTypes = [ 265 { outType: 'vec4', outValue: 'vec4(.75, .5, .25, 1)', expected: expectedFloatColor, clear: clearFloat, check: checkFloat, target: gl.TEXTURE_2D, }, 266 { outType: 'vec4', outValue: 'vec4(.75, .5, .25, 1)', expected: expectedFloatColor, clear: clearFloat, check: checkFloat, target: gl.TEXTURE_3D, }, 267 { outType: 'vec4', outValue: 'vec4(.75, .5, .25, 1)', expected: expectedFloatColor, clear: clearFloat, check: checkFloat, target: gl.TEXTURE_2D_ARRAY, }, 268 ]; 269 270 const expectedIntColor = [1, 2, 4, 3]; 271 const signedIntTypes = [ 272 { outType: 'ivec4', outValue: 'ivec4(1, 2, 4, 3)', expected: expectedIntColor, clear: clearInt, check: checkInt, target: gl.TEXTURE_2D, }, 273 { outType: 'ivec4', outValue: 'ivec4(1, 2, 4, 3)', expected: expectedIntColor, clear: clearInt, check: checkInt, target: gl.TEXTURE_3D, }, 274 { outType: 'ivec4', outValue: 'ivec4(1, 2, 4, 3)', expected: expectedIntColor, clear: clearInt, check: checkInt, target: gl.TEXTURE_2D_ARRAY, }, 275 ]; 276 277 const expectedUintColor = [1, 2, 4, 3]; 278 const unsignedIntTypes = [ 279 { outType: 'uvec4', outValue: 'uvec4(1, 2, 4, 3)', expected: expectedUintColor, clear: clearUint, check: checkUint, target: gl.TEXTURE_2D, }, 280 { outType: 'uvec4', outValue: 'uvec4(1, 2, 4, 3)', expected: expectedUintColor, clear: clearUint, check: checkUint, target: gl.TEXTURE_3D, }, 281 { outType: 'uvec4', outValue: 'uvec4(1, 2, 4, 3)', expected: expectedUintColor, clear: clearUint, check: checkUint, target: gl.TEXTURE_2D_ARRAY, }, 282 ]; 283 284 /** 285 * Gets the number of bytes per element for a given internalFormat / type 286 * @param {number} internalFormat The internalFormat parameter from texImage2D etc.. 287 * @param {number} type The type parameter for texImage2D etc.. 288 * @return {number} the number of bytes per element for the given internalFormat, type combo 289 * @memberOf module:twgl/textures 290 */ 291 function getBytesPerElementForInternalFormat(internalFormat, type) { 292 const info = textureInternalFormatInfo[internalFormat]; 293 if (!info) { 294 throw "unknown internal format"; 295 } 296 const bytesPerElement = info.bytesPerElementMap[type]; 297 if (bytesPerElement === undefined) { 298 throw "unknown internal format"; 299 } 300 return bytesPerElement; 301 } 302 303 function make2DTexture(gl, target, internalFormat, format, type) { 304 gl.texImage2D(target, 0, internalFormat, texWidth, texHeight, 0, format, type, null); 305 } 306 307 function make3DTexture(gl, target, internalFormat, format, type) { 308 gl.texImage3D(target, 0, internalFormat, texWidth, texHeight, texDepth, 0, format, type, null); 309 } 310 311 function attach2DTexture(gl, target, texture) { 312 const level = 0; 313 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, texture, level); 314 } 315 316 function attach3DTexture(gl, target, texture) { 317 const level = 0; 318 const slice = texDepth - 1; 319 gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture, level, slice); 320 } 321 322 const targets = {}; 323 targets[gl.TEXTURE_2D] = { make: make2DTexture, attach: attach2DTexture, }, 324 targets[gl.TEXTURE_3D] = { make: make3DTexture, attach: attach3DTexture, }, 325 targets[gl.TEXTURE_2D_ARRAY] = { make: make3DTexture, attach: attach3DTexture, }, 326 327 debug("create textures"); 328 Object.keys(targets).forEach(function(target) { 329 debug(""); 330 target = parseInt(target); 331 debug(wtu.glEnumToString(gl, target)) 332 const targetInfo = targets[target]; 333 targetInfo.textures = []; 334 Object.keys(textureInternalFormatInfo).forEach(function(internalFormat) { 335 internalFormat = parseInt(internalFormat); 336 const isDepthFormat = depthTextureFormats.indexOf(internalFormat) >= 0; 337 if (isDepthFormat) { 338 return; 339 } 340 const info = textureInternalFormatInfo[internalFormat]; 341 if (!info.colorRenderable) { 342 return; 343 } 344 const texture = gl.createTexture(); 345 gl.bindTexture(target, texture); 346 targetInfo.make(gl, target, internalFormat, info.textureFormat, info.type[0]); 347 targetInfo.textures.push({ 348 internalFormat: internalFormat, 349 texture: texture, 350 }); 351 gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 352 gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 353 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `No errors from setup for ${wtu.glEnumToString(gl, target)} ${wtu.glEnumToString(gl, internalFormat)}`); 354 }); 355 }); 356 357 // set the canvas to a known color 358 const half = 127 / 255; 359 gl.clearColor(half, half, half, half); 360 gl.clear(gl.COLOR_BUFFER_BIT); 361 gl.clearColor(0, 0, 0, 0); 362 363 const framebuffer = gl.createFramebuffer(); 364 gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); 365 gl.viewport(0, 0, texWidth, texHeight); 366 367 const rb = gl.createRenderbuffer(); 368 gl.bindRenderbuffer(gl.RENDERBUFFER, rb); 369 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, texWidth, texHeight); 370 371 testTypes('float', floatTypes, floatTextureFormats); 372 testTypes('int', signedIntTypes, intTextureFormats); 373 testTypes('unsigned', unsignedIntTypes, unsignedIntTextureFormats); 374 375 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 376 wtu.checkCanvas(gl, [127, 127, 127, 127], "canvas should be [127, 127, 127, 127]"); 377 378 function testTypes(label, types, compatibleFormats) { 379 debug(''); 380 types.forEach(function(typeInfo) { 381 debug(`\nchecking ${wtu.glEnumToString(gl, typeInfo.target)} with ${label} texture formats`); 382 const program = wtu.setupProgram(gl, ['vshader', makeFragmentShader(typeInfo)], [], console.log.bind(console)); 383 if (!program) { 384 testFailed("Loading program failed"); 385 return; 386 } 387 testPassed("Loading program succeeded"); 388 389 const target = typeInfo.target; 390 const targetInfo = targets[target]; 391 targetInfo.textures.filter(function(textureInfo) { 392 return compatibleFormats.indexOf(textureInfo.internalFormat) >= 0; 393 }).forEach(function(textureInfo) { 394 const internalFormat = textureInfo.internalFormat; 395 const desc = `${wtu.glEnumToString(gl, target)} ${wtu.glEnumToString(gl, internalFormat)}`; 396 const expected = expectedColorByInternalFormat[internalFormat] || typeInfo.expected; 397 398 debug(''); 399 debug(desc); 400 401 targetInfo.attach(gl, target, textureInfo.texture); 402 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE, `for ${desc}`); 403 typeInfo.clear(gl); 404 if (wtu.glErrorShouldBe(gl, gl.NO_ERROR, `No errors from clear to ${desc}`)) { 405 return; 406 } 407 typeInfo.check(gl, textureInfo, [0, 0, 0, 0]); 408 gl.drawArrays(gl.POINTS, 0, 1); 409 if (wtu.glErrorShouldBe(gl, gl.NO_ERROR, `No errors from render to ${desc}`)) { 410 return; 411 } 412 typeInfo.check(gl, textureInfo, expected); 413 414 typeInfo.clear(gl); 415 if (wtu.glErrorShouldBe(gl, gl.NO_ERROR, `No errors from clear to ${desc}`)) { 416 return; 417 } 418 typeInfo.check(gl, textureInfo, [0, 0, 0, 0]); 419 420 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, rb); 421 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE, `for ${desc} with depth renderbuffer`); 422 gl.clearBufferfv(gl.DEPTH, 0, [1]); 423 gl.drawArrays(gl.POINTS, 0, 1); 424 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, null); 425 426 wtu.glErrorShouldBe(gl, gl.NO_ERROR, `No errors from render to ${desc}`); 427 428 typeInfo.check(gl, textureInfo, expected); 429 }); 430 }); 431 } 432 } 433 434 debug(""); 435 var successfullyParsed = true; 436 </script> 437 <script src="../../js/js-test-post.js"></script> 438 439 </body> 440 </html>