expo-gl 12.5.0 → 13.0.1

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 CHANGED
@@ -10,6 +10,22 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 13.0.1 — 2023-07-04
14
+
15
+ _This version does not introduce any user-facing changes._
16
+
17
+ ## 13.0.0 — 2023-06-13
18
+
19
+ ### 🛠 Breaking changes
20
+
21
+ - Require explicit prop `enableExperimentalWorkletSupport` to use GLView from Reanimated worklet. ([#22613](https://github.com/expo/expo/pull/22613) by [@wkozyra95](https://github.com/wkozyra95))
22
+
23
+ ### 🐛 Bug fixes
24
+
25
+ - 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))
26
+ - 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))
27
+ - Move creating GL context for worklet to UI thread. ([#22634](https://github.com/expo/expo/pull/22634) by [@wkozyra95](https://github.com/wkozyra95))
28
+
13
29
  ## 12.5.0 — 2023-05-08
14
30
 
15
31
  ### 🐛 Bug fixes
@@ -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 = '12.5.0'
9
+ version = '13.0.1'
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 "12.5.0"
99
+ versionName "13.0.1"
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 {
@@ -1,4 +1,3 @@
1
- <manifest package="expo.modules.gl"
2
- xmlns:android="http://schemas.android.com/apk/res/android">
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
2
  <uses-feature android:glEsVersion="0x00020000" android:required="false" />
4
3
  </manifest>
@@ -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(SurfaceTexture surfaceTexture, final Runnable completionCallback) {
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
- mManager.saveContext(glContext);
101
- completionCallback.run();
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/GLUtils.js CHANGED
@@ -18,7 +18,7 @@ export function configureLogging(gl) {
18
18
  return;
19
19
  }
20
20
  // Turn off logging.
21
- if (!option || option === GLLoggingOption.DISABLED) {
21
+ if (option === GLLoggingOption.DISABLED || !option) {
22
22
  Object.entries(gl).forEach(([key, value]) => {
23
23
  if (typeof value === 'function' && value.__logWrapper) {
24
24
  delete gl[key];
@@ -1 +1 @@
1
- {"version":3,"file":"GLUtils.js","sourceRoot":"","sources":["../src/GLUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import GLErrors from './GLErrors';\nimport { ExpoWebGLRenderingContext, GLLoggingOption } from './GLView.types';\n\n/**\n * Maximum length of the strings printed to the console.\n */\nconst MAX_STRING_LENGTH = 20;\n\n/**\n * Sets up `__expoSetLogging` method providing some logging options useful when debugging GL calls.\n */\nexport function configureLogging(gl: ExpoWebGLRenderingContext): void {\n // Enable/disable logging of all GL function calls\n let loggingOption = GLLoggingOption.DISABLED;\n\n gl.__expoSetLogging = (option: GLLoggingOption): void => {\n // If boolean values are the same, just change the internal value,\n // there is no need to wrap/unwrap functions in this case.\n if (!loggingOption === !option) {\n loggingOption = option;\n return;\n }\n\n // Turn off logging.\n if (!option || option === GLLoggingOption.DISABLED) {\n Object.entries(gl).forEach(([key, value]) => {\n if (typeof value === 'function' && value.__logWrapper) {\n delete gl[key];\n }\n });\n loggingOption = option;\n return;\n }\n\n // Turn on logging.\n Object.entries(Object.getPrototypeOf(gl)).forEach(([key, originalValue]) => {\n if (typeof originalValue !== 'function' || key === '__expoSetLogging') {\n return;\n }\n\n gl[key] = (...args) => {\n if (loggingOption & GLLoggingOption.METHOD_CALLS) {\n const params = args.map((arg) => {\n // If the type is `number`, then try to find name of the constant that has such value,\n // so it's easier to read these logs. In some cases it might be misleading\n // if the parameter is for example a width or height, so the number is still logged.\n if (loggingOption & GLLoggingOption.RESOLVE_CONSTANTS && typeof arg === 'number') {\n for (const prop in gl) {\n if (gl[prop] === arg) {\n return `${arg} (${prop})`;\n }\n }\n }\n\n // Truncate strings so they don't produce too much output and don't block the bridge.\n // It mostly applies to shaders which might be very long...\n if (loggingOption & GLLoggingOption.TRUNCATE_STRINGS && typeof arg === 'string') {\n if (arg.length > MAX_STRING_LENGTH) {\n const lastIndex = arg.lastIndexOf(' ', MAX_STRING_LENGTH);\n return arg.substr(0, lastIndex >= 0 ? lastIndex : MAX_STRING_LENGTH) + '...';\n }\n }\n\n // Just return the parameter as a string.\n return '' + arg;\n });\n console.log(`ExpoGL: ${key}(${params.join(', ')})`);\n }\n\n const result = originalValue.apply(gl, args);\n\n if (loggingOption & GLLoggingOption.METHOD_CALLS) {\n console.log(`ExpoGL: = ${result}`);\n }\n if (loggingOption & GLLoggingOption.GET_ERRORS && key !== 'getError') {\n // @ts-ignore We need to call into the original `getError`.\n // eslint-disable-next-line no-proto\n const error = gl.__proto__.getError.call(gl);\n\n if (error && error !== gl.NO_ERROR) {\n // `console.error` would cause a red screen, so let's just log with red color.\n console.log(`\\x1b[31mExpoGL: Error ${GLErrors[error]}\\x1b[0m`);\n }\n }\n gl[key].__logWrapper = true;\n return result;\n };\n });\n\n loggingOption = option;\n };\n}\n"]}
1
+ {"version":3,"file":"GLUtils.js","sourceRoot":"","sources":["../src/GLUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import GLErrors from './GLErrors';\nimport { ExpoWebGLRenderingContext, GLLoggingOption } from './GLView.types';\n\n/**\n * Maximum length of the strings printed to the console.\n */\nconst MAX_STRING_LENGTH = 20;\n\n/**\n * Sets up `__expoSetLogging` method providing some logging options useful when debugging GL calls.\n */\nexport function configureLogging(gl: ExpoWebGLRenderingContext): void {\n // Enable/disable logging of all GL function calls\n let loggingOption = GLLoggingOption.DISABLED;\n\n gl.__expoSetLogging = (option: GLLoggingOption): void => {\n // If boolean values are the same, just change the internal value,\n // there is no need to wrap/unwrap functions in this case.\n if (!loggingOption === !option) {\n loggingOption = option;\n return;\n }\n\n // Turn off logging.\n if (option === GLLoggingOption.DISABLED || !option) {\n Object.entries(gl).forEach(([key, value]) => {\n if (typeof value === 'function' && value.__logWrapper) {\n delete gl[key];\n }\n });\n loggingOption = option;\n return;\n }\n\n // Turn on logging.\n Object.entries(Object.getPrototypeOf(gl)).forEach(([key, originalValue]) => {\n if (typeof originalValue !== 'function' || key === '__expoSetLogging') {\n return;\n }\n\n gl[key] = (...args) => {\n if (loggingOption & GLLoggingOption.METHOD_CALLS) {\n const params = args.map((arg) => {\n // If the type is `number`, then try to find name of the constant that has such value,\n // so it's easier to read these logs. In some cases it might be misleading\n // if the parameter is for example a width or height, so the number is still logged.\n if (loggingOption & GLLoggingOption.RESOLVE_CONSTANTS && typeof arg === 'number') {\n for (const prop in gl) {\n if (gl[prop] === arg) {\n return `${arg} (${prop})`;\n }\n }\n }\n\n // Truncate strings so they don't produce too much output and don't block the bridge.\n // It mostly applies to shaders which might be very long...\n if (loggingOption & GLLoggingOption.TRUNCATE_STRINGS && typeof arg === 'string') {\n if (arg.length > MAX_STRING_LENGTH) {\n const lastIndex = arg.lastIndexOf(' ', MAX_STRING_LENGTH);\n return arg.substr(0, lastIndex >= 0 ? lastIndex : MAX_STRING_LENGTH) + '...';\n }\n }\n\n // Just return the parameter as a string.\n return '' + arg;\n });\n console.log(`ExpoGL: ${key}(${params.join(', ')})`);\n }\n\n const result = originalValue.apply(gl, args);\n\n if (loggingOption & GLLoggingOption.METHOD_CALLS) {\n console.log(`ExpoGL: = ${result}`);\n }\n if (loggingOption & GLLoggingOption.GET_ERRORS && key !== 'getError') {\n // @ts-ignore We need to call into the original `getError`.\n // eslint-disable-next-line no-proto\n const error = gl.__proto__.getError.call(gl);\n\n if (error && error !== gl.NO_ERROR) {\n // `console.error` would cause a red screen, so let's just log with red color.\n console.log(`\\x1b[31mExpoGL: Error ${GLErrors[error]}\\x1b[0m`);\n }\n }\n gl[key].__logWrapper = true;\n return result;\n };\n });\n\n loggingOption = option;\n };\n}\n"]}
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.
@@ -41,6 +42,7 @@ export declare class GLView extends React.Component<GLViewProps> {
41
42
  _setNativeRef: (nativeRef: ComponentOrHandle) => void;
42
43
  _onSurfaceCreate: ({ nativeEvent: { exglCtxId } }: SurfaceCreateEvent) => void;
43
44
  componentWillUnmount(): void;
45
+ componentDidUpdate(prevProps: GLViewProps): void;
44
46
  startARSessionAsync(): Promise<any>;
45
47
  createCameraTextureAsync(cameraRefOrHandle: ComponentOrHandle): Promise<WebGLTexture>;
46
48
  destroyObjectAsync(glObject: WebGLObject): Promise<boolean>;
@@ -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;AAUF;;;GAGG;AACH,qBAAa,MAAO,SAAQ,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC;IACtD,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC;IAEvB,MAAM,CAAC,YAAY;;MAEjB;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;IA0BN,aAAa,cAAe,iBAAiB,KAAG,IAAI,CAKlD;IAEF,gBAAgB,mCAAoC,kBAAkB,KAAG,IAAI,CAQ3E;IAEF,oBAAoB,IAAI,IAAI;IAOtB,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"}
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
@@ -15,6 +15,7 @@ export class GLView extends React.Component {
15
15
  static NativeView;
16
16
  static defaultProps = {
17
17
  msaaSamples: 4,
18
+ enableExperimentalWorkletSupport: false,
18
19
  };
19
20
  /**
20
21
  * Imperative API that creates headless context which is devoid of underlying view.
@@ -53,7 +54,7 @@ export class GLView extends React.Component {
53
54
  exglCtxId;
54
55
  render() {
55
56
  const { onContextCreate, // eslint-disable-line no-unused-vars
56
- msaaSamples, ...viewProps } = this.props;
57
+ msaaSamples, enableExperimentalWorkletSupport, ...viewProps } = this.props;
57
58
  return (React.createElement(View, { ...viewProps },
58
59
  React.createElement(NativeView, { ref: this._setNativeRef, style: {
59
60
  flex: 1,
@@ -62,7 +63,7 @@ export class GLView extends React.Component {
62
63
  backgroundColor: 'transparent',
63
64
  }
64
65
  : {}),
65
- }, onSurfaceCreate: this._onSurfaceCreate, msaaSamples: Platform.OS === 'ios' ? msaaSamples : undefined })));
66
+ }, onSurfaceCreate: this._onSurfaceCreate, enableExperimentalWorkletSupport: enableExperimentalWorkletSupport, msaaSamples: Platform.OS === 'ios' ? msaaSamples : undefined })));
66
67
  }
67
68
  _setNativeRef = (nativeRef) => {
68
69
  if (this.props.nativeRef_EXPERIMENTAL) {
@@ -82,6 +83,11 @@ export class GLView extends React.Component {
82
83
  unregisterGLContext(this.exglCtxId);
83
84
  }
84
85
  }
86
+ componentDidUpdate(prevProps) {
87
+ if (this.props.enableExperimentalWorkletSupport !== prevProps.enableExperimentalWorkletSupport) {
88
+ console.warn('Updating prop enableExperimentalWorkletSupport is not supported');
89
+ }
90
+ }
85
91
  // @docsMissing
86
92
  async startARSessionAsync() {
87
93
  if (!ExponentGLViewManager.startARSessionAsync) {
@@ -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 { 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 };\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 ...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 componentWillUnmount(): void {\n if (this.exglCtxId) {\n unregisterGLContext(this.exglCtxId);\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"]}
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 { 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"]}
@@ -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":"AAmGA,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 * @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"]}
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"]}
@@ -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::mutex contextLookupMutex;
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::lock_guard lock(manager.contextLookupMutex);
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::lock_guard<std::mutex> lock(manager.contextLookupMutex);
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
- std::lock_guard lock(manager.contextLookupMutex);
66
+ {
67
+ std::shared_lock lock(manager.contextLookupMutex);
48
68
 
49
- auto iter = manager.contextMap.find(id);
50
- if (iter != manager.contextMap.end()) {
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
  }
@@ -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(void *jsiPtr, EXGLContextId exglCtxId, std::function<void(void)> flushMethod) {
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) {
@@ -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
- auto viewport = prepareOpenGLESContext();
13
- createWebGLRenderer(runtime, this, viewport, runtime.global());
12
+ this->initialGlesContext = prepareOpenGLESContext();
13
+ createWebGLRenderer(runtime, this, this->initialGlesContext, runtime.global());
14
14
  tryRegisterOnJSRuntimeDestroy(runtime);
15
15
 
16
- maybePrepareWorkletContext(runtime, viewport);
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::maybePrepareWorkletContext(jsi::Runtime &runtime, initGlesContext viewport) {
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 &workletRuntime = *reinterpret_cast<jsi::Runtime *>(rawWorkletRuntimePointer);
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
- workletRuntime,
41
- this,
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
- initGlesContext EXGLContext::prepareOpenGLESContext() {
133
- initGlesContext result;
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 maybePrepareWorkletContext(jsi::Runtime &runtime, initGlesContext viewport);
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
- initGlesContext prepareOpenGLESContext();
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, initGlesContext viewport, jsi::Object&& global) {
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(
@@ -7,7 +7,7 @@
7
7
  namespace expo {
8
8
  namespace gl_cpp {
9
9
 
10
- struct initGlesContext {
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 *, initGlesContext, jsi::Object&& global);
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 andModuleRegistry:(nonnull EXModuleRegistry *)moduleRegistry;
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;
@@ -26,7 +26,8 @@
26
26
 
27
27
  @implementation EXGLContext
28
28
 
29
- - (instancetype)initWithDelegate:(id<EXGLContextDelegate>)delegate andModuleRegistry:(nonnull EXModuleRegistry *)moduleRegistry
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
- // Destroy JS binding
171
- EXGLContextDestroy(self->_contextId);
177
+ id<EXUIManager> uiManager = [_moduleRegistry getModuleImplementingProtocol:@protocol(EXUIManager)];
178
+ [uiManager dispatchOnClientThread:^{
179
+ // Destroy JS binding
180
+ EXGLContextDestroy(self->_contextId);
172
181
 
173
- // Remove from dictionary of contexts
174
- [self->_objectManager deleteContextWithId:@(self->_contextId)];
182
+ // Remove from dictionary of contexts
183
+ [self->_objectManager deleteContextWithId:@(self->_contextId)];
184
+ }];
175
185
  }];
176
186
  }
177
187
 
@@ -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 andModuleRegistry:_moduleRegistry];
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
 
@@ -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": "12.5.0",
3
+ "version": "13.0.1",
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": "4ba50c428c8369bb6b3a51a860d4898ad4ccbe78"
52
+ "gitHead": "cf90d5c30c2a08a6493ebfa8aa3791aa70666759"
53
53
  }
package/src/GLUtils.ts CHANGED
@@ -22,7 +22,7 @@ export function configureLogging(gl: ExpoWebGLRenderingContext): void {
22
22
  }
23
23
 
24
24
  // Turn off logging.
25
- if (!option || option === GLLoggingOption.DISABLED) {
25
+ if (option === GLLoggingOption.DISABLED || !option) {
26
26
  Object.entries(gl).forEach(([key, value]) => {
27
27
  if (typeof value === 'function' && value.__logWrapper) {
28
28
  delete gl[key];
package/src/GLView.tsx CHANGED
@@ -40,6 +40,7 @@ export class GLView extends React.Component<GLViewProps> {
40
40
 
41
41
  static defaultProps = {
42
42
  msaaSamples: 4,
43
+ enableExperimentalWorkletSupport: false,
43
44
  };
44
45
 
45
46
  /**
@@ -90,6 +91,7 @@ export class GLView extends React.Component<GLViewProps> {
90
91
  const {
91
92
  onContextCreate, // eslint-disable-line no-unused-vars
92
93
  msaaSamples,
94
+ enableExperimentalWorkletSupport,
93
95
  ...viewProps
94
96
  } = this.props;
95
97
 
@@ -106,6 +108,7 @@ export class GLView extends React.Component<GLViewProps> {
106
108
  : {}),
107
109
  }}
108
110
  onSurfaceCreate={this._onSurfaceCreate}
111
+ enableExperimentalWorkletSupport={enableExperimentalWorkletSupport}
109
112
  msaaSamples={Platform.OS === 'ios' ? msaaSamples : undefined}
110
113
  />
111
114
  </View>
@@ -135,6 +138,14 @@ export class GLView extends React.Component<GLViewProps> {
135
138
  }
136
139
  }
137
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
+
138
149
  // @docsMissing
139
150
  async startARSessionAsync(): Promise<any> {
140
151
  if (!ExponentGLViewManager.startARSessionAsync) {
@@ -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