From 53f8680794d118a933cd5981b31c9b11980e9fc4 Mon Sep 17 00:00:00 2001 From: Anton Zhuravsky Date: Sun, 2 Mar 2025 18:12:29 +0000 Subject: [PATCH 1/2] Making first frame render synchronous --- .../cpp/rnskia-android/OpenGLWindowContext.cpp | 4 ++-- .../cpp/rnskia-android/OpenGLWindowContext.h | 2 +- .../android/cpp/rnskia-android/RNSkAndroidView.h | 4 ++-- .../rnskia-android/RNSkOpenGLCanvasProvider.cpp | 4 ++-- .../cpp/rnskia-android/RNSkOpenGLCanvasProvider.h | 2 +- packages/skia/cpp/api/JsiSkiaContext.h | 2 +- packages/skia/cpp/rnskia/DawnWindowContext.cpp | 2 +- packages/skia/cpp/rnskia/DawnWindowContext.h | 2 +- packages/skia/cpp/rnskia/RNSkPictureView.h | 8 ++++---- packages/skia/cpp/rnskia/RNSkView.h | 14 +++++++------- packages/skia/cpp/rnskia/WindowContext.h | 2 +- packages/skia/ios/RNSkia-iOS/MetalWindowContext.h | 2 +- packages/skia/ios/RNSkia-iOS/MetalWindowContext.mm | 7 ++++++- .../skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.h | 2 +- .../skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.mm | 4 ++-- packages/skia/ios/RNSkia-iOS/SkiaUIView.mm | 3 ++- packages/skia/src/renderer/Canvas.tsx | 7 ++++++- 17 files changed, 41 insertions(+), 30 deletions(-) diff --git a/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp b/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp index 3916c0d67a..d7ed430eba 100644 --- a/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp +++ b/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp @@ -51,9 +51,9 @@ sk_sp OpenGLWindowContext::getSurface() { return _skSurface; } -void OpenGLWindowContext::present() { +void OpenGLWindowContext::present(bool flush) { _glContext->makeCurrent(_glSurface.get()); - _directContext->flushAndSubmit(); + _directContext->flushAndSubmit(flush ? GrSyncCpu::kNo : GrSyncCpu::kYes); _glSurface->present(); } diff --git a/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.h b/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.h index b2478a3bf3..d934e7ad13 100644 --- a/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.h +++ b/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.h @@ -50,7 +50,7 @@ class OpenGLWindowContext : public WindowContext { sk_sp getSurface() override; - void present() override; + void present(bool flush) override; int getWidth() override { return ANativeWindow_getWidth(_window); }; diff --git a/packages/skia/android/cpp/rnskia-android/RNSkAndroidView.h b/packages/skia/android/cpp/rnskia-android/RNSkAndroidView.h index e0533bf5d9..63b748882c 100644 --- a/packages/skia/android/cpp/rnskia-android/RNSkAndroidView.h +++ b/packages/skia/android/cpp/rnskia-android/RNSkAndroidView.h @@ -38,7 +38,7 @@ class RNSkAndroidView : public T, public RNSkBaseAndroidView { bool opaque) override { std::static_pointer_cast(T::getCanvasProvider()) ->surfaceAvailable(surface, width, height, opaque); - RNSkView::redraw(); + RNSkView::redraw(true); } void surfaceDestroyed() override { @@ -52,7 +52,7 @@ class RNSkAndroidView : public T, public RNSkBaseAndroidView { ->surfaceSizeChanged(surface, width, height, opaque); // This is only need for the first time to frame, this renderImmediate call // will invoke updateTexImage for the previous frame - RNSkView::redraw(); + RNSkView::redraw(true); } float getPixelDensity() override { diff --git a/packages/skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp b/packages/skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp index f9e8a885e3..7da9f84a8b 100644 --- a/packages/skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp +++ b/packages/skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp @@ -46,7 +46,7 @@ int RNSkOpenGLCanvasProvider::getScaledHeight() { } bool RNSkOpenGLCanvasProvider::renderToCanvas( - const std::function &cb) { + const std::function &cb, bool flush) { if (_surfaceHolder != nullptr && cb != nullptr) { // Get the surface auto surface = _surfaceHolder->getSurface(); @@ -66,7 +66,7 @@ bool RNSkOpenGLCanvasProvider::renderToCanvas( // Draw into canvas using callback cb(surface->getCanvas()); // Swap buffers and show on screen - _surfaceHolder->present(); + _surfaceHolder->present(flush); return true; } else { // the render context did not provide a surface diff --git a/packages/skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h b/packages/skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h index 33399574d0..a379824f3b 100644 --- a/packages/skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h +++ b/packages/skia/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h @@ -25,7 +25,7 @@ class RNSkOpenGLCanvasProvider int getScaledHeight() override; - bool renderToCanvas(const std::function &cb) override; + bool renderToCanvas(const std::function &cb, bool flush) override; void surfaceAvailable(jobject surface, int width, int height, bool opaque); diff --git a/packages/skia/cpp/api/JsiSkiaContext.h b/packages/skia/cpp/api/JsiSkiaContext.h index c35a0046d4..cbdc72308d 100644 --- a/packages/skia/cpp/api/JsiSkiaContext.h +++ b/packages/skia/cpp/api/JsiSkiaContext.h @@ -43,7 +43,7 @@ class JsiSkiaContext : public JsiSkWrappingSharedPtrHostObject { } JSI_HOST_FUNCTION(present) { - getObject()->present(); + getObject()->present(true); return jsi::Value::undefined(); } diff --git a/packages/skia/cpp/rnskia/DawnWindowContext.cpp b/packages/skia/cpp/rnskia/DawnWindowContext.cpp index d84780a5fe..eeed2005e2 100644 --- a/packages/skia/cpp/rnskia/DawnWindowContext.cpp +++ b/packages/skia/cpp/rnskia/DawnWindowContext.cpp @@ -4,7 +4,7 @@ namespace RNSkia { -void DawnWindowContext::present() { +void DawnWindowContext::present(bool flush) { auto recording = _recorder->snap(); if (!recording) { throw std::runtime_error("Failed to create graphite recording"); diff --git a/packages/skia/cpp/rnskia/DawnWindowContext.h b/packages/skia/cpp/rnskia/DawnWindowContext.h index b93e8c8aa2..eda0947560 100644 --- a/packages/skia/cpp/rnskia/DawnWindowContext.h +++ b/packages/skia/cpp/rnskia/DawnWindowContext.h @@ -55,7 +55,7 @@ class DawnWindowContext : public WindowContext { return surface; } - void present() override; + void present(bool flush) override; void resize(int width, int height) override { throw std::runtime_error("resize not implemented yet"); diff --git a/packages/skia/cpp/rnskia/RNSkPictureView.h b/packages/skia/cpp/rnskia/RNSkPictureView.h index 02a9e88dbc..9245b1b2c7 100644 --- a/packages/skia/cpp/rnskia/RNSkPictureView.h +++ b/packages/skia/cpp/rnskia/RNSkPictureView.h @@ -44,8 +44,8 @@ class RNSkPictureRenderer _platformContext(std::move(context)) {} void - renderImmediate(std::shared_ptr canvasProvider) override { - performDraw(canvasProvider); + renderImmediate(std::shared_ptr canvasProvider, bool flush) override { + performDraw(canvasProvider, flush); } void setPicture(sk_sp picture) { @@ -54,7 +54,7 @@ class RNSkPictureRenderer } private: - bool performDraw(std::shared_ptr canvasProvider) { + bool performDraw(std::shared_ptr canvasProvider, bool flush) { return canvasProvider->renderToCanvas([=](SkCanvas *canvas) { // Make sure to scale correctly auto pd = _platformContext->getPixelDensity(); @@ -65,7 +65,7 @@ class RNSkPictureRenderer canvas->drawPicture(_picture); } canvas->restore(); - }); + }, flush); } std::shared_ptr _platformContext; diff --git a/packages/skia/cpp/rnskia/RNSkView.h b/packages/skia/cpp/rnskia/RNSkView.h index 6502490038..156cde195f 100644 --- a/packages/skia/cpp/rnskia/RNSkView.h +++ b/packages/skia/cpp/rnskia/RNSkView.h @@ -43,7 +43,7 @@ class RNSkCanvasProvider { /** Render to a canvas */ - virtual bool renderToCanvas(const std::function &) = 0; + virtual bool renderToCanvas(const std::function &, bool flush) = 0; protected: std::function _requestRedraw; @@ -55,7 +55,7 @@ class RNSkRenderer { : _requestRedraw(std::move(requestRedraw)), _showDebugOverlays(false) {} virtual void - renderImmediate(std::shared_ptr canvasProvider) = 0; + renderImmediate(std::shared_ptr canvasProvider, bool flush) = 0; void setShowDebugOverlays(bool showDebugOverlays) { _showDebugOverlays = showDebugOverlays; @@ -114,7 +114,7 @@ class RNSkOffscreenCanvasProvider : public RNSkCanvasProvider { /** Render to a canvas */ - bool renderToCanvas(const std::function &cb) override { + bool renderToCanvas(const std::function &cb, bool flush) override { cb(_surface->getCanvas()); return true; }; @@ -157,7 +157,7 @@ class RNSkView : public std::enable_shared_from_this { if (auto strongThis = weakThis.lock()) { // Only proceed if the object still exists if (strongThis->_renderer && strongThis->_redrawRequested) { - strongThis->_renderer->renderImmediate(strongThis->_canvasProvider); + strongThis->_renderer->renderImmediate(strongThis->_canvasProvider, false); strongThis->_redrawRequested = false; } } @@ -165,8 +165,8 @@ class RNSkView : public std::enable_shared_from_this { } } - void redraw() { - _renderer->renderImmediate(_canvasProvider); + void redraw(bool flush) { + _renderer->renderImmediate(_canvasProvider, flush); _redrawRequested = false; } @@ -197,7 +197,7 @@ class RNSkView : public std::enable_shared_from_this { getPlatformContext(), std::bind(&RNSkView::requestRedraw, this), _canvasProvider->getScaledWidth(), _canvasProvider->getScaledHeight()); - _renderer->renderImmediate(provider); + _renderer->renderImmediate(provider, false); return provider->makeSnapshot(bounds); } diff --git a/packages/skia/cpp/rnskia/WindowContext.h b/packages/skia/cpp/rnskia/WindowContext.h index 6fe778fccf..eaec06a8e7 100644 --- a/packages/skia/cpp/rnskia/WindowContext.h +++ b/packages/skia/cpp/rnskia/WindowContext.h @@ -16,7 +16,7 @@ class WindowContext { public: virtual ~WindowContext() = default; virtual sk_sp getSurface() = 0; - virtual void present() = 0; + virtual void present(bool flush) = 0; virtual void resize(int width, int height) = 0; virtual int getWidth() = 0; virtual int getHeight() = 0; diff --git a/packages/skia/ios/RNSkia-iOS/MetalWindowContext.h b/packages/skia/ios/RNSkia-iOS/MetalWindowContext.h index f2746c74e0..5b91805f16 100644 --- a/packages/skia/ios/RNSkia-iOS/MetalWindowContext.h +++ b/packages/skia/ios/RNSkia-iOS/MetalWindowContext.h @@ -15,7 +15,7 @@ class MetalWindowContext : public RNSkia::WindowContext { sk_sp getSurface() override; - void present() override; + void present(bool flush) override; int getWidth() override { return _layer.frame.size.width * _layer.contentsScale; diff --git a/packages/skia/ios/RNSkia-iOS/MetalWindowContext.mm b/packages/skia/ios/RNSkia-iOS/MetalWindowContext.mm index 3829faf4f4..ef5d8e073e 100644 --- a/packages/skia/ios/RNSkia-iOS/MetalWindowContext.mm +++ b/packages/skia/ios/RNSkia-iOS/MetalWindowContext.mm @@ -48,7 +48,7 @@ return _skSurface; } -void MetalWindowContext::present() { +void MetalWindowContext::present(bool flush) { if (auto dContext = GrAsDirectContext(_skSurface->recordingContext())) { dContext->flushAndSubmit(); } @@ -56,5 +56,10 @@ id commandBuffer([_commandQueue commandBuffer]); [commandBuffer presentDrawable:_currentDrawable]; [commandBuffer commit]; + + if (flush) { + [commandBuffer waitUntilCompleted]; + } + _skSurface = nullptr; } diff --git a/packages/skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.h b/packages/skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.h index d7b4bc05db..5995beb946 100644 --- a/packages/skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.h +++ b/packages/skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.h @@ -23,7 +23,7 @@ class RNSkMetalCanvasProvider : public RNSkia::RNSkCanvasProvider { int getScaledWidth() override; int getScaledHeight() override; - bool renderToCanvas(const std::function &cb) override; + bool renderToCanvas(const std::function &cb, bool flush) override; void setSize(int width, int height); CALayer *getLayer(); diff --git a/packages/skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.mm b/packages/skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.mm index d03b2509dd..850e09fa03 100644 --- a/packages/skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.mm +++ b/packages/skia/ios/RNSkia-iOS/RNSkMetalCanvasProvider.mm @@ -51,7 +51,7 @@ Render to a canvas */ bool RNSkMetalCanvasProvider::renderToCanvas( - const std::function &cb) { + const std::function &cb, bool flush) { if (!_ctx) { return false; } @@ -82,7 +82,7 @@ } auto canvas = surface->getCanvas(); cb(canvas); - _ctx->present(); + _ctx->present(flush); } return true; }; diff --git a/packages/skia/ios/RNSkia-iOS/SkiaUIView.mm b/packages/skia/ios/RNSkia-iOS/SkiaUIView.mm index 22ab6f9d0f..69353cc363 100644 --- a/packages/skia/ios/RNSkia-iOS/SkiaUIView.mm +++ b/packages/skia/ios/RNSkia-iOS/SkiaUIView.mm @@ -69,6 +69,7 @@ - (void)willMoveToSuperview:(UIView *)newWindow { _manager->setSkiaView(_nativeId, _impl->getDrawView()); } _impl->getDrawView()->setShowDebugOverlays(_debugMode); + [self setNeedsDisplay]; } } } @@ -125,7 +126,7 @@ - (void)drawRect:(CGRect)rect { // We override drawRect to ensure we to direct rendering when the // underlying OS view needs to render: if (_impl != nullptr) { - _impl->getDrawView()->redraw(); + _impl->getDrawView()->redraw(true); } } diff --git a/packages/skia/src/renderer/Canvas.tsx b/packages/skia/src/renderer/Canvas.tsx index 088052cf82..5efa2711c5 100644 --- a/packages/skia/src/renderer/Canvas.tsx +++ b/packages/skia/src/renderer/Canvas.tsx @@ -76,7 +76,12 @@ export const Canvas = forwardRef( }, []); // Root - const root = useMemo(() => new SkiaSGRoot(Skia, nativeId), [nativeId]); + const root = useMemo(() => { + const result = new SkiaSGRoot(Skia, nativeId); + result.render(children); + + return result; + }, [nativeId]); // Render effects useEffect(() => { From dcac22c70fb8bf4a6b52f2488410da2770618cda Mon Sep 17 00:00:00 2001 From: Anton Zhuravsky Date: Sun, 2 Mar 2025 18:22:46 +0000 Subject: [PATCH 2/2] Fixing typo --- .../skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp b/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp index d7ed430eba..f1b7695446 100644 --- a/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp +++ b/packages/skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp @@ -53,7 +53,7 @@ sk_sp OpenGLWindowContext::getSurface() { void OpenGLWindowContext::present(bool flush) { _glContext->makeCurrent(_glSurface.get()); - _directContext->flushAndSubmit(flush ? GrSyncCpu::kNo : GrSyncCpu::kYes); + _directContext->flushAndSubmit(flush ? GrSyncCpu::kYes : GrSyncCpu::kNo); _glSurface->present(); }