use crate::{ renderer::{WgpuRenderGraphExecutor, WgpuRenderResourceContext}, wgpu_type_converter::WgpuInto, WgpuBackend, WgpuOptions, WgpuPowerOptions, }; use bevy_app::{Events, ManualEventReader}; use bevy_ecs::world::{Mut, World}; use bevy_render::{ render_graph::{DependentNodeStager, RenderGraph, RenderGraphStager}, renderer::RenderResourceContext, }; use bevy_window::{WindowCreated, WindowResized, Windows}; use std::{ops::Deref, sync::Arc}; pub struct WgpuRenderer { pub instance: wgpu::Instance, pub device: Arc, pub queue: wgpu::Queue, pub window_resized_event_reader: ManualEventReader, pub window_created_event_reader: ManualEventReader, pub initialized: bool, } impl WgpuRenderer { pub async fn new(options: WgpuOptions) -> Self { let backend = match options.backend { WgpuBackend::Auto => wgpu::BackendBit::PRIMARY, WgpuBackend::Vulkan => wgpu::BackendBit::VULKAN, WgpuBackend::Metal => wgpu::BackendBit::METAL, WgpuBackend::Dx12 => wgpu::BackendBit::DX12, WgpuBackend::Dx11 => wgpu::BackendBit::DX11, WgpuBackend::Gl => wgpu::BackendBit::GL, WgpuBackend::BrowserWgpu => wgpu::BackendBit::BROWSER_WEBGPU, }; let instance = wgpu::Instance::new(backend); let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: match options.power_pref { WgpuPowerOptions::HighPerformance => wgpu::PowerPreference::HighPerformance, WgpuPowerOptions::Adaptive => wgpu::PowerPreference::LowPower, WgpuPowerOptions::LowPower => wgpu::PowerPreference::LowPower, }, compatible_surface: None, }) .await .expect("Unable to find a GPU! Make sure you have installed required drivers!"); #[cfg(feature = "trace")] let trace_path = { let path = std::path::Path::new("wgpu_trace"); // ignore potential error, wgpu will log it let _ = std::fs::create_dir(path); Some(path) }; #[cfg(not(feature = "trace"))] let trace_path = None; let (device, queue) = adapter .request_device( &wgpu::DeviceDescriptor { label: options.device_label.as_ref().map(|a| a.as_ref()), features: options.features.wgpu_into(), limits: options.limits.wgpu_into(), }, trace_path, ) .await .unwrap(); let device = Arc::new(device); WgpuRenderer { instance, device, queue, window_resized_event_reader: Default::default(), window_created_event_reader: Default::default(), initialized: false, } } pub fn handle_window_created_events(&mut self, world: &mut World) { let world = world.cell(); let mut render_resource_context = world .get_resource_mut::>() .unwrap(); let render_resource_context = render_resource_context .downcast_mut::() .unwrap(); let windows = world.get_resource::().unwrap(); let window_created_events = world.get_resource::>().unwrap(); for window_created_event in self .window_created_event_reader .iter(&window_created_events) { let window = windows .get(window_created_event.id) .expect("Received window created event for non-existent window."); #[cfg(feature = "bevy_winit")] { let winit_windows = world.get_resource::().unwrap(); let winit_window = winit_windows.get_window(window.id()).unwrap(); // SAFE: The raw window handle created from a `winit::Window` is always valid. let surface = unsafe { self.instance.create_surface(winit_window.deref()) }; render_resource_context.set_window_surface(window.id(), surface); } } } pub fn run_graph(&mut self, world: &mut World) { world.resource_scope(|world, mut render_graph: Mut| { render_graph.prepare(world); // stage nodes let mut stager = DependentNodeStager::loose_grouping(); let stages = stager.get_stages(&render_graph).unwrap(); let mut borrowed = stages.borrow(&mut render_graph); // execute stages let graph_executor = WgpuRenderGraphExecutor { max_thread_count: 2, }; graph_executor.execute(world, self.device.clone(), &mut self.queue, &mut borrowed); }) } pub fn update(&mut self, world: &mut World) { self.handle_window_created_events(world); self.run_graph(world); let render_resource_context = world .get_resource::>() .unwrap(); render_resource_context.drop_all_swap_chain_textures(); render_resource_context.remove_stale_bind_groups(); } }