Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 98318f4fd93d26c39dd554961608fe1852bb4264
https://github.com/WebKit/WebKit/commit/98318f4fd93d26c39dd554961608fe1852bb4264
Author: Nikolas Zimmermann <[email protected]>
Date: 2026-07-16 (Thu, 16 Jul 2026)
Changed paths:
M Source/WebCore/platform/graphics/skia/SkiaDamageRegion.h
M
Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/AcceleratedSurface.cpp
M Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/AcceleratedSurface.h
Log Message:
-----------
[Damage] Track each swap-chain target's damage since it was last current
https://bugs.webkit.org/show_bug.cgi?id=319581
Reviewed by Alejandro G. Castro.
A compositor that repaints only what changed this frame is only correct if it
draws
into the target that holds the previous frame. That is rarely the case: the
swap chain
hands back whichever target is free, and that one is a frame or more behind. So
every
target needs its own record of what changed since it was last current.
The old code built that record on read. damageForTarget() added the pending
frame
damage to every target and returned the one asked for, so a record only grew if
someone
read it that frame. The optional it took meant two things at once, because a
nullopt
dropped every record. Together with setFrameDamage() skipping empty damage,
reading the
damage on a frame that changed nothing wiped the whole chain. The target being
drawn got
a fresh record when it was presented, so the others paid the price and
repainted in full
on their next use. The rectangle threshold went to the record instead of to the
rects
handed to the platform, which did nothing on the composited path: the record is
a
bounding box, and the frame damage the platform got was built without a
threshold.
The new code keeps those steps apart. recordFrameDamage() adds the frame's
damage to
every target right when it is recorded, unless the damage is only meant for the
platform, so every frame counts even if nobody reads it. didPresent() clears
the record
of the target that just became current, and takes a TargetContents telling
whether the
target really holds what it should, dropping the record when it does not. Reads
are now
a plain lookup, and SwapChainDamageTracker is the only writer, which turns
"everything
that changed since this target was last current" into a real invariant.
A record now uses Damage's default grid instead of the threshold's, which on a
wide,
short surface would collapse into a few full-height cells. The threshold now
applies in
takeFrameDamageRects(), bounding the rects handed to the platform. How much
detail a
record keeps is up to its consumer: no GL consumer walks the rects, they only
read the
bounds, so those records stay bounding boxes.
Clearing can take the damage rects too, drawn as a region rather than clipped,
because a
region of more than one rect cannot be a scissor and Skia would build a clip
mask for it.
* Source/WebCore/platform/graphics/skia/SkiaDamageRegion.h:
(WebCore::SkiaDamageRegion::fillCanvasInDeviceSpace const):
* Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/AcceleratedSurface.cpp:
(WebKit::AcceleratedSurface::AcceleratedSurface):
(WebKit::AcceleratedSurface::SwapChainDamageTracker::recordFrameDamage):
(WebKit::AcceleratedSurface::SwapChainDamageTracker::takeFrameDamageRects):
(WebKit::AcceleratedSurface::SwapChainDamageTracker::didPresent):
(WebKit::clearCanvas):
(WebKit::AcceleratedSurface::clear):
(WebKit::AcceleratedSurface::didRenderFrame):
(WebKit::AcceleratedSurface::renderTargetDamage):
(WebKit::AcceleratedSurface::RenderTarget::addDamage): Deleted.
(WebKit::AcceleratedSurface::SwapChainDamageTracker::damageForTarget): Deleted.
* Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/AcceleratedSurface.h:
Canonical link: https://commits.webkit.org/317342@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications