Skip to content

Commit 88dec7f

Browse files
authored
feat(πŸ‘¨πŸ»β€πŸŽ¨): Opaque property (#2776)
The opaque property enables the use of SurfaceView on Android instead of TextureView
1 parent 06ecae8 commit 88dec7f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+488
-162
lines changed

β€Žapps/docs/docs/canvas/canvas.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Behind the scenes, it is using its own React renderer.
1313
|:-----|:---------|:-----------------|
1414
| style? | `ViewStyle` | View style |
1515
| ref? | `Ref<SkiaView>` | Reference to the `SkiaView` object |
16-
| mode? | `default` or `continuous` | By default, the canvas is only updated when the drawing tree or animation values change. With `mode="continuous"`, the canvas will redraw on every frame |
16+
| opaque? | `boolean` | By default, the canvas is transparent but on Android, you can make it opaque to improve performance. |
1717
| onSize? | `SharedValue<Size>` | Reanimated value to which the canvas size will be assigned (see [canvas size](/docs/animations/hooks#canvas-size)) |
1818
| onLayout? | `NativeEvent<LayoutEvent>` | Invoked on mount and on layout changes (see [onLayout](https://reactnative.dev/docs/view#onlayout)) |
1919

β€Žapps/paper/ios/Podfile.lock

+5-5
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,7 @@ PODS:
12831283
- ReactCommon/turbomodule/bridging
12841284
- ReactCommon/turbomodule/core
12851285
- Yoga
1286-
- react-native-wgpu (0.1.19):
1286+
- react-native-wgpu (0.1.20):
12871287
- DoubleConversion
12881288
- glog
12891289
- hermes-engine
@@ -1650,7 +1650,7 @@ PODS:
16501650
- ReactCommon/turbomodule/bridging
16511651
- ReactCommon/turbomodule/core
16521652
- Yoga
1653-
- RNScreens (3.34.0):
1653+
- RNScreens (4.3.0):
16541654
- DoubleConversion
16551655
- glog
16561656
- hermes-engine
@@ -1937,7 +1937,7 @@ SPEC CHECKSUMS:
19371937
react-native-safe-area-context: ab8f4a3d8180913bd78ae75dd599c94cce3d5e9a
19381938
react-native-skia: 1549ee5068efc5a004b84b2e0ba109c6234e2fde
19391939
react-native-slider: 97ce0bd921f40de79cead9754546d5e4e7ba44f8
1940-
react-native-wgpu: 8d0437a304318e0e3d6ccbfed2a39880f8eae4dd
1940+
react-native-wgpu: efaa8c7c3ae15b346d887d13cca2fe72ed5ea105
19411941
React-nativeconfig: 57781b79e11d5af7573e6f77cbf1143b71802a6d
19421942
React-NativeModulesApple: 7ff2e2cfb2e5fa5bdedcecf28ce37e696c6ef1e1
19431943
React-perflogger: 8a360ccf603de6ddbe9ff8f54383146d26e6c936
@@ -1966,10 +1966,10 @@ SPEC CHECKSUMS:
19661966
ReactCommon: 6ef348087d250257c44c0204461c03f036650e9b
19671967
RNGestureHandler: 939f21fabf5d45a725c0bf175eb819dd25cf2e70
19681968
RNReanimated: 190c12cb20dfa828353e99775beaa1bdf36e7ed9
1969-
RNScreens: 19719a9c326e925498ac3b2d35c4e50fe87afc06
1969+
RNScreens: b03d696c70cc5235ce4587fcc27ae1a93a48f98c
19701970
RNSVG: 5da7a24f31968ec74f0b091e3440080f347e279b
19711971
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
1972-
Yoga: 2a45d7e59592db061217551fd3bbe2dd993817ae
1972+
Yoga: a1d7895431387402a674fd0d1c04ec85e87909b8
19731973

19741974
PODFILE CHECKSUM: debc09f5cfcbea21f946ca0be3faa5351e907125
19751975

β€Žapps/paper/src/App.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { HeaderBackButtonProps } from "@react-navigation/elements";
77
import { HeaderBackButton } from "@react-navigation/elements";
88
import { FiberProvider } from "its-fine";
99
import { GestureHandlerRootView } from "react-native-gesture-handler";
10+
import { enableScreens } from "react-native-screens";
1011

1112
import {
1213
ReanimatedExample,
@@ -84,6 +85,8 @@ const HeaderLeft = (props: HeaderBackButtonProps) => {
8485
);
8586
};
8687

88+
enableScreens(true);
89+
8790
const App = () => {
8891
const Stack = createNativeStackNavigator<StackParamList>();
8992
const assets = useAssets();

β€Žapps/paper/src/Examples/Breathe/Breathe.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const Breathe = () => {
6868

6969
return (
7070
<View style={{ flex: 1 }}>
71-
<Canvas style={styles.container}>
71+
<Canvas style={styles.container} opaque>
7272
<Fill color="rgb(36,43,56)" />
7373
<Group origin={center} transform={transform} blendMode="screen">
7474
<BlurMask style="solid" blur={40} />

β€Žapps/paper/src/Examples/Glassmorphism/Glassmorphism.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export const Glassmorphism = () => {
4040
);
4141

4242
return (
43-
<Canvas style={{ flex: 1 }}>
43+
<Canvas style={{ flex: 1 }} opaque>
4444
<Fill color="black" />
4545
<Circle c={c} r={radius}>
4646
<LinearGradient

β€Žapps/paper/src/Examples/Matrix/Matrix.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const Matrix = () => {
4141
}
4242
const symbols = font.getGlyphIDs("abcdefghijklmnopqrstuvwxyz");
4343
return (
44-
<Canvas style={{ flex: 1 }}>
44+
<Canvas style={{ flex: 1 }} opaque>
4545
<Fill color="black" />
4646
<Group>
4747
<BlurMask blur={8} style="solid" />

β€Žapps/paper/src/Examples/Matrix/Symbol.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { interpolateColors, vec, Glyphs } from "@shopify/react-native-skia";
44
import type { SharedValue } from "react-native-reanimated";
55
import { useDerivedValue } from "react-native-reanimated";
66

7-
export const COLS = 15;
8-
export const ROWS = 30;
7+
export const COLS = 8;
8+
export const ROWS = 15;
99
const pos = vec(0, 0);
1010

1111
interface SymbolProps {

β€Žapps/paper/src/Examples/Severance/Severance.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const Severance = () => {
2929
return (
3030
<View style={{ flex: 1 }}>
3131
<GestureDetector gesture={gesture}>
32-
<Canvas style={{ flex: 1 }}>
32+
<Canvas style={{ flex: 1 }} opaque>
3333
<CRT>
3434
<Group>
3535
<Fill color={BG} />

β€Žapps/paper/src/Examples/Stickers/Stickers.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const Stickers = () => {
2424
}
2525
return (
2626
<View>
27-
<Canvas style={{ width, height }}>
27+
<Canvas style={{ width, height }} opaque>
2828
<Picture matrix={pictureMatrix} image={image} />
2929
<HelloSticker matrix={helloMatrix} />
3030
<LocationSticker font={font} matrix={locationMatrix} />

β€Žapps/paper/src/Examples/Video/Video.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const Video = () => {
3737
style={{ flex: 1 }}
3838
onPress={() => (paused.value = !paused.value)}
3939
>
40-
<Canvas style={{ flex: 1 }}>
40+
<Canvas style={{ flex: 1 }} opaque>
4141
<Fill>
4242
<ImageShader
4343
image={currentFrame}
@@ -62,7 +62,7 @@ export const Video = () => {
6262
/>
6363
</Canvas>
6464
</Pressable>
65-
<View style={{ height: 200 }}>
65+
<View style={{ height: 200, backgroundColor: "white" }}>
6666
<Slider
6767
style={{ width, height: 40 }}
6868
minimumValue={0}

β€Žpackages/skia/android/cpp/jni/include/JniSkiaBaseView.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ class JniSkiaBaseView {
2929
}
3030

3131
protected:
32-
virtual void surfaceAvailable(jobject surface, int width, int height) {
33-
_skiaAndroidView->surfaceAvailable(surface, width, height);
32+
virtual void surfaceAvailable(jobject surface, int width, int height,
33+
bool opaque) {
34+
_skiaAndroidView->surfaceAvailable(surface, width, height, opaque);
3435
}
3536

36-
virtual void surfaceSizeChanged(jobject surface, int width, int height) {
37-
_skiaAndroidView->surfaceSizeChanged(surface, width, height);
37+
virtual void surfaceSizeChanged(jobject surface, int width, int height,
38+
bool opaque) {
39+
_skiaAndroidView->surfaceSizeChanged(surface, width, height, opaque);
3840
}
3941

4042
virtual void surfaceDestroyed() { _skiaAndroidView->surfaceDestroyed(); }

β€Žpackages/skia/android/cpp/jni/include/JniSkiaDomView.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,14 @@ class JniSkiaDomView : public jni::HybridClass<JniSkiaDomView>,
4646
}
4747

4848
protected:
49-
void surfaceAvailable(jobject surface, int width, int height) override {
50-
JniSkiaBaseView::surfaceAvailable(surface, width, height);
49+
void surfaceAvailable(jobject surface, int width, int height,
50+
bool opaque) override {
51+
JniSkiaBaseView::surfaceAvailable(surface, width, height, opaque);
5152
}
5253

53-
void surfaceSizeChanged(jobject surface, int width, int height) override {
54-
JniSkiaBaseView::surfaceSizeChanged(surface, width, height);
54+
void surfaceSizeChanged(jobject surface, int width, int height,
55+
bool opaque) override {
56+
JniSkiaBaseView::surfaceSizeChanged(surface, width, height, opaque);
5557
}
5658

5759
void surfaceDestroyed() override { JniSkiaBaseView::surfaceDestroyed(); }

β€Žpackages/skia/android/cpp/jni/include/JniSkiaPictureView.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,14 @@ class JniSkiaPictureView : public jni::HybridClass<JniSkiaPictureView>,
4848
}
4949

5050
protected:
51-
void surfaceAvailable(jobject surface, int width, int height) override {
52-
JniSkiaBaseView::surfaceAvailable(surface, width, height);
51+
void surfaceAvailable(jobject surface, int width, int height,
52+
bool opaque) override {
53+
JniSkiaBaseView::surfaceAvailable(surface, width, height, opaque);
5354
}
5455

55-
void surfaceSizeChanged(jobject surface, int width, int height) override {
56-
JniSkiaBaseView::surfaceSizeChanged(surface, width, height);
56+
void surfaceSizeChanged(jobject surface, int width, int height,
57+
bool opaque) override {
58+
JniSkiaBaseView::surfaceSizeChanged(surface, width, height, opaque);
5759
}
5860

5961
void surfaceDestroyed() override { JniSkiaBaseView::surfaceDestroyed(); }

β€Žpackages/skia/android/cpp/rnskia-android/MainThreadDispatcher.h

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <android/looper.h>
44
#include <unistd.h>
5+
#include <queue>
56

67
class MainThreadDispatcher {
78
private:
@@ -27,6 +28,10 @@ class MainThreadDispatcher {
2728
return instance;
2829
}
2930

31+
bool isOnMainThread() {
32+
return ALooper_forThread() == mainLooper;
33+
}
34+
3035
void post(std::function<void()> task) {
3136
// TODO: this is disabled for now but we can clean this up
3237
// if (ALooper_forThread() == mainLooper) {

β€Žpackages/skia/android/cpp/rnskia-android/OpenGLContext.h

+31-7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,30 @@
1616

1717
namespace RNSkia {
1818

19+
class OpenGLSharedContext {
20+
public:
21+
OpenGLSharedContext(const OpenGLSharedContext &) = delete;
22+
OpenGLSharedContext &operator=(const OpenGLSharedContext &) = delete;
23+
24+
static OpenGLSharedContext &getInstance() {
25+
static OpenGLSharedContext instance;
26+
return instance;
27+
}
28+
29+
gl::Display* getDisplay() { return _glDisplay.get(); }
30+
gl::Context* getContext() { return _glContext.get(); }
31+
32+
private:
33+
std::unique_ptr<gl::Display> _glDisplay;
34+
std::unique_ptr<gl::Context> _glContext;
35+
36+
OpenGLSharedContext() {
37+
_glDisplay = std::make_unique<gl::Display>();
38+
auto glConfig = _glDisplay->chooseConfig();
39+
_glContext = _glDisplay->makeContext(glConfig, nullptr);
40+
}
41+
};
42+
1943
class OpenGLContext {
2044
public:
2145
friend class OpenGLWindowContext;
@@ -128,24 +152,24 @@ class OpenGLContext {
128152
// TODO: remove width, height
129153
std::unique_ptr<WindowContext> MakeWindow(ANativeWindow *window, int width,
130154
int height) {
155+
auto display = OpenGLSharedContext::getInstance().getDisplay();
131156
return std::make_unique<OpenGLWindowContext>(
132-
_directContext.get(), _glDisplay.get(), _glContext.get(), window);
157+
_directContext.get(), display, _glContext.get(), window);
133158
}
134159

135160
GrDirectContext *getDirectContext() { return _directContext.get(); }
136161

137162
private:
138-
EGLConfig _glConfig;
139-
std::unique_ptr<gl::Display> _glDisplay;
140163
std::unique_ptr<gl::Context> _glContext;
141164
std::unique_ptr<gl::Surface> _glSurface;
142165
sk_sp<GrDirectContext> _directContext;
143166

144167
OpenGLContext() {
145-
_glDisplay = std::make_unique<gl::Display>();
146-
_glConfig = _glDisplay->chooseConfig();
147-
_glContext = _glDisplay->makeContext(_glConfig, nullptr);
148-
_glSurface = _glDisplay->makePixelBufferSurface(_glConfig, 1, 1);
168+
auto display = OpenGLSharedContext::getInstance().getDisplay();
169+
auto sharedContext = OpenGLSharedContext::getInstance().getContext();
170+
auto glConfig = display->chooseConfig();
171+
_glContext = display->makeContext(glConfig, sharedContext);
172+
_glSurface = display->makePixelBufferSurface(glConfig, 1, 1);
149173
_glContext->makeCurrent(_glSurface.get());
150174
auto backendInterface = GrGLMakeNativeInterface();
151175
_directContext = GrDirectContexts::MakeGL(backendInterface);

β€Žpackages/skia/android/cpp/rnskia-android/OpenGLWindowContext.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ sk_sp<SkSurface> OpenGLWindowContext::getSurface() {
5353

5454
void OpenGLWindowContext::present() {
5555
_glContext->makeCurrent(_glSurface.get());
56-
// TODO: is flushAndSubmit needed here?
5756
_directContext->flushAndSubmit();
5857
_glSurface->present();
5958
}

β€Žpackages/skia/android/cpp/rnskia-android/RNSkAndroidView.h

+10-9
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ namespace RNSkia {
1111

1212
class RNSkBaseAndroidView {
1313
public:
14-
virtual void surfaceAvailable(jobject surface, int width, int height) = 0;
14+
virtual void surfaceAvailable(jobject surface, int width, int height,
15+
bool opaque) = 0;
1516

1617
virtual void surfaceDestroyed() = 0;
1718

18-
virtual void surfaceSizeChanged(jobject surface, int width, int height) = 0;
19+
virtual void surfaceSizeChanged(jobject surface, int width, int height,
20+
bool opaque) = 0;
1921

2022
virtual float getPixelDensity() = 0;
2123

@@ -34,12 +36,10 @@ class RNSkAndroidView : public T, public RNSkBaseAndroidView {
3436
std::make_shared<RNSkOpenGLCanvasProvider>(
3537
std::bind(&RNSkia::RNSkView::requestRedraw, this), context)) {}
3638

37-
void surfaceAvailable(jobject surface, int width, int height) override {
39+
void surfaceAvailable(jobject surface, int width, int height,
40+
bool opaque) override {
3841
std::static_pointer_cast<RNSkOpenGLCanvasProvider>(T::getCanvasProvider())
39-
->surfaceAvailable(surface, width, height);
40-
41-
// Try to render directly when the surface has been set so that
42-
// we don't have to wait until the draw loop returns.
42+
->surfaceAvailable(surface, width, height, opaque);
4343
RNSkView::redraw();
4444
}
4545

@@ -48,9 +48,10 @@ class RNSkAndroidView : public T, public RNSkBaseAndroidView {
4848
->surfaceDestroyed();
4949
}
5050

51-
void surfaceSizeChanged(jobject surface, int width, int height) override {
51+
void surfaceSizeChanged(jobject surface, int width, int height,
52+
bool opaque) override {
5253
std::static_pointer_cast<RNSkOpenGLCanvasProvider>(T::getCanvasProvider())
53-
->surfaceSizeChanged(surface, width, height);
54+
->surfaceSizeChanged(surface, width, height, opaque);
5455
// This is only need for the first time to frame, this renderImmediate call
5556
// will invoke updateTexImage for the previous frame
5657
RNSkView::redraw();

0 commit comments

Comments
Β (0)