test_queue_copyExternalImageToTexture.html (7222B)
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <script src="/tests/SimpleTest/SimpleTest.js"></script> 6 <link rel="stylesheet" href="/tests/SimpleTest/test.css" /> 7 </head> 8 9 <body> 10 <script type="text/javascript"> 11 "use strict"; 12 13 ok( 14 SpecialPowers.getBoolPref("dom.webgpu.enabled"), 15 "WebGPU pref should be enabled." 16 ); 17 18 SimpleTest.waitForExplicitFinish(); 19 20 function requestAnimationFramePromise() { 21 return new Promise(requestAnimationFrame); 22 } 23 24 function createSourceCanvasWebgl() { 25 const offscreenCanvas = new OffscreenCanvas(200, 200); 26 const gl = offscreenCanvas.getContext("webgl"); 27 28 const COLOR_VALUE = 127.0 / 255.0; 29 const ALPHA_VALUE = 127.0 / 255.0; 30 31 gl.enable(gl.SCISSOR_TEST); 32 33 gl.scissor(0, 0, 100, 100); 34 gl.clearColor(COLOR_VALUE, 0.0, 0.0, ALPHA_VALUE); 35 gl.clear(gl.COLOR_BUFFER_BIT); 36 37 gl.scissor(100, 0, 100, 100); 38 gl.clearColor(0.0, COLOR_VALUE, 0.0, ALPHA_VALUE); 39 gl.clear(gl.COLOR_BUFFER_BIT); 40 41 gl.scissor(0, 100, 100, 100); 42 gl.clearColor(0.0, 0.0, COLOR_VALUE, ALPHA_VALUE); 43 gl.clear(gl.COLOR_BUFFER_BIT); 44 45 gl.scissor(100, 100, 100, 100); 46 gl.clearColor(0.0, 0.0, 0.0, ALPHA_VALUE); 47 gl.clear(gl.COLOR_BUFFER_BIT); 48 49 return { 50 source: offscreenCanvas, 51 origin: { x: 0, y: 0 }, 52 flipY: true, 53 }; 54 } 55 56 function createSourceCanvas2d() { 57 const offscreenCanvas = new OffscreenCanvas(200, 200); 58 const context = offscreenCanvas.getContext("2d"); 59 60 context.fillStyle = "rgba(255,0,0,0.498)"; 61 context.fillRect(0, 0, 100, 100); 62 63 context.fillStyle = "rgba(0,255,0,0.498)"; 64 context.fillRect(100, 0, 100, 100); 65 66 context.fillStyle = "rgba(0,0,255,0.498)"; 67 context.fillRect(0, 100, 100, 100); 68 69 context.fillStyle = "rgba(0,0,0,0.498)"; 70 context.fillRect(100, 100, 100, 100); 71 72 return { 73 source: offscreenCanvas, 74 origin: { x: 0, y: 0 }, 75 flipY: false, 76 }; 77 } 78 79 function createSourceImageBitmap() { 80 const sourceCanvas = createSourceCanvas2d(); 81 return { 82 source: sourceCanvas.source.transferToImageBitmap(), 83 origin: { x: 0, y: 0 }, 84 flipY: false, 85 }; 86 } 87 88 async function mapDestTexture( 89 device, 90 source, 91 destFormat, 92 premultiply, 93 copySize 94 ) { 95 const bytesPerRow = 256 * 4; // 256 aligned for 200 pixels 96 const texture = device.createTexture({ 97 format: destFormat, 98 size: copySize, 99 usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST, 100 }); 101 102 device.queue.copyExternalImageToTexture( 103 source, 104 { texture, premultipliedAlpha: premultiply }, 105 copySize 106 ); 107 108 const buffer = device.createBuffer({ 109 size: 1024 * 200, 110 usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, 111 }); 112 113 const encoder = device.createCommandEncoder(); 114 encoder.copyTextureToBuffer( 115 { texture }, 116 { buffer, bytesPerRow }, 117 copySize 118 ); 119 device.queue.submit([encoder.finish()]); 120 121 await buffer.mapAsync(GPUMapMode.READ); 122 return buffer; 123 } 124 125 async function verifyBuffer( 126 test, 127 device, 128 source, 129 format, 130 premultiply, 131 copyDim, 132 topLeftPixelData 133 ) { 134 try { 135 const buffer = await mapDestTexture( 136 device, 137 source, 138 format, 139 premultiply, 140 copyDim 141 ); 142 const arrayBuffer = buffer.getMappedRange(); 143 const view = new Uint8Array(arrayBuffer); 144 for (let i = 0; i < topLeftPixelData.length; ++i) { 145 is( 146 view[i], 147 topLeftPixelData[i], 148 test + 149 " " + 150 format + 151 " (" + 152 source.origin.x + 153 "," + 154 source.origin.y + 155 ") channel " + 156 i 157 ); 158 } 159 } catch (e) { 160 ok(false, "WebGPU exception: " + e); 161 } 162 } 163 164 async function verifySourceCanvas(test, device, source) { 165 await verifyBuffer( 166 test, 167 device, 168 source, 169 "rgba8unorm", 170 /* premultiply */ true, 171 { width: 200, height: 200 }, 172 [127, 0, 0, 127] 173 ); 174 await verifyBuffer( 175 test, 176 device, 177 source, 178 "bgra8unorm", 179 /* premultiply */ true, 180 { width: 200, height: 200 }, 181 [0, 0, 127, 127] 182 ); 183 await verifyBuffer( 184 test, 185 device, 186 source, 187 "rgba8unorm", 188 /* premultiply */ false, 189 { width: 200, height: 200 }, 190 [255, 0, 0, 127] 191 ); 192 await verifyBuffer( 193 test, 194 device, 195 source, 196 "bgra8unorm", 197 /* premultiply */ false, 198 { width: 200, height: 200 }, 199 [0, 0, 255, 127] 200 ); 201 202 // The copy is flipped but the origin is relative to the original source data, 203 // so we need to invert for WebGL. 204 const topRightPixelData = 205 test === "webgl" ? [0, 0, 0, 127] : [0, 127, 0, 127]; 206 const topRightOrigin = { origin: { x: 100, y: 0 } }; 207 await verifyBuffer( 208 test, 209 device, 210 { ...source, ...topRightOrigin }, 211 "bgra8unorm", 212 /* premultiply */ true, 213 { width: 100, height: 100 }, 214 topRightPixelData 215 ); 216 217 const bottomLeftPixelData = 218 test === "webgl" ? [0, 0, 127, 127] : [127, 0, 0, 127]; 219 const bottomLeftOrigin = { origin: { x: 0, y: 100 } }; 220 await verifyBuffer( 221 test, 222 device, 223 { ...source, ...bottomLeftOrigin }, 224 "bgra8unorm", 225 /* premultiply */ true, 226 { width: 100, height: 100 }, 227 bottomLeftPixelData 228 ); 229 } 230 231 async function writeDestCanvas(source2d, sourceWebgl, sourceImageBitmap) { 232 const adapter = await navigator.gpu.requestAdapter(); 233 const device = await adapter.requestDevice(); 234 await verifySourceCanvas("2d", device, source2d); 235 await verifySourceCanvas("imageBitmap", device, sourceImageBitmap); 236 await verifySourceCanvas("webgl", device, sourceWebgl); 237 } 238 239 async function runTest() { 240 try { 241 const source2d = createSourceCanvas2d(); 242 const sourceWebgl = createSourceCanvasWebgl(); 243 const sourceImageBitmap = createSourceImageBitmap(); 244 await requestAnimationFramePromise(); 245 await requestAnimationFramePromise(); 246 await writeDestCanvas(source2d, sourceWebgl, sourceImageBitmap); 247 } catch (e) { 248 ok(false, "Uncaught exception: " + e); 249 } finally { 250 SimpleTest.finish(); 251 } 252 } 253 254 runTest(); 255 </script> 256 </body> 257 </html>