Diagnostics.FrameCapture
public static class Diagnostics.FrameCaptureWrites one rendered frame to a PNG — the static, process-wide way, kept for one release.
This exists because "the diagnostics say OpenGL" and "the pixels are right" are different claims, and only the second one matters. Capturing the render target itself is better evidence than a window grab: it is exactly what gets composited, at full resolution, with no window server involved — and it works headless, on a build server, and in a browser tab.
Obsolete.Ava3DView.CaptureAsync does the same for one view, returns the pixels rather than a file, queues rather than replaces, and never resizes the view for a scaled capture; and Ava3DView.ComposeAsync takes the view together with the Avalonia content over it. This facade is implemented over that path now: an arm is taken by the first view to render a frame after it — the most recently rendered view, in a process with several — and the PNG is encoded and written on the thread pool, after which FrameCapture.Captured is raised there. What it captures is the picture as shown, bloom and vignette included, which it did not use to be.
Properties
| Member | Description |
|---|---|
| Which frame to capture, counted per view from its first. Not the first: early frames are missing textures that are still streaming, and a screenshot of a half-loaded scene is evidence of nothing. |
| Where to write. Null disables capture entirely, which is the default, and so does an empty string. Empty counts because this is almost always an environment variable, and an environment variable that has been switched off is as likely to be present and empty as it is to be absent — a process started with the switch explicitly cleared is exactly that. It is not a path anybody can write to, so the only thing treating it as one buys is a PNG encoded and thrown away on every frame. |
| A fixed pixel size for the capture, for a reproducible run. Overrides |
| Renders the capture at this multiple of the size the control is shown at, so a capture can be larger than the window. Supersampling rather than enlargement — see |
Events
| Member | Description |
|---|---|
| Raised after a frame is written, with its path, so a harness can shut down at the right moment. Raised on a thread pool thread — the one that wrote the file — never on the render thread or the UI thread. |
Methods
| Member | Description |
|---|---|
| Points this at the next file and arms it again, so a second frame is written after the first. One capture per process is the right default — a screenshot is one picture, and a switch that goes on writing until something stops it is a switch that fills a disk when somebody forgets it. But a sequence is the same evidence extended: a fault that only shows while something is moving cannot be argued about from a single frame, and a film recorded a frame at a time is how this demo is turned into a video without a screen recorder, a compositor or anybody's permission to capture a display. It arms rather than records: the next frame a view renders is written to Arming again before the last frame has landed replaces it: the earlier path is never written and nobody is told. That is the fault
|
| Arms a capture of this exact camera pose. Frames already in flight at an older pose are skipped. Read the camera on its owning UI thread after updating it. This makes deterministic camera replays independent of compositor timing; it does not freeze or synchronise scene edits. |