diff options
-rw-r--r-- | ext/webgpu/02_surface.js | 27 | ||||
-rw-r--r-- | ext/webgpu/Cargo.toml | 2 | ||||
-rw-r--r-- | ext/webgpu/byow.rs | 127 | ||||
-rw-r--r-- | ext/webgpu/lib.rs | 5 | ||||
-rw-r--r-- | runtime/js/90_deno_ns.js | 6 |
5 files changed, 161 insertions, 6 deletions
diff --git a/ext/webgpu/02_surface.js b/ext/webgpu/02_surface.js index 319179dc1..1c9751f62 100644 --- a/ext/webgpu/02_surface.js +++ b/ext/webgpu/02_surface.js @@ -16,6 +16,7 @@ const { ObjectPrototypeIsPrototypeOf, Symbol, SymbolFor, + TypeError, } = primordials; import * as webidl from "ext:deno_webidl/00_webidl.js"; @@ -166,8 +167,28 @@ function createCanvasContext(options) { return canvasContext; } -function presentGPUCanvasContext(ctx) { - ctx[_present](); +// External webgpu surfaces + +// TODO(@littledivy): This will extend `OffscreenCanvas` when we add it. +class UnsafeWindowSurface { + #ctx; + #surfaceRid; + + constructor(system, win, display) { + this.#surfaceRid = ops.op_webgpu_surface_create(system, win, display); + } + + getContext(context) { + if (context !== "webgpu") { + throw new TypeError("Only 'webgpu' context is supported."); + } + this.#ctx = createCanvasContext({ surfaceRid: this.#surfaceRid }); + return this.#ctx; + } + + present() { + this.#ctx[_present](); + } } -export { createCanvasContext, GPUCanvasContext, presentGPUCanvasContext }; +export { GPUCanvasContext, UnsafeWindowSurface }; diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index b98ae20d8..bdc7bb306 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -20,7 +20,7 @@ deno_core.workspace = true serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["full"] } wgpu-types = { workspace = true, features = ["trace", "replay", "serde"] } -raw-window-handle = { workspace = true, optional = true } +raw-window-handle = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgpu-core] workspace = true diff --git a/ext/webgpu/byow.rs b/ext/webgpu/byow.rs new file mode 100644 index 000000000..984eaae1b --- /dev/null +++ b/ext/webgpu/byow.rs @@ -0,0 +1,127 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::type_error; +use deno_core::error::AnyError; +use deno_core::op2; +use deno_core::OpState; +use deno_core::ResourceId; +use std::ffi::c_void; + +use crate::surface::WebGpuSurface; + +#[op2(fast)] +#[smi] +pub fn op_webgpu_surface_create( + state: &mut OpState, + #[string] system: &str, + p1: *const c_void, + p2: *const c_void, +) -> Result<ResourceId, AnyError> { + let instance = state.borrow::<super::Instance>(); + // Security note: + // + // The `p1` and `p2` parameters are pointers to platform-specific window + // handles. + // + // The code below works under the assumption that: + // + // - handles can only be created by the FFI interface which + // enforces --allow-ffi. + // + // - `*const c_void` deserizalizes null and v8::External. + // + // - Only FFI can export v8::External to user code. + if p1.is_null() { + return Err(type_error("Invalid parameters")); + } + + let (win_handle, display_handle) = raw_window(system, p1, p2)?; + let surface = + instance.instance_create_surface(display_handle, win_handle, ()); + + let rid = state + .resource_table + .add(WebGpuSurface(instance.clone(), surface)); + Ok(rid) +} + +type RawHandles = ( + raw_window_handle::RawWindowHandle, + raw_window_handle::RawDisplayHandle, +); + +#[cfg(target_os = "macos")] +fn raw_window( + system: &str, + ns_window: *const c_void, + ns_view: *const c_void, +) -> Result<RawHandles, AnyError> { + if system != "cocoa" { + return Err(type_error("Invalid system on macOS")); + } + + let win_handle = { + let mut handle = raw_window_handle::AppKitWindowHandle::empty(); + handle.ns_window = ns_window as *mut c_void; + handle.ns_view = ns_view as *mut c_void; + + raw_window_handle::RawWindowHandle::AppKit(handle) + }; + let display_handle = raw_window_handle::RawDisplayHandle::AppKit( + raw_window_handle::AppKitDisplayHandle::empty(), + ); + Ok((win_handle, display_handle)) +} + +#[cfg(target_os = "windows")] +fn raw_window( + system: &str, + window: *const c_void, + hinstance: *const c_void, +) -> Result<RawHandles, AnyError> { + use raw_window_handle::WindowsDisplayHandle; + if system != "win32" { + return Err(type_error("Invalid system on Windows")); + } + + let win_handle = { + use raw_window_handle::Win32WindowHandle; + + let mut handle = Win32WindowHandle::empty(); + handle.hwnd = window as *mut c_void; + handle.hinstance = hinstance as *mut c_void; + + raw_window_handle::RawWindowHandle::Win32(handle) + }; + + let display_handle = + raw_window_handle::RawDisplayHandle::Windows(WindowsDisplayHandle::empty()); + Ok((win_handle, display_handle)) +} + +#[cfg(target_os = "linux")] +fn raw_window( + system: &str, + window: *const c_void, + display: *const c_void, +) -> Result<RawHandles, AnyError> { + if system != "x11" { + return Err(type_error("Invalid system on Linux")); + } + + let win_handle = { + let mut handle = raw_window_handle::XlibWindowHandle::empty(); + handle.window = window as *mut c_void as _; + + raw_window_handle::RawWindowHandle::Xlib(handle) + }; + + let display_handle = { + let mut handle = raw_window_handle::XlibDisplayHandle::empty(); + handle.display = display as *mut c_void; + + raw_window_handle::RawDisplayHandle::Xlib(handle) + }; + + Ok((win_handle, display_handle)) +} diff --git a/ext/webgpu/lib.rs b/ext/webgpu/lib.rs index abb36fb8d..99c8fcf6b 100644 --- a/ext/webgpu/lib.rs +++ b/ext/webgpu/lib.rs @@ -67,6 +67,7 @@ mod macros { pub mod binding; pub mod buffer; pub mod bundle; +pub mod byow; pub mod command_encoder; pub mod compute_pass; pub mod error; @@ -214,7 +215,9 @@ deno_core::extension!( // surface surface::op_webgpu_surface_configure, surface::op_webgpu_surface_get_current_texture, - surface::op_webgpu_surface_present + surface::op_webgpu_surface_present, + // byow + byow::op_webgpu_surface_create, ], esm = ["00_init.js", "02_surface.js"], lazy_loaded_esm = ["01_webgpu.js"], diff --git a/runtime/js/90_deno_ns.js b/runtime/js/90_deno_ns.js index 97b4a9531..058985fbf 100644 --- a/runtime/js/90_deno_ns.js +++ b/runtime/js/90_deno_ns.js @@ -29,6 +29,7 @@ import * as tty from "ext:runtime/40_tty.js"; import * as httpRuntime from "ext:runtime/40_http.js"; import * as kv from "ext:deno_kv/01_db.ts"; import * as cron from "ext:deno_cron/01_cron.ts"; +import * as webgpuSurface from "ext:deno_webgpu/02_surface.js"; const denoNs = { metrics: core.metrics, @@ -222,7 +223,9 @@ denoNsUnstableById[unstableIds.net] = { // denoNsUnstableById[unstableIds.unsafeProto] = {} -// denoNsUnstableById[unstableIds.webgpu] = {} +denoNsUnstableById[unstableIds.webgpu] = { + UnsafeWindowSurface: webgpuSurface.UnsafeWindowSurface, +}; // denoNsUnstableById[unstableIds.workerOptions] = {} @@ -242,6 +245,7 @@ const denoNsUnstable = { UnsafePointer: ffi.UnsafePointer, UnsafePointerView: ffi.UnsafePointerView, UnsafeFnPointer: ffi.UnsafeFnPointer, + UnsafeWindowSurface: webgpuSurface.UnsafeWindowSurface, flock: fs.flock, flockSync: fs.flockSync, funlock: fs.funlock, |