frazzle
frazzle6mo ago

Deno BYOW help with macOS [Solved] and X11

https://github.com/fazil47/deno_winit I'm trying to make Deno binding for winit for using WebGPU, it's working for Wayland and Windows but not for macOS and X11.
GitHub
GitHub - fazil47/deno_winit
Contribute to fazil47/deno_winit development by creating an account on GitHub.
6 Replies
frazzle
frazzleOP6mo ago
This is the setup code in Rust (in src/lib.rs):
match window.raw_window_handle() {
raw_window_handle::RawWindowHandle::Win32(handle) => setup_func(
handle.hwnd,
handle.hinstance,
window.inner_size().width,
window.inner_size().height,
),
raw_window_handle::RawWindowHandle::AppKit(handle) => setup_func(
handle.ns_view,
null::<ffi::c_void>() as *mut ffi::c_void,
window.inner_size().width,
window.inner_size().height,
),
_ => (),
}

if let raw_window_handle::RawWindowHandle::Wayland(window_handle) = window.raw_window_handle() {
match window.raw_display_handle() {
raw_window_handle::RawDisplayHandle::Wayland(display_handle) => setup_func(
window_handle.surface,
display_handle.display,
window.inner_size().width,
window.inner_size().height,
),
_ => (),
}
} else if let raw_window_handle::RawWindowHandle::Xlib(window_handle) =
window.raw_window_handle()
{
match window.raw_display_handle() {
raw_window_handle::RawDisplayHandle::Xlib(display_handle) => {
setup_func(
window_handle.window as *mut ffi::c_void,
display_handle.display,
window.inner_size().width,
window.inner_size().height,
);
}
_ => (),
}
}
match window.raw_window_handle() {
raw_window_handle::RawWindowHandle::Win32(handle) => setup_func(
handle.hwnd,
handle.hinstance,
window.inner_size().width,
window.inner_size().height,
),
raw_window_handle::RawWindowHandle::AppKit(handle) => setup_func(
handle.ns_view,
null::<ffi::c_void>() as *mut ffi::c_void,
window.inner_size().width,
window.inner_size().height,
),
_ => (),
}

if let raw_window_handle::RawWindowHandle::Wayland(window_handle) = window.raw_window_handle() {
match window.raw_display_handle() {
raw_window_handle::RawDisplayHandle::Wayland(display_handle) => setup_func(
window_handle.surface,
display_handle.display,
window.inner_size().width,
window.inner_size().height,
),
_ => (),
}
} else if let raw_window_handle::RawWindowHandle::Xlib(window_handle) =
window.raw_window_handle()
{
match window.raw_display_handle() {
raw_window_handle::RawDisplayHandle::Xlib(display_handle) => {
setup_func(
window_handle.window as *mut ffi::c_void,
display_handle.display,
window.inner_size().width,
window.inner_size().height,
);
}
_ => (),
}
}
And these are the callback in Deno (in mod.ts),
let surface: Deno.UnsafeWindowSurface | null = null;
let context: GPUCanvasContext | null = null;
const setupFunctionCallback = new Deno.UnsafeCallback(
{ parameters: ["pointer", "pointer", "u32", "u32"], result: "void" },
(winHandle, displayHandle, width, height) => {
if (!this.system) {
console.error("System not supported.");
return;
}

surface = new Deno.UnsafeWindowSurface(
this.system,
winHandle,
displayHandle
);
context = surface.getContext("webgpu");
context.configure({
device,
format: this.presentationFormat,
width,
height,
});
this.setupFunction(device, context);
}
);

const drawFunctionCallback = new Deno.UnsafeCallback(
{ parameters: [], result: "void" },
() => {
if (!surface) {
console.error("Surface not initialized.");
return;
}

if (!context) {
console.error("Context not initialized.");
return;
}

this.drawFunction(device, context);
surface.present();
}
);
let surface: Deno.UnsafeWindowSurface | null = null;
let context: GPUCanvasContext | null = null;
const setupFunctionCallback = new Deno.UnsafeCallback(
{ parameters: ["pointer", "pointer", "u32", "u32"], result: "void" },
(winHandle, displayHandle, width, height) => {
if (!this.system) {
console.error("System not supported.");
return;
}

surface = new Deno.UnsafeWindowSurface(
this.system,
winHandle,
displayHandle
);
context = surface.getContext("webgpu");
context.configure({
device,
format: this.presentationFormat,
width,
height,
});
this.setupFunction(device, context);
}
);

const drawFunctionCallback = new Deno.UnsafeCallback(
{ parameters: [], result: "void" },
() => {
if (!surface) {
console.error("Surface not initialized.");
return;
}

if (!context) {
console.error("Context not initialized.");
return;
}

this.drawFunction(device, context);
surface.present();
}
);
This is the from the Deno.UnsafeWindowSurface doc:
| system | winHandle | displayHandle |
| ----------------- | ------------- | --------------- |
| "cocoa" (macOS) | `NSView*` | - |
| "win32" (Windows) | `HWND` | `HINSTANCE` |
| "x11" (Linux) | Xlib `Window` | Xlib `Display*` |
| "wayland" (Linux) | `wl_surface*` | `wl_display*` |
| system | winHandle | displayHandle |
| ----------------- | ------------- | --------------- |
| "cocoa" (macOS) | `NSView*` | - |
| "win32" (Windows) | `HWND` | `HINSTANCE` |
| "x11" (Linux) | Xlib `Window` | Xlib `Display*` |
| "wayland" (Linux) | `wl_surface*` | `wl_display*` |
For macOS, I'm passing in handle.ns_view for the window handle and a null pointer for the display handle but I think the draw function callback is being called before the setup function and nothing gets drawn to the window. When I pass in handle.ns_window for the window handle and handle.ns_view for the display handle it does work except it doesn't redraw properly when the window is resized. @divy what am I doing wrong? For X11 I have to check again, the window doesn't even spawn but that could be because I'm not using winit correctly.
frazzle
frazzleOP6mo ago
This is what it looks like when it works correctly:
No description
Deno AI Helper
Deno AI Helper6mo ago
I wasn't able to find the answer to your question in the official Deno documentation. However, based on your message, it seems like you are working on Deno bindings for winit to use WebGPU and are experiencing issues specifically with macOS and X11. Without more specific details or error messages, it's difficult to provide targeted advice. However, here are a few general suggestions that might help: 1. Ensure that you have the necessary dependencies and development tools installed for macOS and X11. This might include XQuartz for X11 support on macOS. 2. Check if there are any platform-specific configurations or conditional compilation flags that need to be set for macOS and X11. 3. Look for any existing issues or pull requests on the deno_winit repository that might be related to macOS or X11 support. Please note that this advice is not based on the Deno documentation, and I recommend double-checking the accuracy of the advice given. If you continue to experience issues, you might want to reach out to the maintainers of the deno_winit repository or seek assistance from the community on platforms like GitHub or Deno-related forums.
divy
divy6mo ago
ns_window is the window handle and ns_view is the display handle. on resize, you need to recreate the surface
frazzle
frazzleOP6mo ago
on resize, you need to recreate the surface
This didn't work either, is this a macOS only limitation? works fine on Windows and Wayland. This is what I did:
WindowEvent::Resized(size) => {
match window.raw_window_handle() {
raw_window_handle::RawWindowHandle::AppKit(handle) => setup_func(
handle.ns_window,
handle.ns_view,
window.inner_size().width,
window.inner_size().height,
),
_ => (),
}
resize_func(size.width, size.height);
}
WindowEvent::Resized(size) => {
match window.raw_window_handle() {
raw_window_handle::RawWindowHandle::AppKit(handle) => setup_func(
handle.ns_window,
handle.ns_view,
window.inner_size().width,
window.inner_size().height,
),
_ => (),
}
resize_func(size.width, size.height);
}
setup_func recreates the WebGPU surface. Worked when I recreated the surface and called the redraw function in the resize callback @divy @crowlKats is it possible to make a headless WebGPU surface and then render it to a texture? I wanted to use three.js with RTT
crowlKats
crowlKats6mo ago
once we have offscreencanvas, you could use that