Skip to content

Commit

Permalink
Make raw_window_handle field in Window and ExtractedWindow an `…
Browse files Browse the repository at this point in the history
…Option`. (#6114)

# Objective

- Trying to make it possible to do write tests that don't require a raw window handle.
- Fixes #6106.

## Solution

- Make the interface and type changes.  Avoid accessing `None`.
---

## Changelog

- Converted `raw_window_handle` field in both `Window` and `ExtractedWindow` to `Option<RawWindowHandleWrapper>`.
- Revised accessor function `Window::raw_window_handle()` to return `Option<RawWindowHandleWrapper>`.
- Skip conditions in loops that would require a raw window handle (to create a `Surface`, for example).

## Migration Guide

`Window::raw_window_handle()` now returns `Option<RawWindowHandleWrapper>`.


Co-authored-by: targrub <62773321+targrub@users.noreply.github.com>
  • Loading branch information
targrub and targrub committed Oct 17, 2022
1 parent bfd6285 commit 964b047
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 19 deletions.
19 changes: 13 additions & 6 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,21 @@ impl Plugin for RenderPlugin {
.register_type::<Color>();

if let Some(backends) = options.backends {
let windows = app.world.resource_mut::<bevy_window::Windows>();
let instance = wgpu::Instance::new(backends);
let surface = {
let windows = app.world.resource_mut::<bevy_window::Windows>();
let raw_handle = windows.get_primary().map(|window| unsafe {
let handle = window.raw_window_handle().get_handle();
instance.create_surface(&handle)
});
raw_handle
if let Some(window) = windows.get_primary() {
if let Some(raw_window_handle) = window.raw_window_handle() {
unsafe {
let handle = raw_window_handle.get_handle();
Some(instance.create_surface(&handle))
}
} else {
None
}
} else {
None
}
};
let request_adapter_options = wgpu::RequestAdapterOptions {
power_preference: options.power_preference,
Expand Down
16 changes: 11 additions & 5 deletions crates/bevy_render/src/view/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl Plugin for WindowRenderPlugin {

pub struct ExtractedWindow {
pub id: WindowId,
pub handle: RawWindowHandleWrapper,
pub raw_window_handle: Option<RawWindowHandleWrapper>,
pub physical_width: u32,
pub physical_height: u32,
pub present_mode: PresentMode,
Expand Down Expand Up @@ -83,7 +83,7 @@ fn extract_windows(
.entry(window.id())
.or_insert(ExtractedWindow {
id: window.id(),
handle: window.raw_window_handle(),
raw_window_handle: window.raw_window_handle(),
physical_width: new_width,
physical_height: new_height,
present_mode: window.present_mode(),
Expand Down Expand Up @@ -161,14 +161,20 @@ pub fn prepare_windows(
render_instance: Res<RenderInstance>,
render_adapter: Res<RenderAdapter>,
) {
let window_surfaces = window_surfaces.deref_mut();
for window in windows.windows.values_mut() {
for window in windows
.windows
.values_mut()
// value of raw_winndow_handle only None if synthetic test
.filter(|x| x.raw_window_handle.is_some())
{
let window_surfaces = window_surfaces.deref_mut();
let surface = window_surfaces
.surfaces
.entry(window.id)
.or_insert_with(|| unsafe {
// NOTE: On some OSes this MUST be called from the main thread.
render_instance.create_surface(&window.handle.get_handle())
render_instance
.create_surface(&window.raw_window_handle.as_ref().unwrap().get_handle())
});

let swap_chain_descriptor = wgpu::SurfaceConfiguration {
Expand Down
69 changes: 62 additions & 7 deletions crates/bevy_window/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,59 @@ impl WindowResizeConstraints {
/// }
/// }
/// ```
/// To test code that uses `Window`s, one can test it with varying `Window` parameters by
/// creating `WindowResizeConstraints` or `WindowDescriptor` structures.
/// values by setting
///
/// ```
/// # use bevy_utils::default;
/// # use bevy_window::{Window, WindowCommand, WindowDescriptor, WindowId, WindowResizeConstraints};
/// # fn compute_window_area(w: &Window) -> f32 {
/// # w.width() * w.height()
/// # }
/// # fn grow_window_to_text_size(_window: &mut Window, _text: &str) {}
/// # fn set_new_title(window: &mut Window, text: String) { window.set_title(text); }
/// # fn a_window_resize_test() {
/// let resize_constraints = WindowResizeConstraints {
/// min_width: 400.0,
/// min_height: 300.0,
/// max_width: 1280.0,
/// max_height: 1024.0,
/// };
/// let window_descriptor = WindowDescriptor {
/// width: 800.0,
/// height: 600.0,
/// resizable: true,
/// resize_constraints,
/// ..default()
/// };
/// let mut window = Window::new(
/// WindowId::new(),
/// &window_descriptor,
/// 100, // physical_width
/// 100, // physical_height
/// 1.0, // scale_factor
/// None, None);
///
/// let area = compute_window_area(&window);
/// assert_eq!(area, 100.0 * 100.0);
///
/// grow_window_to_text_size(&mut window, "very long text that does not wrap");
/// assert_eq!(window.physical_width(), window.requested_width() as u32);
/// grow_window_to_text_size(&mut window, "very long text that does wrap, creating a maximum width window");
/// assert_eq!(window.physical_width(), window.requested_width() as u32);
///
/// set_new_title(&mut window, "new title".to_string());
/// let mut found_command = false;
/// for command in window.drain_commands() {
/// if command == (WindowCommand::SetTitle{ title: "new title".to_string() }) {
/// found_command = true;
/// break;
/// }
/// }
/// assert_eq!(found_command, true);
/// }
/// ```
#[derive(Debug)]
pub struct Window {
id: WindowId,
Expand All @@ -206,7 +259,7 @@ pub struct Window {
cursor_visible: bool,
cursor_locked: bool,
physical_cursor_position: Option<DVec2>,
raw_window_handle: RawWindowHandleWrapper,
raw_window_handle: Option<RawWindowHandleWrapper>,
focused: bool,
mode: WindowMode,
canvas: Option<String>,
Expand All @@ -217,7 +270,7 @@ pub struct Window {
///
/// Bevy apps don't interact with this `enum` directly. Instead, they should use the methods on [`Window`].
/// This `enum` is meant for authors of windowing plugins. See the documentation on [`crate::WindowPlugin`] for more information.
#[derive(Debug)]
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub enum WindowCommand {
/// Set the window's [`WindowMode`].
Expand Down Expand Up @@ -315,7 +368,7 @@ impl Window {
physical_height: u32,
scale_factor: f64,
position: Option<IVec2>,
raw_window_handle: RawWindowHandle,
raw_window_handle: Option<RawWindowHandle>,
) -> Self {
Window {
id,
Expand All @@ -335,7 +388,7 @@ impl Window {
cursor_locked: window_descriptor.cursor_locked,
cursor_icon: CursorIcon::Default,
physical_cursor_position: None,
raw_window_handle: RawWindowHandleWrapper::new(raw_window_handle),
raw_window_handle: raw_window_handle.map(RawWindowHandleWrapper::new),
focused: true,
mode: window_descriptor.mode,
canvas: window_descriptor.canvas.clone(),
Expand Down Expand Up @@ -719,9 +772,11 @@ impl Window {
pub fn is_focused(&self) -> bool {
self.focused
}
/// Get the [`RawWindowHandleWrapper`] corresponding to this window
pub fn raw_window_handle(&self) -> RawWindowHandleWrapper {
self.raw_window_handle.clone()
/// Get the [`RawWindowHandleWrapper`] corresponding to this window if set.
///
/// During normal use, this can be safely unwrapped; the value should only be [`None`] when synthetically constructed for tests.
pub fn raw_window_handle(&self) -> Option<RawWindowHandleWrapper> {
self.raw_window_handle.as_ref().cloned()
}

/// The "html canvas" element selector.
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_winit/src/winit_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ impl WinitWindows {
inner_size.height,
scale_factor,
position,
raw_window_handle,
Some(raw_window_handle),
)
}

Expand Down

0 comments on commit 964b047

Please sign in to comment.