Skip to content

Commit

Permalink
Get raw window handle only after Resume event
Browse files Browse the repository at this point in the history
  • Loading branch information
Gordon-F committed Jan 22, 2022
1 parent 1b7ac51 commit 178ff21
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 75 deletions.
62 changes: 5 additions & 57 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,13 @@ use crate::{
render_graph::RenderGraph,
render_resource::{RenderPipelineCache, Shader, ShaderLoader},
renderer::render_system,
texture::{BevyDefault as _, ImagePlugin, DEFAULT_DEPTH_FORMAT},
texture::ImagePlugin,
view::{ViewPlugin, WindowRenderPlugin},
};
use bevy_app::{App, AppLabel, Plugin};
use bevy_asset::{AddAsset, AssetServer};
use bevy_ecs::prelude::*;
use std::{
ops::{Deref, DerefMut},
sync::Arc,
};
use std::ops::{Deref, DerefMut};

/// Contains the default Bevy rendering backend based on wgpu.
#[derive(Default)]
Expand Down Expand Up @@ -122,59 +119,10 @@ impl Plugin for RenderPlugin {

if let Some(backends) = options.backends {
let instance = wgpu::Instance::new(backends);
let adapter = Arc::new({
#[cfg(not(target_arch = "wasm32"))]
{
let mut selected_adapter = None;
for adapter in instance.enumerate_adapters(backends) {
let default_texture_format_features = adapter
.get_texture_format_features(wgpu::TextureFormat::bevy_default());
let default_depth_format_features =
adapter.get_texture_format_features(DEFAULT_DEPTH_FORMAT);

let requested_device_type = match options.power_preference {
wgpu::PowerPreference::LowPower => wgpu::DeviceType::IntegratedGpu,
wgpu::PowerPreference::HighPerformance => wgpu::DeviceType::DiscreteGpu,
};
if default_texture_format_features
.allowed_usages
.contains(wgpu::TextureUsages::RENDER_ATTACHMENT)
&& default_depth_format_features
.allowed_usages
.contains(wgpu::TextureUsages::RENDER_ATTACHMENT)
&& adapter.get_info().device_type == requested_device_type
{
selected_adapter = Some(adapter);
} else {
continue;
}
}

selected_adapter.expect(
"Unable to find a GPU! Make sure you have installed required drivers!",
)
}

#[cfg(target_arch = "wasm32")]
{
let request_adapter_options = wgpu::RequestAdapterOptions {
power_preference: options.power_preference,
compatible_surface: None,
..Default::default()
};
instance
.request_adapter(request_adapter_options)
.await
.expect(
"Unable to find a GPU! Make sure you have installed required drivers!",
)
}
});
let (device, adapter, queue) = futures_lite::future::block_on(
renderer::initialize_renderer(app, &instance, backends, &mut options),
);
info!("{:?}", adapter.get_info());
let (device, queue) = futures_lite::future::block_on(renderer::initialize_renderer(
&adapter,
&mut options,
));
debug!("Configured wgpu adapter Limits: {:#?}", &adapter.limits());
debug!(
"Configured wgpu adapter Features: {:#?}",
Expand Down
95 changes: 84 additions & 11 deletions crates/bevy_render/src/renderer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod graph_runner;
mod render_device;

use bevy_utils::tracing::{info, info_span};
use bevy_utils::tracing::info_span;
pub use graph_runner::*;
pub use render_device::*;

Expand All @@ -12,7 +12,7 @@ use crate::{
};
use bevy_ecs::prelude::*;
use std::sync::Arc;
use wgpu::{CommandEncoder, Instance, Queue, RequestAdapterOptions};
use wgpu::{Adapter, CommandEncoder, Instance, Queue};

/// Updates the [`RenderGraph`] with all of its nodes and then runs it to render the entire frame.
pub fn render_system(world: &mut World) {
Expand Down Expand Up @@ -57,6 +57,8 @@ pub fn render_system(world: &mut World) {
/// This queue is used to enqueue tasks for the GPU to execute asynchronously.
pub type RenderQueue = Arc<Queue>;

pub type RenderAdapter = Arc<Adapter>;

/// The GPU instance is used to initialize the [`RenderQueue`] and [`RenderDevice`],
/// aswell as to create [`WindowSurfaces`](crate::view::window::WindowSurfaces).
pub type RenderInstance = Instance;
Expand All @@ -69,16 +71,86 @@ pub const DEFAULT_DISABLED_WGPU_FEATURES: wgpu::Features = wgpu::Features::MAPPA
/// Initializes the renderer by retrieving and preparing the GPU instance, device and queue
/// for the specified backend.
pub async fn initialize_renderer(
instance: &Instance,
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))] app: &mut bevy_app::App,
instance: &wgpu::Instance,
#[cfg_attr(target_arch = "wasm32", allow(unused))] backends: wgpu::Backends,
options: &mut WgpuOptions,
request_adapter_options: &RequestAdapterOptions<'_>,
) -> (RenderDevice, RenderQueue) {
let adapter = instance
.request_adapter(request_adapter_options)
.await
.expect("Unable to find a GPU! Make sure you have installed required drivers!");
) -> (RenderDevice, RenderAdapter, RenderQueue) {
let adapter = {
#[cfg(not(target_arch = "wasm32"))]
{
use crate::texture::{BevyDefault as _, DEFAULT_DEPTH_FORMAT};
let mut adapters: Vec<wgpu::Adapter> = instance.enumerate_adapters(backends).collect();
let (mut integrated, mut discrete, mut virt, mut cpu, mut other) =
(None, None, None, None, None);

info!("{:?}", adapter.get_info());
for (i, adapter) in adapters.iter().enumerate() {
let default_texture_format_features =
adapter.get_texture_format_features(wgpu::TextureFormat::bevy_default());
let default_depth_format_features =
adapter.get_texture_format_features(DEFAULT_DEPTH_FORMAT);
if default_texture_format_features
.allowed_usages
.contains(wgpu::TextureUsages::RENDER_ATTACHMENT)
&& default_depth_format_features
.allowed_usages
.contains(wgpu::TextureUsages::RENDER_ATTACHMENT)
{
let info = adapter.get_info();
match info.device_type {
wgpu::DeviceType::IntegratedGpu => {
integrated = integrated.or(Some(i));
}
wgpu::DeviceType::DiscreteGpu => {
discrete = discrete.or(Some(i));
}
wgpu::DeviceType::VirtualGpu => {
virt = virt.or(Some(i));
}
wgpu::DeviceType::Cpu => {
cpu = cpu.or(Some(i));
}
wgpu::DeviceType::Other => {
other = other.or(Some(i));
}
}
}
}

let preferred_gpu_index = match options.power_preference {
wgpu::PowerPreference::LowPower => {
integrated.or(other).or(discrete).or(virt).or(cpu)
}
wgpu::PowerPreference::HighPerformance => {
discrete.or(other).or(integrated).or(virt).or(cpu)
}
}
.expect("Unable to find a GPU! Make sure you have installed required drivers!");

adapters.swap_remove(preferred_gpu_index)
}

#[cfg(target_arch = "wasm32")]
{
let surface = {
let world = app.world.cell();
let windows = world.get_resource_mut::<bevy_window::Windows>().unwrap();
let raw_handle = windows.get_primary().map(|window| unsafe {
let handle = window.raw_window_handle().get_handle();
instance.create_surface(&handle)
});
raw_handle
};
instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: options.power_preference,
compatible_surface: surface.as_ref(),
..Default::default()
})
.await
.expect("Unable to find a GPU! Make sure you have installed required drivers!")
}
};

#[cfg(feature = "wgpu_trace")]
let trace_path = {
Expand Down Expand Up @@ -108,9 +180,10 @@ pub async fn initialize_renderer(
)
.await
.unwrap();
let adapter = Arc::new(adapter);
let device = Arc::new(device);
let queue = Arc::new(queue);
(RenderDevice::from(device), queue)
(RenderDevice::from(device), adapter, queue)
}

/// The context with all information required to interact with the GPU.
Expand Down
9 changes: 7 additions & 2 deletions crates/bevy_render/src/view/window.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
render_resource::TextureView,
renderer::{RenderDevice, RenderInstance},
renderer::{RenderAdapter, RenderDevice, RenderInstance},
texture::BevyDefault,
RenderApp, RenderStage, RenderWorld,
};
Expand Down Expand Up @@ -120,6 +120,7 @@ pub fn prepare_windows(
_marker: NonSend<NonSendMarker>,
mut windows: ResMut<ExtractedWindows>,
mut window_surfaces: ResMut<WindowSurfaces>,
render_adapter: Res<RenderAdapter>,
render_device: Res<RenderDevice>,
render_instance: Res<RenderInstance>,
) {
Expand All @@ -133,8 +134,12 @@ pub fn prepare_windows(
render_instance.create_surface(&window.handle.get_handle())
});

let surface_format = surface
.get_preferred_format(&render_adapter)
.unwrap_or_else(TextureFormat::bevy_default);

let swap_chain_descriptor = wgpu::SurfaceConfiguration {
format: TextureFormat::bevy_default(),
format: surface_format,
width: window.physical_width,
height: window.physical_height,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
Expand Down
13 changes: 8 additions & 5 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ impl Plugin for WinitPlugin {
.set_runner(winit_runner)
.add_system_to_stage(CoreStage::PostUpdate, change_window.exclusive_system());
let event_loop = EventLoop::new();
// TODO: Required for WebGL. Currently breaks only android initialization. Should be a part of init system
#[cfg(not(target_os = "android"))]
handle_initial_window_events(&mut app.world, &event_loop);
app.insert_non_send_resource(event_loop);
}
Expand Down Expand Up @@ -495,12 +497,12 @@ pub fn winit_runner_with(mut app: App) {
active = true;
}
event::Event::MainEventsCleared => {
handle_create_window_events(
&mut app.world,
event_loop,
&mut create_window_event_reader,
);
if active {
handle_create_window_events(
&mut app.world,
event_loop,
&mut create_window_event_reader,
);
app.update();
}
}
Expand Down Expand Up @@ -537,6 +539,7 @@ fn handle_create_window_events(
}
}

#[cfg(not(target_os = "android"))]
fn handle_initial_window_events(world: &mut World, event_loop: &EventLoop<()>) {
let world = world.cell();
let mut winit_windows = world.get_resource_mut::<WinitWindows>().unwrap();
Expand Down

0 comments on commit 178ff21

Please sign in to comment.