bevy_wgpu 0.5.0

A wgpu render backend for Bevy Engine
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<wgpu::Device>,
    pub queue: wgpu::Queue,
    pub window_resized_event_reader: ManualEventReader<WindowResized>,
    pub window_created_event_reader: ManualEventReader<WindowCreated>,
    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 = Some(std::path::Path::new("wgpu_trace"));
        #[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::<Box<dyn RenderResourceContext>>()
            .unwrap();
        let render_resource_context = render_resource_context
            .downcast_mut::<WgpuRenderResourceContext>()
            .unwrap();
        let windows = world.get_resource::<Windows>().unwrap();
        let window_created_events = world.get_resource::<Events<WindowCreated>>().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::<bevy_winit::WinitWindows>().unwrap();
                let winit_window = winit_windows.get_window(window.id()).unwrap();
                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<RenderGraph>| {
            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::<Box<dyn RenderResourceContext>>()
            .unwrap();
        render_resource_context.drop_all_swap_chain_textures();
        render_resource_context.remove_stale_bind_groups();
    }
}