Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::render::SkiaSurface Class Referenceabstract

Skia Graphite rendering surface. More...

#include <skia_surface.hpp>

Classes

struct  Config
class  TrimLevel
 How much a GPU trim frees. More...

Public Types

using InsertOutcomeHook = bool (*)(bool accepted)
 Test seam for Graphite recording inserts.
using TrimClockHook = GpuIdleTrimSchedule::Clock::time_point (*)()
 Test seam for the idle-trim clock.

Public Member Functions

virtual ~SkiaSurface ()=default
virtual canvas::Canvas * begin_frame ()=0
 Begin a frame: returns a Canvas to draw into, or nullptr on failure.
virtual FrameOutcome end_frame ()=0
 End a frame: submits the Graphite recording to the GPU, and reports whether the frame reached its intended output.
virtual FrameOutcome last_frame_outcome () const
 Outcome of the most recent begin_frame()/end_frame() pair.
virtual bool has_presentable_target () const =0
 Whether this surface has a presentable native drawable.
virtual void resize (uint32_t width, uint32_t height, float scale=1.0f)=0
 Record a new logical size and backing scale.
virtual bool set_persistent_scene (bool)
 Enable/disable persistent-scene mode (partial-repaint support, FU-2).
virtual bool persistent_scene () const
 Whether persistent-scene mode is currently active.
virtual void set_text_raster_policy (canvas::TextRasterPolicy)
 Change the glyph preblend of every surface this one creates.
virtual canvas::TextRasterPolicy text_raster_policy () const
 The policy surfaces are currently created with.
virtual bool read_current_rgba (std::vector< uint8_t > &pixels, uint32_t &pixel_width, uint32_t &pixel_height)=0
 Read the current rendered frame into an RGBA buffer.
virtual bool is_available () const =0
 Check if Skia rendering is available.
virtual skgpu::graphite::Context * graphite_context () const =0
 The live Graphite Context backing this surface, or nullptr when Skia/Graphite is unavailable — including on the Ganesh/WebGL2 backend, which has no Graphite context at all.
virtual double gpu_render_time_ms () const =0
 Most recent whole-recording GPU render time in milliseconds, sampled from Skia Graphite's GpuStats(kElapsedTime) finished-with-stats callback.
virtual bool gpu_render_timing_available () const =0
 Whether GPU render timing is available this run — the adapter offered timestamp-query AND Graphite advertises kElapsedTime.
virtual int gpu_frames_in_flight () const
 Frames submitted to the GPU whose work has not finished yet (see GpuFramesInFlight in gpu_render_time.hpp), or -1 when the surface does not track it.
virtual bool wait_for_submitted_work ()
 Block until the GPU has finished the work this surface submitted.
virtual void trim_gpu_resources (TrimLevel)
 Return purgeable GPU memory to the device.
virtual GpuCacheBytes gpu_cache_bytes () const
 Bytes held by this surface's GPU resource caches.
virtual std::uint64_t idle_trim_count () const
 Idle trims end_frame() has run since the surface was created.
virtual std::uint64_t render_target_allocations () const
 Graphite render targets this surface has allocated (the offscreen and persistent-scene targets; the presentable texture is wrapped, not allocated).

Static Public Member Functions

static std::unique_ptr< SkiaSurface > create (GpuSurface &gpu, const Config &config)
 Create a Skia Graphite surface.
static void set_insert_outcome_hook_for_testing (InsertOutcomeHook hook)
static void set_async_readback_for_testing (bool enabled)
 Test seam for read_current_rgba().
static void set_trim_clock_for_testing (TrimClockHook hook)

Detailed Description

Skia Graphite rendering surface.

Connects a GpuSurface (WebGPU device) to Skia's GPU 2D rendering. When GpuSurface has a presentable surface, SkiaSurface renders into the swapchain texture each frame (zero-copy presentation). When offscreen, it renders into a standalone GPU texture.

Usage: gpu->begin_frame(); // acquire swapchain texture auto* canvas = skia->begin_frame(); // get Skia canvas targeting that texture root_view.paint_all(*canvas); skia->end_frame(); // submit Graphite recording gpu->end_frame(); // present to native surface

Member Typedef Documentation

◆ InsertOutcomeHook

using pulp::render::SkiaSurface::InsertOutcomeHook = bool (*)(bool accepted)

Test seam for Graphite recording inserts.

When installed, every SkiaSurface passes whether Graphite accepted each recording it inserts (end_frame()'s and read_current_rgba()'s mid-frame flush) through hook, and acts on the returned value instead. A healthy device does not reject recordings, so this is how a test reaches the rejection path. Process-wide and not synchronized: install before rendering, pass nullptr to remove.

◆ TrimClockHook

using pulp::render::SkiaSurface::TrimClockHook = GpuIdleTrimSchedule::Clock::time_point (*)()

Test seam for the idle-trim clock.

When installed, surfaces read hook() instead of steady_clock::now() for the GpuIdleTrimSchedule they own, so a test can step frames through time. It does not reach Skia's own resource timestamps, which unused_for compares against. Process-wide and not synchronized: install before creating the surface, pass nullptr to remove.

Constructor & Destructor Documentation

◆ ~SkiaSurface()

virtual pulp::render::SkiaSurface::~SkiaSurface ( )
virtualdefault

Member Function Documentation

◆ begin_frame()

virtual canvas::Canvas * pulp::render::SkiaSurface::begin_frame ( )
pure virtual

Begin a frame: returns a Canvas to draw into, or nullptr on failure.

The canvas targets, in order: the retained scene surface in persistent-scene mode; the current swapchain texture when GpuSurface has a presentable surface; the offscreen render target when it does not. The canvas is valid until end_frame() is called.

Returns nullptr — rather than quietly redirecting to the offscreen target — when a PRESENTABLE surface exists but its drawable could not be wrapped. The caller must not treat that as a rendered frame; query last_frame_outcome() for whether to recreate the surface or just retry.

◆ create()

std::unique_ptr< SkiaSurface > pulp::render::SkiaSurface::create ( GpuSurface & gpu,
const Config & config )
static

Create a Skia Graphite surface.

The GpuSurface reference is retained — SkiaSurface queries it each frame for the current swapchain texture when on-screen presentation is active.

◆ end_frame()

virtual FrameOutcome pulp::render::SkiaSurface::end_frame ( )
pure virtual

End a frame: submits the Graphite recording to the GPU, and reports whether the frame reached its intended output.

Actual presentation is handled by GpuSurface::end_frame(); this covers everything up to and including submission of the drawable's contents, so a presented result means "the correct texture was drawn into and submitted", not "the compositor has shown it".

Hosts must not retire pending damage unless frame_reached_output() is true for the returned outcome, or the failed frame's damage is lost and the retry paints nothing.

◆ gpu_cache_bytes()

virtual GpuCacheBytes pulp::render::SkiaSurface::gpu_cache_bytes ( ) const
inlinevirtual

Bytes held by this surface's GPU resource caches.

Zero when the surface has no GPU context. Render thread only.

◆ gpu_frames_in_flight()

virtual int pulp::render::SkiaSurface::gpu_frames_in_flight ( ) const
inlinevirtual

Frames submitted to the GPU whose work has not finished yet (see GpuFramesInFlight in gpu_render_time.hpp), or -1 when the surface does not track it.

Diagnostic only; nothing waits on it.

◆ gpu_render_time_ms()

virtual double pulp::render::SkiaSurface::gpu_render_time_ms ( ) const
pure virtual

Most recent whole-recording GPU render time in milliseconds, sampled from Skia Graphite's GpuStats(kElapsedTime) finished-with-stats callback.

Returns 0 until the first sample lands or when timing is unavailable. This is render-recording time, not total frame time (on the Metal fallback it excludes non-pass uploads/copies and present). See gpu_render_time.hpp.

◆ gpu_render_timing_available()

virtual bool pulp::render::SkiaSurface::gpu_render_timing_available ( ) const
pure virtual

Whether GPU render timing is available this run — the adapter offered timestamp-query AND Graphite advertises kElapsedTime.

When false the inspector should show the honest "GPU timing unavailable".

◆ graphite_context()

virtual skgpu::graphite::Context * pulp::render::SkiaSurface::graphite_context ( ) const
pure virtual

The live Graphite Context backing this surface, or nullptr when Skia/Graphite is unavailable — including on the Ganesh/WebGL2 backend, which has no Graphite context at all.

Hand this to a SkpFrameCapture (or capture_skp_to_file) so a .skp of this surface's frame can read back any GPU-texture-backed embedded images instead of silently dropping them. The pointer is owned by the SkiaSurface.

◆ has_presentable_target()

virtual bool pulp::render::SkiaSurface::has_presentable_target ( ) const
pure virtual

Whether this surface has a presentable native drawable.

False for headless/offscreen surfaces, where offscreen is the intended output rather than a fallback.

◆ idle_trim_count()

virtual std::uint64_t pulp::render::SkiaSurface::idle_trim_count ( ) const
inlinevirtual

Idle trims end_frame() has run since the surface was created.

◆ is_available()

virtual bool pulp::render::SkiaSurface::is_available ( ) const
pure virtual

Check if Skia rendering is available.

◆ last_frame_outcome()

virtual FrameOutcome pulp::render::SkiaSurface::last_frame_outcome ( ) const
inlinevirtual

Outcome of the most recent begin_frame()/end_frame() pair.

Set by begin_frame() too, so a caller that got a null canvas can distinguish "recreate the surface" from "retry" without a second entry point.

◆ persistent_scene()

virtual bool pulp::render::SkiaSurface::persistent_scene ( ) const
inlinevirtual

Whether persistent-scene mode is currently active.

◆ read_current_rgba()

virtual bool pulp::render::SkiaSurface::read_current_rgba ( std::vector< uint8_t > & pixels,
uint32_t & pixel_width,
uint32_t & pixel_height )
pure virtual

Read the current rendered frame into an RGBA buffer.

If a frame is currently open, this finalizes and submits pending canvas work before readback; callers should treat readback as a capture/end-of-frame operation and not continue drawing into the same frame afterward.

◆ render_target_allocations()

virtual std::uint64_t pulp::render::SkiaSurface::render_target_allocations ( ) const
inlinevirtual

Graphite render targets this surface has allocated (the offscreen and persistent-scene targets; the presentable texture is wrapped, not allocated).

Diagnostic and test use; 0 where it is not tracked.

◆ resize()

virtual void pulp::render::SkiaSurface::resize ( uint32_t width,
uint32_t height,
float scale = 1.0f )
pure virtual

Record a new logical size and backing scale.

The render targets are reallocated, and on a scale change the retained layers dropped, only in the next begin_frame(), so several resizes before one frame cost one reallocation.

◆ set_async_readback_for_testing()

void pulp::render::SkiaSurface::set_async_readback_for_testing ( bool enabled)
static

Test seam for read_current_rgba().

Passing false makes every SkiaSurface skip the asynchronous GPU readback and take the synchronous fallback that a timed-out readback takes, which a healthy device never reaches. Process-wide and not synchronized; pass true to restore.

◆ set_insert_outcome_hook_for_testing()

void pulp::render::SkiaSurface::set_insert_outcome_hook_for_testing ( InsertOutcomeHook hook)
static

◆ set_persistent_scene()

virtual bool pulp::render::SkiaSurface::set_persistent_scene ( bool )
inlinevirtual

Enable/disable persistent-scene mode (partial-repaint support, FU-2).

Returns whether the mode is ACTIVE after the call.

In this mode begin_frame() targets a persistent, window-sized Graphite scene surface that RETAINS its content across frames; end_frame() blits that scene 1:1 onto the presentable drawable, then submits. This is what makes a clipped (partial) repaint correct on the non-preserving Dawn swapchain: the host repaints only the damaged rect into the retained scene and the whole scene is re-presented, so pixels outside the clip are the previous frame's — exactly the "static chrome doesn't re-composite" win. The first frame after enabling (or after a resize) is a full repaint into the fresh scene; the host arms that.

Default: unsupported no-op returning false — the base and the Ganesh/WebGL2 surface do not implement it, so a false return tells the caller it must full-repaint every frame. Only the Dawn/Graphite desktop surface implements it.

◆ set_text_raster_policy()

virtual void pulp::render::SkiaSurface::set_text_raster_policy ( canvas::TextRasterPolicy )
inlinevirtual

Change the glyph preblend of every surface this one creates.

An imported panel calls this with select_text_raster_policy() over its text nodes' captured -webkit-font-smoothing. Text already rasterized under the old policy is discarded: retained layers are dropped, and the offscreen and persistent-scene targets are recreated, so like a resize the next frame must be a full repaint. Setting the current policy is a no-op that keeps every cache. Call it between frames: it releases the canvas begin_frame() handed out, so it must not run while one is open.

◆ set_trim_clock_for_testing()

void pulp::render::SkiaSurface::set_trim_clock_for_testing ( TrimClockHook hook)
static

◆ text_raster_policy()

virtual canvas::TextRasterPolicy pulp::render::SkiaSurface::text_raster_policy ( ) const
inlinevirtual

The policy surfaces are currently created with.

◆ trim_gpu_resources()

virtual void pulp::render::SkiaSurface::trim_gpu_resources ( TrimLevel )
inlinevirtual

Return purgeable GPU memory to the device.

Call it between frames, on the render thread: it uses the surface's GPU context, which is not thread-safe. The same holds for gpu_cache_bytes(). Resources still referenced (cached images, retained layers, the scene) and work the GPU has not finished are not freed; a host that wants everything back calls wait_for_submitted_work() first.

end_frame() already runs an idle trim on the GpuIdleTrimSchedule throttle, freeing what went unused for both kUnusedAge and kUnusedFrames frames, so a host calls this directly only for everything(), when its editor is hidden or stops drawing. Default: no-op, for surfaces with no GPU cache.

◆ wait_for_submitted_work()

virtual bool pulp::render::SkiaSurface::wait_for_submitted_work ( )
inlinevirtual

Block until the GPU has finished the work this surface submitted.

A host that must hand the compositor a finished drawable (a first frame presented with its Core Animation transaction) calls it between end_frame() and the present. Returns the synchronizing submit's result: false when the surface has no GPU context or the backend could not submit and wait. Never call it per frame.


The documentation for this class was generated from the following file: