[GTK][WPE] Skia Compositor: use deferred display lists to paint tiles
Source/WebCore/platform/graphics/skia/SkiaPaintingEngine.cpp
Source/WebCore/platform/graphics/skia/SkiaUtilities.cpp
WebKit의 GTK/WPE coordinated compositor는 페이지를 backing store 단위의 tile로 분할하고, worker thread pool을 통해 tile을 병렬로 렌더링합니다. 기존 방식에서는 각 worker가 독립적인 Skia GrContext를 보유해야 했습니다. GrContext는 thread에 종속되며 생성 비용이 높은 GPU 컨텍스트 핸들입니다. Skia의 Deferred Display List(DDL) 기능은 recording과 실행을 분리합니다. SkDeferredDisplayListRecorder는 GPU 호출 없이 draw command를 직렬화된 목록으로 캡처하고, 이후 SkDDLPlayer가 실제 GrContext thread에서 이를 replay합니다. GPU texture는 특정 GrContext에 종속되므로 DDL에 직접 포함할 수 없습니다. 이에 대한 Skia의 해결책이 promise image입니다. Promise image는 SkImage의 placeholder로, replay 시점에 GPU thread에서 fulfillment callback(promiseImageTexture)이 호출되어 실제 backend texture를 제공합니다.
이 commit은 해당 전체 pipeline을 구현합니다. Worker는 GL 관여 없이 DDL에 recording하고, compositor thread가 이를 GPU surface에 replay합니다. 기록 시점에 GPU에 상주하는 image는 Skia promise image로 래핑되며, texture 결정은 PromiseImageContext callback을 통해 replay 시점으로 지연됩니다. 이 commit은 SkiaPaintingEngine::record/replay, SkiaReplayCanvas, 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
Significance
Worker별 GrContext 생성을 제거함으로써 GPU resource 비용을 크게 줄이고, cross-thread 직접 렌더링에서 비롯되던 GL context sharing 위험도 함께 해소되었습니다. Worker의 tile recording에는 더 이상 GL이 관여하지 않으며, 단일 GPU thread가 live GrContext를 독점적으로 소유합니다. 구조적으로 훨씬 단순한 모델입니다. 한편 promise image를 통한 cross-thread GPU texture ownership protocol은 아키텍처 면에서 중요한 변화로, 기존 WebKit에 없던 새로운 동기화 지점을 도입합니다.
Audit directions
- Promise image lifetime.
PromiseImageContext는 worker thread에서 캡처한 accelerated image를 래핑하고, replay 시점에 compositor/GPU thread에서promiseImageTexture()callback이 호출됩니다. record와 replay 사이에GrBackendTexture또는GrContext가 파괴되거나 회수, 재사용되면 cross-thread use-after-free가 발생합니다.~PromiseImageContextdestructor는 진행 중인 Skia GPU fulfillment callback과 반드시 동기화해야 합니다. Skia는SkImage가 파괴되기 전에 callback이 완료된다는 것만 보장하므로, 이 부분의 refcount 및 lifetime 관리를 면밀히 살펴볼 필요가 있습니다. - DDL characterization mismatch. DDL은 특정
SkSurfaceCharacterization(크기, color type, sample count 등)을 기준으로 recording됩니다. replay 시점의 surface characterization이 recording 시점과 달라지면, Skia는 해당 DDL을 조용히 거부하거나 잘못 처리합니다. 공격자가 record와 replay 사이에 surface 속성(color space, device pixel ratio)을 변경하도록 유도할 수 있는 경우, 정의되지 않은 렌더링이나 surface 상태 혼란이 발생할 가능성이 있습니다. waitForRenderingCompletionAndRewrapImageIfNeeded.SkiaReplayCanvas의 이 메서드는 replay 이후 일부 image를 다시 래핑해야 함을 시사합니다. GPU fence 완료를 확인한 뒤에야 image를 화면에 표시하거나 재사용할 수 있기 때문으로 보입니다. 이 동기화 경로에 race condition이 존재하는지 살펴볼 필요가 있습니다. fence 검사가 우회되거나 spurious한 결과를 반환하면, GPU 작업이 완료되기 전에 tile 업데이트가 진행될 수 있습니다. 최악의 경우 이미 해제된 texture의 backing memory에 접근하는 상황으로 이어질 가능성이 있습니다.- Atlas GPU image cross-thread access.
SkiaGPUAtlas::atlasImageForCurrentThread에 변경이 있었습니다. atlas는 공유 GPU texture atlas입니다. recording 맥락에서의 thread별 atlas image 접근 방식이 compositor replay 시와 어떻게 달라지는지, atlas handle에 대한 TOCTOU 관점에서 살펴볼 필요가 있습니다.