Skip to content

Commit 8c42799

Browse files
committed
Make raw_window_handle optional for unit testing purposes.
1 parent 44d09dc commit 8c42799

File tree

4 files changed

+57
-48
lines changed

4 files changed

+57
-48
lines changed

crates/bevy_render/src/lib.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use bevy_app::{App, AppLabel, Plugin};
4545
use bevy_asset::{AddAsset, AssetServer};
4646
use bevy_ecs::prelude::*;
4747
use std::ops::{Deref, DerefMut};
48+
use wgpu::Surface;
4849

4950
/// Contains the default Bevy rendering backend based on wgpu.
5051
#[derive(Default)]
@@ -120,15 +121,7 @@ impl Plugin for RenderPlugin {
120121

121122
if let Some(backends) = options.backends {
122123
let instance = wgpu::Instance::new(backends);
123-
let surface = {
124-
let world = app.world.cell();
125-
let windows = world.get_resource_mut::<bevy_window::Windows>().unwrap();
126-
let raw_handle = windows.get_primary().map(|window| unsafe {
127-
let handle = window.raw_window_handle().get_handle();
128-
instance.create_surface(&handle)
129-
});
130-
raw_handle
131-
};
124+
let surface = try_create_surface(app, &instance);
132125
let request_adapter_options = wgpu::RequestAdapterOptions {
133126
power_preference: options.power_preference,
134127
compatible_surface: surface.as_ref(),
@@ -294,6 +287,17 @@ impl Plugin for RenderPlugin {
294287
}
295288
}
296289

290+
fn try_create_surface(app: &mut App, wgpu_instance: &wgpu::Instance) -> Option<Surface> {
291+
let world = app.world.cell();
292+
let windows = world.get_resource_mut::<bevy_window::Windows>().unwrap();
293+
windows.get_primary().and_then(|window| unsafe {
294+
window.raw_window_handle().map(|handle_wrapper| {
295+
let window_handle = handle_wrapper.get_handle();
296+
wgpu_instance.create_surface(&window_handle)
297+
})
298+
})
299+
}
300+
297301
/// Executes the [`Extract`](RenderStage::Extract) stage of the renderer.
298302
/// This updates the render world with the extracted ECS data of the current frame.
299303
fn extract(app_world: &mut World, render_app: &mut App) {

crates/bevy_render/src/view/window.rs

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl Plugin for WindowRenderPlugin {
4040

4141
pub struct ExtractedWindow {
4242
pub id: WindowId,
43-
pub handle: RawWindowHandleWrapper,
43+
pub handle: Option<RawWindowHandleWrapper>,
4444
pub physical_width: u32,
4545
pub physical_height: u32,
4646
pub vsync: bool,
@@ -125,42 +125,44 @@ pub fn prepare_windows(
125125
) {
126126
let window_surfaces = window_surfaces.deref_mut();
127127
for window in windows.windows.values_mut() {
128-
let surface = window_surfaces
129-
.surfaces
130-
.entry(window.id)
131-
.or_insert_with(|| unsafe {
132-
// NOTE: On some OSes this MUST be called from the main thread.
133-
render_instance.create_surface(&window.handle.get_handle())
134-
});
135-
136-
let swap_chain_descriptor = wgpu::SurfaceConfiguration {
137-
format: TextureFormat::bevy_default(),
138-
width: window.physical_width,
139-
height: window.physical_height,
140-
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
141-
present_mode: if window.vsync {
142-
wgpu::PresentMode::Fifo
143-
} else {
144-
wgpu::PresentMode::Immediate
145-
},
146-
};
147-
148-
// Do the initial surface configuration if it hasn't been configured yet
149-
if window_surfaces.configured_windows.insert(window.id) || window.size_changed {
150-
render_device.configure_surface(surface, &swap_chain_descriptor);
151-
}
128+
if let Some(window_handle_wrapper) = &window.handle {
129+
let surface = window_surfaces
130+
.surfaces
131+
.entry(window.id)
132+
.or_insert_with(|| unsafe {
133+
// NOTE: On some OSes this MUST be called from the main thread.
134+
render_instance.create_surface(&window_handle_wrapper.get_handle())
135+
});
152136

153-
let frame = match surface.get_current_texture() {
154-
Ok(swap_chain_frame) => swap_chain_frame,
155-
Err(wgpu::SurfaceError::Outdated) => {
137+
let swap_chain_descriptor = wgpu::SurfaceConfiguration {
138+
format: TextureFormat::bevy_default(),
139+
width: window.physical_width,
140+
height: window.physical_height,
141+
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
142+
present_mode: if window.vsync {
143+
wgpu::PresentMode::Fifo
144+
} else {
145+
wgpu::PresentMode::Immediate
146+
},
147+
};
148+
149+
// Do the initial surface configuration if it hasn't been configured yet
150+
if window_surfaces.configured_windows.insert(window.id) || window.size_changed {
156151
render_device.configure_surface(surface, &swap_chain_descriptor);
157-
surface
158-
.get_current_texture()
159-
.expect("Error reconfiguring surface")
160152
}
161-
err => err.expect("Failed to acquire next swap chain texture!"),
162-
};
163153

164-
window.swap_chain_texture = Some(TextureView::from(frame));
154+
let frame = match surface.get_current_texture() {
155+
Ok(swap_chain_frame) => swap_chain_frame,
156+
Err(wgpu::SurfaceError::Outdated) => {
157+
render_device.configure_surface(surface, &swap_chain_descriptor);
158+
surface
159+
.get_current_texture()
160+
.expect("Error reconfiguring surface")
161+
}
162+
err => err.expect("Failed to acquire next swap chain texture!"),
163+
};
164+
165+
window.swap_chain_texture = Some(TextureView::from(frame));
166+
}
165167
}
166168
}

crates/bevy_window/src/window.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ impl WindowResizeConstraints {
109109
/// requested size due to operating system limits on the window size, or the
110110
/// quantization of the logical size when converting the physical size to the
111111
/// logical size through the scaling factor.
112+
///
113+
/// ## Headless Testing
114+
/// To run tests without needing to create an actual window, set `raw_window_handle` to `None`.
112115
#[derive(Debug)]
113116
pub struct Window {
114117
id: WindowId,
@@ -128,7 +131,7 @@ pub struct Window {
128131
cursor_visible: bool,
129132
cursor_locked: bool,
130133
physical_cursor_position: Option<DVec2>,
131-
raw_window_handle: RawWindowHandleWrapper,
134+
raw_window_handle: Option<RawWindowHandleWrapper>,
132135
focused: bool,
133136
mode: WindowMode,
134137
#[cfg(target_arch = "wasm32")]
@@ -209,7 +212,7 @@ impl Window {
209212
physical_height: u32,
210213
scale_factor: f64,
211214
position: Option<IVec2>,
212-
raw_window_handle: RawWindowHandle,
215+
raw_window_handle: Option<RawWindowHandle>,
213216
) -> Self {
214217
Window {
215218
id,
@@ -229,7 +232,7 @@ impl Window {
229232
cursor_locked: window_descriptor.cursor_locked,
230233
cursor_icon: CursorIcon::Default,
231234
physical_cursor_position: None,
232-
raw_window_handle: RawWindowHandleWrapper::new(raw_window_handle),
235+
raw_window_handle: raw_window_handle.map(|handle| RawWindowHandleWrapper::new(handle)),
233236
focused: true,
234237
mode: window_descriptor.mode,
235238
#[cfg(target_arch = "wasm32")]
@@ -544,7 +547,7 @@ impl Window {
544547
self.focused
545548
}
546549

547-
pub fn raw_window_handle(&self) -> RawWindowHandleWrapper {
550+
pub fn raw_window_handle(&self) -> Option<RawWindowHandleWrapper> {
548551
self.raw_window_handle.clone()
549552
}
550553
}

crates/bevy_winit/src/winit_windows.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl WinitWindows {
171171
inner_size.height,
172172
scale_factor,
173173
position,
174-
raw_window_handle,
174+
Some(raw_window_handle),
175175
)
176176
}
177177

0 commit comments

Comments
 (0)