diff --git a/externals/depot_tools b/externals/depot_tools index c7aca34c8e..6d0c235dae 160000 --- a/externals/depot_tools +++ b/externals/depot_tools @@ -1 +1 @@ -Subproject commit c7aca34c8e5fff27dd8424b55ef520de960d0bff +Subproject commit 6d0c235dae4b7e664122eba4a02f97d4cf155241 diff --git a/externals/skia b/externals/skia index ffbc376172..f44dbc40d8 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit ffbc376172738894f15bd22909a285a23436fdf4 +Subproject commit f44dbc40d81e6b780465c63a811b12c1143953ef diff --git a/package/android/cpp/jni/include/JniSkiaBaseView.h b/package/android/cpp/jni/include/JniSkiaBaseView.h index b42d12db3e..400933fc44 100644 --- a/package/android/cpp/jni/include/JniSkiaBaseView.h +++ b/package/android/cpp/jni/include/JniSkiaBaseView.h @@ -62,62 +62,6 @@ class JniSkiaBaseView { _skiaAndroidView->viewDidUnmount(); } - /** - * Android specific method for rendering an offscreen GPU buffer to an Android - * bitmap. The result can be used to render the first frame of the Skia render - * to avoid flickering on android. - */ - /* - // TODO: Remove if we find another solution for first frame rendering - // protected native Object renderToBitmap(Object bitmap, int width, int - height); virtual jobject renderToBitmap(jobject bitmapIn, int width, int - height) { auto platformContext = getSkiaManager()->getPlatformContext(); auto - provider = std::make_shared( platformContext, - []() {}, width, height); - - // Render into a gpu backed buffer - _skiaAndroidView->getSkiaView()->getRenderer()->renderImmediate(provider); - auto rect = SkRect::MakeXYWH(0, 0, width, height); - auto image = provider->makeSnapshot(&rect); - - AndroidBitmapInfo infoIn; - auto env = facebook::jni::Environment::current(); - void *pixels; - - // Get image info - if (AndroidBitmap_getInfo(env, bitmapIn, &infoIn) != - ANDROID_BITMAP_RESULT_SUCCESS) { - return env->NewStringUTF("failed"); - } - - // Check image - if (infoIn.format != ANDROID_BITMAP_FORMAT_RGBA_8888 && - infoIn.format != ANDROID_BITMAP_FORMAT_RGB_565) { - return env->NewStringUTF("Only support ANDROID_BITMAP_FORMAT_RGBA_8888 " - "and ANDROID_BITMAP_FORMAT_RGB_565"); - } - - auto imageInfo = SkImageInfo::Make(image->width(), image->height(), - image->colorType(), image->alphaType()); - - // Lock all images - if (AndroidBitmap_lockPixels(env, bitmapIn, &pixels) != - ANDROID_BITMAP_RESULT_SUCCESS) { - return env->NewStringUTF("AndroidBitmap_lockPixels failed!"); - } - - // Set pixels from SkImage - image->readPixels(imageInfo, pixels, imageInfo.minRowBytes(), 0, 0); - - // Unlocks everything - AndroidBitmap_unlockPixels(env, bitmapIn); - - image = nullptr; - provider = nullptr; - - return bitmapIn; - }*/ - private: JniSkiaManager *_manager; std::shared_ptr _skiaAndroidView; diff --git a/package/android/cpp/jni/include/JniSkiaDomView.h b/package/android/cpp/jni/include/JniSkiaDomView.h index d842aa5fd3..68b955def8 100644 --- a/package/android/cpp/jni/include/JniSkiaDomView.h +++ b/package/android/cpp/jni/include/JniSkiaDomView.h @@ -34,21 +34,18 @@ class JniSkiaDomView : public jni::HybridClass, } static void registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", JniSkiaDomView::initHybrid), - makeNativeMethod("surfaceAvailable", JniSkiaDomView::surfaceAvailable), - makeNativeMethod("surfaceDestroyed", JniSkiaDomView::surfaceDestroyed), - makeNativeMethod("surfaceSizeChanged", - JniSkiaDomView::surfaceSizeChanged), - makeNativeMethod("setMode", JniSkiaDomView::setMode), - makeNativeMethod("setDebugMode", JniSkiaDomView::setDebugMode), - makeNativeMethod("updateTouchPoints", - JniSkiaDomView::updateTouchPoints), - makeNativeMethod("registerView", JniSkiaDomView::registerView), - makeNativeMethod("unregisterView", JniSkiaDomView::unregisterView) - // TODO: Remove if we find another solution for first frame rendering - // makeNativeMethod("renderToBitmap", JniSkiaDomView::renderToBitmap) - }); + registerHybrid( + {makeNativeMethod("initHybrid", JniSkiaDomView::initHybrid), + makeNativeMethod("surfaceAvailable", JniSkiaDomView::surfaceAvailable), + makeNativeMethod("surfaceDestroyed", JniSkiaDomView::surfaceDestroyed), + makeNativeMethod("surfaceSizeChanged", + JniSkiaDomView::surfaceSizeChanged), + makeNativeMethod("setMode", JniSkiaDomView::setMode), + makeNativeMethod("setDebugMode", JniSkiaDomView::setDebugMode), + makeNativeMethod("updateTouchPoints", + JniSkiaDomView::updateTouchPoints), + makeNativeMethod("registerView", JniSkiaDomView::registerView), + makeNativeMethod("unregisterView", JniSkiaDomView::unregisterView)}); } protected: @@ -76,11 +73,6 @@ class JniSkiaDomView : public jni::HybridClass, void unregisterView() override { JniSkiaBaseView::unregisterView(); } - // TODO: Remove if we find another solution for first frame rendering - /*jobject renderToBitmap(jobject bitmap, int width, int height) override { - return JniSkiaBaseView::renderToBitmap(bitmap, width, height); - }*/ - private: friend HybridBase; diff --git a/package/android/cpp/jni/include/JniSkiaDrawView.h b/package/android/cpp/jni/include/JniSkiaDrawView.h index b79eb5495c..1cd88bafef 100644 --- a/package/android/cpp/jni/include/JniSkiaDrawView.h +++ b/package/android/cpp/jni/include/JniSkiaDrawView.h @@ -33,21 +33,20 @@ class JniSkiaDrawView : public jni::HybridClass, } static void registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", JniSkiaDrawView::initHybrid), - makeNativeMethod("surfaceAvailable", JniSkiaDrawView::surfaceAvailable), - makeNativeMethod("surfaceDestroyed", JniSkiaDrawView::surfaceDestroyed), - makeNativeMethod("surfaceSizeChanged", - JniSkiaDrawView::surfaceSizeChanged), - makeNativeMethod("setMode", JniSkiaDrawView::setMode), - makeNativeMethod("setDebugMode", JniSkiaDrawView::setDebugMode), - makeNativeMethod("updateTouchPoints", - JniSkiaDrawView::updateTouchPoints), - makeNativeMethod("registerView", JniSkiaDrawView::registerView), - makeNativeMethod("unregisterView", JniSkiaDrawView::unregisterView), - // TODO: Remove if we find another solution for first frame rendering - // makeNativeMethod("renderToBitmap", JniSkiaDrawView::renderToBitmap) - }); + registerHybrid( + {makeNativeMethod("initHybrid", JniSkiaDrawView::initHybrid), + makeNativeMethod("surfaceAvailable", + JniSkiaDrawView::surfaceAvailable), + makeNativeMethod("surfaceDestroyed", + JniSkiaDrawView::surfaceDestroyed), + makeNativeMethod("surfaceSizeChanged", + JniSkiaDrawView::surfaceSizeChanged), + makeNativeMethod("setMode", JniSkiaDrawView::setMode), + makeNativeMethod("setDebugMode", JniSkiaDrawView::setDebugMode), + makeNativeMethod("updateTouchPoints", + JniSkiaDrawView::updateTouchPoints), + makeNativeMethod("registerView", JniSkiaDrawView::registerView), + makeNativeMethod("unregisterView", JniSkiaDrawView::unregisterView)}); } protected: @@ -75,11 +74,6 @@ class JniSkiaDrawView : public jni::HybridClass, void unregisterView() override { JniSkiaBaseView::unregisterView(); } - // TODO: Remove if we find another solution for first frame rendering - /*jobject renderToBitmap(jobject bitmap, int width, int height) override { - return JniSkiaBaseView::renderToBitmap(bitmap, width, height); - }*/ - private: friend HybridBase; diff --git a/package/android/cpp/jni/include/JniSkiaPictureView.h b/package/android/cpp/jni/include/JniSkiaPictureView.h index 039de3c24e..e12113483f 100644 --- a/package/android/cpp/jni/include/JniSkiaPictureView.h +++ b/package/android/cpp/jni/include/JniSkiaPictureView.h @@ -33,24 +33,21 @@ class JniSkiaPictureView : public jni::HybridClass, } static void registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", JniSkiaPictureView::initHybrid), - makeNativeMethod("surfaceAvailable", - JniSkiaPictureView::surfaceAvailable), - makeNativeMethod("surfaceDestroyed", - JniSkiaPictureView::surfaceDestroyed), - makeNativeMethod("surfaceSizeChanged", - JniSkiaPictureView::surfaceSizeChanged), - makeNativeMethod("setMode", JniSkiaPictureView::setMode), - makeNativeMethod("setDebugMode", JniSkiaPictureView::setDebugMode), - makeNativeMethod("updateTouchPoints", - JniSkiaPictureView::updateTouchPoints), - makeNativeMethod("registerView", JniSkiaPictureView::registerView), - makeNativeMethod("unregisterView", JniSkiaPictureView::unregisterView), - // TODO: Remove if we find another solution for first frame rendering - // makeNativeMethod("renderToBitmap", - // JniSkiaPictureView::renderToBitmap) - }); + registerHybrid( + {makeNativeMethod("initHybrid", JniSkiaPictureView::initHybrid), + makeNativeMethod("surfaceAvailable", + JniSkiaPictureView::surfaceAvailable), + makeNativeMethod("surfaceDestroyed", + JniSkiaPictureView::surfaceDestroyed), + makeNativeMethod("surfaceSizeChanged", + JniSkiaPictureView::surfaceSizeChanged), + makeNativeMethod("setMode", JniSkiaPictureView::setMode), + makeNativeMethod("setDebugMode", JniSkiaPictureView::setDebugMode), + makeNativeMethod("updateTouchPoints", + JniSkiaPictureView::updateTouchPoints), + makeNativeMethod("registerView", JniSkiaPictureView::registerView), + makeNativeMethod("unregisterView", + JniSkiaPictureView::unregisterView)}); } protected: @@ -78,12 +75,6 @@ class JniSkiaPictureView : public jni::HybridClass, void unregisterView() override { JniSkiaBaseView::unregisterView(); } - /* - TODO: Remove if we find another solution for first frame rendering - jobject renderToBitmap(jobject bitmap, int width, int height) override { - return JniSkiaBaseView::renderToBitmap(bitmap, width, height); - }*/ - private: friend HybridBase; diff --git a/package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java b/package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java index 7c54991978..18eb39fb78 100644 --- a/package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java +++ b/package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java @@ -9,53 +9,51 @@ import com.facebook.jni.annotations.DoNotStrip; import com.facebook.react.views.view.ReactViewGroup; + public abstract class SkiaBaseView extends ReactViewGroup implements TextureView.SurfaceTextureListener { @DoNotStrip private Surface mSurface; private TextureView mTexture; + private String tag = "SkiaView"; + public SkiaBaseView(Context context) { super(context); - // TODO: Remove if we find another solution for first frame rendering - //setWillNotDraw(!shouldRenderFirstFrameAsBitmap()); mTexture = new TextureView(context); mTexture.setSurfaceTextureListener(this); mTexture.setOpaque(false); addView(mTexture); } - /*@Override - TODO: Remove if we find another solution for first frame rendering - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - // If we haven't got a surface yet, let's ask the view to - // draw into a bitmap and then render the bitmap. This method - // is typically only called once - for the first frame, and - // then the surface will be available and all rendering will - // be done directly to the surface itself. - if (shouldRenderFirstFrameAsBitmap() && mSurface == null) { - int width = getWidth(); - int height = getHeight(); - - if (width > 0 && height > 0) { - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Bitmap result = (Bitmap) renderToBitmap(bitmap, width, height); - - canvas.drawBitmap( - result, - new Rect(0, 0, width, height), - new Rect(0, 0, width, height), - null); - - bitmap.recycle(); - } + public void destroySurface() { + Log.i(tag, "destroySurface"); + surfaceDestroyed(); + mSurface.release(); + mSurface = null; + } + + private void createSurfaceTexture() { + // This API Level is >= 26, we created our own SurfaceTexture to have a faster time to first frame + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + Log.i(tag, "Create SurfaceTexture"); + SurfaceTexture surface = new SurfaceTexture(false); + mTexture.setSurfaceTexture(surface); + this.onSurfaceTextureAvailable(surface, this.getMeasuredWidth(), this.getMeasuredHeight()); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (this.getMeasuredWidth() == 0) { + createSurfaceTexture(); } - }*/ + } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + Log.i(tag, "onLayout " + this.getMeasuredWidth() + "/" + this.getMeasuredHeight()); super.onLayout(changed, left, top, right, bottom); mTexture.layout(0, 0, this.getMeasuredWidth(), this.getMeasuredHeight()); } @@ -132,52 +130,23 @@ private static int motionActionToType(int action) { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { - Log.i("SkiaBaseView", "onSurfaceTextureAvailable " + width + "/" + height); + Log.i(tag, "onSurfaceTextureAvailable " + width + "/" + height); mSurface = new Surface(surface); surfaceAvailable(mSurface, width, height); - - /* - TODO: Remove if we find another solution for first frame rendering - // Clear rendered bitmap when the surface texture has rendered - // We'll post a message to the main loop asking to invalidate - if (shouldRenderFirstFrameAsBitmap()) { - postUpdate(new AtomicInteger()); - }*/ } - /** - * This method is a way for us to clear the bitmap rendered on the first frame - * after at least 16 frames have passed - to avoid seeing blinks on the screen caused by - * TextureView frame sync issues. This is a hack to avoid those pesky blinks. Have no - * idea on how to sync the TextureView OpenGL updates. - * @param counter - */ - /* - TODO: Remove if we find another solution for first frame rendering - void postUpdate(AtomicInteger counter) { - counter.getAndIncrement(); - if (counter.get() > 16) { - invalidate(); - } else { - this.post(() -> { - postUpdate(counter); - }); - } - }*/ - @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { - Log.i("SkiaBaseView", "onSurfaceTextureSizeChanged " + width + "/" + height); + Log.i(tag, "onSurfaceTextureSizeChanged " + width + "/" + height); surfaceSizeChanged(width, height); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { - Log.i("SkiaBaseView", "onSurfaceTextureDestroyed"); + Log.i(tag, "onSurfaceTextureDestroyed"); // https://developer.android.com/reference/android/view/TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed(android.graphics.SurfaceTexture) - surfaceDestroyed(); - mSurface.release(); - mSurface = null; + destroySurface(); + createSurfaceTexture(); return false; } @@ -186,17 +155,6 @@ public void onSurfaceTextureUpdated(SurfaceTexture surface) { // Nothing special to do here } - /** - * Returns true if the view is able to directly render on the - * main thread. This can f.ex then be used to create a first frame - * render of the view. Returns true by default - override if not. - */ - /* - TODO: Remove if we find another solution for first frame rendering - protected boolean shouldRenderFirstFrameAsBitmap() { - return false; - }*/ - protected abstract void surfaceAvailable(Object surface, int width, int height); protected abstract void surfaceSizeChanged(int width, int height); @@ -212,7 +170,4 @@ protected boolean shouldRenderFirstFrameAsBitmap() { protected abstract void registerView(int nativeId); protected abstract void unregisterView(); - - // TODO: Remove if we find another solution for first frame rendering - // protected native Object renderToBitmap(Object bitmap, int width, int height); } diff --git a/package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseViewManager.java b/package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseViewManager.java index ce4005e923..152ed1e9d1 100644 --- a/package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseViewManager.java +++ b/package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseViewManager.java @@ -30,5 +30,6 @@ public void setDebug(ReactViewGroup view, boolean show) { public void onDropViewInstance(@NonNull ReactViewGroup view) { super.onDropViewInstance(view); ((SkiaBaseView)view).unregisterView(); + ((SkiaBaseView)view).destroySurface(); } } \ No newline at end of file diff --git a/package/android/src/main/java/com/shopify/reactnative/skia/SkiaDomView.java b/package/android/src/main/java/com/shopify/reactnative/skia/SkiaDomView.java index b9ac7485f6..d2ec166986 100644 --- a/package/android/src/main/java/com/shopify/reactnative/skia/SkiaDomView.java +++ b/package/android/src/main/java/com/shopify/reactnative/skia/SkiaDomView.java @@ -41,7 +41,4 @@ protected void finalize() throws Throwable { protected native void registerView(int nativeId); protected native void unregisterView(); - - // TODO: Remove if we find another solution for first frame rendering - // protected native Object renderToBitmap(Object bitmap, int width, int height); } diff --git a/package/android/src/main/java/com/shopify/reactnative/skia/SkiaDrawView.java b/package/android/src/main/java/com/shopify/reactnative/skia/SkiaDrawView.java index f84c093972..fb05a798a1 100644 --- a/package/android/src/main/java/com/shopify/reactnative/skia/SkiaDrawView.java +++ b/package/android/src/main/java/com/shopify/reactnative/skia/SkiaDrawView.java @@ -41,7 +41,4 @@ protected void finalize() throws Throwable { protected native void registerView(int nativeId); protected native void unregisterView(); - - // TODO: Remove if we find another solution for first frame rendering - // protected native Object renderToBitmap(Object bitmap, int width, int height); } diff --git a/package/android/src/main/java/com/shopify/reactnative/skia/SkiaPictureView.java b/package/android/src/main/java/com/shopify/reactnative/skia/SkiaPictureView.java index 152be16c4a..56e5bb3e23 100644 --- a/package/android/src/main/java/com/shopify/reactnative/skia/SkiaPictureView.java +++ b/package/android/src/main/java/com/shopify/reactnative/skia/SkiaPictureView.java @@ -41,8 +41,4 @@ protected void finalize() throws Throwable { protected native void registerView(int nativeId); protected native void unregisterView(); - - // TODO: Remove if we find another solution for first frame rendering - // protected native Object renderToBitmap(Object bitmap, int width, int height); - }