/** * The renderer a surface actually drew with. See {@link SciChartSurfaceBase.actualRenderer}. */ export type TActualRenderer = "webgl" | "webgpu"; /** * Answers "has the GPU finished the frame that was just submitted?" for one surface, without * ever blocking the CPU on the GPU. Backs {@link SciChartSurfaceBase.renderInstructionsCompleted}. * * - **WebGL2**: places a fence behind the frame's draw commands, flushes, and polls the fence's * status from a short timer chain. One queue and one timer chain per probe (so per surface), * serviced oldest first. * - **WebGPU**: requests `queue.onSubmittedWorkDone()` on the page's device and reports when the * promise resolves. * * Owned by the surface, which passes it to `addDeletable` so pending fences are released with the * surface. Costs nothing until {@link arm} is called. * * @ignore */ export declare class GpuCompletionProbe { /** * Fences older than this are dropped without ever reporting completion. Something is badly * wrong if a fence sits unsignalled this long (a driver stall, or a context loss that never * reported itself), and an unbounded queue would grow forever rather than recover. */ private static readonly GPU_FENCE_DEADLINE_MS; /** * WebGL2 fences awaiting a signal, oldest first. Serviced by a single {@link pollOldestFence} * timer chain rather than one timer chain per frame, so a slow GPU cannot accumulate many * concurrent poll loops each calling `getSyncParameter` on its own schedule. */ private pendingFences; /** True while a {@link pollOldestFence} timer chain is already running. */ private pollActive; /** Set by {@link delete}; a deleted probe ignores {@link arm} and stops its poll loop. */ private isDeleted; /** * Arms the probe for the frame that was just handed to the GPU. * @param renderer What the surface actually drew with. `undefined` (not yet known, e.g. the * first frame of a copy-canvas WebGL surface) takes the WebGL path, which stays inert without * an existing webgl2 context. * @param webGlCanvas The canvas the WebGL draw calls went to: the shared master canvas for * copy-canvas surfaces, the surface's own canvas otherwise. Ignored under WebGPU. * @param onCompleted Called once, asynchronously, when the GPU has finished. Never called * synchronously, and never called at all on a lost context or device, or past the deadline. */ arm(renderer: TActualRenderer | undefined, webGlCanvas: HTMLCanvasElement | undefined, onCompleted: () => void): void; /** * Releases every pending fence's native sync object (skipped where its context is already * lost) and stops the poll loop. Further {@link arm} calls are ignored. */ delete(): void; /** * Queues a WebGL2 fence and starts the poll loop if it is not already running. The GPU * executes (and therefore signals) fences in the order they were placed, so a single * oldest-first queue is enough to service every frame without one timer chain per frame. */ private enqueueFence; /** * Services only the OLDEST pending fence. The GPU signals fences in submission order, so once * the oldest has signalled every fence behind it is at least as close to done, and checking any * but the oldest would just burn an extra `getSyncParameter` call for no new information. * * A short timer rather than requestAnimationFrame: rAF would quantise the completion time to * the next frame boundary (up to 16 ms), coarser than the gaps being measured. Chrome only * updates a sync object's status after a round trip to the GPU process, so checking in the same * task always reads UNSIGNALED. Real browsers also clamp a chain of nested `setTimeout` calls to * about 4 ms after the first few iterations, so completion times end up quantised to that floor * in practice, not to the 1 ms requested here. Never `clientWaitSync` with a timeout and never * `gl.finish()`: both block the CPU on the GPU and destroy the pipelining this probe exists to * observe. Measured cost (completionProbeOverhead.spec.ts, 2026-09-15): 1.2 to 1.5 status * polls per frame on a single surface, a few microseconds each. */ private pollOldestFence; private clearPendingFences; }