tex-image-and-sub-image-2d-with-array-buffer-view.html (13368B)
1 <!-- 2 Copyright (c) 2019 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 <link rel="stylesheet" href="../../../resources/js-test-style.css"/> 12 <script src="../../../js/js-test-pre.js"></script> 13 <script src="../../../js/webgl-test-utils.js"></script> 14 </head> 15 <body> 16 <canvas id="example" width="16" height="16"></canvas> 17 <div id="description"></div> 18 <div id="console"></div> 19 <script> 20 "use strict"; 21 description('Verifies texImage2D and texSubImage2D code paths taking ArrayBufferView'); 22 23 var wtu = WebGLTestUtils; 24 25 function roundUpToAlignment(value, alignment) { 26 return Math.floor((value + alignment - 1) / alignment) * alignment; 27 } 28 29 function generateRGBAData(type, unpackAlignment, sourceData, width, height) 30 { 31 var numColors = sourceData.length / 4; 32 var colorOffset = function(y) { 33 return 4 * Math.floor(y * numColors / height); 34 }; 35 36 switch (type) { 37 case gl.UNSIGNED_BYTE: { 38 var rowWidth = roundUpToAlignment(width * 4, unpackAlignment); 39 var data = new Uint8Array(height * rowWidth); 40 for (var y = 0; y < height; ++y) { 41 var index = y * rowWidth; 42 var offset = colorOffset(y); 43 for (var element = 0; element < width * 4; ++element) { 44 data[index + element] = sourceData[offset + element % 4]; 45 } 46 } 47 return data; 48 } 49 case gl.UNSIGNED_SHORT_4_4_4_4: { 50 var rowWidth = roundUpToAlignment(width * 2, unpackAlignment) / 2; 51 var data = new Uint16Array(height * rowWidth); 52 for (var y = 0; y < height; ++y) { 53 var offset = colorOffset(y); 54 for (var x = 0; x < width; ++x) { 55 var index = y * rowWidth + x; 56 data[index] = (((sourceData[offset + 0] & 0xF0) << 8) 57 | ((sourceData[offset + 1] & 0xF0) << 4) 58 | ((sourceData[offset + 2] & 0xF0) >> 0) 59 | ((sourceData[offset + 3] & 0xF0) >> 4)); 60 } 61 } 62 return data; 63 } 64 case gl.UNSIGNED_SHORT_5_5_5_1: { 65 var rowWidth = roundUpToAlignment(width * 2, unpackAlignment) / 2; 66 var data = new Uint16Array(height * rowWidth); 67 for (var y = 0; y < height; ++y) { 68 var offset = colorOffset(y); 69 for (var x = 0; x < width; ++x) { 70 var index = y * rowWidth + x; 71 data[index] = (((sourceData[offset + 0] & 0xF8) << 8) 72 | ((sourceData[offset + 1] & 0xF8) << 3) 73 | ((sourceData[offset + 2] & 0xF8) >> 2) 74 | ((sourceData[offset + 3] & 0x80) >> 7)); 75 } 76 } 77 return data; 78 } 79 } 80 } 81 82 function typeToString(type) 83 { 84 switch (type) { 85 case gl.UNSIGNED_BYTE: return 'UNSIGNED_BYTE'; 86 case gl.UNSIGNED_SHORT_5_5_5_1: return 'UNSIGNED_SHORT_5_5_5_1'; 87 case gl.UNSIGNED_SHORT_4_4_4_4: return 'UNSIGNED_SHORT_4_4_4_4'; 88 } 89 return 'Unknown type ' + type; 90 } 91 92 function runOneIteration(useTexSubImage2D, type, unpackAlignment, flipY, premultiplyAlpha, 93 topColor, bottomColor, extraColor, bindingTarget, program) 94 { 95 debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') + 96 ' with type=' + typeToString(type) + 97 ', unpackAlignment=' + unpackAlignment + 98 ', flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha + 99 ', bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP')); 100 gl.colorMask(true, true, true, true); 101 gl.clearColor(0, 0, 0, 1.0); 102 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 103 // Enable writes to the RGB channels 104 gl.colorMask(true, true, true, false); 105 var texture = gl.createTexture(); 106 // Bind the texture to texture unit 0 107 gl.bindTexture(bindingTarget, texture); 108 // Set up texture parameters 109 gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 110 gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 111 gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 112 gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 113 // Set up pixel store parameters 114 gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); 115 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); 116 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha); 117 // Generate the data 118 var sourceData = [ 255, 0, 0, 255, 119 0, 255, 0, 0 ]; 120 var texWidth = 5; // this must be mod 4 + 1 to test unpackAlignment 121 // cube map texture must be square. 122 if (bindingTarget == gl.TEXTURE_CUBE_MAP) 123 texWidth = 16; 124 var texHeight = 16; 125 var data = generateRGBAData(type, unpackAlignment, sourceData, texWidth, texHeight); 126 if (gl.getError() != gl.NO_ERROR) 127 testFailed("GL error before texture upload"); 128 var targets = [gl.TEXTURE_2D]; 129 if (bindingTarget == gl.TEXTURE_CUBE_MAP) { 130 targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X, 131 gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 132 gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 133 gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 134 gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 135 gl.TEXTURE_CUBE_MAP_NEGATIVE_Z]; 136 } 137 // Upload the image into the texture 138 for (var tt = 0; tt < targets.length; ++tt) { 139 if (useTexSubImage2D) { 140 // Initialize the texture to black first 141 gl.texImage2D(targets[tt], 0, gl.RGBA, texWidth, texHeight, 0, 142 gl.RGBA, type, null); 143 if (gl.getError() != gl.NO_ERROR) 144 testFailed("GL error after texImage2D(null)"); 145 gl.texSubImage2D(targets[tt], 0, 0, 0, texWidth, texHeight, gl.RGBA, type, data); 146 if (gl.getError() != gl.NO_ERROR) 147 testFailed("GL error after texSubImage2D"); 148 } else { 149 gl.texImage2D(targets[tt], 0, gl.RGBA, texWidth, texHeight, 0, gl.RGBA, type, data); 150 if (gl.getError() != gl.NO_ERROR) 151 testFailed("GL error after texImage2D"); 152 } 153 } 154 155 var testWidth = gl.drawingBufferWidth; 156 var testHeight = gl.drawingBufferHeight / 2; 157 158 var loc; 159 if (bindingTarget == gl.TEXTURE_CUBE_MAP) { 160 loc = gl.getUniformLocation(program, "face"); 161 } 162 163 for (var tt = 0; tt < targets.length; ++tt) { 164 if (bindingTarget == gl.TEXTURE_CUBE_MAP) { 165 gl.uniform1i(loc, targets[tt]); 166 } 167 168 // Draw the triangles 169 wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); 170 171 // Check the top pixel and bottom pixel and make sure they have 172 // the right color. 173 var rects = [wtu.makeCheckRect(0, 0, testWidth, testHeight, bottomColor, "bottom pixel should be " + bottomColor, 0), 174 wtu.makeCheckRect(0, testHeight, testWidth, testHeight, topColor, "top pixel should be " + topColor, 0)]; 175 wtu.checkCanvasRects(gl, rects); 176 } 177 178 // Change part of the texture. 179 var partWidth = 16; 180 var partHeight = 16; 181 // make texture double res of part. 182 var data = generateRGBAData(type, unpackAlignment, sourceData, partWidth * 2, partHeight * 2); 183 for (var tt = 0; tt < targets.length; ++tt) { 184 gl.texImage2D(targets[tt], 0, gl.RGBA, partWidth * 2, partHeight * 2, 0, gl.RGBA, type, data); 185 } 186 // set part. 187 var extraData = [ 188 255, 0, 0, 255, 189 0, 0, 255, 0 190 ]; 191 var data = generateRGBAData(type, unpackAlignment, extraData, partWidth, partHeight); 192 for (var tt = 0; tt < targets.length; ++tt) { 193 gl.texSubImage2D(targets[tt], 0, 0, 0, partWidth, partHeight, gl.RGBA, type, data); 194 } 195 var halfWidth = gl.drawingBufferWidth / 2; 196 var halfHeight = gl.drawingBufferHeight / 2; 197 var quarterHeight = gl.drawingBufferHeight / 4; 198 var red = [255, 0, 0, 255]; 199 var tcolor0 = flipY ? extraColor : red; 200 var tcolor1 = flipY ? red : extraColor; 201 202 for (var tt = 0; tt < targets.length; ++tt) { 203 if (bindingTarget == gl.TEXTURE_CUBE_MAP) { 204 gl.uniform1i(loc, targets[tt]); 205 } 206 207 wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); 208 wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); 209 var rects = [wtu.makeCheckRect(0, 0, halfWidth, quarterHeight, tcolor0, "bottom left bottom pixels should be " + tcolor0, 0), 210 wtu.makeCheckRect(0, quarterHeight, halfWidth, quarterHeight, tcolor1, "bottom left top pixels should be " + tcolor1, 0), 211 wtu.makeCheckRect(halfWidth, 0, halfWidth, halfHeight, bottomColor, "bottom right pixels should be " + bottomColor, 0), 212 wtu.makeCheckRect(0, halfHeight, testWidth, halfHeight, topColor, "top pixels should be " + topColor, 0)]; 213 wtu.checkCanvasRects(gl, rects); 214 } 215 216 // set far corner. 217 for (var tt = 0; tt < targets.length; ++tt) { 218 gl.texSubImage2D(targets[tt], 0, partWidth, partHeight, partWidth, partHeight, gl.RGBA, type, data); 219 } 220 for (var tt = 0; tt < targets.length; ++tt) { 221 if (bindingTarget == gl.TEXTURE_CUBE_MAP) { 222 gl.uniform1i(loc, targets[tt]); 223 } 224 225 wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); 226 var rects = [wtu.makeCheckRect(0, 0, halfWidth, quarterHeight, tcolor0, "bottom left bottom pixels should be " + tcolor0, 0), 227 wtu.makeCheckRect(0, quarterHeight, halfWidth, quarterHeight, tcolor1, "bottom left top pixels should be " + tcolor1, 0), 228 wtu.makeCheckRect(halfWidth, 0, halfWidth, halfHeight, bottomColor, "bottom left pixels should be " + bottomColor, 0), 229 wtu.makeCheckRect(0, halfHeight, halfWidth, halfHeight, topColor, "top right pixels should be " + topColor, 0), 230 wtu.makeCheckRect(halfWidth, halfHeight, halfWidth, quarterHeight, tcolor0, "top right bottom pixels should be " + tcolor0, 0), 231 wtu.makeCheckRect(halfWidth, halfHeight + quarterHeight, halfWidth, quarterHeight, tcolor1, "top right top pixels should be " + tcolor1, 0)]; 232 wtu.checkCanvasRects(gl, rects); 233 } 234 } 235 236 function runTest(bindingTarget, program) 237 { 238 var red = [255, 0, 0, 255]; 239 var green = [0, 255, 0, 255]; 240 var blue = [0, 0, 255, 255]; 241 var redPremultiplyAlpha = [255, 0, 0, 255]; 242 var greenPremultiplyAlpha = [0, 0, 0, 255]; 243 var bluePremultiplyAlpha = [0, 0, 0, 255]; 244 245 var types = [ gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT_5_5_5_1, gl.UNSIGNED_SHORT_4_4_4_4 ]; 246 var unpackAlignments = [ 1, 2, 4, 8 ]; 247 248 var cases = [ 249 { sub: false, flipY: true, premultiplyAlpha: false, topColor: red, bottomColor: green, extraColor: blue }, 250 { sub: false, flipY: false, premultiplyAlpha: false, topColor: green, bottomColor: red, extraColor: blue }, 251 { sub: false, flipY: true, premultiplyAlpha: true, topColor: redPremultiplyAlpha, bottomColor: greenPremultiplyAlpha, extraColor: bluePremultiplyAlpha }, 252 { sub: false, flipY: false, premultiplyAlpha: true, topColor: greenPremultiplyAlpha, bottomColor: redPremultiplyAlpha, extraColor: bluePremultiplyAlpha }, 253 { sub: true, flipY: true, premultiplyAlpha: false, topColor: red, bottomColor: green, extraColor: blue }, 254 { sub: true, flipY: false, premultiplyAlpha: false, topColor: green, bottomColor: red, extraColor: blue }, 255 { sub: true, flipY: true, premultiplyAlpha: true, topColor: redPremultiplyAlpha, bottomColor: greenPremultiplyAlpha, extraColor: bluePremultiplyAlpha }, 256 { sub: true, flipY: false, premultiplyAlpha: true, topColor: greenPremultiplyAlpha, bottomColor: redPremultiplyAlpha, extraColor: bluePremultiplyAlpha }, 257 ]; 258 259 for (var i in types) { 260 for (var j in unpackAlignments) { 261 for (var k in cases) { 262 runOneIteration(cases[k].sub, types[i], unpackAlignments[j], cases[k].flipY, cases[k].premultiplyAlpha, 263 cases[k].topColor, cases[k].bottomColor, cases[k].extraColor, bindingTarget, program); 264 } 265 } 266 } 267 } 268 269 var gl = wtu.create3DContext("example"); 270 271 var program = wtu.setupTexturedQuad(gl); 272 runTest(gl.TEXTURE_2D, program); 273 program = wtu.setupTexturedQuadWithCubeMap(gl); 274 runTest(gl.TEXTURE_CUBE_MAP, program); 275 276 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 277 278 const tex = gl.createTexture(); 279 gl.bindTexture(gl.TEXTURE_2D, tex); 280 281 const validDatas = [ 282 `new Uint8Array(4)`, 283 `new Uint8Array(new ArrayBuffer(4))`, 284 `new Uint8ClampedArray(4)`, 285 `new Uint8ClampedArray(new ArrayBuffer(4))`, 286 ]; 287 if (window.SharedArrayBuffer) { 288 validDatas.push( 289 `new Uint8Array(new SharedArrayBuffer(4))`, 290 `new Uint8ClampedArray(new SharedArrayBuffer(4))` 291 ); 292 } 293 for (const x of validDatas) { 294 shouldNotThrow(`gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1, 0, gl.RGBA, gl.UNSIGNED_BYTE, ${x});`); 295 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 296 shouldNotThrow(`gl.texSubImage2D(gl.TEXTURE_2D, 0, 0,0, 1,1, gl.RGBA, gl.UNSIGNED_BYTE, ${x});`); 297 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 298 } 299 300 var successfullyParsed = true; 301 </script> 302 <script src="../../../js/js-test-post.js"></script> 303 </body> 304 </html>