Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions apps/example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1748,7 +1748,7 @@ PODS:
- React-RCTFBReactNativeSpec
- ReactCommon/turbomodule/core
- SocketRocket
- react-native-safe-area-context (5.4.0):
- react-native-safe-area-context (5.6.1):
- boost
- DoubleConversion
- fast_float
Expand All @@ -1766,8 +1766,8 @@ PODS:
- React-graphics
- React-ImageManager
- React-jsi
- react-native-safe-area-context/common (= 5.4.0)
- react-native-safe-area-context/fabric (= 5.4.0)
- react-native-safe-area-context/common (= 5.6.1)
- react-native-safe-area-context/fabric (= 5.6.1)
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
Expand All @@ -1778,7 +1778,7 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-safe-area-context/common (5.4.0):
- react-native-safe-area-context/common (5.6.1):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -1806,7 +1806,7 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-safe-area-context/fabric (5.4.0):
- react-native-safe-area-context/fabric (5.6.1):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -1865,7 +1865,7 @@ PODS:
- ReactCommon/turbomodule/core
- SocketRocket
- Yoga
- react-native-wgpu (0.2.7):
- react-native-wgpu (0.2.8):
- boost
- DoubleConversion
- fast_float
Expand Down Expand Up @@ -2901,9 +2901,9 @@ SPEC CHECKSUMS:
React-logger: a3cb5b29c32b8e447b5a96919340e89334062b48
React-Mapbuffer: 9d2434a42701d6144ca18f0ca1c4507808ca7696
React-microtasksnativemodule: 75b6604b667d297292345302cc5bfb6b6aeccc1b
react-native-safe-area-context: 84f35326241e8a61b9e3b6f69e1bf098da4c5642
react-native-safe-area-context: c6e2edd1c1da07bdce287fa9d9e60c5f7b514616
react-native-skia: 5bf2b2107cd7f2d806fd364f5e16b1c7554ed3cd
react-native-wgpu: cf92463dcf22589d51d1e314d40732bb2c5fc9d0
react-native-wgpu: fa319a78b8773740fd2247cff8054f4bb3cd341e
React-NativeModulesApple: 879fbdc5dcff7136abceb7880fe8a2022a1bd7c3
React-oscompat: 93b5535ea7f7dff46aaee4f78309a70979bdde9d
React-perflogger: 5536d2df3d18fe0920263466f7b46a56351c0510
Expand Down
3 changes: 2 additions & 1 deletion apps/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@tensorflow/tfjs": "^4.22.0",
"@tensorflow/tfjs-backend-webgpu": "^4.22.0",
"@tensorflow/tfjs-vis": "^1.5.1",
"async-mutex": "^0.5.0",
"fast-text-encoding": "^1.0.6",
"react": "19.1.0",
"react-native": "0.81.4",
Expand All @@ -50,7 +51,7 @@
"@types/react": "^18.2.6",
"@types/react-test-renderer": "^18.0.0",
"@types/three": "0.172.0",
"@webgpu/types": "0.1.51",
"@webgpu/types": "0.1.65",
"babel-jest": "^29.6.3",
"eslint": "9.35.0",
"eslint-config-react-native-wcandillon": "4.0.1",
Expand Down
2 changes: 2 additions & 0 deletions apps/example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { ThreeJS } from "./ThreeJS";
import { GradientTiles } from "./GradientTiles";
import { CanvasAPI } from "./CanvasAPI";
import { Tensorflow } from "./Tensorflow";
import { ComputeToys } from "./ComputeToys";

// The two lines below are needed by three.js
import "fast-text-encoding";
Expand All @@ -51,6 +52,7 @@ function App() {
name="HelloTriangleMSAA"
component={HelloTriangleMSAA}
/>
<Stack.Screen name="ComputeToys" component={ComputeToys} />
<Stack.Screen name="ThreeJS" component={ThreeJS} />
<Stack.Screen name="Tensorflow" component={Tensorflow} />
<Stack.Screen name="CanvasAPI" component={CanvasAPI} />
Expand Down
169 changes: 169 additions & 0 deletions apps/example/src/ComputeToys/ComputeToy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import { useCallback, useEffect, useRef, useState } from "react";
import { Canvas, useCanvasEffect } from "react-native-wgpu";
import { useWindowDimensions } from "react-native";
import { useSharedValue } from "react-native-reanimated";
import { Gesture, GestureDetector } from "react-native-gesture-handler";

import { ComputeEngine } from "./engine";

export interface ComputeToy {
shader: string;
uniforms: Record<string, number>;
}

export const useComputeToy = (toyId: number) => {
const [props, setProps] = useState<ComputeToy | null>(null);

useEffect(() => {
(async () => {
const shaderURL = `https://compute.toys/view/${toyId}/wgsl`;
const uniformsURL = `https://compute.toys/view/${toyId}/json`;

// Execute both fetch requests in parallel
const [shaderResponse, uniformsResponse] = await Promise.all([
fetch(shaderURL),
fetch(uniformsURL),
]);

// Process the responses in parallel
const [shader, uniformsJSON] = await Promise.all([
shaderResponse.text(),
uniformsResponse.json(),
]);
const uniforms: Record<string, number> = {};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
uniformsJSON.body.uniforms.forEach((uniform: any) => {
uniforms[uniform.name] = uniform.value;
});
setProps({ shader, uniforms });
})();
}, [toyId]);
return props;
};

export interface ComputeToyProps {
toy: ComputeToy;
}

export const ComputeToy = ({ toy: { shader, uniforms } }: ComputeToyProps) => {
const mouse = useSharedValue({ pos: { x: 0, y: 0 }, click: false });
const { width, height } = useWindowDimensions();
const [engine, setEngine] = useState<ComputeEngine | null>(null);
const animationRef = useRef<number | null>(null);
const lastTimeRef = useRef<number>(0);

// Initialize WebGPU and the compute engine
const canvasRef = useCanvasEffect(() => {
const initWebGPU = async () => {
try {
// Create the compute engine
await ComputeEngine.create();
const eng = ComputeEngine.getInstance();

// Set the canvas surface
if (canvasRef.current) {
eng.setSurface(canvasRef.current!);

// Set the canvas size based on your CANVAS constants
// TODO: use PixelRatio.get()?
eng.resize(width, height, 1);

// Initialize render state
eng.reset();

// Set callbacks for shader compilation
eng.onSuccess((entryPoints) => {
console.log(
"Shader compiled successfully with entry points:",
entryPoints,
);
});

eng.onError((message, row, col) => {
console.error(`Shader error at ${row}:${col} - ${message}`);
});
eng.setCustomFloats(
Object.keys(uniforms),
new Float32Array(Object.values(uniforms)),
);
// Process and compile the shader
const preprocessed = await eng.preprocess(shader);
if (preprocessed) {
await eng.compile(preprocessed);
}

setEngine(eng);
}
} catch (error) {
console.error("Failed to initialize WebGPU:", error);
}
};

initWebGPU();

return () => {
if (animationRef.current !== null) {
cancelAnimationFrame(animationRef.current);
}
};
});

// Animation/render loop
const renderLoop = useCallback(
(timestamp: number) => {
if (!engine) {
return;
}

// Calculate time delta
const delta = lastTimeRef.current
? (timestamp - lastTimeRef.current) / 1000
: 0;
lastTimeRef.current = timestamp;

// Update time uniforms
engine.setTimeElapsed(timestamp / 1000);
engine.setTimeDelta(delta);
if (mouse) {
engine.setMousePos(mouse.value.pos.x, mouse.value.pos.y);
engine.setMouseClick(mouse.value.click);
}
// Render frame

engine.render();
// Schedule next frame
animationRef.current = requestAnimationFrame(renderLoop);
},
[engine, mouse],
);

useEffect(() => {
renderLoop(new Date().getTime());
}, [renderLoop]);

const gesture = Gesture.Pan()
.onChange((e) => {
mouse.value = {
pos: {
x: e.absoluteX / width,
y: e.absoluteY / height,
},
click: true,
};
})
.onEnd((e) => {
mouse.value = {
pos: {
x: e.absoluteX / width,
y: e.absoluteY / height,
},
click: false,
};
});

return (
<GestureDetector gesture={gesture}>
<Canvas ref={canvasRef} style={{ width, height }} />
</GestureDetector>
);
};
10 changes: 10 additions & 0 deletions apps/example/src/ComputeToys/ComputeToys.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ComputeToy, useComputeToy } from "./ComputeToy";

export const ComputeToys = () => {
//1806
const toy = useComputeToy(537);
if (!toy) {
return null;
}
return <ComputeToy toy={toy} />;
};
Loading