Skip to content

Commit c805546

Browse files
authored
feat(🎥): SharedMemoryTexture API (#358)
1 parent d188e19 commit c805546

39 files changed

Lines changed: 1736 additions & 50 deletions

.github/workflows/ci.yml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,7 @@ jobs:
3737

3838
- name: Install CocoaPods
3939
working-directory: apps/example/ios
40-
run: |
41-
HASH_FILE="/tmp/.podfile-lock-hash"
42-
CURRENT_HASH=$(shasum Podfile.lock | cut -d' ' -f1)
43-
if [ -f "$HASH_FILE" ] && [ "$(cat "$HASH_FILE")" = "$CURRENT_HASH" ] && [ -d "Pods" ]; then
44-
echo "Podfile.lock unchanged and Pods exists — skipping pod install"
45-
else
46-
pod install
47-
echo "$CURRENT_HASH" > "$HASH_FILE"
48-
fi
40+
run: pod install
4941

5042
- name: Ensure Metro port is free
5143
run: |

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,41 @@ device.queue.copyExternalImageToTexture(
222222
);
223223
```
224224

225+
### Shared Texture Memory
226+
227+
React Native WebGPU exposes Dawn's `SharedTextureMemory` so you can import a native pixel surface (an `IOSurface`-backed `CVPixelBuffer` on iOS, an `AHardwareBuffer` on Android) as a sampleable `GPUTexture` without copying pixels through the CPU. This is the path you want for camera frames, video frames, or anything coming out of a hardware producer.
228+
229+
We expose a single umbrella feature name, `"rnwebgpu/shared-texture-memory"`. Request it at device creation.
230+
231+
```tsx
232+
import type { VideoFrame } from "react-native-wgpu";
233+
234+
const FEATURE = "rnwebgpu/shared-texture-memory" as GPUFeatureName;
235+
236+
const adapter = await navigator.gpu.requestAdapter();
237+
const requiredFeatures = adapter!.features.has(FEATURE) ? [FEATURE] : [];
238+
const device = await adapter!.requestDevice({ requiredFeatures });
239+
240+
// `frame` here is a VideoFrame whose .handle is the native surface
241+
// (IOSurfaceRef / AHardwareBuffer*). VideoFrames are produced by helpers
242+
// like RNWebGPU.createVideoPlayer or RNWebGPU.createTestVideoFrame, or by
243+
// any third-party module that hands you a compatible native pointer.
244+
const memory = device.importSharedTextureMemory({
245+
handle: frame.handle,
246+
label: "video-frame",
247+
});
248+
const texture = memory.createTexture();
249+
250+
memory.beginAccess(texture, /* initialized */ true);
251+
// ... bind `texture` into a sampler and render normally ...
252+
memory.endAccess(texture);
253+
254+
texture.destroy();
255+
frame.release();
256+
```
257+
258+
`beginAccess`/`endAccess` bracket the GPU's read window on the shared surface. Pass `initialized: true` when the producer has already written meaningful pixels (the typical video/camera case) and `false` when the next pass will fully overwrite the texture.
259+
225260
### Reanimated Integration
226261

227262
React Native WebGPU supports running WebGPU rendering on the UI thread using [React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/) and [React Native Worklets](https://github.com/margelo/react-native-worklets).

apps/example/android/gradle.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
3636
newArchEnabled=true
3737
hermesEnabled=true
3838

39+
# react-native-wgpu requires API 26+ (AHardwareBuffer for shared texture memory,
40+
# and Dawn's Android backend itself).
41+
react.minSdkVersion=26
42+
3943
# Use this property to enable support to the new architecture.
4044
# This will allow you to use TurboModules and the Fabric render in
4145
# your application. You should enable this flag either if you want

apps/example/ios/Podfile.lock

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,7 +1865,7 @@ PODS:
18651865
- ReactCommon/turbomodule/core
18661866
- SocketRocket
18671867
- Yoga
1868-
- react-native-wgpu (0.5.11):
1868+
- react-native-wgpu (0.5.12):
18691869
- boost
18701870
- DoubleConversion
18711871
- fast_float
@@ -2460,7 +2460,7 @@ PODS:
24602460
- ReactCommon/turbomodule/core
24612461
- SocketRocket
24622462
- Yoga
2463-
- RNReanimated (4.2.1):
2463+
- RNReanimated (4.3.1):
24642464
- boost
24652465
- DoubleConversion
24662466
- fast_float
@@ -2487,11 +2487,12 @@ PODS:
24872487
- ReactCodegen
24882488
- ReactCommon/turbomodule/bridging
24892489
- ReactCommon/turbomodule/core
2490-
- RNReanimated/reanimated (= 4.2.1)
2490+
- RNReanimated/apple (= 4.3.1)
2491+
- RNReanimated/common (= 4.3.1)
24912492
- RNWorklets
24922493
- SocketRocket
24932494
- Yoga
2494-
- RNReanimated/reanimated (4.2.1):
2495+
- RNReanimated/apple (4.3.1):
24952496
- boost
24962497
- DoubleConversion
24972498
- fast_float
@@ -2518,11 +2519,10 @@ PODS:
25182519
- ReactCodegen
25192520
- ReactCommon/turbomodule/bridging
25202521
- ReactCommon/turbomodule/core
2521-
- RNReanimated/reanimated/apple (= 4.2.1)
25222522
- RNWorklets
25232523
- SocketRocket
25242524
- Yoga
2525-
- RNReanimated/reanimated/apple (4.2.1):
2525+
- RNReanimated/common (4.3.1):
25262526
- boost
25272527
- DoubleConversion
25282528
- fast_float
@@ -2552,7 +2552,7 @@ PODS:
25522552
- RNWorklets
25532553
- SocketRocket
25542554
- Yoga
2555-
- RNWorklets (0.7.2):
2555+
- RNWorklets (0.8.3):
25562556
- boost
25572557
- DoubleConversion
25582558
- fast_float
@@ -2579,10 +2579,11 @@ PODS:
25792579
- ReactCodegen
25802580
- ReactCommon/turbomodule/bridging
25812581
- ReactCommon/turbomodule/core
2582-
- RNWorklets/worklets (= 0.7.2)
2582+
- RNWorklets/apple (= 0.8.3)
2583+
- RNWorklets/common (= 0.8.3)
25832584
- SocketRocket
25842585
- Yoga
2585-
- RNWorklets/worklets (0.7.2):
2586+
- RNWorklets/apple (0.8.3):
25862587
- boost
25872588
- DoubleConversion
25882589
- fast_float
@@ -2609,10 +2610,9 @@ PODS:
26092610
- ReactCodegen
26102611
- ReactCommon/turbomodule/bridging
26112612
- ReactCommon/turbomodule/core
2612-
- RNWorklets/worklets/apple (= 0.7.2)
26132613
- SocketRocket
26142614
- Yoga
2615-
- RNWorklets/worklets/apple (0.7.2):
2615+
- RNWorklets/common (0.8.3):
26162616
- boost
26172617
- DoubleConversion
26182618
- fast_float
@@ -2938,7 +2938,7 @@ SPEC CHECKSUMS:
29382938
React-microtasksnativemodule: 75b6604b667d297292345302cc5bfb6b6aeccc1b
29392939
react-native-safe-area-context: c00143b4823773bba23f2f19f85663ae89ceb460
29402940
react-native-skia: fc73e9bdc46ebb420a98c9c2be29fee80f565e79
2941-
react-native-wgpu: 990ed34b0216cb4980a52344ec959cb8899d2845
2941+
react-native-wgpu: 274ffec11ee3a082260d9f3d1fb54030a5ca0873
29422942
React-NativeModulesApple: 879fbdc5dcff7136abceb7880fe8a2022a1bd7c3
29432943
React-oscompat: 93b5535ea7f7dff46aaee4f78309a70979bdde9d
29442944
React-perflogger: 5536d2df3d18fe0920263466f7b46a56351c0510
@@ -2973,8 +2973,8 @@ SPEC CHECKSUMS:
29732973
ReactTestApp-DevSupport: 9b7bbba5e8fed998e763809171d9906a1375f9d3
29742974
ReactTestApp-Resources: 1bd9ff10e4c24f2ad87101a32023721ae923bccf
29752975
RNGestureHandler: e37bdb684df1ac17c7e1d8f71a3311b2793c186b
2976-
RNReanimated: 464375ff2caa801358547c44eca894ff0bf68e74
2977-
RNWorklets: ee58e869ea579800ec5f2f1cb6ae195fd3537546
2976+
RNReanimated: 9d012d4031abc9df896f8a82f9928eb2b9eae417
2977+
RNWorklets: 0da2552f9ff5d17506918a692304110cfebb9f0a
29782978
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
29792979
Yoga: a3ed390a19db0459bd6839823a6ac6d9c6db198d
29802980

apps/example/src/App.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { Reanimated } from "./Reanimated";
3636
import { AsyncStarvation } from "./Diagnostics/AsyncStarvation";
3737
import { DeviceLostHang } from "./Diagnostics/DeviceLostHang";
3838
import { StorageBufferVertices } from "./StorageBufferVertices";
39+
import { SharedTextureMemory } from "./SharedTextureMemory";
3940

4041
// The two lines below are needed by three.js
4142
import "fast-text-encoding";
@@ -97,6 +98,10 @@ function App() {
9798
name="StorageBufferVertices"
9899
component={StorageBufferVertices}
99100
/>
101+
<Stack.Screen
102+
name="SharedTextureMemory"
103+
component={SharedTextureMemory}
104+
/>
100105
</Stack.Navigator>
101106
</NavigationContainer>
102107
</GestureHandlerRootView>

apps/example/src/Home.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ export const examples = [
127127
screen: "StorageBufferVertices",
128128
title: "💾 Storage Buffer Vertices",
129129
},
130+
{
131+
screen: "SharedTextureMemory",
132+
title: "🎞️ Shared Texture Memory",
133+
},
130134
];
131135

132136
const styles = StyleSheet.create({

apps/example/src/Route.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ export type Routes = {
2929
AsyncStarvation: undefined;
3030
DeviceLostHang: undefined;
3131
StorageBufferVertices: undefined;
32+
SharedTextureMemory: undefined;
3233
};

0 commit comments

Comments
 (0)