From efba6963e439b26326d9ffbb1fefbab59f1cf811 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Thu, 23 Oct 2025 21:17:58 +0200 Subject: [PATCH 1/4] :wrench: --- .github/actions/setup/action.yml | 14 +- .github/workflows/build-dawn.yml | 45 ---- README.md | 22 +- apps/example/ios/Podfile.lock | 4 +- packages/webgpu/package.json | 4 +- packages/webgpu/scripts/install-dawn.ts | 263 ++++++++++++++++++++++++ 6 files changed, 279 insertions(+), 73 deletions(-) delete mode 100644 .github/workflows/build-dawn.yml create mode 100644 packages/webgpu/scripts/install-dawn.ts diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index d25bc4195..c69a3931a 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -31,17 +31,7 @@ runs: run: yarn install --immutable shell: bash - - name: Download Dawn Binary Artifacts - uses: dawidd6/action-download-artifact@v2 - with: - workflow: "build-dawn.yml" - repo: wcandillon/react-native-webgpu - github_token: ${{ inputs.github_token }} - path: artifacts - branch: main - name: dawn-libs - - - name: Copy Artifacts to libs folder + - name: Install Dawn working-directory: packages/webgpu shell: bash - run: yarn copy-artifacts + run: yarn install-dawn diff --git a/.github/workflows/build-dawn.yml b/.github/workflows/build-dawn.yml deleted file mode 100644 index 711beb5ef..000000000 --- a/.github/workflows/build-dawn.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Build Dawn -on: workflow_dispatch -jobs: - build: - runs-on: macos-latest-large - steps: - - name: checkout - uses: actions/checkout@v2 - with: - submodules: true - - name: Initialize Dawn's abseil-cpp submodule - run: | - cd externals/dawn - git submodule update --init third_party/abseil-cpp - - name: Install NDK - uses: nttld/setup-ndk@afb4c9964b521afb97c864b7d40b11e6911bd410 # v1.5.0 - id: setup-ndk - with: - ndk-version: r27d - - name: Set ANDROID_NDK - run: echo "ANDROID_NDK=$ANDROID_HOME/ndk-bundle" >> $GITHUB_ENV - - name: Setup Ninja - uses: seanmiddleditch/gha-setup-ninja@master - - uses: actions/setup-node@v3 - with: - cache: 'yarn' - cache-dependency-path: yarn.lock - - name: Install Package - run: yarn install --frozen-lockfile - - name: Build Dawn - working-directory: packages/webgpu - env: - ANDROID_NDK: ${{ steps.setup-ndk.outputs.ndk-path }} - run: yarn build-dawn - - name: Upload artifacts - Dawn Library Files - if: github.ref == 'refs/heads/main' - uses: actions/upload-artifact@v4 - with: - name: dawn-libs - path: | - packages/webgpu/libs/dawn.json - packages/webgpu/libs/android - packages/webgpu/libs/apple/*.xcframework - packages/webgpu/cpp/dawn - packages/webgpu/cpp/webgpu diff --git a/README.md b/README.md index 605d57a87..2b5197451 100644 --- a/README.md +++ b/README.md @@ -212,27 +212,25 @@ git submodule update --init Make sure you have all the tools required for building the Skia libraries (Android Studio, XCode, Ninja, CMake, Android NDK/build tools). -### Building Dawn - -```sh -yarn -cd packages/webgpu -yarn build-dawn -``` - ### Downloading Dawn There is an alternative way which is to download the prebuilt binaries from GitHub. -You need to have the [Github CLI](https://cli.github.com/) installed: ```sh $ yarn $ cd packages/webgpu -$ yarn download-artifacts -$ yarn copy-artifacts +$ yarn install-dawn ``` -Alternatively you can also download the prebuilt binaries [here](https://github.com/wcandillon/react-native-webgpu/actions/workflows/build-dawn.yml). +### Building Dawn + +Alternatively, you can build Dawn locally. + +```sh +yarn +cd packages/webgpu +yarn build-dawn +``` ### Upgrading diff --git a/apps/example/ios/Podfile.lock b/apps/example/ios/Podfile.lock index b95bf68e5..9fbb71070 100644 --- a/apps/example/ios/Podfile.lock +++ b/apps/example/ios/Podfile.lock @@ -1865,7 +1865,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-wgpu (0.2.9): + - react-native-wgpu (0.2.10): - boost - DoubleConversion - fast_float @@ -2903,7 +2903,7 @@ SPEC CHECKSUMS: React-microtasksnativemodule: 75b6604b667d297292345302cc5bfb6b6aeccc1b react-native-safe-area-context: c6e2edd1c1da07bdce287fa9d9e60c5f7b514616 react-native-skia: 5bf2b2107cd7f2d806fd364f5e16b1c7554ed3cd - react-native-wgpu: 6b98abaead58c53560720db8074bb82b29edd9a8 + react-native-wgpu: 9c80c820813ecb17fe331794180a00fb21a33af2 React-NativeModulesApple: 879fbdc5dcff7136abceb7880fe8a2022a1bd7c3 React-oscompat: 93b5535ea7f7dff46aaee4f78309a70979bdde9d React-perflogger: 5536d2df3d18fe0920263466f7b46a56351c0510 diff --git a/packages/webgpu/package.json b/packages/webgpu/package.json index a7b2f0c9e..f81f323e4 100644 --- a/packages/webgpu/package.json +++ b/packages/webgpu/package.json @@ -19,6 +19,7 @@ "libs/**", "*.podspec" ], + "dawn": "chromium/7472", "scripts": { "test": "NODE_OPTIONS='--experimental-require-module' jest -i", "test:ref": "REFERENCE=true NODE_OPTIONS='--experimental-require-module' jest -i", @@ -32,8 +33,7 @@ "clang-format-android": "find android/cpp/ -iname \"*.h\" -o -iname \"*.m\" -o -iname \"*.cpp\" | xargs clang-format -i", "clang-format-common": "find cpp/rnwgpu -iname \"*.h\" -o -iname \"*.m\" -o -iname \"*.cpp\" | xargs clang-format -i", "cpplint": "cpplint --linelength=230 --filter=-legal/copyright,-whitespace/indent,-whitespace/comments,-whitespace/ending_newline,-build/include_order,-runtime/references,-readability/todo,-whitespace/blank_line,-whitespace/todo,-runtime/int,-build/c++11,-whitespace/parens --exclude=example --exclude=android/.cxx --exclude=cpp/webgpu --exclude=cpp/dawn --exclude=ios --exclude=android/build --exclude=node_modules --recursive .", - "download-artifacts": "tsx scripts/build/download-artifacts.ts && yarn copy-artifacts", - "copy-artifacts": "tsx scripts/build/copy-artifacts.ts", + "install-dawn": "tsx scripts/install-dawn.ts", "codegen": "tsx scripts/codegen/codegen.ts && yarn clang-format" }, "keywords": [ diff --git a/packages/webgpu/scripts/install-dawn.ts b/packages/webgpu/scripts/install-dawn.ts new file mode 100644 index 000000000..f5fb105bc --- /dev/null +++ b/packages/webgpu/scripts/install-dawn.ts @@ -0,0 +1,263 @@ +#!/usr/bin/env tsx + +import { execSync } from "child_process"; +import { existsSync, mkdirSync, readFileSync, rmSync } from "fs"; +import { join } from "path"; + +import { checkBuildArtifacts } from "./build/dawn-configuration"; + +// ANSI color codes +const colors = { + reset: "\x1b[0m", + bright: "\x1b[1m", + dim: "\x1b[2m", + red: "\x1b[31m", + green: "\x1b[32m", + yellow: "\x1b[33m", + blue: "\x1b[34m", + cyan: "\x1b[36m", + white: "\x1b[37m", +}; + +const symbols = { + success: "✅", + error: "❌", + warning: "⚠️", + info: "ℹ️", + download: "⬇️", + extract: "📦", + clean: "🧹", + check: "✓", + arrow: "→", + rocket: "🚀", +}; + +// Helper functions for colored output +const log = { + info: (msg: string) => + console.log(`${colors.cyan}${symbols.info} ${msg}${colors.reset}`), + success: (msg: string) => + console.log(`${colors.green}${symbols.success} ${msg}${colors.reset}`), + error: (msg: string) => + console.error(`${colors.red}${symbols.error} ${msg}${colors.reset}`), + warning: (msg: string) => + console.log(`${colors.yellow}${symbols.warning} ${msg}${colors.reset}`), + step: (msg: string) => + console.log(`${colors.blue}${symbols.arrow} ${msg}${colors.reset}`), + header: (msg: string) => { + console.log(""); + console.log( + `${colors.bright}${colors.cyan}${"=".repeat(60)}${colors.reset}`, + ); + console.log( + `${colors.bright}${colors.cyan}${symbols.rocket} ${msg}${colors.reset}`, + ); + console.log( + `${colors.bright}${colors.cyan}${"=".repeat(60)}${colors.reset}`, + ); + console.log(""); + }, + subheader: (msg: string) => { + console.log(""); + console.log(`${colors.bright}${colors.blue}── ${msg} ──${colors.reset}`); + }, +}; + +// Read the dawn version from package.json +const packageJsonPath = join(__dirname, "..", "package.json"); +const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")); +const dawnVersion = packageJson.dawn; + +if (!dawnVersion) { + log.error("No 'dawn' field found in package.json"); + process.exit(1); +} + +// Parse the dawn version to construct the release tag +// Format: "chromium/7472" -> "dawn-chromium-7472" +const releaseTag = `dawn-${dawnVersion.replace("/", "-")}`; +const releaseUrl = `https://github.com/Shopify/react-native-skia/releases/tag/${releaseTag}`; + +log.header(`Installing Dawn ${dawnVersion}`); +log.info(`Release: ${colors.dim}${releaseUrl}${colors.reset}`); + +// Define the libs directory +const libsDir = join(__dirname, "..", "libs"); + +// Clean up existing libs directory if it exists +if (existsSync(libsDir)) { + log.step(`${symbols.clean} Cleaning existing libs directory...`); + rmSync(libsDir, { recursive: true, force: true }); +} + +// Create libs directory +mkdirSync(libsDir, { recursive: true }); + +// Define the cpp directory +const cppDir = join(__dirname, "..", "cpp"); + +// Define the assets to download +const assets = [ + { + name: `dawn-android-${releaseTag}.tar.gz`, + extractTo: libsDir, + postProcess: () => { + // Rename dawn-android to android for compatibility + const oldPath = join(libsDir, "dawn-android"); + const newPath = join(libsDir, "android"); + if (existsSync(oldPath)) { + execSync(`mv "${oldPath}" "${newPath}"`); + } + }, + }, + { + name: `dawn-apple-${releaseTag}.xcframework.tar.gz`, + extractTo: libsDir, + postProcess: () => { + // The extracted xcframework needs to be placed as libs/apple/libwebgpu_dawn.xcframework + const extractedPath = join(libsDir, "dawn-apple.xcframework"); + const targetDir = join(libsDir, "apple"); + const targetPath = join(targetDir, "libwebgpu_dawn.xcframework"); + + if (existsSync(extractedPath)) { + // Create apple directory if it doesn't exist + if (!existsSync(targetDir)) { + mkdirSync(targetDir, { recursive: true }); + } + // Move the xcframework to the correct location + execSync(`mv "${extractedPath}" "${targetPath}"`); + } + }, + }, + { + name: `dawn-headers-${releaseTag}.tar.gz`, + extractTo: libsDir, + postProcess: () => { + // Move headers directly to cpp directory + const headersIncludePath = join(libsDir, "dawn-headers", "include"); + if (existsSync(join(headersIncludePath, "webgpu"))) { + execSync(`cp -R "${join(headersIncludePath, "webgpu")}" "${cppDir}/"`); + } + if (existsSync(join(headersIncludePath, "dawn"))) { + execSync(`cp -R "${join(headersIncludePath, "dawn")}" "${cppDir}/"`); + } + // Remove the dawn-headers directory after copying + rmSync(join(libsDir, "dawn-headers"), { recursive: true, force: true }); + }, + }, +]; + +// Download and extract assets +log.subheader("Downloading Assets"); + +// Add nice names for display +const assetNames: { [key: string]: string } = { + [`dawn-android-${releaseTag}.tar.gz`]: "Android Libraries", + [`dawn-apple-${releaseTag}.xcframework.tar.gz`]: "Apple Framework", + [`dawn-headers-${releaseTag}.tar.gz`]: "C++ Headers", +}; + +for (const [index, asset] of assets.entries()) { + const assetUrl = `https://github.com/Shopify/react-native-skia/releases/download/${releaseTag}/${asset.name}`; + const tarPath = join(libsDir, asset.name); + const displayName = assetNames[asset.name] || asset.name; + + console.log(""); + log.step(`[${index + 1}/${assets.length}] ${displayName}`); + + try { + // Download the asset + process.stdout.write( + ` ${colors.dim}${symbols.download} Downloading...${colors.reset}`, + ); + execSync(`curl -L -o "${tarPath}" "${assetUrl}" 2>&1`, { stdio: "pipe" }); + process.stdout.write("\r\x1b[K"); // Clear the line + + // Extract the tar file + process.stdout.write( + ` ${colors.dim}${symbols.extract} Extracting...${colors.reset}`, + ); + execSync(`tar -xzf "${tarPath}" -C "${asset.extractTo}"`, { + stdio: "pipe", + }); + process.stdout.write("\r\x1b[K"); // Clear the line + + // Remove the tar file after extraction + rmSync(tarPath); + + // Run post-processing if defined + if (asset.postProcess) { + asset.postProcess(); + } + + log.success(`${displayName} installed`); + } catch (error) { + console.log(""); // New line after progress + log.error(`Failed to process ${displayName}`); + console.error(error); + process.exit(1); + } +} + +// Download dawn.json from the Dawn repository +log.subheader("Configuration"); + +console.log(""); +log.step("Downloading dawn.json configuration"); +const dawnJsonUrl = `https://raw.githubusercontent.com/google/dawn/${dawnVersion}/src/dawn/dawn.json`; +const dawnJsonPath = join(libsDir, "dawn.json"); + +try { + process.stdout.write( + ` ${colors.dim}${symbols.download} Fetching configuration...${colors.reset}`, + ); + execSync(`curl -L -o "${dawnJsonPath}" "${dawnJsonUrl}" 2>&1`, { + stdio: "pipe", + }); + process.stdout.write("\r\x1b[K"); // Clear the line + log.success("Configuration downloaded"); +} catch (error) { + console.log(""); // New line after progress + log.error("Failed to download dawn.json"); + console.error(error); + process.exit(1); +} + +// Verify build artifacts +log.subheader("Verifying Installation"); +console.log(""); + +const originalLog = console.log; +try { + // Capture the output to format it nicely + const artifacts: string[] = []; + console.log = (msg: string) => { + if (msg.includes("✅")) { + artifacts.push(msg.replace("✅", "").trim()); + } else if (msg.includes("Check build artifacts")) { + // Skip this line + } else if (msg.includes("Failed:")) { + // Will be handled by the error + } else { + originalLog(msg); + } + }; + + checkBuildArtifacts(); + console.log = originalLog; + + // Display verified artifacts + artifacts.forEach((artifact) => { + console.log( + ` ${colors.green}${symbols.check}${colors.reset} ${colors.dim}${artifact}${colors.reset}`, + ); + }); + + console.log(""); + log.header(`Dawn ${dawnVersion} installed successfully!`); +} catch (error) { + console.log = originalLog; + console.log(""); + log.error("Installation verification failed"); + throw error; +} From 5c1bcb5bbd329b2e780252bce486cdcdeb29c6e9 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Thu, 23 Oct 2025 21:26:48 +0200 Subject: [PATCH 2/4] :wrench: --- .../scripts/build/dawn-configuration.ts | 2 +- packages/webgpu/scripts/codegen/model/dawn.ts | 5 +++- packages/webgpu/scripts/install-dawn.ts | 24 ------------------- 3 files changed, 5 insertions(+), 26 deletions(-) diff --git a/packages/webgpu/scripts/build/dawn-configuration.ts b/packages/webgpu/scripts/build/dawn-configuration.ts index f82f7c254..1cc73f44f 100644 --- a/packages/webgpu/scripts/build/dawn-configuration.ts +++ b/packages/webgpu/scripts/build/dawn-configuration.ts @@ -93,5 +93,5 @@ export const checkBuildArtifacts = () => { libs.forEach((lib) => { checkFileExists(`libs/apple/${lib}.xcframework`); }); - checkFileExists("libs/dawn.json"); + //checkFileExists("libs/dawn.json"); }; diff --git a/packages/webgpu/scripts/codegen/model/dawn.ts b/packages/webgpu/scripts/codegen/model/dawn.ts index fb74c6479..ccde1ddf7 100644 --- a/packages/webgpu/scripts/codegen/model/dawn.ts +++ b/packages/webgpu/scripts/codegen/model/dawn.ts @@ -1,5 +1,7 @@ import _ from "lodash"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error import dawn from "../../../libs/dawn.json"; export const mapKeys = (obj: T) => @@ -222,7 +224,8 @@ export const resolveNative = ( if (!hasPropery(object, "methods")) { return null; } - return object.methods.find((m) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (object.methods as any).find((m: any) => { return _.camelCase(m.name.toLowerCase()) === methodName; }); }; diff --git a/packages/webgpu/scripts/install-dawn.ts b/packages/webgpu/scripts/install-dawn.ts index f5fb105bc..6fa8f3cc4 100644 --- a/packages/webgpu/scripts/install-dawn.ts +++ b/packages/webgpu/scripts/install-dawn.ts @@ -199,30 +199,6 @@ for (const [index, asset] of assets.entries()) { } } -// Download dawn.json from the Dawn repository -log.subheader("Configuration"); - -console.log(""); -log.step("Downloading dawn.json configuration"); -const dawnJsonUrl = `https://raw.githubusercontent.com/google/dawn/${dawnVersion}/src/dawn/dawn.json`; -const dawnJsonPath = join(libsDir, "dawn.json"); - -try { - process.stdout.write( - ` ${colors.dim}${symbols.download} Fetching configuration...${colors.reset}`, - ); - execSync(`curl -L -o "${dawnJsonPath}" "${dawnJsonUrl}" 2>&1`, { - stdio: "pipe", - }); - process.stdout.write("\r\x1b[K"); // Clear the line - log.success("Configuration downloaded"); -} catch (error) { - console.log(""); // New line after progress - log.error("Failed to download dawn.json"); - console.error(error); - process.exit(1); -} - // Verify build artifacts log.subheader("Verifying Installation"); console.log(""); From 18e4c901fc2934234202ae85e200ad78a423204a Mon Sep 17 00:00:00 2001 From: William Candillon Date: Thu, 23 Oct 2025 21:32:56 +0200 Subject: [PATCH 3/4] :wrench: --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cceebf135..c6a2bc10b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,10 +36,6 @@ jobs: - name: Typecheck files run: yarn tsc - - name: Codegen - working-directory: packages/webgpu - run: yarn codegen - test: runs-on: macos-latest steps: From 4b5d47ec31e3f46a5343d701cf0f771b75014aca Mon Sep 17 00:00:00 2001 From: William Candillon Date: Thu, 23 Oct 2025 22:10:04 +0200 Subject: [PATCH 4/4] :green_heart: --- packages/webgpu/cpp/rnwgpu/api/GPU.h | 1 - packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/webgpu/cpp/rnwgpu/api/GPU.h b/packages/webgpu/cpp/rnwgpu/api/GPU.h index d64f08122..ad4de4a68 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPU.h +++ b/packages/webgpu/cpp/rnwgpu/api/GPU.h @@ -12,7 +12,6 @@ #include "AsyncRunner.h" -#include "dawn/dawn_proc.h" #include "dawn/native/DawnNative.h" #include "webgpu/webgpu_cpp.h" diff --git a/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp b/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp index b6f7f0aa2..15e7f4acd 100644 --- a/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp +++ b/packages/webgpu/cpp/rnwgpu/api/GPUCanvasContext.cpp @@ -4,7 +4,11 @@ #include #ifdef __APPLE__ -#include "dawn/native/MetalBackend.h" +namespace dawn::native::metal { + +void WaitForCommandsToBeScheduled(WGPUDevice device); + +} #endif namespace rnwgpu {