expo-gl 12.4.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +11 -11
- package/android/build.gradle +8 -10
- package/android/src/main/AndroidManifest.xml +1 -2
- package/android/src/main/cpp/EXGLJniApi.cpp +7 -6
- package/android/src/main/java/expo/modules/gl/GLContext.java +19 -6
- package/android/src/main/java/expo/modules/gl/GLObjectManagerModule.java +1 -1
- package/android/src/main/java/expo/modules/gl/GLView.kt +2 -1
- package/android/src/main/java/expo/modules/gl/GLViewModule.kt +3 -0
- package/android/src/main/java/expo/modules/gl/cpp/EXGL.java +1 -1
- package/build/GLView.d.ts +3 -0
- package/build/GLView.d.ts.map +1 -1
- package/build/GLView.js +23 -4
- package/build/GLView.js.map +1 -1
- package/build/GLView.types.d.ts +5 -0
- package/build/GLView.types.d.ts.map +1 -1
- package/build/GLView.types.js.map +1 -1
- package/build/GLWorkletContextManager.d.ts +6 -0
- package/build/GLWorkletContextManager.d.ts.map +1 -0
- package/build/GLWorkletContextManager.js +37 -0
- package/build/GLWorkletContextManager.js.map +1 -0
- package/common/EXGLContextManager.cpp +33 -8
- package/common/EXGLNativeApi.cpp +12 -2
- package/common/EXGLNativeApi.h +3 -0
- package/common/EXGLNativeContext.cpp +18 -13
- package/common/EXGLNativeContext.h +8 -3
- package/common/EXWebGLRenderer.cpp +1 -8
- package/common/EXWebGLRenderer.h +2 -2
- package/ios/EXGLContext.h +3 -2
- package/ios/EXGLContext.mm +16 -6
- package/ios/EXGLObjectManager.mm +3 -2
- package/ios/EXGLView.h +1 -0
- package/ios/EXGLView.mm +1 -1
- package/ios/GLViewModule.swift +3 -0
- package/package.json +2 -2
- package/src/GLView.tsx +28 -2
- package/src/GLView.types.ts +5 -0
- package/src/GLWorkletContextManager.ts +40 -0
- package/build/GLWorkletContextProvider.d.ts +0 -3
- package/build/GLWorkletContextProvider.d.ts.map +0 -1
- package/build/GLWorkletContextProvider.js +0 -25
- package/build/GLWorkletContextProvider.js.map +0 -1
- package/src/GLWorkletContextProvider.ts +0 -25
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,28 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 13.0.0 — 2023-06-13
|
|
14
|
+
|
|
15
|
+
### 🛠 Breaking changes
|
|
16
|
+
|
|
17
|
+
- Require explicit prop `enableExperimentalWorkletSupport` to use GLView from Reanimated worklet. ([#22613](https://github.com/expo/expo/pull/22613) by [@wkozyra95](https://github.com/wkozyra95))
|
|
18
|
+
|
|
19
|
+
### 🐛 Bug fixes
|
|
20
|
+
|
|
21
|
+
- Fixed Android build warnings for Gradle version 8. ([#22537](https://github.com/expo/expo/pull/22537), [#22609](https://github.com/expo/expo/pull/22609) by [@kudo](https://github.com/kudo))
|
|
22
|
+
- Fix deadlock when creating and destroying GLViews in a quick succession. ([#22484](https://github.com/expo/expo/pull/22484) by [@wkozyra95](https://github.com/wkozyra95))
|
|
23
|
+
- Move creating GL context for worklet to UI thread. ([#22634](https://github.com/expo/expo/pull/22634) by [@wkozyra95](https://github.com/wkozyra95))
|
|
24
|
+
|
|
25
|
+
## 12.5.0 — 2023-05-08
|
|
26
|
+
|
|
27
|
+
### 🐛 Bug fixes
|
|
28
|
+
|
|
29
|
+
- Fixed leaking GL context. ([#21247](https://github.com/expo/expo/pull/21247) by [@wkozyra95](https://github.com/wkozyra95))
|
|
30
|
+
|
|
31
|
+
### 💡 Others
|
|
32
|
+
|
|
33
|
+
- Remove legacy code for old Expo Go. ([#21247](https://github.com/expo/expo/pull/21247) by [@wkozyra95](https://github.com/wkozyra95))
|
|
34
|
+
|
|
13
35
|
## 12.4.0 — 2023-02-14
|
|
14
36
|
|
|
15
37
|
### 🎉 New features
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Provides GLView that acts as OpenGL ES render target and gives GL context object
|
|
|
16
16
|
|
|
17
17
|
# Installation in managed Expo projects
|
|
18
18
|
|
|
19
|
-
For [managed](https://docs.expo.dev/
|
|
19
|
+
For [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](https://docs.expo.dev/versions/latest/sdk/gl-view/).
|
|
20
20
|
|
|
21
21
|
# Installation in bare React Native projects
|
|
22
22
|
|
|
@@ -25,25 +25,25 @@ For bare React Native projects, you must ensure that you have [installed and con
|
|
|
25
25
|
### Add the package to your npm dependencies
|
|
26
26
|
|
|
27
27
|
```
|
|
28
|
-
expo install expo-gl
|
|
28
|
+
npx expo install expo-gl
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
### Compatibility
|
|
32
32
|
|
|
33
33
|
To use version `11.2.0` or newer of `expo-gl` you will need to use at least version `0.68.0` of React Native.
|
|
34
34
|
|
|
35
|
-
| expo-gl | react-native
|
|
36
|
-
| ------------------ |
|
|
37
|
-
| <=8.x.x | \*
|
|
38
|
-
| >=9.0.0 && <11.2.0 | >=0.63.1 &&
|
|
39
|
-
| >=11.2.0 | >=0.68.0
|
|
35
|
+
| expo-gl | react-native |
|
|
36
|
+
| ------------------ | ------------------- |
|
|
37
|
+
| <=8.x.x | \* |
|
|
38
|
+
| >=9.0.0 && <11.2.0 | >=0.63.1 && <0.65.0 |
|
|
39
|
+
| >=11.2.0 | >=0.68.0 |
|
|
40
40
|
|
|
41
41
|
To use reanimated worklets you will need compatible version of `react-native-reanimated`.
|
|
42
42
|
|
|
43
|
-
| expo-gl
|
|
44
|
-
|
|
|
45
|
-
| <11.3.0
|
|
46
|
-
| >=11.3.0
|
|
43
|
+
| expo-gl | react-native-reanimated |
|
|
44
|
+
| -------- | ----------------------- |
|
|
45
|
+
| <11.3.0 | <=2.8.0 |
|
|
46
|
+
| >=11.3.0 | >2.8.0 |
|
|
47
47
|
|
|
48
48
|
### Configure for iOS
|
|
49
49
|
|
package/android/build.gradle
CHANGED
|
@@ -6,7 +6,7 @@ apply plugin: 'maven-publish'
|
|
|
6
6
|
apply plugin: "de.undercouch.download"
|
|
7
7
|
|
|
8
8
|
group = 'host.exp.exponent'
|
|
9
|
-
version = '
|
|
9
|
+
version = '13.0.0'
|
|
10
10
|
|
|
11
11
|
def REACT_NATIVE_BUILD_FROM_SOURCE = findProject(":ReactAndroid") != null
|
|
12
12
|
def REACT_NATIVE_DIR = REACT_NATIVE_BUILD_FROM_SOURCE
|
|
@@ -57,19 +57,11 @@ buildscript {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
// Creating sources with comments
|
|
61
|
-
task androidSourcesJar(type: Jar) {
|
|
62
|
-
classifier = 'sources'
|
|
63
|
-
from android.sourceSets.main.java.srcDirs
|
|
64
|
-
}
|
|
65
|
-
|
|
66
60
|
afterEvaluate {
|
|
67
61
|
publishing {
|
|
68
62
|
publications {
|
|
69
63
|
release(MavenPublication) {
|
|
70
64
|
from components.release
|
|
71
|
-
// Add additional sourcesJar to artifacts
|
|
72
|
-
artifact(androidSourcesJar)
|
|
73
65
|
}
|
|
74
66
|
}
|
|
75
67
|
repositories {
|
|
@@ -99,11 +91,12 @@ android {
|
|
|
99
91
|
jvmTarget = JavaVersion.VERSION_11.majorVersion
|
|
100
92
|
}
|
|
101
93
|
|
|
94
|
+
namespace "expo.modules.gl"
|
|
102
95
|
defaultConfig {
|
|
103
96
|
minSdkVersion safeExtGet("minSdkVersion", 21)
|
|
104
97
|
targetSdkVersion safeExtGet("targetSdkVersion", 33)
|
|
105
98
|
versionCode 31
|
|
106
|
-
versionName "
|
|
99
|
+
versionName "13.0.0"
|
|
107
100
|
|
|
108
101
|
externalNativeBuild {
|
|
109
102
|
cmake {
|
|
@@ -145,6 +138,11 @@ android {
|
|
|
145
138
|
lintOptions {
|
|
146
139
|
abortOnError false
|
|
147
140
|
}
|
|
141
|
+
publishing {
|
|
142
|
+
singleVariant("release") {
|
|
143
|
+
withSourcesJar()
|
|
144
|
+
}
|
|
145
|
+
}
|
|
148
146
|
}
|
|
149
147
|
|
|
150
148
|
repositories {
|
|
@@ -34,6 +34,13 @@ Java_expo_modules_gl_cpp_EXGL_EXGLContextPrepare
|
|
|
34
34
|
EXGLContextPrepare((void*) jsiPtr, exglCtxId, flushMethod);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
JNIEXPORT void JNICALL
|
|
38
|
+
Java_expo_modules_gl_cpp_EXGL_EXGLContextPrepareWorklet
|
|
39
|
+
(JNIEnv *env, jclass clazz, jint exglCtxId) {
|
|
40
|
+
threadLocalEnv = env;
|
|
41
|
+
EXGLContextPrepareWorklet(exglCtxId);
|
|
42
|
+
}
|
|
43
|
+
|
|
37
44
|
JNIEXPORT void JNICALL
|
|
38
45
|
Java_expo_modules_gl_cpp_EXGL_EXGLContextDestroy
|
|
39
46
|
(JNIEnv *env, jclass clazz, jint exglCtxId) {
|
|
@@ -70,12 +77,6 @@ Java_expo_modules_gl_cpp_EXGL_EXGLContextGetObject
|
|
|
70
77
|
return EXGLContextGetObject(exglCtxId, exglObjId);
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
JNIEXPORT void JNICALL
|
|
74
|
-
Java_expo_modules_gl_cpp_EXGL_EXGLRegisterThread
|
|
75
|
-
(JNIEnv *env, jclass clazz) {
|
|
76
|
-
threadLocalEnv = env;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
80
|
JNIEXPORT bool JNICALL
|
|
80
81
|
Java_expo_modules_gl_cpp_EXGL_EXGLContextNeedsRedraw
|
|
81
82
|
(JNIEnv *env, jclass clazz, jint exglCtxId) {
|
|
@@ -32,6 +32,7 @@ import expo.modules.core.Promise;
|
|
|
32
32
|
import expo.modules.core.interfaces.JavaScriptContextProvider;
|
|
33
33
|
import expo.modules.core.interfaces.RuntimeEnvironmentInterface;
|
|
34
34
|
import expo.modules.core.interfaces.services.UIManager;
|
|
35
|
+
import expo.modules.gl.cpp.EXGL;
|
|
35
36
|
import expo.modules.gl.utils.FileSystemUtils;
|
|
36
37
|
|
|
37
38
|
import static android.opengl.GLES30.*;
|
|
@@ -70,13 +71,17 @@ public class GLContext {
|
|
|
70
71
|
mEventQueue.add(r);
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
public void initialize(
|
|
74
|
+
public void initialize(
|
|
75
|
+
SurfaceTexture surfaceTexture,
|
|
76
|
+
Boolean enableExperimentalWorkletSupport,
|
|
77
|
+
final Runnable completionCallback) {
|
|
74
78
|
if (mGLThread != null) {
|
|
75
79
|
return;
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
mGLThread = new GLThread(surfaceTexture);
|
|
79
83
|
mGLThread.start();
|
|
84
|
+
mEXGLCtxId = EXGLContextCreate();
|
|
80
85
|
|
|
81
86
|
// On JS thread, get JavaScriptCore context, create EXGL context, call JS callback
|
|
82
87
|
final GLContext glContext = this;
|
|
@@ -85,20 +90,28 @@ public class GLContext {
|
|
|
85
90
|
final JavaScriptContextProvider jsContextProvider = moduleRegistry.getModule(JavaScriptContextProvider.class);
|
|
86
91
|
final RuntimeEnvironmentInterface environment = moduleRegistry.getModule(RuntimeEnvironmentInterface.class);
|
|
87
92
|
|
|
88
|
-
EXGLRegisterThread();
|
|
89
93
|
uiManager.runOnClientCodeQueueThread(new Runnable() {
|
|
90
94
|
@Override
|
|
91
95
|
public void run() {
|
|
92
96
|
long jsContextRef = jsContextProvider.getJavaScriptContextRef();
|
|
93
97
|
synchronized (uiManager) {
|
|
94
98
|
if (jsContextRef != 0) {
|
|
95
|
-
mEXGLCtxId = EXGLContextCreate();
|
|
96
|
-
EXGLRegisterThread();
|
|
97
99
|
EXGLContextPrepare(jsContextRef, mEXGLCtxId, glContext);
|
|
98
100
|
}
|
|
99
101
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
if (enableExperimentalWorkletSupport) {
|
|
103
|
+
uiManager.runOnUiQueueThread(new Runnable() {
|
|
104
|
+
@Override
|
|
105
|
+
public void run() {
|
|
106
|
+
EXGLContextPrepareWorklet(mEXGLCtxId);
|
|
107
|
+
mManager.saveContext(glContext);
|
|
108
|
+
completionCallback.run();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
mManager.saveContext(glContext);
|
|
113
|
+
completionCallback.run();
|
|
114
|
+
}
|
|
102
115
|
}
|
|
103
116
|
});
|
|
104
117
|
}
|
|
@@ -120,7 +120,7 @@ public class GLObjectManagerModule extends ExportedModule {
|
|
|
120
120
|
public void createContextAsync(final Promise promise) {
|
|
121
121
|
final GLContext glContext = new GLContext(this);
|
|
122
122
|
|
|
123
|
-
glContext.initialize(null, new Runnable() {
|
|
123
|
+
glContext.initialize(null, false, new Runnable() {
|
|
124
124
|
@Override
|
|
125
125
|
public void run() {
|
|
126
126
|
Bundle results = new Bundle();
|
|
@@ -27,6 +27,7 @@ class GLView(context: Context, appContext: AppContext) : TextureView(context), S
|
|
|
27
27
|
private val exglContextId: Int
|
|
28
28
|
get() = glContext.contextId
|
|
29
29
|
|
|
30
|
+
var enableExperimentalWorkletSupport: Boolean = false
|
|
30
31
|
val onSurfaceCreate by EventDispatcher<OnSurfaceCreateRecord>()
|
|
31
32
|
|
|
32
33
|
init {
|
|
@@ -78,7 +79,7 @@ class GLView(context: Context, appContext: AppContext) : TextureView(context), S
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
private fun initializeSurfaceInGLContext(surfaceTexture: SurfaceTexture) {
|
|
81
|
-
glContext.initialize(surfaceTexture) {
|
|
82
|
+
glContext.initialize(surfaceTexture, enableExperimentalWorkletSupport) {
|
|
82
83
|
onSurfaceCreate(OnSurfaceCreateRecord(exglContextId))
|
|
83
84
|
}
|
|
84
85
|
}
|
|
@@ -9,6 +9,9 @@ class GLViewModule : Module() {
|
|
|
9
9
|
|
|
10
10
|
View(GLView::class) {
|
|
11
11
|
Events("onSurfaceCreate")
|
|
12
|
+
Prop("enableExperimentalWorkletSupport") { view: GLView, enableExperimentalWorkletSupport: Boolean? ->
|
|
13
|
+
view.enableExperimentalWorkletSupport = enableExperimentalWorkletSupport ?: false
|
|
14
|
+
}
|
|
12
15
|
}
|
|
13
16
|
}
|
|
14
17
|
}
|
|
@@ -9,6 +9,7 @@ public class EXGL {
|
|
|
9
9
|
}
|
|
10
10
|
public static native int EXGLContextCreate();
|
|
11
11
|
public static native void EXGLContextPrepare(long jsCtxPtr, int exglCtxId, Object glContext);
|
|
12
|
+
public static native void EXGLContextPrepareWorklet(int exglCtxId);
|
|
12
13
|
|
|
13
14
|
public static native void EXGLContextDestroy(int exglCtxId);
|
|
14
15
|
public static native void EXGLContextFlush(int exglCtxId);
|
|
@@ -17,7 +18,6 @@ public class EXGL {
|
|
|
17
18
|
public static native void EXGLContextDestroyObject(int exglCtxId, int exglObjId);
|
|
18
19
|
public static native void EXGLContextMapObject(int exglCtxId, int exglObjId, int glObj);
|
|
19
20
|
public static native int EXGLContextGetObject(int exglCtxId, int exglObjId);
|
|
20
|
-
public static native void EXGLRegisterThread();
|
|
21
21
|
public static native boolean EXGLContextNeedsRedraw(int exglCtxId);
|
|
22
22
|
public static native void EXGLContextDrawEnded(int exglCtxId);
|
|
23
23
|
}
|
package/build/GLView.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare class GLView extends React.Component<GLViewProps> {
|
|
|
11
11
|
static NativeView: any;
|
|
12
12
|
static defaultProps: {
|
|
13
13
|
msaaSamples: number;
|
|
14
|
+
enableExperimentalWorkletSupport: boolean;
|
|
14
15
|
};
|
|
15
16
|
/**
|
|
16
17
|
* Imperative API that creates headless context which is devoid of underlying view.
|
|
@@ -40,6 +41,8 @@ export declare class GLView extends React.Component<GLViewProps> {
|
|
|
40
41
|
render(): JSX.Element;
|
|
41
42
|
_setNativeRef: (nativeRef: ComponentOrHandle) => void;
|
|
42
43
|
_onSurfaceCreate: ({ nativeEvent: { exglCtxId } }: SurfaceCreateEvent) => void;
|
|
44
|
+
componentWillUnmount(): void;
|
|
45
|
+
componentDidUpdate(prevProps: GLViewProps): void;
|
|
43
46
|
startARSessionAsync(): Promise<any>;
|
|
44
47
|
createCameraTextureAsync(cameraRefOrHandle: ComponentOrHandle): Promise<WebGLTexture>;
|
|
45
48
|
destroyObjectAsync(glObject: WebGLObject): Promise<boolean>;
|
package/build/GLView.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GLView.d.ts","sourceRoot":"","sources":["../src/GLView.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,yBAAyB,EACzB,eAAe,EACf,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAIxB,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;
|
|
1
|
+
{"version":3,"file":"GLView.d.ts","sourceRoot":"","sources":["../src/GLView.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,yBAAyB,EACzB,eAAe,EACf,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAIxB,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAUF;;;GAGG;AACH,qBAAa,MAAO,SAAQ,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC;IACtD,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC;IAEvB,MAAM,CAAC,YAAY;;;MAGjB;IAEF;;;;;;;OAOG;WACU,kBAAkB,IAAI,OAAO,CAAC,yBAAyB,CAAC;IAKrE;;;;OAIG;WACU,mBAAmB,CAAC,IAAI,CAAC,EAAE,yBAAyB,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAM7F;;;;;OAKG;WACU,iBAAiB,CAC5B,IAAI,CAAC,EAAE,yBAAyB,GAAG,MAAM,EACzC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,UAAU,CAAC;IAKtB,MAAM,CAAC,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,yBAAyB,GAAG,SAAS,CACnD;IAEnC,SAAS,EAAE,iBAAiB,CAAQ;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,MAAM;IA4BN,aAAa,cAAe,iBAAiB,KAAG,IAAI,CAKlD;IAEF,gBAAgB,mCAAoC,kBAAkB,KAAG,IAAI,CAQ3E;IAEF,oBAAoB,IAAI,IAAI;IAM5B,kBAAkB,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI;IAS1C,mBAAmB,IAAI,OAAO,CAAC,GAAG,CAAC;IAQnC,wBAAwB,CAAC,iBAAiB,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC;IAoBrF,kBAAkB,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAOjE;;;;OAIG;IACG,iBAAiB,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,UAAU,CAAC;CAO5E"}
|
package/build/GLView.js
CHANGED
|
@@ -2,9 +2,10 @@ import { NativeModulesProxy, UnavailabilityError, requireNativeViewManager, Code
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { Platform, View, findNodeHandle } from 'react-native';
|
|
4
4
|
import { configureLogging } from './GLUtils';
|
|
5
|
-
import {
|
|
5
|
+
import { createWorkletContextManager } from './GLWorkletContextManager';
|
|
6
6
|
const { ExponentGLObjectManager, ExponentGLViewManager } = NativeModulesProxy;
|
|
7
7
|
const NativeView = requireNativeViewManager('ExponentGLView');
|
|
8
|
+
const workletContextManager = createWorkletContextManager();
|
|
8
9
|
// @needsAudit
|
|
9
10
|
/**
|
|
10
11
|
* A View that acts as an OpenGL ES render target. On mounting, an OpenGL ES context is created.
|
|
@@ -14,6 +15,7 @@ export class GLView extends React.Component {
|
|
|
14
15
|
static NativeView;
|
|
15
16
|
static defaultProps = {
|
|
16
17
|
msaaSamples: 4,
|
|
18
|
+
enableExperimentalWorkletSupport: false,
|
|
17
19
|
};
|
|
18
20
|
/**
|
|
19
21
|
* Imperative API that creates headless context which is devoid of underlying view.
|
|
@@ -34,6 +36,7 @@ export class GLView extends React.Component {
|
|
|
34
36
|
*/
|
|
35
37
|
static async destroyContextAsync(exgl) {
|
|
36
38
|
const exglCtxId = getContextId(exgl);
|
|
39
|
+
unregisterGLContext(exglCtxId);
|
|
37
40
|
return ExponentGLObjectManager.destroyContextAsync(exglCtxId);
|
|
38
41
|
}
|
|
39
42
|
/**
|
|
@@ -46,12 +49,12 @@ export class GLView extends React.Component {
|
|
|
46
49
|
const exglCtxId = getContextId(exgl);
|
|
47
50
|
return ExponentGLObjectManager.takeSnapshotAsync(exglCtxId, options);
|
|
48
51
|
}
|
|
49
|
-
static getWorkletContext =
|
|
52
|
+
static getWorkletContext = workletContextManager.getContext;
|
|
50
53
|
nativeRef = null;
|
|
51
54
|
exglCtxId;
|
|
52
55
|
render() {
|
|
53
56
|
const { onContextCreate, // eslint-disable-line no-unused-vars
|
|
54
|
-
msaaSamples, ...viewProps } = this.props;
|
|
57
|
+
msaaSamples, enableExperimentalWorkletSupport, ...viewProps } = this.props;
|
|
55
58
|
return (React.createElement(View, { ...viewProps },
|
|
56
59
|
React.createElement(NativeView, { ref: this._setNativeRef, style: {
|
|
57
60
|
flex: 1,
|
|
@@ -60,7 +63,7 @@ export class GLView extends React.Component {
|
|
|
60
63
|
backgroundColor: 'transparent',
|
|
61
64
|
}
|
|
62
65
|
: {}),
|
|
63
|
-
}, onSurfaceCreate: this._onSurfaceCreate, msaaSamples: Platform.OS === 'ios' ? msaaSamples : undefined })));
|
|
66
|
+
}, onSurfaceCreate: this._onSurfaceCreate, enableExperimentalWorkletSupport: enableExperimentalWorkletSupport, msaaSamples: Platform.OS === 'ios' ? msaaSamples : undefined })));
|
|
64
67
|
}
|
|
65
68
|
_setNativeRef = (nativeRef) => {
|
|
66
69
|
if (this.props.nativeRef_EXPERIMENTAL) {
|
|
@@ -75,6 +78,16 @@ export class GLView extends React.Component {
|
|
|
75
78
|
this.props.onContextCreate(gl);
|
|
76
79
|
}
|
|
77
80
|
};
|
|
81
|
+
componentWillUnmount() {
|
|
82
|
+
if (this.exglCtxId) {
|
|
83
|
+
unregisterGLContext(this.exglCtxId);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
componentDidUpdate(prevProps) {
|
|
87
|
+
if (this.props.enableExperimentalWorkletSupport !== prevProps.enableExperimentalWorkletSupport) {
|
|
88
|
+
console.warn('Updating prop enableExperimentalWorkletSupport is not supported');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
78
91
|
// @docsMissing
|
|
79
92
|
async startARSessionAsync() {
|
|
80
93
|
if (!ExponentGLViewManager.startARSessionAsync) {
|
|
@@ -116,6 +129,12 @@ export class GLView extends React.Component {
|
|
|
116
129
|
}
|
|
117
130
|
}
|
|
118
131
|
GLView.NativeView = NativeView;
|
|
132
|
+
function unregisterGLContext(exglCtxId) {
|
|
133
|
+
if (global.__EXGLContexts) {
|
|
134
|
+
delete global.__EXGLContexts[String(exglCtxId)];
|
|
135
|
+
}
|
|
136
|
+
workletContextManager.unregister?.(exglCtxId);
|
|
137
|
+
}
|
|
119
138
|
// Get the GL interface from an EXGLContextId
|
|
120
139
|
const getGl = (exglCtxId) => {
|
|
121
140
|
if (!global.__EXGLContexts) {
|
package/build/GLView.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GLView.js","sourceRoot":"","sources":["../src/GLView.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n NativeModulesProxy,\n UnavailabilityError,\n requireNativeViewManager,\n CodedError,\n} from 'expo-modules-core';\nimport * as React from 'react';\nimport { Platform, View, findNodeHandle } from 'react-native';\n\nimport { configureLogging } from './GLUtils';\nimport {\n ComponentOrHandle,\n SurfaceCreateEvent,\n GLSnapshot,\n ExpoWebGLRenderingContext,\n SnapshotOptions,\n GLViewProps,\n} from './GLView.types';\nimport { createWorkletContextProvider } from './GLWorkletContextProvider';\n\n// @docsMissing\nexport type WebGLObject = {\n id: number;\n};\n\ndeclare let global: any;\n\nconst { ExponentGLObjectManager, ExponentGLViewManager } = NativeModulesProxy;\n\nconst NativeView = requireNativeViewManager('ExponentGLView');\n\n// @needsAudit\n/**\n * A View that acts as an OpenGL ES render target. On mounting, an OpenGL ES context is created.\n * Its drawing buffer is presented as the contents of the View every frame.\n */\nexport class GLView extends React.Component<GLViewProps> {\n static NativeView: any;\n\n static defaultProps = {\n msaaSamples: 4,\n };\n\n /**\n * Imperative API that creates headless context which is devoid of underlying view.\n * It's useful for headless rendering or in case you want to keep just one context per application and share it between multiple components.\n * It is slightly faster than usual context as it doesn't swap framebuffers and doesn't present them on the canvas,\n * however it may require you to take a snapshot in order to present its results.\n * Also, keep in mind that you need to set up a viewport and create your own framebuffer and texture that you will be drawing to, before you take a snapshot.\n * @return A promise that resolves to WebGL context object. See [WebGL API](#webgl-api) for more details.\n */\n static async createContextAsync(): Promise<ExpoWebGLRenderingContext> {\n const { exglCtxId } = await ExponentGLObjectManager.createContextAsync();\n return getGl(exglCtxId);\n }\n\n /**\n * Destroys given context.\n * @param exgl WebGL context to destroy.\n * @return A promise that resolves to boolean value that is `true` if given context existed and has been destroyed successfully.\n */\n static async destroyContextAsync(exgl?: ExpoWebGLRenderingContext | number): Promise<boolean> {\n const exglCtxId = getContextId(exgl);\n return ExponentGLObjectManager.destroyContextAsync(exglCtxId);\n }\n\n /**\n * Takes a snapshot of the framebuffer and saves it as a file to app's cache directory.\n * @param exgl WebGL context to take a snapshot from.\n * @param options\n * @return A promise that resolves to `GLSnapshot` object.\n */\n static async takeSnapshotAsync(\n exgl?: ExpoWebGLRenderingContext | number,\n options: SnapshotOptions = {}\n ): Promise<GLSnapshot> {\n const exglCtxId = getContextId(exgl);\n return ExponentGLObjectManager.takeSnapshotAsync(exglCtxId, options);\n }\n\n static getWorkletContext: (contextId: number) => ExpoWebGLRenderingContext | undefined =\n createWorkletContextProvider();\n\n nativeRef: ComponentOrHandle = null;\n exglCtxId?: number;\n\n render() {\n const {\n onContextCreate, // eslint-disable-line no-unused-vars\n msaaSamples,\n ...viewProps\n } = this.props;\n\n return (\n <View {...viewProps}>\n <NativeView\n ref={this._setNativeRef}\n style={{\n flex: 1,\n ...(Platform.OS === 'ios'\n ? {\n backgroundColor: 'transparent',\n }\n : {}),\n }}\n onSurfaceCreate={this._onSurfaceCreate}\n msaaSamples={Platform.OS === 'ios' ? msaaSamples : undefined}\n />\n </View>\n );\n }\n\n _setNativeRef = (nativeRef: ComponentOrHandle): void => {\n if (this.props.nativeRef_EXPERIMENTAL) {\n this.props.nativeRef_EXPERIMENTAL(nativeRef);\n }\n this.nativeRef = nativeRef;\n };\n\n _onSurfaceCreate = ({ nativeEvent: { exglCtxId } }: SurfaceCreateEvent): void => {\n const gl = getGl(exglCtxId);\n\n this.exglCtxId = exglCtxId;\n\n if (this.props.onContextCreate) {\n this.props.onContextCreate(gl);\n }\n };\n\n // @docsMissing\n async startARSessionAsync(): Promise<any> {\n if (!ExponentGLViewManager.startARSessionAsync) {\n throw new UnavailabilityError('expo-gl', 'startARSessionAsync');\n }\n return await ExponentGLViewManager.startARSessionAsync(findNodeHandle(this.nativeRef));\n }\n\n // @docsMissing\n async createCameraTextureAsync(cameraRefOrHandle: ComponentOrHandle): Promise<WebGLTexture> {\n if (!ExponentGLObjectManager.createCameraTextureAsync) {\n throw new UnavailabilityError('expo-gl', 'createCameraTextureAsync');\n }\n\n const { exglCtxId } = this;\n\n if (!exglCtxId) {\n throw new Error(\"GLView's surface is not created yet!\");\n }\n\n const cameraTag = findNodeHandle(cameraRefOrHandle);\n const { exglObjId } = await ExponentGLObjectManager.createCameraTextureAsync(\n exglCtxId,\n cameraTag\n );\n return { id: exglObjId } as WebGLTexture;\n }\n\n // @docsMissing\n async destroyObjectAsync(glObject: WebGLObject): Promise<boolean> {\n if (!ExponentGLObjectManager.destroyObjectAsync) {\n throw new UnavailabilityError('expo-gl', 'destroyObjectAsync');\n }\n return await ExponentGLObjectManager.destroyObjectAsync(glObject.id);\n }\n\n /**\n * Same as static [`takeSnapshotAsync()`](#glviewtakesnapshotasyncgl-options),\n * but uses WebGL context that is associated with the view on which the method is called.\n * @param options\n */\n async takeSnapshotAsync(options: SnapshotOptions = {}): Promise<GLSnapshot> {\n if (!GLView.takeSnapshotAsync) {\n throw new UnavailabilityError('expo-gl', 'takeSnapshotAsync');\n }\n const { exglCtxId } = this;\n return await GLView.takeSnapshotAsync(exglCtxId, options);\n }\n}\n\nGLView.NativeView = NativeView;\n\n// Get the GL interface from an EXGLContextId\nconst getGl = (exglCtxId: number): ExpoWebGLRenderingContext => {\n if (!global.__EXGLContexts) {\n throw new CodedError(\n 'ERR_GL_NOT_AVAILABLE',\n 'GL is currently not available. (Have you enabled remote debugging? GL is not available while debugging remotely.)'\n );\n }\n const gl = global.__EXGLContexts[String(exglCtxId)];\n\n configureLogging(gl);\n\n return gl;\n};\n\nconst getContextId = (exgl?: ExpoWebGLRenderingContext | number): number => {\n const exglCtxId = exgl && typeof exgl === 'object' ? exgl.contextId : exgl;\n\n if (!exglCtxId || typeof exglCtxId !== 'number') {\n throw new Error(`Invalid EXGLContext id: ${String(exglCtxId)}`);\n }\n return exglCtxId;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"GLView.js","sourceRoot":"","sources":["../src/GLView.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAS7C,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AASxE,MAAM,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,GAAG,kBAAkB,CAAC;AAE9E,MAAM,UAAU,GAAG,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;AAC9D,MAAM,qBAAqB,GAAG,2BAA2B,EAAE,CAAC;AAE5D,cAAc;AACd;;;GAGG;AACH,MAAM,OAAO,MAAO,SAAQ,KAAK,CAAC,SAAsB;IACtD,MAAM,CAAC,UAAU,CAAM;IAEvB,MAAM,CAAC,YAAY,GAAG;QACpB,WAAW,EAAE,CAAC;QACd,gCAAgC,EAAE,KAAK;KACxC,CAAC;IAEF;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,CAAC,kBAAkB;QAC7B,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,uBAAuB,CAAC,kBAAkB,EAAE,CAAC;QACzE,OAAO,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAyC;QACxE,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QACrC,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC/B,OAAO,uBAAuB,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAC5B,IAAyC,EACzC,UAA2B,EAAE;QAE7B,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QACrC,OAAO,uBAAuB,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,CAAC,iBAAiB,GACtB,qBAAqB,CAAC,UAAU,CAAC;IAEnC,SAAS,GAAsB,IAAI,CAAC;IACpC,SAAS,CAAU;IAEnB,MAAM;QACJ,MAAM,EACJ,eAAe,EAAE,qCAAqC;QACtD,WAAW,EACX,gCAAgC,EAChC,GAAG,SAAS,EACb,GAAG,IAAI,CAAC,KAAK,CAAC;QAEf,OAAO,CACL,oBAAC,IAAI,OAAK,SAAS;YACjB,oBAAC,UAAU,IACT,GAAG,EAAE,IAAI,CAAC,aAAa,EACvB,KAAK,EAAE;oBACL,IAAI,EAAE,CAAC;oBACP,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,KAAK;wBACvB,CAAC,CAAC;4BACE,eAAe,EAAE,aAAa;yBAC/B;wBACH,CAAC,CAAC,EAAE,CAAC;iBACR,EACD,eAAe,EAAE,IAAI,CAAC,gBAAgB,EACtC,gCAAgC,EAAE,gCAAgC,EAClE,WAAW,EAAE,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,GAC5D,CACG,CACR,CAAC;IACJ,CAAC;IAED,aAAa,GAAG,CAAC,SAA4B,EAAQ,EAAE;QACrD,IAAI,IAAI,CAAC,KAAK,CAAC,sBAAsB,EAAE;YACrC,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC;SAC9C;QACD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC,CAAC;IAEF,gBAAgB,GAAG,CAAC,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,EAAsB,EAAQ,EAAE;QAC9E,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;QAE5B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAE3B,IAAI,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE;YAC9B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;SAChC;IACH,CAAC,CAAC;IAEF,oBAAoB;QAClB,IAAI,IAAI,CAAC,SAAS,EAAE;YAClB,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;SACrC;IACH,CAAC;IAED,kBAAkB,CAAC,SAAsB;QACvC,IACE,IAAI,CAAC,KAAK,CAAC,gCAAgC,KAAK,SAAS,CAAC,gCAAgC,EAC1F;YACA,OAAO,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;SACjF;IACH,CAAC;IAED,eAAe;IACf,KAAK,CAAC,mBAAmB;QACvB,IAAI,CAAC,qBAAqB,CAAC,mBAAmB,EAAE;YAC9C,MAAM,IAAI,mBAAmB,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAC;SACjE;QACD,OAAO,MAAM,qBAAqB,CAAC,mBAAmB,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IACzF,CAAC;IAED,eAAe;IACf,KAAK,CAAC,wBAAwB,CAAC,iBAAoC;QACjE,IAAI,CAAC,uBAAuB,CAAC,wBAAwB,EAAE;YACrD,MAAM,IAAI,mBAAmB,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC;SACtE;QAED,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAE3B,IAAI,CAAC,SAAS,EAAE;YACd,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;SACzD;QAED,MAAM,SAAS,GAAG,cAAc,CAAC,iBAAiB,CAAC,CAAC;QACpD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,uBAAuB,CAAC,wBAAwB,CAC1E,SAAS,EACT,SAAS,CACV,CAAC;QACF,OAAO,EAAE,EAAE,EAAE,SAAS,EAAkB,CAAC;IAC3C,CAAC;IAED,eAAe;IACf,KAAK,CAAC,kBAAkB,CAAC,QAAqB;QAC5C,IAAI,CAAC,uBAAuB,CAAC,kBAAkB,EAAE;YAC/C,MAAM,IAAI,mBAAmB,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;SAChE;QACD,OAAO,MAAM,uBAAuB,CAAC,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,iBAAiB,CAAC,UAA2B,EAAE;QACnD,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE;YAC7B,MAAM,IAAI,mBAAmB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;SAC/D;QACD,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAC3B,OAAO,MAAM,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;;AAGH,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC;AAE/B,SAAS,mBAAmB,CAAC,SAAiB;IAC5C,IAAI,MAAM,CAAC,cAAc,EAAE;QACzB,OAAO,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;KACjD;IACD,qBAAqB,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,CAAC;AAChD,CAAC;AAED,6CAA6C;AAC7C,MAAM,KAAK,GAAG,CAAC,SAAiB,EAA6B,EAAE;IAC7D,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;QAC1B,MAAM,IAAI,UAAU,CAClB,sBAAsB,EACtB,mHAAmH,CACpH,CAAC;KACH;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IAEpD,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAErB,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,IAAyC,EAAU,EAAE;IACzE,MAAM,SAAS,GAAG,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;IAE3E,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE;QAC/C,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;KACjE;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC","sourcesContent":["import {\n NativeModulesProxy,\n UnavailabilityError,\n requireNativeViewManager,\n CodedError,\n} from 'expo-modules-core';\nimport * as React from 'react';\nimport { Platform, View, findNodeHandle } from 'react-native';\n\nimport { configureLogging } from './GLUtils';\nimport {\n ComponentOrHandle,\n SurfaceCreateEvent,\n GLSnapshot,\n ExpoWebGLRenderingContext,\n SnapshotOptions,\n GLViewProps,\n} from './GLView.types';\nimport { createWorkletContextManager } from './GLWorkletContextManager';\n\n// @docsMissing\nexport type WebGLObject = {\n id: number;\n};\n\ndeclare let global: any;\n\nconst { ExponentGLObjectManager, ExponentGLViewManager } = NativeModulesProxy;\n\nconst NativeView = requireNativeViewManager('ExponentGLView');\nconst workletContextManager = createWorkletContextManager();\n\n// @needsAudit\n/**\n * A View that acts as an OpenGL ES render target. On mounting, an OpenGL ES context is created.\n * Its drawing buffer is presented as the contents of the View every frame.\n */\nexport class GLView extends React.Component<GLViewProps> {\n static NativeView: any;\n\n static defaultProps = {\n msaaSamples: 4,\n enableExperimentalWorkletSupport: false,\n };\n\n /**\n * Imperative API that creates headless context which is devoid of underlying view.\n * It's useful for headless rendering or in case you want to keep just one context per application and share it between multiple components.\n * It is slightly faster than usual context as it doesn't swap framebuffers and doesn't present them on the canvas,\n * however it may require you to take a snapshot in order to present its results.\n * Also, keep in mind that you need to set up a viewport and create your own framebuffer and texture that you will be drawing to, before you take a snapshot.\n * @return A promise that resolves to WebGL context object. See [WebGL API](#webgl-api) for more details.\n */\n static async createContextAsync(): Promise<ExpoWebGLRenderingContext> {\n const { exglCtxId } = await ExponentGLObjectManager.createContextAsync();\n return getGl(exglCtxId);\n }\n\n /**\n * Destroys given context.\n * @param exgl WebGL context to destroy.\n * @return A promise that resolves to boolean value that is `true` if given context existed and has been destroyed successfully.\n */\n static async destroyContextAsync(exgl?: ExpoWebGLRenderingContext | number): Promise<boolean> {\n const exglCtxId = getContextId(exgl);\n unregisterGLContext(exglCtxId);\n return ExponentGLObjectManager.destroyContextAsync(exglCtxId);\n }\n\n /**\n * Takes a snapshot of the framebuffer and saves it as a file to app's cache directory.\n * @param exgl WebGL context to take a snapshot from.\n * @param options\n * @return A promise that resolves to `GLSnapshot` object.\n */\n static async takeSnapshotAsync(\n exgl?: ExpoWebGLRenderingContext | number,\n options: SnapshotOptions = {}\n ): Promise<GLSnapshot> {\n const exglCtxId = getContextId(exgl);\n return ExponentGLObjectManager.takeSnapshotAsync(exglCtxId, options);\n }\n\n static getWorkletContext: (contextId: number) => ExpoWebGLRenderingContext | undefined =\n workletContextManager.getContext;\n\n nativeRef: ComponentOrHandle = null;\n exglCtxId?: number;\n\n render() {\n const {\n onContextCreate, // eslint-disable-line no-unused-vars\n msaaSamples,\n enableExperimentalWorkletSupport,\n ...viewProps\n } = this.props;\n\n return (\n <View {...viewProps}>\n <NativeView\n ref={this._setNativeRef}\n style={{\n flex: 1,\n ...(Platform.OS === 'ios'\n ? {\n backgroundColor: 'transparent',\n }\n : {}),\n }}\n onSurfaceCreate={this._onSurfaceCreate}\n enableExperimentalWorkletSupport={enableExperimentalWorkletSupport}\n msaaSamples={Platform.OS === 'ios' ? msaaSamples : undefined}\n />\n </View>\n );\n }\n\n _setNativeRef = (nativeRef: ComponentOrHandle): void => {\n if (this.props.nativeRef_EXPERIMENTAL) {\n this.props.nativeRef_EXPERIMENTAL(nativeRef);\n }\n this.nativeRef = nativeRef;\n };\n\n _onSurfaceCreate = ({ nativeEvent: { exglCtxId } }: SurfaceCreateEvent): void => {\n const gl = getGl(exglCtxId);\n\n this.exglCtxId = exglCtxId;\n\n if (this.props.onContextCreate) {\n this.props.onContextCreate(gl);\n }\n };\n\n componentWillUnmount(): void {\n if (this.exglCtxId) {\n unregisterGLContext(this.exglCtxId);\n }\n }\n\n componentDidUpdate(prevProps: GLViewProps): void {\n if (\n this.props.enableExperimentalWorkletSupport !== prevProps.enableExperimentalWorkletSupport\n ) {\n console.warn('Updating prop enableExperimentalWorkletSupport is not supported');\n }\n }\n\n // @docsMissing\n async startARSessionAsync(): Promise<any> {\n if (!ExponentGLViewManager.startARSessionAsync) {\n throw new UnavailabilityError('expo-gl', 'startARSessionAsync');\n }\n return await ExponentGLViewManager.startARSessionAsync(findNodeHandle(this.nativeRef));\n }\n\n // @docsMissing\n async createCameraTextureAsync(cameraRefOrHandle: ComponentOrHandle): Promise<WebGLTexture> {\n if (!ExponentGLObjectManager.createCameraTextureAsync) {\n throw new UnavailabilityError('expo-gl', 'createCameraTextureAsync');\n }\n\n const { exglCtxId } = this;\n\n if (!exglCtxId) {\n throw new Error(\"GLView's surface is not created yet!\");\n }\n\n const cameraTag = findNodeHandle(cameraRefOrHandle);\n const { exglObjId } = await ExponentGLObjectManager.createCameraTextureAsync(\n exglCtxId,\n cameraTag\n );\n return { id: exglObjId } as WebGLTexture;\n }\n\n // @docsMissing\n async destroyObjectAsync(glObject: WebGLObject): Promise<boolean> {\n if (!ExponentGLObjectManager.destroyObjectAsync) {\n throw new UnavailabilityError('expo-gl', 'destroyObjectAsync');\n }\n return await ExponentGLObjectManager.destroyObjectAsync(glObject.id);\n }\n\n /**\n * Same as static [`takeSnapshotAsync()`](#glviewtakesnapshotasyncgl-options),\n * but uses WebGL context that is associated with the view on which the method is called.\n * @param options\n */\n async takeSnapshotAsync(options: SnapshotOptions = {}): Promise<GLSnapshot> {\n if (!GLView.takeSnapshotAsync) {\n throw new UnavailabilityError('expo-gl', 'takeSnapshotAsync');\n }\n const { exglCtxId } = this;\n return await GLView.takeSnapshotAsync(exglCtxId, options);\n }\n}\n\nGLView.NativeView = NativeView;\n\nfunction unregisterGLContext(exglCtxId: number) {\n if (global.__EXGLContexts) {\n delete global.__EXGLContexts[String(exglCtxId)];\n }\n workletContextManager.unregister?.(exglCtxId);\n}\n\n// Get the GL interface from an EXGLContextId\nconst getGl = (exglCtxId: number): ExpoWebGLRenderingContext => {\n if (!global.__EXGLContexts) {\n throw new CodedError(\n 'ERR_GL_NOT_AVAILABLE',\n 'GL is currently not available. (Have you enabled remote debugging? GL is not available while debugging remotely.)'\n );\n }\n const gl = global.__EXGLContexts[String(exglCtxId)];\n\n configureLogging(gl);\n\n return gl;\n};\n\nconst getContextId = (exgl?: ExpoWebGLRenderingContext | number): number => {\n const exglCtxId = exgl && typeof exgl === 'object' ? exgl.contextId : exgl;\n\n if (!exglCtxId || typeof exglCtxId !== 'number') {\n throw new Error(`Invalid EXGLContext id: ${String(exglCtxId)}`);\n }\n return exglCtxId;\n};\n"]}
|
package/build/GLView.types.d.ts
CHANGED
|
@@ -78,6 +78,11 @@ export type GLViewProps = {
|
|
|
78
78
|
* @default 4
|
|
79
79
|
*/
|
|
80
80
|
msaaSamples: number;
|
|
81
|
+
/**
|
|
82
|
+
* Enables support for interacting with a `gl` object from code running on the Reanimated worklet thread.
|
|
83
|
+
* @default false
|
|
84
|
+
*/
|
|
85
|
+
enableExperimentalWorkletSupport: boolean;
|
|
81
86
|
/**
|
|
82
87
|
* @hidden
|
|
83
88
|
* A ref callback for the native GLView
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GLView.types.d.ts","sourceRoot":"","sources":["../src/GLView.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAGF,MAAM,MAAM,eAAe,GAAG;IAC5B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B;;OAEG;IACH,IAAI,CAAC,EAAE;QACL,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAGF,MAAM,MAAM,UAAU,GAAG;IACvB;;OAEG;IACH,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF,MAAM,WAAW,yBAA0B,SAAQ,sBAAsB;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,IAAI,IAAI,CAAC;IACpB,QAAQ,IAAI,IAAI,CAAC;IACjB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;CACjD;AAGD,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;AAG1F,MAAM,MAAM,WAAW,GAAG;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,EAAE,yBAAyB,GAAG,IAAI,CAAC;IACrD;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,sBAAsB,CAAC,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,OAAE;CAC7D,GAAG,SAAS,CAAC;AAGd,oBAAY,eAAe;IACzB;;OAEG;IACH,QAAQ,IAAI;IACZ;;OAEG;IACH,YAAY,IAAI;IAChB;;;OAGG;IACH,UAAU,IAAI;IACd;;OAEG;IACH,iBAAiB,IAAI;IACrB;;;OAGG;IACH,gBAAgB,IAAI;IACpB;;OAEG;IACH,GAAG,KAAmE;CACvE"}
|
|
1
|
+
{"version":3,"file":"GLView.types.d.ts","sourceRoot":"","sources":["../src/GLView.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAGF,MAAM,MAAM,eAAe,GAAG;IAC5B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B;;OAEG;IACH,IAAI,CAAC,EAAE;QACL,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAGF,MAAM,MAAM,UAAU,GAAG;IACvB;;OAEG;IACH,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF,MAAM,WAAW,yBAA0B,SAAQ,sBAAsB;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,IAAI,IAAI,CAAC;IACpB,QAAQ,IAAI,IAAI,CAAC;IACjB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;CACjD;AAGD,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;AAG1F,MAAM,MAAM,WAAW,GAAG;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,EAAE,yBAAyB,GAAG,IAAI,CAAC;IACrD;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,gCAAgC,EAAE,OAAO,CAAC;IAC1C;;;OAGG;IACH,sBAAsB,CAAC,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,OAAE;CAC7D,GAAG,SAAS,CAAC;AAGd,oBAAY,eAAe;IACzB;;OAEG;IACH,QAAQ,IAAI;IACZ;;OAEG;IACH,YAAY,IAAI;IAChB;;;OAGG;IACH,UAAU,IAAI;IACd;;OAEG;IACH,iBAAiB,IAAI;IACrB;;;OAGG;IACH,gBAAgB,IAAI;IACpB;;OAEG;IACH,GAAG,KAAmE;CACvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GLView.types.js","sourceRoot":"","sources":["../src/GLView.types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GLView.types.js","sourceRoot":"","sources":["../src/GLView.types.ts"],"names":[],"mappings":"AAwGA,cAAc;AACd,MAAM,CAAN,IAAY,eA2BX;AA3BD,WAAY,eAAe;IACzB;;OAEG;IACH,6DAAY,CAAA;IACZ;;OAEG;IACH,qEAAgB,CAAA;IAChB;;;OAGG;IACH,iEAAc,CAAA;IACd;;OAEG;IACH,+EAAqB,CAAA;IACrB;;;OAGG;IACH,6EAAoB,CAAA;IACpB;;OAEG;IACH,oDAAsE,CAAA;AACxE,CAAC,EA3BW,eAAe,KAAf,eAAe,QA2B1B","sourcesContent":["import { Component, ComponentClass } from 'react';\nimport { ViewProps } from 'react-native';\n\n// @docsMissing\nexport type SurfaceCreateEvent = {\n nativeEvent: {\n exglCtxId: number;\n };\n};\n\n// @needsAudit\nexport type SnapshotOptions = {\n /**\n * Whether to flip the snapshot vertically.\n * @default false\n */\n flip?: boolean;\n /**\n * Specify the framebuffer that we will be reading from.\n * Defaults to underlying framebuffer that is presented in the view or the current framebuffer if context is headless.\n */\n framebuffer?: WebGLFramebuffer;\n /**\n * Rect to crop the snapshot. It's passed directly to `glReadPixels`.\n */\n rect?: {\n x: number;\n y: number;\n width: number;\n height: number;\n };\n /**\n * Specifies what type of compression should be used and what is the result file extension.\n * PNG compression is lossless but slower, JPEG is faster but the image has visible artifacts.\n * > **Note:** When using WebP format, the iOS version will print a warning, and generate a `'png'` file instead.\n * > It is recommendable to use platform dependant code in this case. You can refer to the [documentation on platform specific code](/versions/latest/react-native/platform-specific-code).\n * @default 'jpeg'\n */\n format?: 'jpeg' | 'png' | 'webp';\n /**\n * A value in range `0` to `1.0` specifying compression level of the result image.\n * `1.0` means no compression and `0` the highest compression.\n * @default 1.0\n */\n compress?: number;\n};\n\n// @needsAudit\nexport type GLSnapshot = {\n /**\n * URI to the snapshot.\n */\n uri: string | Blob | null;\n /**\n * Synonym for `uri`. Makes snapshot object compatible with `texImage2D`.\n */\n localUri: string;\n /**\n * Width of the snapshot.\n */\n width: number;\n /**\n * Height of the snapshot.\n */\n height: number;\n};\n\n// @docsMissing\nexport interface ExpoWebGLRenderingContext extends WebGL2RenderingContext {\n contextId: number;\n endFrameEXP(): void;\n flushEXP(): void;\n __expoSetLogging(option: GLLoggingOption): void;\n}\n\n// @docsMissing\nexport type ComponentOrHandle = null | number | Component<any, any> | ComponentClass<any>;\n\n// @needsAudit\nexport type GLViewProps = {\n /**\n * A function that will be called when the OpenGL ES context is created.\n * The function is passed a single argument `gl` that extends a [WebGLRenderingContext](https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14) interface.\n */\n onContextCreate(gl: ExpoWebGLRenderingContext): void;\n /**\n * `GLView` can enable iOS's built-in [multisampling](https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_framebuffer_multisample.txt).\n * This prop specifies the number of samples to use. Setting this to `0` turns off multisampling.\n * @platform ios\n * @default 4\n */\n msaaSamples: number;\n /**\n * Enables support for interacting with a `gl` object from code running on the Reanimated worklet thread.\n * @default false\n */\n enableExperimentalWorkletSupport: boolean;\n /**\n * @hidden\n * A ref callback for the native GLView\n */\n nativeRef_EXPERIMENTAL?(callback: ComponentOrHandle | null);\n} & ViewProps;\n\n// @needsAudit\nexport enum GLLoggingOption {\n /**\n * Disables logging entirely.\n */\n DISABLED = 0,\n /**\n * Logs method calls, their parameters and results.\n */\n METHOD_CALLS = 1,\n /**\n * Calls `gl.getError()` after each other method call and prints an error if any is returned.\n * This option has a significant impact on the performance as this method is blocking.\n */\n GET_ERRORS = 2,\n /**\n * Resolves parameters of type `number` to their constant names.\n */\n RESOLVE_CONSTANTS = 4,\n /**\n * When this option is enabled, long strings will be truncated.\n * It's useful if your shaders are really big and logging them significantly reduces performance.\n */\n TRUNCATE_STRINGS = 8,\n /**\n * Enables all other options. It implies `GET_ERRORS` so be aware of the slowdown.\n */\n ALL = METHOD_CALLS | GET_ERRORS | RESOLVE_CONSTANTS | TRUNCATE_STRINGS,\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ExpoWebGLRenderingContext } from './GLView.types';
|
|
2
|
+
export declare function createWorkletContextManager(): {
|
|
3
|
+
getContext: (contextId: number) => ExpoWebGLRenderingContext | undefined;
|
|
4
|
+
unregister?: (contextId: number) => void;
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=GLWorkletContextManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GLWorkletContextManager.d.ts","sourceRoot":"","sources":["../src/GLWorkletContextManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAU3D,wBAAgB,2BAA2B,IAAI;IAC7C,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,yBAAyB,GAAG,SAAS,CAAC;IACzE,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C,CA0BA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// This method needs to be in a separate file because react-native-reanimated
|
|
2
|
+
// import wrapped in try catch does not work correctly with inlineRequires option
|
|
3
|
+
// in metro.config.js
|
|
4
|
+
//
|
|
5
|
+
// It looks like in generated bundle "react-native-reanimated" is not present
|
|
6
|
+
// in _dependencyMap, but references to it count it as if it was, e.g. bundle contains
|
|
7
|
+
// a line "(0, _$$_REQUIRE(_dependencyMap[15], "./GLUtils").configureLogging)(gl);"
|
|
8
|
+
// but dependencyMap contains only 15 elements
|
|
9
|
+
export function createWorkletContextManager() {
|
|
10
|
+
try {
|
|
11
|
+
// reanimated needs to be imported before any workletized code
|
|
12
|
+
// is created, but we don't want to make it dependency on expo-gl.
|
|
13
|
+
const { runOnUI } = require('react-native-reanimated');
|
|
14
|
+
return {
|
|
15
|
+
getContext: (contextId) => {
|
|
16
|
+
'worklet';
|
|
17
|
+
return global.__EXGLContexts?.[String(contextId)];
|
|
18
|
+
},
|
|
19
|
+
unregister: (contextId) => {
|
|
20
|
+
runOnUI((contextId) => {
|
|
21
|
+
'worklet';
|
|
22
|
+
if (global.__EXGLContexts) {
|
|
23
|
+
delete global.__EXGLContexts[String(contextId)];
|
|
24
|
+
}
|
|
25
|
+
})(contextId);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return {
|
|
31
|
+
getContext: () => {
|
|
32
|
+
throw new Error('Worklet runtime is not available');
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=GLWorkletContextManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GLWorkletContextManager.js","sourceRoot":"","sources":["../src/GLWorkletContextManager.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,iFAAiF;AACjF,qBAAqB;AACrB,EAAE;AACF,6EAA6E;AAC7E,sFAAsF;AACtF,mFAAmF;AACnF,8CAA8C;AAC9C,MAAM,UAAU,2BAA2B;IAIzC,IAAI;QACF,8DAA8D;QAC9D,kEAAkE;QAClE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;QACvD,OAAO;YACL,UAAU,EAAE,CAAC,SAAiB,EAAyC,EAAE;gBACvE,SAAS,CAAC;gBACV,OAAO,MAAM,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;YACpD,CAAC;YACD,UAAU,EAAE,CAAC,SAAiB,EAAQ,EAAE;gBACtC,OAAO,CAAC,CAAC,SAAiB,EAAE,EAAE;oBAC5B,SAAS,CAAC;oBACV,IAAI,MAAM,CAAC,cAAc,EAAE;wBACzB,OAAO,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;qBACjD;gBACH,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAChB,CAAC;SACF,CAAC;KACH;IAAC,MAAM;QACN,OAAO;YACL,UAAU,EAAE,GAAG,EAAE;gBACf,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;YACtD,CAAC;SACF,CAAC;KACH;AACH,CAAC","sourcesContent":["import { ExpoWebGLRenderingContext } from './GLView.types';\n\n// This method needs to be in a separate file because react-native-reanimated\n// import wrapped in try catch does not work correctly with inlineRequires option\n// in metro.config.js\n//\n// It looks like in generated bundle \"react-native-reanimated\" is not present\n// in _dependencyMap, but references to it count it as if it was, e.g. bundle contains\n// a line \"(0, _$$_REQUIRE(_dependencyMap[15], \"./GLUtils\").configureLogging)(gl);\"\n// but dependencyMap contains only 15 elements\nexport function createWorkletContextManager(): {\n getContext: (contextId: number) => ExpoWebGLRenderingContext | undefined;\n unregister?: (contextId: number) => void;\n} {\n try {\n // reanimated needs to be imported before any workletized code\n // is created, but we don't want to make it dependency on expo-gl.\n const { runOnUI } = require('react-native-reanimated');\n return {\n getContext: (contextId: number): ExpoWebGLRenderingContext | undefined => {\n 'worklet';\n return global.__EXGLContexts?.[String(contextId)];\n },\n unregister: (contextId: number): void => {\n runOnUI((contextId: number) => {\n 'worklet';\n if (global.__EXGLContexts) {\n delete global.__EXGLContexts[String(contextId)];\n }\n })(contextId);\n },\n };\n } catch {\n return {\n getContext: () => {\n throw new Error('Worklet runtime is not available');\n },\n };\n }\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "EXGLContextManager.h"
|
|
2
|
+
#include <mutex>
|
|
2
3
|
|
|
3
4
|
namespace expo {
|
|
4
5
|
namespace gl_cpp {
|
|
@@ -10,14 +11,32 @@ struct ContextState {
|
|
|
10
11
|
|
|
11
12
|
struct ContextManager {
|
|
12
13
|
std::unordered_map<EXGLContextId, ContextState> contextMap;
|
|
13
|
-
std::
|
|
14
|
+
std::shared_mutex contextLookupMutex;
|
|
14
15
|
EXGLContextId nextId = 1;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
ContextManager manager;
|
|
18
19
|
|
|
20
|
+
// When multiple threads are attempting to establish shared and unique locks on a mutex
|
|
21
|
+
// we can reach a situation where an unique lock gets priority to run first, but waits
|
|
22
|
+
// for existing shared locks to be released, while no new shared locks can be acquired.
|
|
23
|
+
//
|
|
24
|
+
// When we run ContextPrepare we hold a shared lock, but we also trigger flush on
|
|
25
|
+
// a different thread which also needs to hold a shared lock. This situation can lead
|
|
26
|
+
// to deadlock if unique lock have a priority and flush can never start.
|
|
27
|
+
//
|
|
28
|
+
// This solution resolves an issue, but introduces a risk that uniqe lock will never
|
|
29
|
+
// be establish, but given the use-case that should never happen.
|
|
30
|
+
std::unique_lock<std::shared_mutex> getUniqueLockSafely(std::shared_mutex &mutex) {
|
|
31
|
+
std::unique_lock lock(mutex, std::defer_lock);
|
|
32
|
+
while (!lock.try_lock()) {
|
|
33
|
+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
34
|
+
}
|
|
35
|
+
return lock;
|
|
36
|
+
}
|
|
37
|
+
|
|
19
38
|
ContextWithLock ContextGet(EXGLContextId id) {
|
|
20
|
-
std::
|
|
39
|
+
std::shared_lock lock(manager.contextLookupMutex);
|
|
21
40
|
auto iter = manager.contextMap.find(id);
|
|
22
41
|
// if ctx is null then destroy is in progress
|
|
23
42
|
if (iter == manager.contextMap.end() || iter->second.ctx == nullptr) {
|
|
@@ -33,7 +52,7 @@ EXGLContextId ContextCreate() {
|
|
|
33
52
|
return 0;
|
|
34
53
|
}
|
|
35
54
|
|
|
36
|
-
std::
|
|
55
|
+
std::unique_lock lock = getUniqueLockSafely(manager.contextLookupMutex);
|
|
37
56
|
EXGLContextId ctxId = manager.nextId++;
|
|
38
57
|
if (manager.contextMap.find(ctxId) != manager.contextMap.end()) {
|
|
39
58
|
EXGLSysLog("Tried to reuse an EXGLContext id. This shouldn't really happen...");
|
|
@@ -44,14 +63,20 @@ EXGLContextId ContextCreate() {
|
|
|
44
63
|
}
|
|
45
64
|
|
|
46
65
|
void ContextDestroy(EXGLContextId id) {
|
|
47
|
-
|
|
66
|
+
{
|
|
67
|
+
std::shared_lock lock(manager.contextLookupMutex);
|
|
48
68
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
std::unique_lock lock(iter->second.mutex);
|
|
69
|
+
auto iter = manager.contextMap.find(id);
|
|
70
|
+
if (iter != manager.contextMap.end()) {
|
|
71
|
+
std::unique_lock lock = getUniqueLockSafely(iter->second.mutex);
|
|
53
72
|
delete iter->second.ctx;
|
|
73
|
+
iter->second.ctx = nullptr;
|
|
54
74
|
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
std::unique_lock lock = getUniqueLockSafely(manager.contextLookupMutex);
|
|
78
|
+
auto iter = manager.contextMap.find(id);
|
|
79
|
+
if (iter != manager.contextMap.end()) {
|
|
55
80
|
manager.contextMap.erase(iter);
|
|
56
81
|
}
|
|
57
82
|
}
|
package/common/EXGLNativeApi.cpp
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#include "EXGLNativeApi.h"
|
|
2
|
-
#include "EXGLNativeContext.h"
|
|
3
2
|
#include "EXGLContextManager.h"
|
|
3
|
+
#include "EXGLNativeContext.h"
|
|
4
4
|
|
|
5
5
|
using namespace expo::gl_cpp;
|
|
6
6
|
|
|
@@ -8,13 +8,23 @@ EXGLContextId EXGLContextCreate() {
|
|
|
8
8
|
return ContextCreate();
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
void EXGLContextPrepare(
|
|
11
|
+
void EXGLContextPrepare(
|
|
12
|
+
void *jsiPtr,
|
|
13
|
+
EXGLContextId exglCtxId,
|
|
14
|
+
std::function<void(void)> flushMethod) {
|
|
12
15
|
auto [exglCtx, lock] = ContextGet(exglCtxId);
|
|
13
16
|
if (exglCtx) {
|
|
14
17
|
exglCtx->prepareContext(*reinterpret_cast<jsi::Runtime *>(jsiPtr), flushMethod);
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
void EXGLContextPrepareWorklet(EXGLContextId exglCtxId) {
|
|
22
|
+
auto [exglCtx, lock] = ContextGet(exglCtxId);
|
|
23
|
+
if (exglCtx) {
|
|
24
|
+
exglCtx->prepareWorkletContext();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
bool EXGLContextNeedsRedraw(EXGLContextId exglCtxId) {
|
|
19
29
|
auto [exglCtx, lock] = ContextGet(exglCtxId);
|
|
20
30
|
if (exglCtx) {
|
package/common/EXGLNativeApi.h
CHANGED
|
@@ -35,6 +35,9 @@ EXGLContextId EXGLContextCreate();
|
|
|
35
35
|
void EXGLContextPrepare(void *runtime, EXGLContextId exglCtxId, std::function<void(void)> flushMethod);
|
|
36
36
|
#endif // __cplusplus
|
|
37
37
|
|
|
38
|
+
// [UI thread] Creates an EXGL context inside Reanimated worklet.
|
|
39
|
+
void EXGLContextPrepareWorklet(EXGLContextId exglCtxId);
|
|
40
|
+
|
|
38
41
|
// [Any thread] Check whether we should redraw the surface
|
|
39
42
|
bool EXGLContextNeedsRedraw(EXGLContextId exglCtxId);
|
|
40
43
|
|
|
@@ -9,17 +9,17 @@ constexpr const char *OnJSRuntimeDestroyPropertyName = "__EXGLOnJsRuntimeDestroy
|
|
|
9
9
|
void EXGLContext::prepareContext(jsi::Runtime &runtime, std::function<void(void)> flushMethod) {
|
|
10
10
|
this->flushOnGLThread = flushMethod;
|
|
11
11
|
try {
|
|
12
|
-
|
|
13
|
-
createWebGLRenderer(runtime, this,
|
|
12
|
+
this->initialGlesContext = prepareOpenGLESContext();
|
|
13
|
+
createWebGLRenderer(runtime, this, this->initialGlesContext, runtime.global());
|
|
14
14
|
tryRegisterOnJSRuntimeDestroy(runtime);
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
maybeResolveWorkletContext(runtime);
|
|
17
17
|
} catch (const std::runtime_error &err) {
|
|
18
18
|
EXGLSysLog("Failed to setup EXGLContext [%s]", err.what());
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
void EXGLContext::
|
|
22
|
+
void EXGLContext::maybeResolveWorkletContext(jsi::Runtime &runtime) {
|
|
23
23
|
jsi::Value workletRuntimeValue = runtime.global().getProperty(runtime, "_WORKLET_RUNTIME");
|
|
24
24
|
if (!workletRuntimeValue.isObject()) {
|
|
25
25
|
return;
|
|
@@ -34,14 +34,19 @@ void EXGLContext::maybePrepareWorkletContext(jsi::Runtime &runtime, initGlesCont
|
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
uintptr_t rawWorkletRuntimePointer =
|
|
37
|
-
*reinterpret_cast<uintptr_t*>(workletRuntimeArrayBuffer.data(runtime));
|
|
38
|
-
jsi::Runtime
|
|
37
|
+
*reinterpret_cast<uintptr_t *>(workletRuntimeArrayBuffer.data(runtime));
|
|
38
|
+
jsi::Runtime *workletRuntime = reinterpret_cast<jsi::Runtime *>(rawWorkletRuntimePointer);
|
|
39
|
+
this->maybeWorkletRuntime = workletRuntime;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
void EXGLContext::prepareWorkletContext() {
|
|
43
|
+
if (maybeWorkletRuntime == nullptr) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
jsi::Runtime &runtime = *this->maybeWorkletRuntime;
|
|
39
47
|
createWebGLRenderer(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
viewport,
|
|
43
|
-
workletRuntime.global().getPropertyAsObject(workletRuntime, "global"));
|
|
44
|
-
tryRegisterOnJSRuntimeDestroy(workletRuntime);
|
|
48
|
+
runtime, this, initialGlesContext, runtime.global().getPropertyAsObject(runtime, "global"));
|
|
49
|
+
tryRegisterOnJSRuntimeDestroy(runtime);
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
void EXGLContext::endNextBatch() noexcept {
|
|
@@ -129,8 +134,8 @@ void EXGLContext::tryRegisterOnJSRuntimeDestroy(jsi::Runtime &runtime) {
|
|
|
129
134
|
runtime, std::make_shared<InvalidateCacheOnDestroy>(runtime)));
|
|
130
135
|
}
|
|
131
136
|
|
|
132
|
-
|
|
133
|
-
|
|
137
|
+
glesContext EXGLContext::prepareOpenGLESContext() {
|
|
138
|
+
glesContext result;
|
|
134
139
|
// Clear everything to initial values
|
|
135
140
|
addBlockingToNextBatch([&] {
|
|
136
141
|
std::string version = reinterpret_cast<const char *>(glGetString(GL_VERSION));
|
|
@@ -49,9 +49,10 @@ class EXGLContext {
|
|
|
49
49
|
using Batch = std::vector<Op>;
|
|
50
50
|
|
|
51
51
|
public:
|
|
52
|
-
EXGLContext(EXGLContextId ctxId): ctxId(ctxId) {}
|
|
52
|
+
EXGLContext(EXGLContextId ctxId) : ctxId(ctxId) {}
|
|
53
53
|
void prepareContext(jsi::Runtime &runtime, std::function<void(void)> flushMethod);
|
|
54
|
-
void
|
|
54
|
+
void maybeResolveWorkletContext(jsi::Runtime &runtime);
|
|
55
|
+
void prepareWorkletContext();
|
|
55
56
|
|
|
56
57
|
// --- Queue handling --------------------------------------------------------
|
|
57
58
|
|
|
@@ -106,7 +107,7 @@ class EXGLContext {
|
|
|
106
107
|
GLuint lookupObject(EXGLObjectId exglObjId) noexcept;
|
|
107
108
|
|
|
108
109
|
void tryRegisterOnJSRuntimeDestroy(jsi::Runtime &runtime);
|
|
109
|
-
|
|
110
|
+
glesContext prepareOpenGLESContext();
|
|
110
111
|
void maybeReadAndCacheSupportedExtensions();
|
|
111
112
|
|
|
112
113
|
private:
|
|
@@ -117,6 +118,10 @@ class EXGLContext {
|
|
|
117
118
|
|
|
118
119
|
public:
|
|
119
120
|
EXGLContextId ctxId;
|
|
121
|
+
// Worklet runtime is stored here only to avoid it passing through Java/Obj-C.
|
|
122
|
+
// It should only be used in prepareContext and prepareWorkletContext.
|
|
123
|
+
jsi::Runtime *maybeWorkletRuntime = nullptr;
|
|
124
|
+
glesContext initialGlesContext;
|
|
120
125
|
|
|
121
126
|
// Object mapping
|
|
122
127
|
std::unordered_map<EXGLObjectId, GLuint> objects;
|
|
@@ -37,7 +37,7 @@ void installConstants(jsi::Runtime &runtime, jsi::Object &gl);
|
|
|
37
37
|
void installWebGLMethods(jsi::Runtime &runtime, jsi::Object &gl);
|
|
38
38
|
void installWebGL2Methods(jsi::Runtime &runtime, jsi::Object &gl);
|
|
39
39
|
|
|
40
|
-
void createWebGLRenderer(jsi::Runtime &runtime, EXGLContext *ctx,
|
|
40
|
+
void createWebGLRenderer(jsi::Runtime &runtime, EXGLContext *ctx, glesContext viewport, jsi::Object&& global) {
|
|
41
41
|
ensurePrototypes(runtime);
|
|
42
42
|
jsi::Object gl = ctx->supportsWebGL2
|
|
43
43
|
? createWebGLObject(
|
|
@@ -52,13 +52,6 @@ void createWebGLRenderer(jsi::Runtime &runtime, EXGLContext *ctx, initGlesContex
|
|
|
52
52
|
gl.setProperty(runtime, "supportsWebGL2", ctx->supportsWebGL2);
|
|
53
53
|
gl.setProperty(runtime, "contextId", static_cast<double>(ctx->ctxId));
|
|
54
54
|
|
|
55
|
-
// Legacy case for older SDKs in Expo Go
|
|
56
|
-
bool legacyJs = !runtime.global().getProperty(runtime, "__EXGLConstructorReady").isBool();
|
|
57
|
-
if (legacyJs) {
|
|
58
|
-
installConstants(runtime, gl);
|
|
59
|
-
ctx->supportsWebGL2 ? installWebGL2Methods(runtime, gl) : installWebGLMethods(runtime, gl);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
55
|
jsi::Value jsContextMap = global.getProperty(runtime, EXGLContextsMapPropertyName);
|
|
63
56
|
if (jsContextMap.isNull() || jsContextMap.isUndefined()) {
|
|
64
57
|
global.setProperty(runtime, EXGLContextsMapPropertyName, jsi::Object(runtime));
|
package/common/EXWebGLRenderer.h
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
namespace expo {
|
|
8
8
|
namespace gl_cpp {
|
|
9
9
|
|
|
10
|
-
struct
|
|
10
|
+
struct glesContext {
|
|
11
11
|
int32_t viewportWidth;
|
|
12
12
|
int32_t viewportHeight;
|
|
13
13
|
};
|
|
@@ -37,7 +37,7 @@ enum class EXWebGLClass {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
void ensurePrototypes(jsi::Runtime &runtime);
|
|
40
|
-
void createWebGLRenderer(jsi::Runtime &runtime, EXGLContext *,
|
|
40
|
+
void createWebGLRenderer(jsi::Runtime &runtime, EXGLContext *, glesContext, jsi::Object&& global);
|
|
41
41
|
jsi::Value createWebGLObject(
|
|
42
42
|
jsi::Runtime &runtime,
|
|
43
43
|
EXWebGLClass webglClass,
|
package/ios/EXGLContext.h
CHANGED
|
@@ -17,9 +17,10 @@
|
|
|
17
17
|
|
|
18
18
|
@interface EXGLContext : NSObject
|
|
19
19
|
|
|
20
|
-
- (nullable instancetype)initWithDelegate:(nullable id<EXGLContextDelegate>)delegate
|
|
20
|
+
- (nullable instancetype)initWithDelegate:(nullable id<EXGLContextDelegate>)delegate
|
|
21
|
+
andModuleRegistry:(nonnull EXModuleRegistry *)moduleRegistry;
|
|
21
22
|
- (void)initialize;
|
|
22
|
-
- (void)prepare:(nullable void(^)(BOOL))callback;
|
|
23
|
+
- (void)prepare:(nullable void(^)(BOOL))callback andEnableExperimentalWorkletSupport:(BOOL)enableExperimentalWorkletSupport;
|
|
23
24
|
- (BOOL)isInitialized;
|
|
24
25
|
- (nullable EAGLContext *)createSharedEAGLContext;
|
|
25
26
|
- (void)runAsync:(nonnull void(^)(void))callback;
|
package/ios/EXGLContext.mm
CHANGED
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
|
|
27
27
|
@implementation EXGLContext
|
|
28
28
|
|
|
29
|
-
- (instancetype)initWithDelegate:(id<EXGLContextDelegate>)delegate
|
|
29
|
+
- (instancetype)initWithDelegate:(id<EXGLContextDelegate>)delegate
|
|
30
|
+
andModuleRegistry:(nonnull EXModuleRegistry *)moduleRegistry
|
|
30
31
|
{
|
|
31
32
|
if (self = [super init]) {
|
|
32
33
|
self.delegate = delegate;
|
|
@@ -98,7 +99,7 @@
|
|
|
98
99
|
[self flush];
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
- (void)prepare:(void(^)(BOOL))callback
|
|
102
|
+
- (void)prepare:(void(^)(BOOL))callback andEnableExperimentalWorkletSupport:(BOOL)enableExperimentalWorkletSupport
|
|
102
103
|
{
|
|
103
104
|
if (_wasPrepareCalled) {
|
|
104
105
|
return;
|
|
@@ -127,7 +128,13 @@
|
|
|
127
128
|
[self flush];
|
|
128
129
|
});
|
|
129
130
|
|
|
131
|
+
if (enableExperimentalWorkletSupport) {
|
|
132
|
+
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
133
|
+
EXGLContextPrepareWorklet(self->_contextId);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
130
136
|
_isContextReady = YES;
|
|
137
|
+
|
|
131
138
|
if ([self.delegate respondsToSelector:@selector(glContextInitialized:)]) {
|
|
132
139
|
[self.delegate glContextInitialized:self];
|
|
133
140
|
}
|
|
@@ -167,11 +174,14 @@
|
|
|
167
174
|
// Flush all the stuff
|
|
168
175
|
EXGLContextFlush(self->_contextId);
|
|
169
176
|
|
|
170
|
-
|
|
171
|
-
|
|
177
|
+
id<EXUIManager> uiManager = [_moduleRegistry getModuleImplementingProtocol:@protocol(EXUIManager)];
|
|
178
|
+
[uiManager dispatchOnClientThread:^{
|
|
179
|
+
// Destroy JS binding
|
|
180
|
+
EXGLContextDestroy(self->_contextId);
|
|
172
181
|
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
// Remove from dictionary of contexts
|
|
183
|
+
[self->_objectManager deleteContextWithId:@(self->_contextId)];
|
|
184
|
+
}];
|
|
175
185
|
}];
|
|
176
186
|
}
|
|
177
187
|
|
package/ios/EXGLObjectManager.mm
CHANGED
|
@@ -96,7 +96,8 @@ EX_EXPORT_METHOD_AS(createContextAsync,
|
|
|
96
96
|
createContext:(EXPromiseResolveBlock)resolve
|
|
97
97
|
reject:(EXPromiseRejectBlock)reject)
|
|
98
98
|
{
|
|
99
|
-
EXGLContext *glContext = [[EXGLContext alloc] initWithDelegate:nil
|
|
99
|
+
EXGLContext *glContext = [[EXGLContext alloc] initWithDelegate:nil
|
|
100
|
+
andModuleRegistry:_moduleRegistry];
|
|
100
101
|
|
|
101
102
|
[glContext initialize];
|
|
102
103
|
[glContext prepare:^(BOOL success) {
|
|
@@ -109,7 +110,7 @@ EX_EXPORT_METHOD_AS(createContextAsync,
|
|
|
109
110
|
EXErrorWithMessage(@"ExponentGLObjectManager.createContextAsync: Unexpected error occurred when initializing headless context")
|
|
110
111
|
);
|
|
111
112
|
}
|
|
112
|
-
}];
|
|
113
|
+
} andEnableExperimentalWorkletSupport:NO];
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
EX_EXPORT_METHOD_AS(destroyContextAsync,
|
package/ios/EXGLView.h
CHANGED
|
@@ -17,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
17
17
|
|
|
18
18
|
@property (nonatomic, copy, nullable) EXDirectEventBlock onSurfaceCreate;
|
|
19
19
|
@property (nonatomic, assign) NSInteger msaaSamples;
|
|
20
|
+
@property (nonatomic, assign) BOOL enableExperimentalWorkletSupport;
|
|
20
21
|
|
|
21
22
|
// "protected"
|
|
22
23
|
@property (nonatomic, strong, nullable) EXGLContext *glContext;
|
package/ios/EXGLView.mm
CHANGED
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
height:self.contentScaleFactor * self.frame.size.height];
|
|
99
99
|
|
|
100
100
|
_isLayouted = YES;
|
|
101
|
-
[_glContext prepare:nil];
|
|
101
|
+
[_glContext prepare:nil andEnableExperimentalWorkletSupport:self.enableExperimentalWorkletSupport];
|
|
102
102
|
[self maybeCallSurfaceCreated];
|
|
103
103
|
}
|
|
104
104
|
|
package/ios/GLViewModule.swift
CHANGED
|
@@ -12,6 +12,9 @@ public final class GLViewModule: Module {
|
|
|
12
12
|
Prop("msaaSamples") { (view, msaaSamples: Int) in
|
|
13
13
|
view.msaaSamples = msaaSamples
|
|
14
14
|
}
|
|
15
|
+
Prop("enableExperimentalWorkletSupport") { (view, enableExperimentalWorkletSupport: Bool) in
|
|
16
|
+
view.enableExperimentalWorkletSupport = enableExperimentalWorkletSupport
|
|
17
|
+
}
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
20
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-gl",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0",
|
|
4
4
|
"description": "Provides GLView that acts as OpenGL ES render target and gives GL context object implementing WebGL 2.0 specification.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"expo": "*"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "3ccd2edee9cbfed217557675cb50f0ba5e55a9e4"
|
|
53
53
|
}
|
package/src/GLView.tsx
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
SnapshotOptions,
|
|
17
17
|
GLViewProps,
|
|
18
18
|
} from './GLView.types';
|
|
19
|
-
import {
|
|
19
|
+
import { createWorkletContextManager } from './GLWorkletContextManager';
|
|
20
20
|
|
|
21
21
|
// @docsMissing
|
|
22
22
|
export type WebGLObject = {
|
|
@@ -28,6 +28,7 @@ declare let global: any;
|
|
|
28
28
|
const { ExponentGLObjectManager, ExponentGLViewManager } = NativeModulesProxy;
|
|
29
29
|
|
|
30
30
|
const NativeView = requireNativeViewManager('ExponentGLView');
|
|
31
|
+
const workletContextManager = createWorkletContextManager();
|
|
31
32
|
|
|
32
33
|
// @needsAudit
|
|
33
34
|
/**
|
|
@@ -39,6 +40,7 @@ export class GLView extends React.Component<GLViewProps> {
|
|
|
39
40
|
|
|
40
41
|
static defaultProps = {
|
|
41
42
|
msaaSamples: 4,
|
|
43
|
+
enableExperimentalWorkletSupport: false,
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
/**
|
|
@@ -61,6 +63,7 @@ export class GLView extends React.Component<GLViewProps> {
|
|
|
61
63
|
*/
|
|
62
64
|
static async destroyContextAsync(exgl?: ExpoWebGLRenderingContext | number): Promise<boolean> {
|
|
63
65
|
const exglCtxId = getContextId(exgl);
|
|
66
|
+
unregisterGLContext(exglCtxId);
|
|
64
67
|
return ExponentGLObjectManager.destroyContextAsync(exglCtxId);
|
|
65
68
|
}
|
|
66
69
|
|
|
@@ -79,7 +82,7 @@ export class GLView extends React.Component<GLViewProps> {
|
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
static getWorkletContext: (contextId: number) => ExpoWebGLRenderingContext | undefined =
|
|
82
|
-
|
|
85
|
+
workletContextManager.getContext;
|
|
83
86
|
|
|
84
87
|
nativeRef: ComponentOrHandle = null;
|
|
85
88
|
exglCtxId?: number;
|
|
@@ -88,6 +91,7 @@ export class GLView extends React.Component<GLViewProps> {
|
|
|
88
91
|
const {
|
|
89
92
|
onContextCreate, // eslint-disable-line no-unused-vars
|
|
90
93
|
msaaSamples,
|
|
94
|
+
enableExperimentalWorkletSupport,
|
|
91
95
|
...viewProps
|
|
92
96
|
} = this.props;
|
|
93
97
|
|
|
@@ -104,6 +108,7 @@ export class GLView extends React.Component<GLViewProps> {
|
|
|
104
108
|
: {}),
|
|
105
109
|
}}
|
|
106
110
|
onSurfaceCreate={this._onSurfaceCreate}
|
|
111
|
+
enableExperimentalWorkletSupport={enableExperimentalWorkletSupport}
|
|
107
112
|
msaaSamples={Platform.OS === 'ios' ? msaaSamples : undefined}
|
|
108
113
|
/>
|
|
109
114
|
</View>
|
|
@@ -127,6 +132,20 @@ export class GLView extends React.Component<GLViewProps> {
|
|
|
127
132
|
}
|
|
128
133
|
};
|
|
129
134
|
|
|
135
|
+
componentWillUnmount(): void {
|
|
136
|
+
if (this.exglCtxId) {
|
|
137
|
+
unregisterGLContext(this.exglCtxId);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
componentDidUpdate(prevProps: GLViewProps): void {
|
|
142
|
+
if (
|
|
143
|
+
this.props.enableExperimentalWorkletSupport !== prevProps.enableExperimentalWorkletSupport
|
|
144
|
+
) {
|
|
145
|
+
console.warn('Updating prop enableExperimentalWorkletSupport is not supported');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
130
149
|
// @docsMissing
|
|
131
150
|
async startARSessionAsync(): Promise<any> {
|
|
132
151
|
if (!ExponentGLViewManager.startARSessionAsync) {
|
|
@@ -179,6 +198,13 @@ export class GLView extends React.Component<GLViewProps> {
|
|
|
179
198
|
|
|
180
199
|
GLView.NativeView = NativeView;
|
|
181
200
|
|
|
201
|
+
function unregisterGLContext(exglCtxId: number) {
|
|
202
|
+
if (global.__EXGLContexts) {
|
|
203
|
+
delete global.__EXGLContexts[String(exglCtxId)];
|
|
204
|
+
}
|
|
205
|
+
workletContextManager.unregister?.(exglCtxId);
|
|
206
|
+
}
|
|
207
|
+
|
|
182
208
|
// Get the GL interface from an EXGLContextId
|
|
183
209
|
const getGl = (exglCtxId: number): ExpoWebGLRenderingContext => {
|
|
184
210
|
if (!global.__EXGLContexts) {
|
package/src/GLView.types.ts
CHANGED
|
@@ -90,6 +90,11 @@ export type GLViewProps = {
|
|
|
90
90
|
* @default 4
|
|
91
91
|
*/
|
|
92
92
|
msaaSamples: number;
|
|
93
|
+
/**
|
|
94
|
+
* Enables support for interacting with a `gl` object from code running on the Reanimated worklet thread.
|
|
95
|
+
* @default false
|
|
96
|
+
*/
|
|
97
|
+
enableExperimentalWorkletSupport: boolean;
|
|
93
98
|
/**
|
|
94
99
|
* @hidden
|
|
95
100
|
* A ref callback for the native GLView
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ExpoWebGLRenderingContext } from './GLView.types';
|
|
2
|
+
|
|
3
|
+
// This method needs to be in a separate file because react-native-reanimated
|
|
4
|
+
// import wrapped in try catch does not work correctly with inlineRequires option
|
|
5
|
+
// in metro.config.js
|
|
6
|
+
//
|
|
7
|
+
// It looks like in generated bundle "react-native-reanimated" is not present
|
|
8
|
+
// in _dependencyMap, but references to it count it as if it was, e.g. bundle contains
|
|
9
|
+
// a line "(0, _$$_REQUIRE(_dependencyMap[15], "./GLUtils").configureLogging)(gl);"
|
|
10
|
+
// but dependencyMap contains only 15 elements
|
|
11
|
+
export function createWorkletContextManager(): {
|
|
12
|
+
getContext: (contextId: number) => ExpoWebGLRenderingContext | undefined;
|
|
13
|
+
unregister?: (contextId: number) => void;
|
|
14
|
+
} {
|
|
15
|
+
try {
|
|
16
|
+
// reanimated needs to be imported before any workletized code
|
|
17
|
+
// is created, but we don't want to make it dependency on expo-gl.
|
|
18
|
+
const { runOnUI } = require('react-native-reanimated');
|
|
19
|
+
return {
|
|
20
|
+
getContext: (contextId: number): ExpoWebGLRenderingContext | undefined => {
|
|
21
|
+
'worklet';
|
|
22
|
+
return global.__EXGLContexts?.[String(contextId)];
|
|
23
|
+
},
|
|
24
|
+
unregister: (contextId: number): void => {
|
|
25
|
+
runOnUI((contextId: number) => {
|
|
26
|
+
'worklet';
|
|
27
|
+
if (global.__EXGLContexts) {
|
|
28
|
+
delete global.__EXGLContexts[String(contextId)];
|
|
29
|
+
}
|
|
30
|
+
})(contextId);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
} catch {
|
|
34
|
+
return {
|
|
35
|
+
getContext: () => {
|
|
36
|
+
throw new Error('Worklet runtime is not available');
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GLWorkletContextProvider.d.ts","sourceRoot":"","sources":["../src/GLWorkletContextProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAU3D,wBAAgB,4BAA4B,gBAKrB,MAAM,KAAG,yBAAyB,GAAG,SAAS,CASpE"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// This method needs to be in a separate file because react-native-reanimated
|
|
2
|
-
// import wrapped in try catch does not work correctly with inlineRequires option
|
|
3
|
-
// in metro.config.js
|
|
4
|
-
//
|
|
5
|
-
// It looks like in generated bundle "react-native-reanimated" is not present
|
|
6
|
-
// in _dependencyMap, but references to it count it as if it was, e.g. bundle contains
|
|
7
|
-
// a line "(0, _$$_REQUIRE(_dependencyMap[15], "./GLUtils").configureLogging)(gl);"
|
|
8
|
-
// but dependencyMap contains only 15 elements
|
|
9
|
-
export function createWorkletContextProvider() {
|
|
10
|
-
try {
|
|
11
|
-
// reanimated needs to be imported before any workletized code
|
|
12
|
-
// is created, but we don't want to make it dependency on expo-gl.
|
|
13
|
-
require('react-native-reanimated');
|
|
14
|
-
return (contextId) => {
|
|
15
|
-
'worklet';
|
|
16
|
-
return global.__EXGLContexts?.[String(contextId)];
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
return () => {
|
|
21
|
-
throw new Error('Worklet runtime is not available');
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=GLWorkletContextProvider.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GLWorkletContextProvider.js","sourceRoot":"","sources":["../src/GLWorkletContextProvider.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,iFAAiF;AACjF,qBAAqB;AACrB,EAAE;AACF,6EAA6E;AAC7E,sFAAsF;AACtF,mFAAmF;AACnF,8CAA8C;AAC9C,MAAM,UAAU,4BAA4B;IAC1C,IAAI;QACF,8DAA8D;QAC9D,kEAAkE;QAClE,OAAO,CAAC,yBAAyB,CAAC,CAAC;QACnC,OAAO,CAAC,SAAiB,EAAyC,EAAE;YAClE,SAAS,CAAC;YACV,OAAO,MAAM,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QACpD,CAAC,CAAC;KACH;IAAC,MAAM;QACN,OAAO,GAAG,EAAE;YACV,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC,CAAC;KACH;AACH,CAAC","sourcesContent":["import { ExpoWebGLRenderingContext } from './GLView.types';\n\n// This method needs to be in a separate file because react-native-reanimated\n// import wrapped in try catch does not work correctly with inlineRequires option\n// in metro.config.js\n//\n// It looks like in generated bundle \"react-native-reanimated\" is not present\n// in _dependencyMap, but references to it count it as if it was, e.g. bundle contains\n// a line \"(0, _$$_REQUIRE(_dependencyMap[15], \"./GLUtils\").configureLogging)(gl);\"\n// but dependencyMap contains only 15 elements\nexport function createWorkletContextProvider() {\n try {\n // reanimated needs to be imported before any workletized code\n // is created, but we don't want to make it dependency on expo-gl.\n require('react-native-reanimated');\n return (contextId: number): ExpoWebGLRenderingContext | undefined => {\n 'worklet';\n return global.__EXGLContexts?.[String(contextId)];\n };\n } catch {\n return () => {\n throw new Error('Worklet runtime is not available');\n };\n }\n}\n"]}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { ExpoWebGLRenderingContext } from './GLView.types';
|
|
2
|
-
|
|
3
|
-
// This method needs to be in a separate file because react-native-reanimated
|
|
4
|
-
// import wrapped in try catch does not work correctly with inlineRequires option
|
|
5
|
-
// in metro.config.js
|
|
6
|
-
//
|
|
7
|
-
// It looks like in generated bundle "react-native-reanimated" is not present
|
|
8
|
-
// in _dependencyMap, but references to it count it as if it was, e.g. bundle contains
|
|
9
|
-
// a line "(0, _$$_REQUIRE(_dependencyMap[15], "./GLUtils").configureLogging)(gl);"
|
|
10
|
-
// but dependencyMap contains only 15 elements
|
|
11
|
-
export function createWorkletContextProvider() {
|
|
12
|
-
try {
|
|
13
|
-
// reanimated needs to be imported before any workletized code
|
|
14
|
-
// is created, but we don't want to make it dependency on expo-gl.
|
|
15
|
-
require('react-native-reanimated');
|
|
16
|
-
return (contextId: number): ExpoWebGLRenderingContext | undefined => {
|
|
17
|
-
'worklet';
|
|
18
|
-
return global.__EXGLContexts?.[String(contextId)];
|
|
19
|
-
};
|
|
20
|
-
} catch {
|
|
21
|
-
return () => {
|
|
22
|
-
throw new Error('Worklet runtime is not available');
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
}
|