diff --git a/packages/skia/apple/MetalWindowContext.mm b/packages/skia/apple/MetalWindowContext.mm index b93d4c37a3..1e15fdb3ce 100644 --- a/packages/skia/apple/MetalWindowContext.mm +++ b/packages/skia/apple/MetalWindowContext.mm @@ -89,7 +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; } 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 {