Skip to content

Commit 7d40f6d

Browse files
committed
Canvases painted into CG display list image buffers don't ever update
https://bugs.webkit.org/show_bug.cgi?id=250196 rdar://98798050 Reviewed by Simon Fraser and Dean Jackson. WebKit has long accidentally depended on the combination of two somewhat unusual behavioral quirks in CGIOSurfaceContext: 1) (Source) If you make a CGImageRef from one CGIOSurfaceContext via CGIOSurfaceContextCreateImage, and mutate the original IOSurface under the hood (or in a different process) in a way that CGIOSurfaceContext does not know, CGIOSurfaceContextCreateImage will return the same CGImageRef when called later. 2) (Destination) If you make a CGImageRef from one CGIOSurfaceContext via CGIOSurfaceContextCreateImage, paint it into a different CGIOSurfaceContext, then mutate the original IOSurface, and paint the same CGImageRef again, the updated IOSurface contents will be used the second time. The second quirk has never worked with unaccelerated CoreGraphics bitmap context destinations. Instead, in the unaccelerated case, the CGImageRef acts as a snapshot of the surface at the time it was created. We've long had code to handle this, forcing CGIOSurfaceContextCreateImage to re-create the CGImageRef each time we paint it (by drawing an empty rect into the CGIOSurfaceContext), working around quirk #1 and thus bypassing quirk #2, if we're painting into an unaccelerated backing store. It turns out our CG display list backing store implementation behaves like a CG bitmap context (without quirk #2), and so currently any IOSurfaces painted into CG display list backing store from a CGImageRef created by CGIOSurfaceContextCreateImage (but not -CreateImageReference) become stale if painted multiple times. To avoid this, extend the workaround to apply to any destination context that claims that it needs the workaround, and use it whenever painting an IOSurface into anything other than a CGIOSurfaceContext. * Source/WebCore/platform/graphics/BifurcatedGraphicsContext.cpp: (WebCore::BifurcatedGraphicsContext::needsCachedNativeImageInvalidationWorkaround): * Source/WebCore/platform/graphics/BifurcatedGraphicsContext.h: Make BifurcatedGraphicsContext assume the more conservative mode of its two children. * Source/WebCore/platform/graphics/GraphicsContext.h: (WebCore::GraphicsContext::needsCachedNativeImageInvalidationWorkaround): Assume that by default, GraphicsContexts need the workaround. * Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp: (WebCore::GraphicsContextCG::needsCachedNativeImageInvalidationWorkaround): * Source/WebCore/platform/graphics/cg/GraphicsContextCG.h: GraphicsContextCG needs the workaround, except in the IOSurface->IOSurface case. * Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp: (WebCore::ImageBufferIOSurfaceBackend::finalizeDrawIntoContext): Confer with the GraphicsContext about its need for the workaround instead of hardcoding the behavior here. * Source/WebKit/Shared/RemoteLayerTree/CGDisplayListImageBufferBackend.mm: CG display list graphics contexts need the workaround. Canonical link: https://commits.webkit.org/258586@main
1 parent ba4235d commit 7d40f6d

File tree

7 files changed

+24
-3
lines changed

7 files changed

+24
-3
lines changed

Source/WebCore/platform/graphics/BifurcatedGraphicsContext.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,11 @@ void BifurcatedGraphicsContext::drawNativeImage(NativeImage& nativeImage, const
340340
VERIFY_STATE_SYNCHRONIZATION();
341341
}
342342

343+
bool BifurcatedGraphicsContext::needsCachedNativeImageInvalidationWorkaround(RenderingMode renderingMode)
344+
{
345+
return m_primaryContext.needsCachedNativeImageInvalidationWorkaround(renderingMode) || m_secondaryContext.needsCachedNativeImageInvalidationWorkaround(renderingMode);
346+
}
347+
343348
void BifurcatedGraphicsContext::drawSystemImage(SystemImage& systemImage, const FloatRect& destinationRect)
344349
{
345350
m_primaryContext.drawSystemImage(systemImage, destinationRect);

Source/WebCore/platform/graphics/BifurcatedGraphicsContext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class WEBCORE_EXPORT BifurcatedGraphicsContext : public GraphicsContext {
9898
void setMiterLimit(float) final;
9999

100100
void drawNativeImage(NativeImage&, const FloatSize& selfSize, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& = { }) final;
101+
bool needsCachedNativeImageInvalidationWorkaround(RenderingMode) final;
101102
void drawSystemImage(SystemImage&, const FloatRect&) final;
102103
void drawPattern(NativeImage&, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, const ImagePaintingOptions& = { }) final;
103104
ImageDrawResult drawImage(Image&, const FloatRect& destination, const FloatRect& source, const ImagePaintingOptions& = { ImageOrientation::FromImage }) final;

Source/WebCore/platform/graphics/GraphicsContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ class GraphicsContext {
248248

249249
virtual void drawNativeImage(NativeImage&, const FloatSize& selfSize, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& = { }) = 0;
250250

251+
virtual bool needsCachedNativeImageInvalidationWorkaround(RenderingMode) { return true; }
252+
251253
WEBCORE_EXPORT virtual void drawSystemImage(SystemImage&, const FloatRect&);
252254

253255
WEBCORE_EXPORT ImageDrawResult drawImage(Image&, const FloatPoint& destination, const ImagePaintingOptions& = { ImageOrientation::FromImage });

Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,18 @@ void GraphicsContextCG::drawNativeImage(NativeImage& nativeImage, const FloatSiz
374374
LOG_WITH_STREAM(Images, stream << "GraphicsContextCG::drawNativeImage " << image.get() << " size " << imageSize << " into " << destRect << " took " << (MonotonicTime::now() - startTime).milliseconds() << "ms");
375375
}
376376

377+
bool GraphicsContextCG::needsCachedNativeImageInvalidationWorkaround(RenderingMode imageRenderingMode)
378+
{
379+
// Only accelerated images cache CGImageRefs underneath us (when returned by
380+
// IOSurface::createImage), and thus need the workaround.
381+
if (imageRenderingMode == RenderingMode::Unaccelerated)
382+
return false;
383+
384+
// Accelerated destinations have "live" CGImageRefs, so we only need
385+
// the workaround when painting into an unaccelerated context.
386+
return renderingMode() == RenderingMode::Unaccelerated;
387+
}
388+
377389
static void drawPatternCallback(void* info, CGContextRef context)
378390
{
379391
CGImageRef image = (CGImageRef)info;

Source/WebCore/platform/graphics/cg/GraphicsContextCG.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class WEBCORE_EXPORT GraphicsContextCG : public GraphicsContext {
9696

9797
void drawNativeImage(NativeImage&, const FloatSize& selfSize, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& = { }) final;
9898
void drawPattern(NativeImage&, const FloatRect& destRect, const FloatRect& tileRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, const ImagePaintingOptions& = { }) final;
99+
bool needsCachedNativeImageInvalidationWorkaround(RenderingMode) override;
99100

100101
using GraphicsContext::scale;
101102
void scale(const FloatSize&) final;

Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,7 @@ RefPtr<NativeImage> ImageBufferIOSurfaceBackend::sinkIntoNativeImage()
195195

196196
void ImageBufferIOSurfaceBackend::finalizeDrawIntoContext(GraphicsContext& destinationContext)
197197
{
198-
// Accelerated to unaccelerated image buffers need complex caching. We trust that
199-
// this is a one-off draw, and as such we clear the caches of the source image after each draw.
200-
if (destinationContext.renderingMode() == RenderingMode::Unaccelerated)
198+
if (destinationContext.needsCachedNativeImageInvalidationWorkaround(ImageBufferIOSurfaceBackend::renderingMode))
201199
invalidateCachedNativeImage();
202200
}
203201

Source/WebKit/Shared/RemoteLayerTree/CGDisplayListImageBufferBackend.mm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ void setCTM(const WebCore::AffineTransform& transform) final
8484

8585
bool canUseShadowBlur() const final { return false; }
8686

87+
bool needsCachedNativeImageInvalidationWorkaround(WebCore::RenderingMode) override { return true; }
88+
8789
protected:
8890
void setCGShadow(WebCore::RenderingMode renderingMode, const WebCore::FloatSize& offset, float blur, const WebCore::Color& color, bool shadowsIgnoreTransforms) override
8991
{

0 commit comments

Comments
 (0)