From 9396d39499c1690e9e5bed2b11130ea1f32ab3c5 Mon Sep 17 00:00:00 2001 From: Vivek Indlebele Narasimha Prasad <90718779+invivek26@users.noreply.github.com> Date: Fri, 4 Sep 2026 11:23:16 -0700 Subject: [PATCH 1/2] fix(ios): redraw when the view re-enters a window A SkiaUIView that draws while its screen is detached from the window (an inactive tab in a react-native-screens container, a covered stack screen) never presents that frame, and nothing asks it to draw again when the screen comes back, so it keeps showing the last frame it presented before it left. Static canvases whose content changed while offscreen come back stale. Redraw the current picture in didMoveToWindow, and present that frame with presentsWithTransaction so it lands in the same Core Animation transaction as the view's return rather than one frame later. --- packages/skia/apple/MetalWindowContext.mm | 3 +++ packages/skia/apple/SkiaUIView.mm | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/packages/skia/apple/MetalWindowContext.mm b/packages/skia/apple/MetalWindowContext.mm index b93d4c37a3..7182a98d83 100644 --- a/packages/skia/apple/MetalWindowContext.mm +++ b/packages/skia/apple/MetalWindowContext.mm @@ -91,5 +91,8 @@ id commandBuffer([_commandQueue commandBuffer]); [commandBuffer presentDrawable:_currentDrawable]; [commandBuffer commit]; + if (_layer.presentsWithTransaction) { + [commandBuffer waitUntilScheduled]; + } _skSurface = nullptr; } diff --git a/packages/skia/apple/SkiaUIView.mm b/packages/skia/apple/SkiaUIView.mm index 33a67871cb..0a8c8ba915 100644 --- a/packages/skia/apple/SkiaUIView.mm +++ b/packages/skia/apple/SkiaUIView.mm @@ -138,6 +138,24 @@ - (void)drawRect:(CGRect)rect { } } +#if !TARGET_OS_OSX +- (void)didMoveToWindow { + [super didMoveToWindow]; + // A frame drawn while the view was detached from the window (an inactive + // tab, a covered screen) is never presented, so redraw the current picture + // as soon as the view is back in a window instead of showing the last + // frame that was presented before it left. Present it inside the current + // Core Animation transaction so it is on screen in the same frame the view + // appears rather than one later. + if (self.window != nil && _impl != nullptr) { + CAMetalLayer *layer = (CAMetalLayer *)_impl->getLayer(); + layer.presentsWithTransaction = YES; + _impl->getDrawView()->redraw(); + layer.presentsWithTransaction = NO; + } +} +#endif // !TARGET_OS_OSX + #pragma mark Layout - (void)layoutSubviews { From 67adfd87e1da6fd91a560faa17304faf7fc9e4be Mon Sep 17 00:00:00 2001 From: Vivek Indlebele Narasimha Prasad <90718779+invivek26@users.noreply.github.com> Date: Fri, 4 Sep 2026 14:55:22 -0700 Subject: [PATCH 2/2] fix(ios): present the attach-time frame in the documented transactional order --- packages/skia/apple/MetalWindowContext.mm | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/skia/apple/MetalWindowContext.mm b/packages/skia/apple/MetalWindowContext.mm index 7182a98d83..1e15fdb3ce 100644 --- a/packages/skia/apple/MetalWindowContext.mm +++ b/packages/skia/apple/MetalWindowContext.mm @@ -89,10 +89,16 @@ } id commandBuffer([_commandQueue commandBuffer]); - [commandBuffer presentDrawable:_currentDrawable]; - [commandBuffer commit]; if (_layer.presentsWithTransaction) { + // Present inside the current Core Animation transaction: commit, wait + // until the command buffer is scheduled, then present the drawable + // directly (CAMetalLayer.presentsWithTransaction documentation). + [commandBuffer commit]; [commandBuffer waitUntilScheduled]; + [_currentDrawable present]; + } else { + [commandBuffer presentDrawable:_currentDrawable]; + [commandBuffer commit]; } _skSurface = nullptr; }