Optimize viewer shaders and camera controls; sample GPU profiles asynchronously

Amp-Thread-ID: https://ampcode.com/threads/T-01a0b382-1e79-712b-abd1-d29201c9bb5e
Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
Amp
2026-09-18 11:52:09 +00:00
co-authored by heaust
parent bc957cf40d
commit eb8aa0e9dc
21 changed files with 762 additions and 174 deletions
+17 -6
View File
@@ -1,3 +1,5 @@
import { SharedProfile } from "./profile.js";
const views = Object.freeze({ f32: Float32Array, u32: Uint32Array, i32: Int32Array });
export class SharedRows {
@@ -49,6 +51,8 @@ export class YawnCore {
#arrays = new Map();
#pending = new Map();
#profileListeners = new Set();
#profile = new SharedProfile();
#profileTimer;
#next = 1;
/** Optional WebGPU features the device has (WebGPU spelling); populated once `ready` resolves. */
features = new Set();
@@ -64,7 +68,7 @@ export class YawnCore {
this.#worker.addEventListener("messageerror", () => this.#fail("WORKER_ERROR"));
this.#worker.start?.();
const offscreen = canvas.transferControlToOffscreen?.() ?? canvas;
this.ready = this.#request("init", { canvas: offscreen, arenaBytes }, [offscreen]).then(async result => {
this.ready = this.#request("init", { canvas: offscreen, arenaBytes, profileBuffer: this.#profile.buffer }, [offscreen]).then(async result => {
this.#buffer = result.buffer;
this.features = new Set(result.features);
for (const descriptor of result.rows) this.#arrays.set(
@@ -195,7 +199,17 @@ export class YawnCore {
onProfile(listener) {
if (typeof listener !== "function") throw new TypeError("PROFILE_LISTENER");
this.#profileListeners.add(listener);
return () => this.#profileListeners.delete(listener);
if (!this.#profileTimer) this.#profileTimer = setInterval(() => {
const stats = this.#profile.read();
if (stats) for (const listener of this.#profileListeners) listener(stats);
}, 100);
return () => {
this.#profileListeners.delete(listener);
if (!this.#profileListeners.size) {
clearInterval(this.#profileTimer);
this.#profileTimer = undefined;
}
};
}
array(name) {
@@ -213,10 +227,6 @@ export class YawnCore {
}
#message(message) {
if (message?.type === "profile") {
for (const listener of this.#profileListeners) listener(message.stats);
return;
}
const pending = this.#pending.get(message?.request);
if (!pending) return;
this.#pending.delete(message.request);
@@ -231,6 +241,7 @@ export class YawnCore {
dispose() {
this.#fail("DISPOSED");
clearInterval(this.#profileTimer);
this.#profileListeners.clear();
this.#worker.terminate();
}