From b55dbfec64a721b41a4846a8b41db6a91b6d9954 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 15 Aug 2025 12:29:43 +0100 Subject: [PATCH 1/4] Support Embedded Swift in `WebGPUDemo` This adopts new `DefaultExecutorFactory`, which means we can mark `main` entrypoint as `async`. Due to https://github.com/swiftlang/swift/issues/83750 we have to use `JSPromise`-returning functions from WebAPIKit, but otherwise this is now fully compatible with Embedded Swift. --- WebGPUDemo/.sourcekit-lsp/config.json | 2 +- WebGPUDemo/Package.resolved | 6 ++-- WebGPUDemo/Package.swift | 2 +- WebGPUDemo/Sources/Entrypoint.swift | 47 ++++++++++++++------------- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/WebGPUDemo/.sourcekit-lsp/config.json b/WebGPUDemo/.sourcekit-lsp/config.json index b789e87..0833e7b 100644 --- a/WebGPUDemo/.sourcekit-lsp/config.json +++ b/WebGPUDemo/.sourcekit-lsp/config.json @@ -1,5 +1,5 @@ { "swiftPM": { - "swiftSDK": "swift-DEVELOPMENT-SNAPSHOT-2025-06-03-a_wasm" + "swiftSDK": "swift-DEVELOPMENT-SNAPSHOT-2025-08-14-a_wasm-embedded" } } diff --git a/WebGPUDemo/Package.resolved b/WebGPUDemo/Package.resolved index 275b55a..0dc37ac 100644 --- a/WebGPUDemo/Package.resolved +++ b/WebGPUDemo/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "dcbd3e085935ccdf4178dc9a180a6938b0e73f641b50437486b67cc0f3d7c82b", + "originHash" : "78d4c78903f08d936d36ab5b76f8b1098413d1b183a55c2f385b3f32a7b53682", "pins" : [ { "identity" : "javascriptkit", "kind" : "remoteSourceControl", "location" : "https://github.com/swiftwasm/JavaScriptKit.git", "state" : { - "branch" : "main", - "revision" : "7eb770ee75b3c1832eef6e7a8a1d46d996fc86ae" + "branch" : "yt/embedded-fix", + "revision" : "a2c2963f1e730be63398f24b7d1ac52ddf6cce17" } }, { diff --git a/WebGPUDemo/Package.swift b/WebGPUDemo/Package.swift index a766efb..1d1501c 100644 --- a/WebGPUDemo/Package.swift +++ b/WebGPUDemo/Package.swift @@ -11,7 +11,7 @@ let package = Package( ), .package( url: "https://github.com/swiftwasm/JavaScriptKit.git", - branch: "main", + branch: "yt/embedded-fix", ), ], targets: [ diff --git a/WebGPUDemo/Sources/Entrypoint.swift b/WebGPUDemo/Sources/Entrypoint.swift index 4cf2a38..656945f 100644 --- a/WebGPUDemo/Sources/Entrypoint.swift +++ b/WebGPUDemo/Sources/Entrypoint.swift @@ -30,32 +30,33 @@ func fetchImageBitmap(url: String) async throws(JSException) -> ImageBitmap { ) } +typealias DefaultExecutorFactory = JavaScriptEventLoop + @main struct Entrypoint { - static func main() { - JavaScriptEventLoop.installGlobalExecutor() + static func main() async { let gpu = Window.global.navigator.gpu - Task { - do throws(JSException) { - let adapter = try await gpu.requestAdapter()! - let device = try await adapter.requestDevice() - - let renderer = try await Renderer( - device: device, - gpu: gpu, - assets: .init( - shaders: fetchString(url: "Resources/shaders.wgsl"), - model: fetchString(url: "Resources/SwiftLogo/Swift3DLogo.obj"), - albedo: fetchImageBitmap(url: "Resources/SwiftLogo/T_M_swiftLogo_BaseColor.png"), - normal: fetchImageBitmap(url: "Resources/SwiftLogo/T_M_swiftLogo_Normal.png"), - metalRoughness: fetchImageBitmap(url: "Resources/SwiftLogo/T_M_swiftLogo_MetalRoughness.png"), - ), - ) - - draw(renderer: renderer) - } catch { - console.error(data: error.thrownValue) - } + + do throws(JSException) { + let adapterPromise: JSPromise = gpu.requestAdapter() + let devicePromise = JSPromise(from: try await adapterPromise.value().requestDevice())! + let device = try await GPUDevice(unsafelyWrapping: devicePromise.value().object!) + + let renderer = try await Renderer( + device: device, + gpu: gpu, + assets: .init( + shaders: fetchString(url: "Resources/shaders.wgsl"), + model: fetchString(url: "Resources/SwiftLogo/Swift3DLogo.obj"), + albedo: fetchImageBitmap(url: "Resources/SwiftLogo/T_M_swiftLogo_BaseColor.png"), + normal: fetchImageBitmap(url: "Resources/SwiftLogo/T_M_swiftLogo_Normal.png"), + metalRoughness: fetchImageBitmap(url: "Resources/SwiftLogo/T_M_swiftLogo_MetalRoughness.png"), + ), + ) + + draw(renderer: renderer) + } catch { + console.error(data: error.thrownValue) } } } From 9291fb527bc0d4b6311c8cfdc9eab43864a5b607 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 15 Aug 2025 14:31:46 +0100 Subject: [PATCH 2/4] Update WebGPUDemo/Sources/Entrypoint.swift --- WebGPUDemo/Sources/Entrypoint.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/WebGPUDemo/Sources/Entrypoint.swift b/WebGPUDemo/Sources/Entrypoint.swift index 656945f..4d0d62e 100644 --- a/WebGPUDemo/Sources/Entrypoint.swift +++ b/WebGPUDemo/Sources/Entrypoint.swift @@ -38,6 +38,7 @@ struct Entrypoint { let gpu = Window.global.navigator.gpu do throws(JSException) { + // Using promises instead of `async` functions due to https://github.com/swiftlang/swift/issues/83750 let adapterPromise: JSPromise = gpu.requestAdapter() let devicePromise = JSPromise(from: try await adapterPromise.value().requestDevice())! let device = try await GPUDevice(unsafelyWrapping: devicePromise.value().object!) From b339b600d30dcab70cc43b60aa322303e839fe7b Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 15 Aug 2025 14:32:24 +0100 Subject: [PATCH 3/4] Bump JavaScriptKit dependency to 0.33.1 --- WebGPUDemo/Package.resolved | 6 +++--- WebGPUDemo/Package.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/WebGPUDemo/Package.resolved b/WebGPUDemo/Package.resolved index 0dc37ac..52fa2d6 100644 --- a/WebGPUDemo/Package.resolved +++ b/WebGPUDemo/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "78d4c78903f08d936d36ab5b76f8b1098413d1b183a55c2f385b3f32a7b53682", + "originHash" : "8b1d9dc30426eb64ddd75cf52781d1b481727ea88d6e78f3147f650919d2e2a6", "pins" : [ { "identity" : "javascriptkit", "kind" : "remoteSourceControl", "location" : "https://github.com/swiftwasm/JavaScriptKit.git", "state" : { - "branch" : "yt/embedded-fix", - "revision" : "a2c2963f1e730be63398f24b7d1ac52ddf6cce17" + "revision" : "7510b04120bb26a25dd287af71de47065d577c7e", + "version" : "0.33.1" } }, { diff --git a/WebGPUDemo/Package.swift b/WebGPUDemo/Package.swift index 1d1501c..fed0dee 100644 --- a/WebGPUDemo/Package.swift +++ b/WebGPUDemo/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 6.1 +// swift-tools-version: 6.2 import PackageDescription @@ -11,7 +11,7 @@ let package = Package( ), .package( url: "https://github.com/swiftwasm/JavaScriptKit.git", - branch: "yt/embedded-fix", + from: "0.33.1", ), ], targets: [ From 2355eb4996aa54f8bc3f826e04f907fbfb7ee8a5 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 15 Aug 2025 16:29:46 +0100 Subject: [PATCH 4/4] Update README.md --- WebGPUDemo/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/WebGPUDemo/README.md b/WebGPUDemo/README.md index 519ff7a..69b93ad 100644 --- a/WebGPUDemo/README.md +++ b/WebGPUDemo/README.md @@ -9,6 +9,16 @@ the Swift SDK in the following command to the version that matches your installe swift package --swift-sdk swift-6.2-DEVELOPMENT-SNAPSHOT-2025-06-17-a_wasm js --use-cdn ``` +If you'd like to produce a smaller binary (under 400 kB), you'll have to use +`swift-DEVELOPMENT-SNAPSHOT-2025-08-11` or later development snapshot of the `main` Swift toolchain +branch. Earlier versions (including Swift 6.2) have no support for `async` functions in Embedded Swift, +which is required for WebGPU setup. Use the following command to build with Embedded Swift (update for +your installed toolchain version if needed): + +``` +swift package --swift-sdk swift-DEVELOPMENT-SNAPSHOT-2025-08-11-a_wasm-embedded js --use-cdn -c release +``` + WebGPU is enabled by default in beta and technical preview versions of Safari. Safari 17 and 18 require enabling WebGPU feature flag as shown on the screenshot: