@daugasauron/dolly-host-gpu 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/abi.mjs +33 -1
- package/bridge.mjs +2 -2
- package/gpu.mjs +22 -9
- package/package.json +2 -2
- package/worker.mjs +1446 -559
package/abi.mjs
CHANGED
|
@@ -46,5 +46,37 @@ export const DOLLY_GPU_BEGIN_RENDER_PASS = 23;
|
|
|
46
46
|
export const DOLLY_GPU_END_RENDER_PASS = 24;
|
|
47
47
|
export const DOLLY_GPU_DRAW_MESH = 25;
|
|
48
48
|
export const DOLLY_GPU_VIEWPORT = 26;
|
|
49
|
+
export const DOLLY_GPU_FEATURE_EXPLICIT = 1024;
|
|
50
|
+
export const DOLLY_GPU_LIMITS = 8;
|
|
51
|
+
export const DOLLY_GPU_BATCH_CONTINUE = 1;
|
|
52
|
+
export const DOLLY_GPU_MAX_LAYOUT_ENTRIES = 128;
|
|
53
|
+
export const DOLLY_GPU_CREATE_VIEW = 27;
|
|
54
|
+
export const DOLLY_GPU_CREATE_BIND_GROUP_LAYOUT = 28;
|
|
55
|
+
export const DOLLY_GPU_CREATE_PIPELINE_LAYOUT = 29;
|
|
56
|
+
export const DOLLY_GPU_CREATE_BIND_GROUP = 30;
|
|
57
|
+
export const DOLLY_GPU_CREATE_RENDER_PIPELINE = 31;
|
|
58
|
+
export const DOLLY_GPU_CREATE_COMPUTE_PIPELINE = 32;
|
|
59
|
+
export const DOLLY_GPU_CREATE_QUERY_SET = 33;
|
|
60
|
+
export const DOLLY_GPU_COPY_BUFFER_TO_TEXTURE = 34;
|
|
61
|
+
export const DOLLY_GPU_COPY_TEXTURE_TO_BUFFER = 35;
|
|
62
|
+
export const DOLLY_GPU_COPY_TEXTURE_TO_TEXTURE = 36;
|
|
63
|
+
export const DOLLY_GPU_CLEAR_BUFFER = 37;
|
|
64
|
+
export const DOLLY_GPU_WRITE_TIMESTAMP = 38;
|
|
65
|
+
export const DOLLY_GPU_RESOLVE_QUERY_SET = 39;
|
|
66
|
+
export const DOLLY_GPU_BEGIN_VIEW_PASS = 40;
|
|
67
|
+
export const DOLLY_GPU_BEGIN_COMPUTE_PASS = 41;
|
|
68
|
+
export const DOLLY_GPU_END_COMPUTE_PASS = 42;
|
|
69
|
+
export const DOLLY_GPU_SET_PIPELINE = 43;
|
|
70
|
+
export const DOLLY_GPU_SET_BIND_GROUP = 44;
|
|
71
|
+
export const DOLLY_GPU_SET_VERTEX_BUFFER = 45;
|
|
72
|
+
export const DOLLY_GPU_SET_INDEX_BUFFER = 46;
|
|
73
|
+
export const DOLLY_GPU_DRAW = 47;
|
|
74
|
+
export const DOLLY_GPU_DRAW_INDEXED = 48;
|
|
75
|
+
export const DOLLY_GPU_DRAW_INDIRECT = 49;
|
|
76
|
+
export const DOLLY_GPU_DRAW_INDEXED_INDIRECT = 50;
|
|
77
|
+
export const DOLLY_GPU_SET_BLEND_CONSTANT = 51;
|
|
78
|
+
export const DOLLY_GPU_SET_STENCIL_REFERENCE = 52;
|
|
79
|
+
export const DOLLY_GPU_DISPATCH = 53;
|
|
80
|
+
export const DOLLY_GPU_DISPATCH_INDIRECT = 54;
|
|
49
81
|
export const DOLLY_ERRNO = Object.freeze({ E2BIG: 1, EACCES: 2, EADDRINUSE: 3, EADDRNOTAVAIL: 4, EAFNOSUPPORT: 5, EAGAIN: 6, EALREADY: 7, EBADF: 8, EBADMSG: 9, EBUSY: 10, ECANCELED: 11, ECHILD: 12, ECONNABORTED: 13, ECONNREFUSED: 14, ECONNRESET: 15, EDEADLK: 16, EDESTADDRREQ: 17, EDOM: 18, EDQUOT: 19, EEXIST: 20, EFAULT: 21, EFBIG: 22, EHOSTUNREACH: 23, EIDRM: 24, EILSEQ: 25, EINPROGRESS: 26, EINTR: 27, EINVAL: 28, EIO: 29, EISCONN: 30, EISDIR: 31, ELOOP: 32, EMFILE: 33, EMLINK: 34, EMSGSIZE: 35, EMULTIHOP: 36, ENAMETOOLONG: 37, ENETDOWN: 38, ENETRESET: 39, ENETUNREACH: 40, ENFILE: 41, ENOBUFS: 42, ENODEV: 43, ENOENT: 44, ENOEXEC: 45, ENOLCK: 46, ENOLINK: 47, ENOMEM: 48, ENOMSG: 49, ENOPROTOOPT: 50, ENOSPC: 51, ENOSYS: 52, ENOTCONN: 53, ENOTDIR: 54, ENOTEMPTY: 55, ENOTRECOVERABLE: 56, ENOTSOCK: 57, ENOTTY: 59, ENXIO: 60, EOVERFLOW: 61, EOWNERDEAD: 62, EPERM: 63, EPIPE: 64, EPROTO: 65, EPROTONOSUPPORT: 66, EPROTOTYPE: 67, ERANGE: 68, EROFS: 69, ESPIPE: 70, ESRCH: 71, ESTALE: 72, ETIMEDOUT: 73, ETXTBSY: 74, EXDEV: 75, ENODATA: 116, ENOTSUP: 138 });
|
|
50
|
-
export const DOLLY_GPU_ABI_DIGEST = "
|
|
82
|
+
export const DOLLY_GPU_ABI_DIGEST = "3657d729d8b45db3587d12ec22ac9e83010045d9cdc6b068843f195acb65d52d";
|
package/bridge.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DOLLY_ERRNO as E } from "./abi.mjs";
|
|
2
2
|
import { DOLLY_GPU_SLOTS, DOLLY_GPU_REPLY_BYTES } from "./abi.mjs";
|
|
3
3
|
|
|
4
|
-
export async function createGpuBridge(memory, mailbox, canvas, complete, status) {
|
|
4
|
+
export async function createGpuBridge(memory, mailbox, canvas, shown, complete, status) {
|
|
5
5
|
const worker = new Worker(new URL("./worker.mjs", import.meta.url), { type: "module", name: "dolly-gpu" });
|
|
6
6
|
const control = new Int32Array(new SharedArrayBuffer(8));
|
|
7
7
|
let failed = false;
|
|
@@ -28,7 +28,7 @@ export async function createGpuBridge(memory, mailbox, canvas, complete, status)
|
|
|
28
28
|
else if (data.type === "status") status(data);
|
|
29
29
|
};
|
|
30
30
|
worker.onerror = () => stop("GPU provider worker failed");
|
|
31
|
-
worker.postMessage({type:"configure", memory, mailbox, canvas, control:control.buffer}, canvas ? [canvas] : []);
|
|
31
|
+
worker.postMessage({type:"configure", memory, mailbox, canvas, shown, control:control.buffer}, canvas ? [canvas] : []);
|
|
32
32
|
await initialized;
|
|
33
33
|
function dispatch({address, bytes}) {
|
|
34
34
|
if (failed) return -E.EIO;
|
package/gpu.mjs
CHANGED
|
@@ -43,7 +43,7 @@ function indicate(page, info, unavailable) {
|
|
|
43
43
|
element.className = "page-indicator";
|
|
44
44
|
element.setAttribute("role", "status");
|
|
45
45
|
element.style.cssText = "position:absolute;right:0.5rem;bottom:2rem;z-index:8;max-width:calc(100% - 1rem);" +
|
|
46
|
-
"padding:0.15rem 0.45rem;background
|
|
46
|
+
"padding:0.15rem 0.45rem;background:var(--dolly-ui-background);border:1px solid;font-size:13px;pointer-events:none";
|
|
47
47
|
}
|
|
48
48
|
if (unavailable) {
|
|
49
49
|
element.replaceChildren(`No GPU: ${unavailable}`);
|
|
@@ -51,17 +51,17 @@ function indicate(page, info, unavailable) {
|
|
|
51
51
|
if (page.site) {
|
|
52
52
|
const link = Object.assign(document.createElement("a"), { textContent: "How to enable WebGPU ↗",
|
|
53
53
|
href: new URL("docs/gpu.md#enabling-webgpu", page.site).href, target: "_blank", rel: "noopener" });
|
|
54
|
-
link.style.cssText = "color
|
|
54
|
+
link.style.cssText = "color:var(--dolly-ui-accent);pointer-events:auto";
|
|
55
55
|
element.append(" · ", link);
|
|
56
56
|
}
|
|
57
|
-
announce(page, element, "unavailable", "
|
|
57
|
+
announce(page, element, "unavailable", "var(--dolly-ui-alert)");
|
|
58
58
|
return {};
|
|
59
59
|
}
|
|
60
60
|
const adapter = [info.vendor, info.architecture, info.description].filter(Boolean).join(" ") || "unnamed WebGPU adapter";
|
|
61
61
|
// SwiftShader and llvmpipe are software adapters even where a browser does not flag them.
|
|
62
62
|
const software = info.isFallbackAdapter || /swiftshader|llvmpipe/i.test(adapter);
|
|
63
63
|
element.textContent = `${software ? "Software adapter, not a GPU" : "GPU"}: ${adapter} · ${info.f16 ? "" : "no "}shader-f16`;
|
|
64
|
-
announce(page, element, software ? "software" : "hardware", software ? "
|
|
64
|
+
announce(page, element, software ? "software" : "hardware", software ? "var(--dolly-ui-accent)" : "var(--dolly-ui-quiet)");
|
|
65
65
|
return { adapter, isFallbackAdapter: info.isFallbackAdapter };
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -72,7 +72,10 @@ export function browser(page) {
|
|
|
72
72
|
canvas = document.createElement("canvas");
|
|
73
73
|
canvas.id = "gpu-display";
|
|
74
74
|
canvas.hidden = true;
|
|
75
|
-
|
|
75
|
+
// Over the terminal: beside a smaller surface, its letterbox is the terminal's background, as
|
|
76
|
+
// display@0's is.
|
|
77
|
+
canvas.style.cssText = "position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none;" +
|
|
78
|
+
"background:var(--dolly-ui-background)";
|
|
76
79
|
mount.append(canvas);
|
|
77
80
|
surface = canvas.transferControlToOffscreen();
|
|
78
81
|
}
|
|
@@ -99,16 +102,26 @@ export function browser(page) {
|
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
export function worker({ send, configuration, get }) {
|
|
102
|
-
let bridge;
|
|
105
|
+
let bridge, animation = 0;
|
|
106
|
+
// This Worker's animation frames, counted while a program draws: the GPU Worker retires a
|
|
107
|
+
// presented frame at one of them, so a surface goes at the display's rate. The page's would
|
|
108
|
+
// make Chrome hold its pointer and wheel events for a frame; Chrome gives the GPU Worker,
|
|
109
|
+
// nested in this one, none.
|
|
110
|
+
const shown = configuration.canvas && new Int32Array(new SharedArrayBuffer(4));
|
|
111
|
+
const count = () => { Atomics.add(shown, 0, 1); Atomics.notify(shown, 0); animation = requestAnimationFrame(count); };
|
|
112
|
+
const counting = active => {
|
|
113
|
+
if (shown && active && !animation) animation = requestAnimationFrame(count);
|
|
114
|
+
if (shown && active === false) { cancelAnimationFrame(animation); animation = 0; }
|
|
115
|
+
};
|
|
103
116
|
return {
|
|
104
117
|
bindings: { "env.dolly_gpu_dispatch": (address, bytes) => {
|
|
105
118
|
if (!bridge) return -E.ENOSYS;
|
|
106
119
|
return bridge.dispatch({ address, bytes });
|
|
107
120
|
} },
|
|
108
121
|
async start({ kernel, memory }) {
|
|
109
|
-
bridge = await createGpuBridge(memory, Number(kernel.dolly_gpu_mailbox_address()), configuration.canvas,
|
|
110
|
-
() => get("runtime").serviceDeferred(), status => send({ ...status, type: "gpu-status" }));
|
|
122
|
+
bridge = await createGpuBridge(memory, Number(kernel.dolly_gpu_mailbox_address()), configuration.canvas, shown?.buffer,
|
|
123
|
+
() => get("runtime").serviceDeferred(), status => { counting(status.active); send({ ...status, type: "gpu-status" }); });
|
|
111
124
|
},
|
|
112
|
-
dispose() { bridge?.dispose(); bridge = null; },
|
|
125
|
+
dispose() { counting(false); bridge?.dispose(); bridge = null; },
|
|
113
126
|
};
|
|
114
127
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.1.
|
|
2
|
+
"version": "0.1.6",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"name": "@daugasauron/dolly-host-gpu",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@daugasauron/dolly": "0.1.
|
|
7
|
+
"@daugasauron/dolly": "0.1.6"
|
|
8
8
|
},
|
|
9
9
|
"description": "Dolly's gpu@0 host module: WebGPU on the browser's adapter, over the display.",
|
|
10
10
|
"repository": {
|