forked from webgpu/webgpu-samples
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutil.ts
More file actions
112 lines (98 loc) · 3.21 KB
/
util.ts
File metadata and controls
112 lines (98 loc) · 3.21 KB
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
// Show an error dialog if there's any uncaught exception or promise rejection.
// This gets set up on all pages that include util.ts.
globalThis.addEventListener('unhandledrejection', (ev) => {
fail(`unhandled promise rejection, please report a bug!
https://github.com/webgpu/webgpu-samples/issues/new\n${ev.reason}`);
});
globalThis.addEventListener('error', (ev) => {
fail(`uncaught exception, please report a bug!
https://github.com/webgpu/webgpu-samples/issues/new\n${ev.error}`);
});
/** Shows an error dialog if getting an adapter wasn't successful. */
export function quitIfAdapterNotAvailable(
adapter: GPUAdapter | null
): asserts adapter {
if (!('gpu' in navigator)) {
fail('navigator.gpu is not defined - WebGPU not available in this browser');
}
if (!adapter) {
fail("requestAdapter returned null - this sample can't run on this system");
}
}
export function quitIfLimitLessThan(
adapter: GPUAdapter,
limit: string,
requiredValue: number,
limits: Record<string, GPUSize32>
) {
if (limit in adapter.limits) {
const limitKey = limit as keyof GPUSupportedLimits;
const limitValue = adapter.limits[limitKey] as number;
if (limitValue < requiredValue) {
fail(
`This sample can't run on this system. ${limit} is ${limitValue}, and this sample requires at least ${requiredValue}.`
);
}
limits[limit] = requiredValue;
}
}
/**
* Shows an error dialog if getting a adapter or device wasn't successful,
* or if/when the device is lost or has an uncaptured error.
*/
export function quitIfWebGPUNotAvailable(
adapter: GPUAdapter | null,
device: GPUDevice | null
): asserts device {
if (!device) {
quitIfAdapterNotAvailable(adapter);
fail('Unable to get a device for an unknown reason');
return;
}
device.lost.then((reason) => {
fail(`Device lost ("${reason.reason}"):\n${reason.message}`);
});
device.addEventListener('uncapturederror', (ev) => {
fail(`Uncaptured error:\n${ev.error.message}`);
});
}
/** Fail by showing a console error, and dialog box if possible. */
const fail = (() => {
type ErrorOutput = { show(msg: string): void };
function createErrorOutput() {
if (typeof document === 'undefined') {
// Not implemented in workers.
return {
show(msg: string) {
console.error(msg);
},
};
}
const dialogBox = document.createElement('dialog');
dialogBox.close();
document.body.append(dialogBox);
const dialogText = document.createElement('pre');
dialogText.style.whiteSpace = 'pre-wrap';
dialogBox.append(dialogText);
const closeBtn = document.createElement('button');
closeBtn.textContent = 'OK';
closeBtn.onclick = () => dialogBox.close();
dialogBox.append(closeBtn);
return {
show(msg: string) {
// Don't overwrite the dialog message while it's still open
// (show the first error, not the most recent error).
if (!dialogBox.open) {
dialogText.textContent = msg;
dialogBox.showModal();
}
},
};
}
let output: ErrorOutput | undefined;
return (message: string) => {
if (!output) output = createErrorOutput();
output.show(message);
throw new Error(message);
};
})();