tex-image-and-sub-image-3d-with-canvas-sub-rectangle.js (15077B)
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 realRedColor = [255, 0, 0]; 13 var realGreenColor = [0, 255, 0]; 14 var realBlueColor = [0, 0, 255]; 15 var realCyanColor = [0, 255, 255]; 16 var redColor = [255, 0, 0]; 17 var greenColor = [0, 255, 0]; 18 var blueColor = [0, 0, 255]; 19 var cyanColor = [0, 255, 255]; 20 21 function init() 22 { 23 description('Verify texImage3D and texSubImage3D code paths taking a sub-rectangle of a canvas (' + internalFormat + '/' + pixelFormat + '/' + pixelType + ')'); 24 25 // Set the default context version while still allowing the webglVersion URL query string to override it. 26 wtu.setDefault3DContextVersion(defaultContextVersion); 27 gl = wtu.create3DContext("example"); 28 29 if (!prologue(gl)) { 30 finishTest(); 31 return; 32 } 33 34 switch (gl[pixelFormat]) { 35 case gl.RED: 36 case gl.RED_INTEGER: 37 greenColor = [0, 0, 0]; 38 blueColor = [0, 0, 0]; 39 cyanColor = [0, 0, 0]; 40 break; 41 42 case gl.RG: 43 case gl.RG_INTEGER: 44 blueColor = [0, 0, 0]; 45 cyanColor = [0, 255, 0]; 46 break; 47 48 default: 49 break; 50 } 51 52 gl.clearColor(0,0,0,1); 53 gl.clearDepth(1); 54 55 var canvas2d = document.createElement('canvas'); 56 runTest(canvas2d, setupSourceCanvas2D, '2D-rendered canvas'); 57 58 var canvasWebGL = document.createElement('canvas'); 59 runTest(canvasWebGL, setupSourceCanvasWebGL, 'WebGL-rendered canvas'); 60 61 finishTest(); 62 } 63 64 function uploadCanvasToTexture(canvas, useTexSubImage3D, flipY, bindingTarget, 65 depth, sourceSubRectangle, unpackImageHeight) 66 { 67 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 68 // Disable any writes to the alpha channel 69 gl.colorMask(1, 1, 1, 0); 70 var texture = gl.createTexture(); 71 // Bind the texture to texture unit 0 72 gl.bindTexture(bindingTarget, texture); 73 // Set up texture parameters 74 gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 75 gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 76 gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 77 gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 78 gl.texParameteri(bindingTarget, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE); 79 // Set up pixel store parameters 80 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); 81 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); 82 gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); 83 var uploadWidth = canvas.width; 84 var uploadHeight = canvas.height; 85 if (sourceSubRectangle) { 86 gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]); 87 gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]); 88 uploadWidth = sourceSubRectangle[2]; 89 uploadHeight = sourceSubRectangle[3]; 90 } 91 if (unpackImageHeight) { 92 gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight); 93 } 94 // Upload the image into the texture 95 if (useTexSubImage3D) { 96 // Initialize the texture to black first 97 gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0, 98 gl[pixelFormat], gl[pixelType], null); 99 gl.texSubImage3D(bindingTarget, 0, 0, 0, 0, uploadWidth, uploadHeight, depth, 100 gl[pixelFormat], gl[pixelType], canvas); 101 } else { 102 gl.texImage3D(bindingTarget, 0, gl[internalFormat], uploadWidth, uploadHeight, depth, 0, 103 gl[pixelFormat], gl[pixelType], canvas); 104 } 105 gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0); 106 gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0); 107 gl.pixelStorei(gl.UNPACK_IMAGE_HEIGHT, 0); 108 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from texture upload"); 109 } 110 111 function fillStyle2D(ctx, color) { 112 ctx.fillStyle = 'rgb(' + color[0] + ', ' + color[1] + ', ' + color[2] + ')'; 113 } 114 115 function setupSourceCanvas2D(canvas) { 116 var width = canvas.width; 117 var height = canvas.height; 118 var halfWidth = Math.floor(width / 2); 119 var halfHeight = Math.floor(height / 2); 120 121 var ctx = canvas.getContext('2d'); 122 // Always use the same pattern for this test: four quadrants: 123 // red green 124 // blue cyan 125 // Handle odd-sized canvases 126 fillStyle2D(ctx, realRedColor); 127 ctx.fillRect(0, 0, halfWidth, halfHeight); 128 fillStyle2D(ctx, realGreenColor); 129 ctx.fillRect(halfWidth, 0, width - halfWidth, halfHeight); 130 fillStyle2D(ctx, realBlueColor); 131 ctx.fillRect(0, halfHeight, halfWidth, height - halfHeight); 132 fillStyle2D(ctx, realCyanColor); 133 ctx.fillRect(halfWidth, halfHeight, width - halfWidth, height - halfHeight); 134 } 135 136 function clearColorWebGL(ctx, color) { 137 ctx.clearColor(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0, 1.0); 138 ctx.clear(ctx.COLOR_BUFFER_BIT); 139 } 140 141 function setupSourceCanvasWebGL(canvas) { 142 var width = canvas.width; 143 var height = canvas.height; 144 var halfWidth = Math.floor(width / 2); 145 var halfHeight = Math.floor(height / 2); 146 147 var ctx = canvas.getContext('webgl'); 148 // Always use the same pattern for this test: four quadrants: 149 // red green 150 // blue cyan 151 // Handle odd-sized canvases 152 153 ctx.viewport(0, 0, width, height); 154 ctx.enable(ctx.SCISSOR_TEST); 155 // OpenGL origin is lower-left 156 ctx.scissor(0, 0, halfWidth, halfHeight); 157 clearColorWebGL(ctx, realBlueColor); 158 ctx.scissor(halfWidth, 0, width - halfWidth, halfHeight); 159 clearColorWebGL(ctx, realCyanColor); 160 ctx.scissor(0, halfHeight, halfWidth, height - halfHeight); 161 clearColorWebGL(ctx, realRedColor); 162 ctx.scissor(halfWidth, halfHeight, width - halfWidth, height - halfHeight); 163 clearColorWebGL(ctx, realGreenColor); 164 } 165 166 function runOneIteration(canvas, useTexSubImage3D, flipY, bindingTarget, 167 depth, sourceSubRectangle, unpackImageHeight, 168 rTextureCoord, expectedColor, program, 169 canvasSize, canvasSetupFunction, sourceDescription) 170 { 171 debug(''); 172 debug('Testing ' + sourceDescription + ' with ' + 173 (useTexSubImage3D ? 'texSubImage3D' : 'texImage3D') + 174 ', flipY=' + flipY + ', bindingTarget=' + 175 (bindingTarget == gl.TEXTURE_3D ? 'TEXTURE_3D' : 'TEXTURE_2D_ARRAY') + 176 ', sourceSubRectangle=' + sourceSubRectangle + 177 ', depth=' + depth + 178 (unpackImageHeight ? ', unpackImageHeight=' + unpackImageHeight : '') + 179 ', rTextureCoord=' + rTextureCoord); 180 181 // Initialize the contents of the source canvas. 182 var width = canvasSize[0]; 183 var height = canvasSize[1]; 184 var halfWidth = Math.floor(width / 2); 185 var halfHeight = Math.floor(height / 2); 186 canvas.width = width; 187 canvas.height = height; 188 canvasSetupFunction(canvas); 189 190 uploadCanvasToTexture(canvas, useTexSubImage3D, flipY, bindingTarget, 191 depth, sourceSubRectangle, unpackImageHeight); 192 var rCoordLocation = gl.getUniformLocation(program, 'uRCoord'); 193 if (!rCoordLocation) { 194 testFailed('Shader incorrectly set up; couldn\'t find uRCoord uniform'); 195 return; 196 } 197 gl.uniform1f(rCoordLocation, rTextureCoord); 198 199 // Draw the triangles 200 wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); 201 // Check the rendered canvas 202 wtu.checkCanvasRect(gl, 0, 0, canvasSize[0], canvasSize[1], expectedColor, "shouldBe " + expectedColor); 203 } 204 205 function runTest(canvas, canvasSetupFunction, sourceDescription) 206 { 207 var cases = [ 208 // Small canvas cases. Expected that these won't be 209 // GPU-accelerated in most browsers' implementations. 210 211 // No UNPACK_IMAGE_HEIGHT specified. 212 { expected: redColor, flipY: false, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 0.0 }, 213 { expected: blueColor, flipY: false, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 1.0 }, 214 { expected: blueColor, flipY: true, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 0.0 }, 215 { expected: redColor, flipY: true, size: [4, 4], subRect: [0, 0, 2, 2], depth: 2, rTextureCoord: 1.0 }, 216 { expected: greenColor, flipY: false, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 0.0 }, 217 { expected: cyanColor, flipY: false, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 1.0 }, 218 { expected: cyanColor, flipY: true, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 0.0 }, 219 { expected: greenColor, flipY: true, size: [4, 4], subRect: [2, 0, 2, 2], depth: 2, rTextureCoord: 1.0 }, 220 221 // Use UNPACK_IMAGE_HEIGHT to skip some pixels. 222 { expected: redColor, flipY: false, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 }, 223 { expected: blueColor, flipY: false, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 }, 224 { expected: blueColor, flipY: true, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 }, 225 { expected: redColor, flipY: true, size: [4, 4], subRect: [0, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 }, 226 { expected: greenColor, flipY: false, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 }, 227 { expected: cyanColor, flipY: false, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 }, 228 { expected: cyanColor, flipY: true, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 0.0 }, 229 { expected: greenColor, flipY: true, size: [4, 4], subRect: [2, 0, 1, 1], depth: 2, unpackImageHeight: 2, rTextureCoord: 1.0 }, 230 231 // Larger canvas cases. Expected that these will be 232 // GPU-accelerated in most browsers' implementations. 233 // Changes will be gladly accepted to trigger more 234 // browsers' heuristics to accelerate these canvases. 235 236 // No UNPACK_IMAGE_HEIGHT specified. 237 { expected: redColor, flipY: false, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 0.0 }, 238 { expected: blueColor, flipY: false, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 1.0 }, 239 { expected: blueColor, flipY: true, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 0.0 }, 240 { expected: redColor, flipY: true, size: [384, 384], subRect: [0, 0, 192, 192], depth: 2, rTextureCoord: 1.0 }, 241 { expected: greenColor, flipY: false, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 0.0 }, 242 { expected: cyanColor, flipY: false, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 1.0 }, 243 { expected: cyanColor, flipY: true, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 0.0 }, 244 { expected: greenColor, flipY: true, size: [384, 384], subRect: [192, 0, 192, 192], depth: 2, rTextureCoord: 1.0 }, 245 246 // Use UNPACK_IMAGE_HEIGHT to skip some pixels. 247 { expected: redColor, flipY: false, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 }, 248 { expected: blueColor, flipY: false, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 }, 249 { expected: blueColor, flipY: true, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 }, 250 { expected: redColor, flipY: true, size: [384, 384], subRect: [0, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 }, 251 { expected: greenColor, flipY: false, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 }, 252 { expected: cyanColor, flipY: false, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 }, 253 { expected: cyanColor, flipY: true, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 0.0 }, 254 { expected: greenColor, flipY: true, size: [384, 384], subRect: [192, 0, 96, 96], depth: 2, unpackImageHeight: 192, rTextureCoord: 1.0 }, 255 ]; 256 257 var program = tiu.setupTexturedQuadWith3D(gl, internalFormat); 258 for (var i in cases) { 259 runOneIteration(canvas, false, cases[i].flipY, gl.TEXTURE_3D, 260 cases[i].depth, cases[i].subRect, 261 cases[i].unpackImageHeight, cases[i].rTextureCoord, 262 cases[i].expected, 263 program, cases[i].size, canvasSetupFunction, sourceDescription); 264 runOneIteration(canvas, true, cases[i].flipY, gl.TEXTURE_3D, 265 cases[i].depth, cases[i].subRect, 266 cases[i].unpackImageHeight, cases[i].rTextureCoord, 267 cases[i].expected, 268 program, cases[i].size, canvasSetupFunction, sourceDescription); 269 } 270 271 program = tiu.setupTexturedQuadWith2DArray(gl, internalFormat); 272 for (var i in cases) { 273 runOneIteration(canvas, false, cases[i].flipY, gl.TEXTURE_2D_ARRAY, 274 cases[i].depth, cases[i].subRect, 275 cases[i].unpackImageHeight, cases[i].rTextureCoord, 276 cases[i].expected, 277 program, cases[i].size, canvasSetupFunction, sourceDescription); 278 runOneIteration(canvas, true, cases[i].flipY, gl.TEXTURE_2D_ARRAY, 279 cases[i].depth, cases[i].subRect, 280 cases[i].unpackImageHeight, cases[i].rTextureCoord, 281 cases[i].expected, 282 program, cases[i].size, canvasSetupFunction, sourceDescription); 283 } 284 } 285 286 return init; 287 }