| <html> |
| |
| <head> |
| <script type='module'> |
| let lostJustHappened = false; |
| const initTextureColor = [1.0, 0.0, 0.0]; |
| const reinitTextureColor = [0.0, 1.0, 0.0]; |
| const reinitTextureColorArray = new Uint8Array([0x00, 0xff, 0x00, 0xff]); |
| |
| function contextLostTest(kind) { |
| switch (kind) { |
| case 'kill_after_notification': |
| // The browser test waits for notification from the page that it |
| // has been loaded before navigating to about:gpucrash. |
| window.domAutomationController.send('LOADED'); |
| break; |
| } |
| } |
| |
| async function init(canvas, color) { |
| let adapter = await navigator.gpu.requestAdapter(); |
| if (!adapter) { |
| console.warn('Failed to get WebGPU adapter'); |
| } |
| |
| let device = await adapter.requestDevice(); |
| device.lost.then(async value => { |
| // After device lost, re-initialize for new adapter and device. |
| // We choose a different texture color from when we first |
| // init to be sure that the texture is coming from here |
| device = null; |
| adapter = null; |
| lostJustHappened = true; |
| await init(canvas, reinitTextureColor); |
| }); |
| |
| const context = canvas.getContext('gpupresent'); |
| if (!context) |
| return; |
| |
| const swapChainFormat = 'bgra8unorm'; |
| const swapChain = context.configureSwapChain({ |
| device, |
| format: swapChainFormat, |
| usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT |
| }); |
| |
| async function checkTextureColor( |
| src, |
| format, |
| { x, y }, |
| exp |
| ) { |
| const byteLength = 4; |
| const bytesPerRow = 256; |
| const rowsPerImage = 1; |
| const mipSize = [1, 1, 1]; |
| const buffer = device.createBuffer({ |
| size: byteLength, |
| usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST, |
| }); |
| |
| const commandEncoder = device.createCommandEncoder(); |
| commandEncoder.copyTextureToBuffer( |
| { texture: src, mipLevel: 0, arrayLayer: 0, origin: { x, y, z: 0 } }, |
| { buffer, bytesPerRow, rowsPerImage }, |
| mipSize |
| ); |
| device.queue.submit([commandEncoder.finish()]); |
| await buffer.mapAsync(GPUMapMode.READ); |
| const actual = new Uint8Array(buffer.getMappedRange()); |
| |
| // check that the actual and expected buffers are the same |
| if (actual.byteLength !== exp.byteLength) { |
| window.domAutomationController.send('FAILED'); |
| } |
| for (var i = 0; i !== actual.byteLength; i++) { |
| if (actual[i] != exp[i]) { |
| window.domAutomationController.send('FAILED'); |
| return; |
| } |
| } |
| // if we did not fail in the previous checks, the context successfully restored |
| window.domAutomationController.send('SUCCESS'); |
| } |
| |
| function drawFrame() { |
| const commandEncoder = device.createCommandEncoder(); |
| const texture = swapChain ? swapChain.getCurrentTexture() : null; |
| const textureView = texture ? texture.createView() : null; |
| |
| const renderPassDescriptor = { |
| colorAttachments: [{ |
| view: textureView, |
| loadValue: { r: color[0], g: color[1], b: color[2], a: 1.0 }, |
| storeOp: 'store' |
| }], |
| }; |
| |
| const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); |
| passEncoder.endPass(); |
| |
| device.queue.submit([commandEncoder.finish()]); |
| if (lostJustHappened) { |
| // We don't want to check for the texture color until device and adapter have been reinitialized |
| // Checking prematurely was causing hangs in buffer.mapAync to never return (crbug.com/dawn/556) |
| if (device == null || adapter == null) { |
| return; |
| } |
| // We want to check if it's been restored to the reinit texture color. |
| checkTextureColor(texture, swapChainFormat, { x: 0, y: 0 }, reinitTextureColorArray); |
| lostJustHappened = false; |
| } |
| } |
| |
| function doFrame(timestamp) { |
| drawFrame(timestamp); |
| requestAnimationFrame(doFrame); |
| } |
| requestAnimationFrame(doFrame); |
| } |
| |
| export async function onLoad() { |
| const container = document.getElementById('container'); |
| const canvas = document.createElement('canvas'); |
| canvas.width = 100; |
| canvas.height = 100; |
| container.appendChild(canvas); |
| |
| if (!navigator.gpu) { |
| console.warn('webgpu not supported'); |
| return; |
| } |
| |
| await init(canvas, initTextureColor); |
| |
| const query = new URLSearchParams(window.location.search).get('query'); |
| if (query) |
| contextLostTest(query); |
| } |
| |
| document.addEventListener('DOMContentLoaded', onLoad); |
| </script> |
| </head> |
| |
| <body> |
| <div id='container'></div> |
| </body> |
| |
| </html> |