← All issues

[GTK][WPE] Skia Compositor: use deferred display lists to paint tiles

63f86c3

Source/WebCore/platform/graphics/skia/SkiaPaintingEngine.cpp

+ void SkiaPaintingEngine::record(Tile&, ...) { ... }
+ void SkiaPaintingEngine::replay(Tile&, ...) { ... }

Source/WebCore/platform/graphics/skia/SkiaUtilities.cpp

+ SkiaUtilities::PromiseImageContext::PromiseImageContext(...)
+ SkiaUtilities::PromiseImageContext::~PromiseImageContext()
+ GrBackendTexture SkiaUtilities::PromiseImageContext::promiseImageTexture()
+ sk_sp<SkImage> SkiaUtilities::createPromiseImageIfNeeded(sk_sp<SkImage> acceleratedImage, ...)

WebKit's GTK/WPE coordinated compositor tiles the page into a backing store and paints tiles concurrently using a worker thread pool. Previously each worker required a full Skia GrContext — a costly, thread-bound GPU context handle. Skia's Deferred Display List (DDL) feature decouples recording from execution: an SkDeferredDisplayListRecorder captures draw commands into a serialized list without any GPU calls, and an SkDDLPlayer replays them later on the real GrContext thread. GPU textures cannot be embedded directly into a DDL because they are bound to a specific GrContext; Skia's answer is promise images — placeholder SkImages carrying a fulfillment callback (promiseImageTexture) invoked during replay on the GPU thread to supply the actual backend texture.

This commit implements that full pipeline. Workers record into a DDL with no GL involvement, then the compositor thread replays the DDL onto the GPU surface. GPU-resident images are wrapped as Skia promise images during recording, with texture resolution deferred to replay time via PromiseImageContext callbacks. The commit adds SkiaPaintingEngine::record/replay, SkiaReplayCanvas, and PromiseImageContext.

Before (direct GL on workers):           After (DDL record/replay):
  Worker Thread N                          Worker Thread N           Compositor Thread
    └── GrContext (per thread)               └── SkDDLRecorder         └── SkiaReplayCanvas
          └── paint tile → GPU surface             └── record(tile)         └── replay(DDL, GrContext)
                                                         └── accel image         └── PromiseImageContext::
                                                               → PromiseImage          promiseImageTexture()
                                                               (placeholder)             └── resolve → GPU texture

Eliminating per-worker GrContext creation removes both a major GPU resource cost and the GL-context-sharing hazards that came with cross-thread direct rendering. Tile recording on workers no longer needs any GL involvement, and a single GPU thread owns the live GrContext — a structurally simpler model. The cross-thread GPU texture ownership protocol via promise images is architecturally significant and introduces a new synchronization surface that did not previously exist in WebKit.

🔒

Cross-thread GPU texture lifetime, DDL surface characterization mismatches, and post-replay fence sync are all worth close audit here.

Subscribe to read more