| 1 | /** A synchronous, borrowed frame. The producer releases its source after present returns. */ |
| 2 | export interface DeviceFrameSink { |
| 3 | readonly present: (source: CanvasImageSource, width: number, height: number) => boolean; |
| 4 | } |
| 5 | |
| 6 | /** Retains the latest frame in a canvas; consumers can invalidate textures after each draw. */ |
| 7 | export function createCanvasFrameSink( |
| 8 | canvas: HTMLCanvasElement, |
| 9 | onFrame?: (width: number, height: number) => void, |
| 10 | ): DeviceFrameSink { |
| 11 | return { |
| 12 | present(source, width, height) { |
| 13 | const context = canvas.getContext("2d"); |
| 14 | if (!context) return false; |
| 15 | if (canvas.width !== width || canvas.height !== height) { |
| 16 | canvas.width = width; |
| 17 | canvas.height = height; |
| 18 | } |
| 19 | context.drawImage(source, 0, 0, width, height); |
| 20 | onFrame?.(width, height); |
| 21 | return true; |
| 22 | }, |
| 23 | }; |
| 24 | } |