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:
@@ -4,7 +4,7 @@ All fields below are top-level beside `type` and `request`. Except for `init` an
|
||||
|
||||
| `type` | Fields | Transfer list | Success `result` | Constraints / effects |
|
||||
|---|---|---|---|---|
|
||||
| `init` | `canvas: OffscreenCanvas`, `arenaBytes: number` | `[canvas]` | `{ buffer: SharedArrayBuffer, rows: Descriptor[], features: string[] }` | Once only; initializes WASM/WebGPU. `features` lists optional device features that were available (`timestamp-query`, `indirect-first-instance`). |
|
||||
| `init` | `canvas: OffscreenCanvas`, `arenaBytes: number`, `profileBuffer: SharedArrayBuffer` | `[canvas]` | `{ buffer: SharedArrayBuffer, rows: Descriptor[], features: string[] }` | Once only; initializes WASM/WebGPU. `features` lists optional device features that were available (`timestamp-query`, `indirect-first-instance`). `profileBuffer` is shared, not transferred. |
|
||||
| `create-rows` | `name`, `rows`, `stride`, `format` | — | `{ rows: descriptor, commit: boolean }` | Nonempty name; rows > 0; stride ≥16 and multiple of 16; format f32/u32/i32. Existing name may only retain format/stride and grow. `commit: true` means the rows moved: copy the old bytes into the descriptor and send `commit-rows`. |
|
||||
| `create-rows-batch` | `rows: Array<{name,rows,stride,format}>` | — | `{ rows: descriptor[] (input order), commit: string[] }` | Nonempty. Sequential; in-place creations/growths survive a later failure, staged relocations are discarded. `commit` lists the arrays that moved. Active GPU resources refresh once for in-place growth. |
|
||||
| `commit-rows` | `names: string[]` | — | `undefined` | Publishes staged relocations after the caller copied them. Must name every staged array. Frees the old rows, refreshes bound GPU buffers once, sets `sabDirty`. While a relocation is staged the worker queues every other request until this arrives. |
|
||||
@@ -23,25 +23,26 @@ All fields below are top-level beside `type` and `request`. Except for `init` an
|
||||
|
||||
Rust/WASM numeric conversion applies to `u32` fields; callers should send finite nonnegative integers in range rather than rely on coercion.
|
||||
|
||||
## Profiler events
|
||||
## Shared profiler results
|
||||
|
||||
When enabled and supported, the worker polls every 250 ms and may send an unsolicited message with **no request field**:
|
||||
When enabled and supported, GPU timestamp queries are sampled at most once every 100 ms, with only one readback in flight. Completion of `map_async` wakes an awaiting future; neither the worker nor render loop polls for GPU completion. Rendering continues independently.
|
||||
|
||||
Completed results are published into `profileBuffer`, not sent as worker messages. `YawnCore.onProfile` reads this buffer locally every 100 ms while listeners exist and delivers the same stats shape:
|
||||
|
||||
```js
|
||||
{
|
||||
type: "profile",
|
||||
stats: {
|
||||
frame: 42,
|
||||
milliseconds: 0.31,
|
||||
readbackMilliseconds: 4.8,
|
||||
adapter: "Adapter name · DeviceType · Backend",
|
||||
canvas: { width: 1280, height: 720 },
|
||||
passes: [{ name: "triangle", milliseconds: 0.31 }]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
One pass timing corresponds to a compiled execution; compatible adjacent render passes are merged into one execution labelled `first … last (N draws)`. Samples are throttled and asynchronous, so they are diagnostics, not one event per frame. Disabling clears pending published statistics and the worker polling interval.
|
||||
One pass timing corresponds to a compiled execution; compatible adjacent render passes are merged into one execution labelled `first … last (N draws)`. `milliseconds` is GPU time; `readbackMilliseconds` includes the asynchronous wait. Disabling clears published statistics and suppresses results from older profiling sessions.
|
||||
|
||||
The default mailbox is a separate 1 MiB SAB. Its first two `Int32` values are ownership state and UTF-8 JSON length; the payload starts at byte 8. State 0 means empty, 1 means owned by a reader or writer, and 2 means a complete sample. Both sides claim ownership using `Atomics.compareExchange` and never wait. An unread sample is replaced by the latest sample; a publication during a read, or larger than the payload capacity, is skipped. The reader copies the bytes before releasing ownership, so it cannot observe a partially written result. Initialization and profiler enable/disable remain ordinary control requests; results never use `postMessage`.
|
||||
|
||||
## Texture lifecycle
|
||||
|
||||
|
||||
Reference in New Issue
Block a user