33React Native implementation of WebGPU using [ Dawn] ( https://dawn.googlesource.com/dawn ) .
44This is currently a technical preview for early adopters.
55
6+ React Native WebGPU requires React Native 0.81 or newer and doesn't run on legacy architecture.
7+
68## Installation
79
810Please note that the package name is ` react-native-wgpu ` .
@@ -15,19 +17,19 @@ Below are some examples from the [example app](/apps/example/).
1517
1618https://github.com/user-attachments/assets/116a41b2-2cf8-49f1-9f16-a5c83637c198
1719
18- ## Three.js
19-
2020Starting from ` r168 ` , Three.js runs out of the box with React Native WebGPU.
2121You need to have a slight modification of [ the metro config] ( /apps/example/metro.config.js ) to resolve Three.js to the WebGPU build.
22- We also support [ three-fiber] ( /apps/example/src/ThreeJS/Fiber.tsx ) .
23- For model loading, we also need the following polyfill:
22+ We also support [ react-three-fiber] ( /apps/example/src/ThreeJS/Fiber.tsx ) ; to make it work, patch ` node_modules/@react-three/fiber/package.json ` (for instance via ` patch-package ` ) so that it resolves to the WebGPU entry point instead of the React Native bundle:
2423
25- ``` tsx
26- // The two lines below are needed by three.js
27- import " fast-text-encoding" ;
28- window .parent = window ;
24+ ``` diff
25+ diff --git a/node_modules/@react-three/fiber/package.json b/node_modules/@react-three/fiber/package.json
26+ @@
27+ - "react-native": "native/dist/react-three-fiber-native.cjs.js",
28+ + "react-native": "dist/react-three-fiber.cjs.js",
2929```
3030
31+ For model loading, we also need [ the following polyfill] ( /apps/example/src/App.tsx#29 ) .
32+
3133https://github.com/user-attachments/assets/5b49ef63-0a3c-4679-aeb5-e4b4dddfcc1d
3234
3335We also provide prebuilt binaries for visionOS and macOS.
@@ -36,87 +38,91 @@ https://github.com/user-attachments/assets/2d5c618e-5b15-4cef-8558-d4ddf8c70667
3638
3739## Usage
3840
39- Currently we recommend to use the ` useCanvasEffect ` to access the WebGPU context .
41+ Usage is identical to Web .
4042
4143``` tsx
4244import React from " react" ;
4345import { StyleSheet , View , PixelRatio } from " react-native" ;
44- import { Canvas , useCanvasEffect } from " react-native-wgpu" ;
46+ import { Canvas , CanvasRef } from " react-native-wgpu" ;
4547
4648import { redFragWGSL , triangleVertWGSL } from " ./triangle" ;
4749
4850export function HelloTriangle() {
49- const ref = useCanvasEffect (async () => {
50- const adapter = await navigator .gpu .requestAdapter ();
51- if (! adapter ) {
52- throw new Error (" No adapter" );
53- }
54- const device = await adapter .requestDevice ();
55- const presentationFormat = navigator .gpu .getPreferredCanvasFormat ();
56-
57- const context = ref .current ! .getContext (" webgpu" )! ;
58- const canvas = context .canvas as HTMLCanvasElement ;
59- canvas .width = canvas .clientWidth * PixelRatio .get ();
60- canvas .height = canvas .clientHeight * PixelRatio .get ();
61-
62- if (! context ) {
63- throw new Error (" No context" );
64- }
65-
66- context .configure ({
67- device ,
68- format: presentationFormat ,
69- alphaMode: " opaque" ,
70- });
71-
72- const pipeline = device .createRenderPipeline ({
73- layout: " auto" ,
74- vertex: {
75- module: device .createShaderModule ({
76- code: triangleVertWGSL ,
77- }),
78- entryPoint: " main" ,
79- },
80- fragment: {
81- module: device .createShaderModule ({
82- code: redFragWGSL ,
83- }),
84- entryPoint: " main" ,
85- targets: [
51+ const ref = useRef <CanvasRef >(null );
52+ useEffect (() => {
53+ const helloTriangle = async () => {
54+ const adapter = await navigator .gpu .requestAdapter ();
55+ if (! adapter ) {
56+ throw new Error (" No adapter" );
57+ }
58+ const device = await adapter .requestDevice ();
59+ const presentationFormat = navigator .gpu .getPreferredCanvasFormat ();
60+
61+ const context = ref .current ! .getContext (" webgpu" )! ;
62+ const canvas = context .canvas as HTMLCanvasElement ;
63+ canvas .width = canvas .clientWidth * PixelRatio .get ();
64+ canvas .height = canvas .clientHeight * PixelRatio .get ();
65+
66+ if (! context ) {
67+ throw new Error (" No context" );
68+ }
69+
70+ context .configure ({
71+ device ,
72+ format: presentationFormat ,
73+ alphaMode: " opaque" ,
74+ });
75+
76+ const pipeline = device .createRenderPipeline ({
77+ layout: " auto" ,
78+ vertex: {
79+ module: device .createShaderModule ({
80+ code: triangleVertWGSL ,
81+ }),
82+ entryPoint: " main" ,
83+ },
84+ fragment: {
85+ module: device .createShaderModule ({
86+ code: redFragWGSL ,
87+ }),
88+ entryPoint: " main" ,
89+ targets: [
90+ {
91+ format: presentationFormat ,
92+ },
93+ ],
94+ },
95+ primitive: {
96+ topology: " triangle-list" ,
97+ },
98+ });
99+
100+ const commandEncoder = device .createCommandEncoder ();
101+
102+ const textureView = context .getCurrentTexture ().createView ();
103+
104+ const renderPassDescriptor: GPURenderPassDescriptor = {
105+ colorAttachments: [
86106 {
87- format: presentationFormat ,
107+ view: textureView ,
108+ clearValue: [0 , 0 , 0 , 1 ],
109+ loadOp: " clear" ,
110+ storeOp: " store" ,
88111 },
89112 ],
90- },
91- primitive: {
92- topology: " triangle-list" ,
93- },
94- });
95-
96- const commandEncoder = device .createCommandEncoder ();
97-
98- const textureView = context .getCurrentTexture ().createView ();
99-
100- const renderPassDescriptor: GPURenderPassDescriptor = {
101- colorAttachments: [
102- {
103- view: textureView ,
104- clearValue: [0 , 0 , 0 , 1 ],
105- loadOp: " clear" ,
106- storeOp: " store" ,
107- },
108- ],
109- };
113+ };
110114
111- const passEncoder = commandEncoder .beginRenderPass (renderPassDescriptor );
112- passEncoder .setPipeline (pipeline );
113- passEncoder .draw (3 );
114- passEncoder .end ();
115+ const passEncoder = commandEncoder .beginRenderPass (renderPassDescriptor );
116+ passEncoder .setPipeline (pipeline );
117+ passEncoder .draw (3 );
118+ passEncoder .end ();
115119
116- device .queue .submit ([commandEncoder .finish ()]);
120+ device .queue .submit ([commandEncoder .finish ()]);
117121
118- context .present ();
119- });
122+ context .present ();
123+ };
124+ helloTriangle ();
125+ }, [ref ]);
120126
121127 return (
122128 <View style = { style .container } >
@@ -137,7 +143,7 @@ const style = StyleSheet.create({
137143
138144## Example App
139145
140- To run the example app you first need to [ build Dawn or download the prebuilt binaries ] ( #building -dawn ) .
146+ To run the example app you first need to [ install Dawn] ( #installing -dawn ) .
141147
142148From there you will be able to run the example app properly.
143149
@@ -212,9 +218,9 @@ git submodule update --init
212218
213219Make sure you have all the tools required for building the Skia libraries (Android Studio, XCode, Ninja, CMake, Android NDK/build tools).
214220
215- ### Downloading Dawn
221+ ### Installing Dawn
216222
217- There is an alternative way which is to download the prebuilt binaries from GitHub.
223+ There is an alternative way which is to install the prebuilt binaries from GitHub.
218224
219225``` sh
220226$ yarn
0 commit comments