tex-image-and-sub-image-3d-with-image-data.js (10681B)
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 function generateTest(internalFormat, pixelFormat, pixelType, prologue, resourcePath, defaultContextVersion) { 8 var wtu = WebGLTestUtils; 9 var tiu = TexImageUtils; 10 var gl = null; 11 var successfullyParsed = false; 12 var imageData = null; 13 var blackColor = [0, 0, 0]; 14 var originalPixels = (function() { 15 // (red|green|blue|cyan)(opaque|transparent) 16 var ro = [255, 0, 0, 255]; var rt = [255, 0, 0, 0]; 17 var go = [0, 255, 0, 255]; var gt = [0, 255, 0, 0]; 18 var bo = [0, 0, 255, 255]; var bt = [0, 0, 255, 0]; 19 var co = [0, 255, 255, 255]; var ct = [0, 255, 255, 0]; 20 return [ro, rt, go, gt, 21 ro, rt, go, gt, 22 bo, bt, co, ct, 23 bo, bt, co, ct]; 24 })(); 25 26 function init() 27 { 28 description('Verify texImage3D and texSubImage3D code paths taking ImageData (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')'); 29 30 // Set the default context version while still allowing the webglVersion URL query string to override it. 31 wtu.setDefault3DContextVersion(defaultContextVersion); 32 gl = wtu.create3DContext("example"); 33 34 if (!prologue(gl)) { 35 finishTest(); 36 return; 37 } 38 39 gl.clearColor(0,0,0,1); 40 gl.clearDepth(1); 41 gl.disable(gl.BLEND); 42 43 var canvas2d = document.getElementById("texcanvas"); 44 var context2d = canvas2d.getContext("2d"); 45 imageData = context2d.createImageData(4, 4); 46 var data = imageData.data; 47 for (var i = 0; i < originalPixels.length; i++) { 48 data.set(originalPixels[i], 4 * i); 49 } 50 51 runTest(); 52 } 53 54 function runOneIteration(useTexSubImage3D, flipY, premultiplyAlpha, bindingTarget, 55 depth, sourceSubRectangle, rTexCoord, program) 56 { 57 var expected = simulate(flipY, premultiplyAlpha, depth, sourceSubRectangle, rTexCoord); 58 var sourceSubRectangleString = ''; 59 if (sourceSubRectangle) { 60 sourceSubRectangleString = ', sourceSubRectangle=' + sourceSubRectangle; 61 sourceSubRectangleString += ', rTexCoord=' + rTexCoord; 62 } 63 debug(''); 64 debug('Testing ' + (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') + 65 ' with flipY=' + flipY + ', premultiplyAlpha=' + premultiplyAlpha + 66 ', bindingTarget=' + (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') + 67 sourceSubRectangleString); 68 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 69 // Enable writes to the RGBA channels 70 gl.colorMask(1, 1, 1, 0); 71 var texture = gl.createTexture(); 72 // Bind the texture to texture unit 0 73 gl.bindTexture(bindingTarget, texture); 74 // Set up texture parameters 75 gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 76 gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 77 gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 78 gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 79 gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE); 80 // Set up pixel store parameters 81 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); 82 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha); 83 gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); 84 var uploadWidth = imageData.width; 85 var uploadHeight = imageData.height; 86 if (sourceSubRectangle) { 87 gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]); 88 gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]); 89 uploadWidth = sourceSubRectangle[2]; 90 uploadHeight = sourceSubRectangle[3]; 91 } 92 // Upload the image into the texture 93 if (useTexSubImage3D) { 94 // Initialize the texture to black first 95 gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0, 96 gl[pixelFormat], gl[pixelType], null); 97 gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, uploadWidth, uploadHeight, depth, 98 gl[pixelFormat], gl[pixelType], imageData); 99 } else { 100 gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0, 101 gl[pixelFormat], gl[pixelType], imageData); 102 } 103 gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0); 104 gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0); 105 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture upload"); 106 107 var tl = expected[0][0]; 108 var tr = expected[0][1]; 109 var bl = expected[1][0]; 110 var br = expected[1][1]; 111 112 var rCoordLocation = gl.getUniformLocation(program, 'uRCoord'); 113 if (!rCoordLocation) { 114 testFailed("Shader incorrectly set up; couldn't find uRCoord uniform"); 115 return; 116 } 117 gl.uniform1f(rCoordLocation, rTexCoord); 118 // Draw the triangles 119 wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); 120 121 var width = gl.canvas.width; 122 var halfWidth = Math.floor(width / 2); 123 var height = gl.canvas.height; 124 var halfHeight = Math.floor(height / 2); 125 126 var top = 0; 127 var bottom = height - halfHeight; 128 var left = 0; 129 var right = width - halfWidth; 130 131 debug("Checking pixel values"); 132 debug("Expecting: " + expected); 133 var expectedH = expected.length; 134 var expectedW = expected[0].length; 135 var texelH = Math.floor(gl.canvas.height / expectedH); 136 var texelW = Math.floor(gl.canvas.width / expectedW); 137 // For each entry of the expected[][] array, check the appropriate 138 // canvas rectangle for correctness. 139 for (var row = 0; row < expectedH; row++) { 140 var y = row * texelH; 141 for (var col = 0; col < expectedW; col++) { 142 var x = col * texelW; 143 var val = expected[row][col]; 144 wtu.checkCanvasRect(gl, x, y, texelW, texelH, val, "should be " + val); 145 } 146 } 147 } 148 149 function runTest() 150 { 151 var program = tiu.setupTexturedQuadWith3D(gl, internalFormat); 152 runTestOnBindingTarget(gl.TEXTURE_3D, program); 153 program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat); 154 runTestOnBindingTarget(gl.TEXTURE_2D_ARRAY, program); 155 156 debug(""); 157 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 158 finishTest(); 159 } 160 161 function simulate(flipY, premultiplyAlpha, depth, sourceSubRectangle, rTexCoord) { 162 var ro = [255, 0, 0]; var rt = premultiplyAlpha ? [0, 0, 0] : [255, 0, 0]; 163 var go = [0, 255, 0]; var gt = premultiplyAlpha ? [0, 0, 0] : [0, 255, 0]; 164 var bo = [0, 0, 255]; var bt = premultiplyAlpha ? [0, 0, 0] : [0, 0, 255]; 165 var co = [0, 255, 255]; var ct = premultiplyAlpha ? [0, 0, 0] : [0, 255, 255]; 166 var expected = [[ro, rt, go, gt], 167 [ro, rt, go, gt], 168 [bo, bt, co, ct], 169 [bo, bt, co, ct]]; 170 switch (gl[pixelFormat]) { 171 case gl.RED: 172 case gl.RED_INTEGER: 173 for (var row = 0; row < 4; row++) { 174 for (var col = 0; col < 4; col++) { 175 expected[row][col][1] = 0; // zero the green channel 176 } 177 } 178 // fall-through 179 case gl.RG: 180 case gl.RG_INTEGER: 181 for (var row = 0; row < 4; row++) { 182 for (var col = 0; col < 4; col++) { 183 expected[row][col][2] = 0; // zero the blue channel 184 } 185 } 186 break; 187 default: 188 break; 189 } 190 191 if (flipY) { 192 expected.reverse(); 193 } 194 195 if (sourceSubRectangle) { 196 let expected2 = []; 197 for (var row = 0; row < sourceSubRectangle[3]; row++) { 198 expected2[row] = []; 199 for (var col = 0; col < sourceSubRectangle[2]; col++) { 200 expected2[row][col] = 201 expected[sourceSubRectangle[1] + row + rTexCoord * sourceSubRectangle[3]][sourceSubRectangle[0] + col]; 202 } 203 } 204 expected = expected2; 205 } 206 207 return expected; 208 } 209 210 function runTestOnBindingTarget(bindingTarget, program) { 211 var rects = [ 212 undefined, 213 [0, 0, 2, 2], 214 [2, 0, 2, 2], 215 ]; 216 var dbg = false; // Set to true for debug output images 217 if (dbg) { 218 (function() { 219 debug(""); 220 debug("Original ImageData (transparent pixels appear black):"); 221 var cvs = document.createElement("canvas"); 222 cvs.width = 4; 223 cvs.height = 4; 224 cvs.style.width = "32px"; 225 cvs.style.height = "32px"; 226 cvs.style.imageRendering = "pixelated"; 227 cvs.style.background = "#000"; 228 var ctx = cvs.getContext("2d"); 229 ctx.putImageData(imageData, 0, 0); 230 var output = document.getElementById("console"); 231 output.appendChild(cvs); 232 })(); 233 } 234 for (const sub of [false, true]) { 235 for (const flipY of [false, true]) { 236 for (const premul of [false, true]) { 237 for (let irect = 0; irect < rects.length; irect++) { 238 var rect = rects[irect]; 239 let depth = rect ? 2 : 1; 240 for (let rTexCoord = 0; rTexCoord < depth; rTexCoord++) { 241 // TODO: add tests for UNPACK_IMAGE_HEIGHT. 242 runOneIteration(sub, flipY, premul, bindingTarget, 243 depth, rect, rTexCoord, program); 244 if (dbg) { 245 debug("Actual:"); 246 var img = document.createElement("img"); 247 img.src = gl.canvas.toDataURL("image/png"); 248 var output = document.getElementById("console"); 249 output.appendChild(img); 250 } 251 } 252 } 253 } 254 } 255 } 256 } 257 258 return init; 259 }