Skip to content

Commit 36f17fd

Browse files
committed
Add x11 and split out surface methods.
1 parent 61161fe commit 36f17fd

File tree

14 files changed

+524
-1021
lines changed

14 files changed

+524
-1021
lines changed

Cargo.lock

Lines changed: 19 additions & 828 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ autoexamples = false
77
[lints]
88
workspace = true
99

10+
[features]
11+
default = ["wayland"]
12+
wayland = ["processing_render/wayland"]
13+
x11 = ["processing_render/x11"]
14+
1015
[workspace]
1116
resolver = "3"
1217
members = ["crates/*"]
@@ -16,9 +21,13 @@ type_complexity = "allow"
1621
too_many_arguments = "allow"
1722

1823
[workspace.dependencies]
19-
bevy = { git = "https://github.com/bevyengine/bevy", branch = "main", no-default-features = true, features = [
24+
bevy = { git = "https://github.com/bevyengine/bevy", branch = "main", default-features = false, features = [
2025
"bevy_render",
2126
"bevy_color",
27+
"bevy_pbr",
28+
"bevy_log",
29+
"bevy_window",
30+
"bevy_winit",
2231
] }
2332
processing = { path = "." }
2433
processing_pyo3 = { path = "crates/processing_pyo3" }

crates/processing_ffi/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ workspace = true
1010
name = "processing"
1111
crate-type = ["cdylib"]
1212

13+
[features]
14+
default = []
15+
wayland = ["processing/wayland"]
16+
x11 = ["processing/x11"]
17+
1318
[dependencies]
1419
processing = { workspace = true }
1520
bevy = { workspace = true }

crates/processing_ffi/src/lib.rs

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,90 @@ pub extern "C" fn processing_init() {
2020
error::check(init);
2121
}
2222

23-
/// Create a WebGPU surface from a native window handle.
24-
/// Returns a window ID (entity ID) that should be used for subsequent operations.
25-
/// Returns 0 on failure.
23+
/// Create a WebGPU surface from a macOS NSWindow handle.
2624
///
2725
/// SAFETY:
2826
/// - Init has been called.
29-
/// - window_handle is a valid GLFW window pointer.
27+
/// - window_handle is a valid NSWindow pointer.
3028
/// - This is called from the same thread as init.
29+
#[cfg(target_os = "macos")]
3130
#[unsafe(no_mangle)]
3231
pub extern "C" fn processing_surface_create(
32+
window_handle: u64,
33+
_display_handle: u64,
34+
width: u32,
35+
height: u32,
36+
scale_factor: f32,
37+
) -> u64 {
38+
error::clear_error();
39+
error::check(|| surface_create_macos(window_handle, width, height, scale_factor))
40+
.map(|e| e.to_bits())
41+
.unwrap_or(0)
42+
}
43+
44+
/// Create a WebGPU surface from a Windows HWND handle.
45+
///
46+
/// SAFETY:
47+
/// - Init has been called.
48+
/// - window_handle is a valid HWND.
49+
/// - This is called from the same thread as init.
50+
#[cfg(target_os = "windows")]
51+
#[unsafe(no_mangle)]
52+
pub extern "C" fn processing_surface_create(
53+
window_handle: u64,
54+
_display_handle: u64,
55+
width: u32,
56+
height: u32,
57+
scale_factor: f32,
58+
) -> u64 {
59+
error::clear_error();
60+
error::check(|| surface_create_windows(window_handle, width, height, scale_factor))
61+
.map(|e| e.to_bits())
62+
.unwrap_or(0)
63+
}
64+
65+
/// Create a WebGPU surface from a Wayland window and display handle.
66+
///
67+
/// SAFETY:
68+
/// - Init has been called.
69+
/// - window_handle is a valid wl_surface pointer.
70+
/// - display_handle is a valid wl_display pointer.
71+
/// - This is called from the same thread as init.
72+
#[cfg(all(target_os = "linux", feature = "wayland"))]
73+
#[unsafe(no_mangle)]
74+
pub extern "C" fn processing_surface_create_wayland(
75+
window_handle: u64,
76+
display_handle: u64,
77+
width: u32,
78+
height: u32,
79+
scale_factor: f32,
80+
) -> u64 {
81+
error::clear_error();
82+
error::check(|| {
83+
surface_create_wayland(window_handle, display_handle, width, height, scale_factor)
84+
})
85+
.map(|e| e.to_bits())
86+
.unwrap_or(0)
87+
}
88+
89+
/// Create a WebGPU surface from an X11 window and display handle.
90+
///
91+
/// SAFETY:
92+
/// - Init has been called.
93+
/// - window_handle is a valid X11 Window ID.
94+
/// - display_handle is a valid X11 Display pointer.
95+
/// - This is called from the same thread as init.
96+
#[cfg(all(target_os = "linux", feature = "x11"))]
97+
#[unsafe(no_mangle)]
98+
pub extern "C" fn processing_surface_create_x11(
3399
window_handle: u64,
34100
display_handle: u64,
35101
width: u32,
36102
height: u32,
37103
scale_factor: f32,
38104
) -> u64 {
39105
error::clear_error();
40-
error::check(|| surface_create(window_handle, display_handle, width, height, scale_factor))
106+
error::check(|| surface_create_x11(window_handle, display_handle, width, height, scale_factor))
41107
.map(|e| e.to_bits())
42108
.unwrap_or(0)
43109
}

crates/processing_pyo3/Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ workspace = true
1010
name = "processing"
1111
crate-type = ["cdylib"]
1212

13+
[features]
14+
default = []
15+
wayland = ["processing/wayland", "glfw/wayland"]
16+
x11 = ["processing/x11"]
17+
1318
[dependencies]
1419
pyo3 = "0.27.0"
1520
processing = { workspace = true }
@@ -18,6 +23,3 @@ glfw = { version = "0.60.0"}
1823

1924
[target.'cfg(target_os = "macos")'.dependencies]
2025
glfw = { version = "0.60.0", features = ["static-link"] }
21-
22-
[target.'cfg(target_os = "linux")'.dependencies]
23-
glfw = { version = "0.60.0", features = ["wayland"] }

crates/processing_pyo3/src/glfw.rs

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/// Minimal GLFW helper for Processing examples
2+
use bevy::prelude::Entity;
23
use glfw::{Glfw, GlfwReceiver, PWindow, WindowEvent, WindowMode};
34
use processing::prelude::error::Result;
45

@@ -30,28 +31,39 @@ impl GlfwContext {
3031
}
3132

3233
#[cfg(target_os = "macos")]
33-
pub fn get_window(&self) -> u64 {
34-
self.window.get_cocoa_window() as u64
34+
pub fn create_surface(&self, width: u32, height: u32, scale_factor: f32) -> Result<Entity> {
35+
use processing::prelude::surface_create_macos;
36+
surface_create_macos(self.window.get_cocoa_window() as u64, width, height, scale_factor)
3537
}
3638

3739
#[cfg(target_os = "windows")]
38-
pub fn get_window(&self) -> u64 {
39-
self.window.get_win32_window() as u64
40+
pub fn create_surface(&self, width: u32, height: u32, scale_factor: f32) -> Result<Entity> {
41+
use processing::prelude::surface_create_windows;
42+
surface_create_windows(self.window.get_win32_window() as u64, width, height, scale_factor)
4043
}
4144

42-
#[cfg(target_os = "linux")]
43-
pub fn get_window(&self) -> u64 {
44-
self.window.get_wayland_window() as u64
45+
#[cfg(all(target_os = "linux", feature = "wayland"))]
46+
pub fn create_surface(&self, width: u32, height: u32, scale_factor: f32) -> Result<Entity> {
47+
use processing::prelude::surface_create_wayland;
48+
surface_create_wayland(
49+
self.window.get_wayland_window() as u64,
50+
self.glfw.get_wayland_display() as u64,
51+
width,
52+
height,
53+
scale_factor,
54+
)
4555
}
4656

47-
#[cfg(not(target_os = "linux"))]
48-
pub fn get_display(&self) -> u64 {
49-
0
50-
}
51-
52-
#[cfg(target_os = "linux")]
53-
pub fn get_display(&self) -> u64 {
54-
self.glfw.get_wayland_display() as u64
57+
#[cfg(all(target_os = "linux", feature = "x11"))]
58+
pub fn create_surface(&self, width: u32, height: u32, scale_factor: f32) -> Result<Entity> {
59+
use processing::prelude::surface_create_x11;
60+
surface_create_x11(
61+
self.window.get_x11_window() as u64,
62+
self.glfw.get_x11_display() as u64,
63+
width,
64+
height,
65+
scale_factor,
66+
)
5567
}
5668

5769
pub fn poll_events(&mut self) -> bool {

crates/processing_pyo3/src/graphics.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,8 @@ impl Graphics {
4444

4545
init().map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
4646

47-
let window_handle = glfw_ctx.get_window();
48-
let display_handle = glfw_ctx.get_display();
49-
let surface = surface_create(window_handle, display_handle, width, height, 1.0)
47+
let surface = glfw_ctx
48+
.create_surface(width, height, 1.0)
5049
.map_err(|e| PyRuntimeError::new_err(format!("{e}")))?;
5150

5251
let surface = Surface {

crates/processing_render/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ edition = "2024"
66
[lints]
77
workspace = true
88

9+
[features]
10+
default = []
11+
wayland = ["bevy/wayland"]
12+
x11 = ["bevy/x11"]
13+
914
[dependencies]
1015
bevy = { workspace = true }
1116
lyon = "1.0"

crates/processing_render/src/lib.rs

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,43 @@ fn app_mut<T>(cb: impl FnOnce(&mut App) -> error::Result<T>) -> error::Result<T>
4242
Ok(res)
4343
}
4444

45-
/// Create a WebGPU surface from a native window handle.
46-
///
47-
/// Currently, this just creates a bevy window with the given parameters and
48-
/// stores the raw window handle for later use by the renderer, which will
49-
/// actually create the surface.
50-
pub fn surface_create(
45+
/// Create a WebGPU surface from a macOS NSWindow handle.
46+
#[cfg(target_os = "macos")]
47+
pub fn surface_create_macos(
48+
window_handle: u64,
49+
width: u32,
50+
height: u32,
51+
scale_factor: f32,
52+
) -> error::Result<Entity> {
53+
app_mut(|app| {
54+
surface::create_surface_macos(app.world_mut(), window_handle, width, height, scale_factor)
55+
})
56+
}
57+
58+
/// Create a WebGPU surface from a Windows HWND handle.
59+
#[cfg(target_os = "windows")]
60+
pub fn surface_create_windows(
61+
window_handle: u64,
62+
width: u32,
63+
height: u32,
64+
scale_factor: f32,
65+
) -> error::Result<Entity> {
66+
app_mut(|app| {
67+
surface::create_surface_windows(app.world_mut(), window_handle, width, height, scale_factor)
68+
})
69+
}
70+
71+
/// Create a WebGPU surface from a Wayland window and display handle.
72+
#[cfg(all(target_os = "linux", feature = "wayland"))]
73+
pub fn surface_create_wayland(
5174
window_handle: u64,
5275
display_handle: u64,
5376
width: u32,
5477
height: u32,
5578
scale_factor: f32,
5679
) -> error::Result<Entity> {
5780
app_mut(|app| {
58-
surface::create(
81+
surface::create_surface_wayland(
5982
app.world_mut(),
6083
window_handle,
6184
display_handle,
@@ -66,6 +89,40 @@ pub fn surface_create(
6689
})
6790
}
6891

92+
/// Create a WebGPU surface from an X11 window and display handle.
93+
#[cfg(all(target_os = "linux", feature = "x11"))]
94+
pub fn surface_create_x11(
95+
window_handle: u64,
96+
display_handle: u64,
97+
width: u32,
98+
height: u32,
99+
scale_factor: f32,
100+
) -> error::Result<Entity> {
101+
app_mut(|app| {
102+
surface::create_surface_x11(
103+
app.world_mut(),
104+
window_handle,
105+
display_handle,
106+
width,
107+
height,
108+
scale_factor,
109+
)
110+
})
111+
}
112+
113+
/// Create a WebGPU surface from a web canvas element pointer.
114+
#[cfg(target_arch = "wasm32")]
115+
pub fn surface_create_web(
116+
window_handle: u64,
117+
width: u32,
118+
height: u32,
119+
scale_factor: f32,
120+
) -> error::Result<Entity> {
121+
app_mut(|app| {
122+
surface::create_surface_web(app.world_mut(), window_handle, width, height, scale_factor)
123+
})
124+
}
125+
69126
pub fn surface_create_offscreen(
70127
width: u32,
71128
height: u32,
@@ -106,7 +163,7 @@ pub fn surface_create_from_canvas(
106163
// TODO: not sure if this is right to force here
107164
let scale_factor = 1.0;
108165

109-
surface_create(canvas_ptr, 0, width, height, scale_factor)
166+
surface_create_web(canvas_ptr, width, height, scale_factor)
110167
}
111168

112169
pub fn surface_destroy(graphics_entity: Entity) -> error::Result<()> {
@@ -124,9 +181,8 @@ fn create_app() -> App {
124181
#[cfg(not(target_arch = "wasm32"))]
125182
let plugins = DefaultPlugins
126183
.build()
127-
.disable::<bevy::log::LogPlugin>()
128184
.disable::<bevy::winit::WinitPlugin>()
129-
.disable::<bevy::render::pipelined_rendering::PipelinedRenderingPlugin>()
185+
.disable::<bevy::log::LogPlugin>()
130186
.set(WindowPlugin {
131187
primary_window: None,
132188
exit_condition: bevy::window::ExitCondition::DontExit,
@@ -136,9 +192,8 @@ fn create_app() -> App {
136192
#[cfg(target_arch = "wasm32")]
137193
let plugins = DefaultPlugins
138194
.build()
139-
.disable::<bevy::log::LogPlugin>()
140195
.disable::<bevy::winit::WinitPlugin>()
141-
.disable::<bevy::audio::AudioPlugin>()
196+
.disable::<bevy::log::LogPlugin>()
142197
.set(WindowPlugin {
143198
primary_window: None,
144199
exit_condition: bevy::window::ExitCondition::DontExit,

0 commit comments

Comments
 (0)