Vixen
dd8b0a81
csharp
public sealed class GpuOverlay

`stat gpu`: where the frame's GPU time went, pass by pass, while you watch.

Read the guide page for this →

Remarks

The panel exists so that a cost distribution is noticed rather than measured. Every number here has been available from AppGraphics.GpuFrame since the render graph started emitting a scope per pass, and Samples/13 already prints the same breakdown to its log — but a log line is read by somebody who already suspects something. Three fixes this repository shipped in one week (a 17× screen march, a page-marking pass at 11 % of the frame, a thickness shell that made a hit test meaningless) were each found by reading a breakdown after forming a suspicion. What a log cannot do is show the distribution move as the camera turns.

⚠ Which is why the rows are in the frame's own order and not in cost order. A panel that re-sorts every frame cannot be read while anything is moving: the eye tracks a row's position, and a table whose rows swap places is a table nobody can watch. Cost decides which passes get a row — the most expensive MaxRows of them — and the graph's declaration order decides where each one sits. FrameGraphOverlay makes the identical argument about its colours.

⚠ And why each bar carries a peak that decays rather than a bare instantaneous value. A GPU reading moves by more than ten percent between two frames of a still camera, so an unsmoothed number is unreadable and a smoothed one hides exactly the spike worth seeing. The bar is the smoothed cost and the tick is the worst this pass has been in the last PeakSeconds seconds — so a pass that costs three milliseconds once, while you walk past a wall, leaves a mark that is still there when you look down.

⚠ Two rows exist to stop the panel lying by omission. unattributed is the frame span minus the passes that fill it, which is non-zero when GPU work happens outside any pass the graph ran — a breakdown that does not describe the whole frame. dropped is Dropped, and a non-zero value means the timeline simply stops partway through the frame: the bars that are there look right and the expensive pass somebody opened this for is absent. Neither is a detail; a panel that hid either would make its own incompleteness authoritative.

Here rather than in Vixen.Engine for the reason the assembly exists: GpuFrame is Vixen.Graphics' and IDiagnosticOverlay is Vixen.Engine's, and neither may reference the other. This is the join.

Fields and properties (13)

  • public const int MaxRows

    How many passes get a row before the rest are folded into one.

  • public const float PeakSeconds

    How long a peak is held before it decays back toward the current cost.

  • public string Name

    What the console and the toggles call it. Lower case, no spaces.

  • public OverlayAnchor Anchor

    Which corner it is pinned to.

  • public bool Enabled

    Whether it is drawn.

  • public float Width

    How wide the panel is, in pixels.

  • public GpuFrame Frame

    The last frame the GPU finished timing. The host sets this once a frame.

  • public int Latency

    How many frames back Frame was recorded.

  • public bool Available

    Whether a profiler is attached at all.

  • public int Dropped

    How many scopes the frame being recorded could not fit. ⚠ Non-zero is a lie by omission.

  • public int DrawnRows

    How many pass rows the last Draw put on screen.

  • public float UnattributedFraction

    The share of the frame no pass accounted for, from zero to one.

  • public IReadOnlyList<string> VisiblePasses

    Which passes have a row, top to bottom, as of the last Draw.

Methods (3)

  • public double PeakOf(string? pass)

    The decaying peak cost of one pass, in milliseconds, or zero if it has no history.

  • public void Reset()

    Forgets every smoothed cost and every peak.

  • public void Draw(OverlaySurface surface, in GameTime time)

    Draws it.

Used by (2)

  • AppGraphicsVixen.App.Hosting
  • GpuOverlayTestsVixen.Engine.Renderer.Tests