Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
frame_cost_probe.hpp File Reference

Headless per-frame cost accounting for an animated view tree. More...

#include <pulp/view/plugin_view_host.hpp>
#include <pulp/view/view.hpp>
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <limits>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>

Go to the source code of this file.

Classes

class  pulp::view::FrameCostProbe
struct  pulp::view::FrameCostProbe::Frame
struct  pulp::view::FrameCostProbe::Summary
struct  pulp::view::FrameCostProbe::Budget

Namespaces

namespace  pulp
namespace  pulp::view
 Hover-cursor tracking for platform window hosts.

Detailed Description

Headless per-frame cost accounting for an animated view tree.

"Is this animation cheap?" has three answers a wall clock cannot give on its own, and each one is a separate way an animated control goes wrong:

  • DAMAGE – did the frame ask to repaint only what moved, or the whole surface? A control that calls the rect-less View::request_repaint() on its value path re-composites every static pixel of the editor each frame, and no partial-repaint host can ever engage.
  • LAYOUT – did the frame run a layout pass? A value tick that writes a size or position re-lays the tree at the display rate.
  • TIME – how long the frame's own work took, as p50 / p95 / max. The mean hides exactly the frames that drop.

FrameCostProbe attaches a recording PluginViewHost to the root for its lifetime and measures each frame the caller drives (measure(fn)): the damage the frame requested (bounded rect union, or whole surface), the layout passes it ran (View::layout_pass_count) and its wall time. check() holds a Summary to a Budget – optionally relative to a baseline Summary of the same tree without the animation – and returns one line per breach, so a test asserts the list is empty and prints it when it is not.

Damage is classified per REQUEST, not per frame: the recorder takes the pending damage on every repaint() call, and View routes a bounded request through mark_dirty_region() (rect already in the damage) and a rect-less one through mark_dirty_full(). So a frame mixing both is reported full, which is what a partial-repaint host would have to paint.

Headless only: the root must not have a WindowHost (its damage would go there instead). Not thread-safe; drive it from the thread that owns the tree. Pair every passing budget with a negative control that must fail it (a plant that forces full invalidation) – a probe that cannot see damage passes every budget.