1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
content / test / data / gpu / webgpu-context-lost.html [blame]
<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('webgpu');
if (!context)
return;
const swapChainFormat = 'bgra8unorm';
context.configure({
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 = context ? context.getCurrentTexture() : null;
const textureView = texture ? texture.createView() : null;
const renderPassDescriptor = {
colorAttachments: [{
view: textureView,
loadOp: 'clear',
clearValue: { r: color[0], g: color[1], b: color[2], a: 1.0 },
storeOp: 'store',
}],
};
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.end();
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>