plinth_core/
graphics.rs

1use std::cell::RefCell;
2
3use wgpu::{
4    Adapter, Device, DeviceDescriptor, Features, Instance, Limits, MemoryHints, PowerPreference,
5    Queue, RenderPipeline, RequestAdapterOptions, Surface, SurfaceConfiguration,
6};
7use winit::{dpi::PhysicalSize, event_loop::EventLoopProxy, window::Window};
8
9use crate::plinth_app::PlinthApp;
10
11#[cfg(target_arch = "wasm32")]
12pub type Rc<T> = std::rc::Rc<T>;
13
14#[cfg(not(target_arch = "wasm32"))]
15pub type Rc<T> = std::sync::Arc<T>;
16
17pub async fn create_graphics(
18    window: Rc<Window>,
19    proxy: EventLoopProxy<Graphics>,
20    user_app: Rc<RefCell<dyn PlinthApp>>,
21) {
22    let instance = Instance::default();
23    let surface = instance.create_surface(Rc::clone(&window)).unwrap();
24    let adapter = instance
25        .request_adapter(&RequestAdapterOptions {
26            power_preference: PowerPreference::default(), // Power preference for the device
27            force_fallback_adapter: false, // Indicates that only a fallback ("software") adapter can be used
28            compatible_surface: Some(&surface), // Guarantee that the adapter can render to this surface
29        })
30        .await
31        .expect("Could not get an adapter (GPU).");
32
33    let (device, queue) = adapter
34        .request_device(
35            &DeviceDescriptor {
36                label: None,
37                required_features: Features::empty(), // Specifies the required features by the device request. Fails if the adapter can't provide them.
38                required_limits: Limits::downlevel_webgl2_defaults()
39                    .using_resolution(adapter.limits()),
40                memory_hints: MemoryHints::Performance,
41            },
42            None,
43        )
44        .await
45        .expect("Failed to get device");
46
47    // Get physical pixel dimensiosn inside the window
48    let size = window.inner_size();
49    // Make the dimensions at least size 1, otherwise wgpu would panic
50    let width = size.width.max(1);
51    let height = size.height.max(1);
52    let surface_config = surface.get_default_config(&adapter, width, height).unwrap();
53
54    #[cfg(not(target_arch = "wasm32"))]
55    surface.configure(&device, &surface_config);
56
57    let render_pipelines = vec![];
58
59    let mut gfx = Graphics {
60        window: window.clone(),
61        _instance: instance,
62        surface,
63        surface_config,
64        _adapter: adapter,
65        device,
66        queue,
67        render_pipelines,
68    };
69
70    let render_pipeline = user_app.borrow_mut().create_pipeline(&mut gfx);
71
72    gfx.render_pipelines.push(render_pipeline);
73
74    let _ = proxy.send_event(gfx);
75}
76
77#[derive(Debug)]
78pub struct Graphics {
79    pub window: Rc<Window>,
80    pub _instance: Instance,
81    pub surface: Surface<'static>,
82    pub surface_config: SurfaceConfiguration,
83    pub _adapter: Adapter,
84    pub device: Device,
85    pub queue: Queue,
86    pub render_pipelines: Vec<RenderPipeline>,
87}
88
89impl Graphics {
90    pub fn resize(&mut self, new_size: PhysicalSize<u32>) {
91        self.surface_config.width = new_size.width.max(1);
92        self.surface_config.height = new_size.height.max(1);
93        self.surface.configure(&self.device, &self.surface_config);
94    }
95}