tex-image-and-sub-image-2d-with-canvas-sub-rectangle.js (12381B)
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 = realRedColor; 17 var greenColor = realGreenColor; 18 var blueColor = realBlueColor; 19 var cyanColor = realCyanColor; 20 21 function init() 22 { 23 description('Verify texImage2D and texSubImage2D 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 28 // The sub-rectangle tests only apply to WebGL 2.0 for the 29 // time being, though the tests for the WebGL 1.0 30 // format/internal format/type combinations are generated into 31 // conformance/textures/. 32 if (wtu.getDefault3DContextVersion() < 2) { 33 debug('Test only applies to WebGL 2.0'); 34 finishTest(); 35 return; 36 } 37 38 gl = wtu.create3DContext("example", { preserveDrawingBuffer: true }); 39 40 if (!prologue(gl)) { 41 finishTest(); 42 return; 43 } 44 45 switch (gl[pixelFormat]) { 46 case gl.RED: 47 case gl.RED_INTEGER: 48 greenColor = [0, 0, 0]; 49 blueColor = [0, 0, 0]; 50 cyanColor = [0, 0, 0]; 51 break; 52 53 case gl.RG: 54 case gl.RG_INTEGER: 55 blueColor = [0, 0, 0]; 56 cyanColor = [0, 255, 0]; 57 break; 58 59 case gl.LUMINANCE: 60 case gl.LUMINANCE_ALPHA: 61 redColor = [255, 255, 255]; 62 greenColor = [0, 0, 0]; 63 blueColor = [0, 0, 0]; 64 cyanColor = [0, 0, 0]; 65 break; 66 67 case gl.ALPHA: 68 redColor = [0, 0, 0]; 69 greenColor = [0, 0, 0]; 70 blueColor = [0, 0, 0]; 71 cyanColor = [0, 0, 0]; 72 break; 73 74 default: 75 break; 76 } 77 78 gl.clearColor(0,0,0,1); 79 gl.clearDepth(1); 80 gl.disable(gl.BLEND); 81 82 var canvas2d = document.createElement('canvas'); 83 runTest(canvas2d, setupSourceCanvas2D, '2D-rendered canvas'); 84 85 var canvasWebGL = document.createElement('canvas'); 86 runTest(canvasWebGL, setupSourceCanvasWebGL, 'WebGL-rendered canvas'); 87 88 finishTest(); 89 } 90 91 function fillStyle2D(ctx, color) { 92 ctx.fillStyle = 'rgb(' + color[0] + ', ' + color[1] + ', ' + color[2] + ')'; 93 } 94 95 function setupSourceCanvas2D(canvas) { 96 var width = canvas.width; 97 var height = canvas.height; 98 var halfWidth = Math.floor(width / 2); 99 var halfHeight = Math.floor(height / 2); 100 101 var ctx = canvas.getContext('2d'); 102 // Always use the same pattern for this test: four quadrants: 103 // red green 104 // blue cyan 105 // Handle odd-sized canvases 106 fillStyle2D(ctx, realRedColor); 107 ctx.fillRect(0, 0, halfWidth, halfHeight); 108 fillStyle2D(ctx, realGreenColor); 109 ctx.fillRect(halfWidth, 0, width - halfWidth, halfHeight); 110 fillStyle2D(ctx, realBlueColor); 111 ctx.fillRect(0, halfHeight, halfWidth, height - halfHeight); 112 fillStyle2D(ctx, realCyanColor); 113 ctx.fillRect(halfWidth, halfHeight, width - halfWidth, height - halfHeight); 114 } 115 116 function clearColorWebGL(ctx, color) { 117 ctx.clearColor(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0, 1.0); 118 ctx.clear(ctx.COLOR_BUFFER_BIT); 119 } 120 121 function setupSourceCanvasWebGL(canvas) { 122 var width = canvas.width; 123 var height = canvas.height; 124 var halfWidth = Math.floor(width / 2); 125 var halfHeight = Math.floor(height / 2); 126 127 var ctx = canvas.getContext('webgl'); 128 // Always use the same pattern for this test: four quadrants: 129 // red green 130 // blue cyan 131 // Handle odd-sized canvases 132 133 ctx.viewport(0, 0, width, height); 134 ctx.enable(ctx.SCISSOR_TEST); 135 // OpenGL origin is lower-left 136 ctx.scissor(0, 0, halfWidth, halfHeight); 137 clearColorWebGL(ctx, realBlueColor); 138 ctx.scissor(halfWidth, 0, width - halfWidth, halfHeight); 139 clearColorWebGL(ctx, realCyanColor); 140 ctx.scissor(0, halfHeight, halfWidth, height - halfHeight); 141 clearColorWebGL(ctx, realRedColor); 142 ctx.scissor(halfWidth, halfHeight, width - halfWidth, height - halfHeight); 143 clearColorWebGL(ctx, realGreenColor); 144 } 145 146 function runOneIteration(sourceDescription, useTexSubImage2D, flipY, 147 canvas, canvasSize, canvasSetupFunction, 148 sourceSubRectangle, expected, 149 bindingTarget, program) 150 { 151 sourceSubRectangleString = ''; 152 if (sourceSubRectangle) { 153 sourceSubRectangleString = ', sourceSubRectangle=' + sourceSubRectangle; 154 } 155 debug(''); 156 debug('Testing ' + sourceDescription + ' with ' + 157 (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') + 158 ', flipY=' + flipY + 159 ', bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') + 160 sourceSubRectangleString); 161 162 var loc; 163 if (bindingTarget == gl.TEXTURE_CUBE_MAP) { 164 loc = gl.getUniformLocation(program, "face"); 165 } 166 167 // Initialize the contents of the source canvas. 168 var width = canvasSize[0]; 169 var height = canvasSize[1]; 170 var halfWidth = Math.floor(width / 2); 171 var halfHeight = Math.floor(height / 2); 172 canvas.width = width; 173 canvas.height = height; 174 canvasSetupFunction(canvas); 175 176 // Upload the source canvas to the texture and draw it to a quad. 177 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 178 // Enable writes to the RGBA channels 179 gl.colorMask(1, 1, 1, 0); 180 var texture = gl.createTexture(); 181 // Bind the texture to texture unit 0 182 gl.bindTexture(bindingTarget, texture); 183 // Set up texture parameters 184 gl.texParameteri(bindingTarget, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 185 gl.texParameteri(bindingTarget, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 186 // Set up pixel store parameters 187 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY); 188 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); 189 wtu.failIfGLError(gl, 'gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);'); 190 var targets = [gl.TEXTURE_2D]; 191 if (bindingTarget == gl.TEXTURE_CUBE_MAP) { 192 targets = [gl.TEXTURE_CUBE_MAP_POSITIVE_X, 193 gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 194 gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 195 gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 196 gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 197 gl.TEXTURE_CUBE_MAP_NEGATIVE_Z]; 198 } 199 // In this test, this is always specified. It's currently WebGL 2.0-specific. 200 gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]); 201 gl.pixelStorei(gl.UNPACK_SKIP_ROWS, sourceSubRectangle[1]); 202 // Upload the image into the texture 203 var uploadWidth = sourceSubRectangle[2]; 204 var uploadHeight = sourceSubRectangle[3]; 205 for (var tt = 0; tt < targets.length; ++tt) { 206 if (useTexSubImage2D) { 207 // Initialize the texture to black first 208 gl.texImage2D(targets[tt], 0, gl[internalFormat], 209 uploadWidth, uploadHeight, 0, 210 gl[pixelFormat], gl[pixelType], null); 211 gl.texSubImage2D(targets[tt], 0, 0, 0, 212 uploadWidth, uploadHeight, 213 gl[pixelFormat], gl[pixelType], canvas); 214 } else { 215 gl.texImage2D(targets[tt], 0, gl[internalFormat], 216 uploadWidth, uploadHeight, 0, 217 gl[pixelFormat], gl[pixelType], canvas); 218 } 219 } 220 221 gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0); 222 gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0); 223 224 // The tests are constructed to upload a single solid color 225 // out of the canvas. 226 var outputCanvasWidth = gl.drawingBufferWidth; 227 var outputCanvasHeight = gl.drawingBufferHeight; 228 229 for (var tt = 0; tt < targets.length; ++tt) { 230 if (bindingTarget == gl.TEXTURE_CUBE_MAP) { 231 gl.uniform1i(loc, targets[tt]); 232 } 233 // Draw the triangles 234 wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); 235 236 var msg = 'should be ' + expected; 237 wtu.checkCanvasRect(gl, 0, 0, outputCanvasWidth, outputCanvasHeight, expected, msg); 238 } 239 } 240 241 function runTest(canvas, canvasSetupFunction, sourceDescription) 242 { 243 var program = tiu.setupTexturedQuad(gl, internalFormat); 244 runTestOnBindingTarget(gl.TEXTURE_2D, program, canvas, canvasSetupFunction, sourceDescription); 245 program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat); 246 runTestOnBindingTarget(gl.TEXTURE_CUBE_MAP, program, canvas, canvasSetupFunction, sourceDescription); 247 248 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 249 } 250 251 function runTestOnBindingTarget(bindingTarget, program, canvas, canvasSetupFunction, sourceDescription) { 252 var cases = [ 253 // Small canvas cases. Expected that these won't be 254 // GPU-accelerated in most browsers' implementations. 255 { expected: redColor, flipY: false, size: [2, 2], subRect: [0, 0, 1, 1] }, 256 { expected: greenColor, flipY: false, size: [2, 2], subRect: [1, 0, 1, 1] }, 257 { expected: blueColor, flipY: false, size: [2, 2], subRect: [0, 1, 1, 1] }, 258 { expected: cyanColor, flipY: false, size: [2, 2], subRect: [1, 1, 1, 1] }, 259 { expected: redColor, flipY: true, size: [2, 2], subRect: [0, 1, 1, 1] }, 260 { expected: greenColor, flipY: true, size: [2, 2], subRect: [1, 1, 1, 1] }, 261 { expected: blueColor, flipY: true, size: [2, 2], subRect: [0, 0, 1, 1] }, 262 { expected: cyanColor, flipY: true, size: [2, 2], subRect: [1, 0, 1, 1] }, 263 264 // Larger canvas cases. Expected that these will be 265 // GPU-accelerated in most browsers' implementations. 266 // Changes will be gladly accepted to trigger more 267 // browsers' heuristics to accelerate these canvases. 268 { expected: redColor, flipY: false, size: [384, 384], subRect: [ 0, 0, 192, 192] }, 269 { expected: greenColor, flipY: false, size: [384, 384], subRect: [192, 0, 192, 192] }, 270 { expected: blueColor, flipY: false, size: [384, 384], subRect: [ 0, 192, 192, 192] }, 271 { expected: cyanColor, flipY: false, size: [384, 384], subRect: [192, 192, 192, 192] }, 272 { expected: blueColor, flipY: true, size: [384, 384], subRect: [ 0, 0, 192, 192] }, 273 { expected: cyanColor, flipY: true, size: [384, 384], subRect: [192, 0, 192, 192] }, 274 { expected: redColor, flipY: true, size: [384, 384], subRect: [ 0, 192, 192, 192] }, 275 { expected: greenColor, flipY: true, size: [384, 384], subRect: [192, 192, 192, 192] }, 276 277 ]; 278 279 for (var i in cases) { 280 runOneIteration(sourceDescription, false, cases[i].flipY, 281 canvas, cases[i].size, canvasSetupFunction, 282 cases[i].subRect, 283 cases[i].expected, bindingTarget, program); 284 runOneIteration(sourceDescription, true, cases[i].flipY, 285 canvas, cases[i].size, canvasSetupFunction, 286 cases[i].subRect, 287 cases[i].expected, bindingTarget, program); 288 } 289 } 290 291 return init; 292 }