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(&DeviceDescriptor {
35            label: None,
36            required_features: Features::empty(), // Specifies the required features by the device request. Fails if the adapter can't provide them.
37            required_limits: Limits::downlevel_webgl2_defaults().using_resolution(adapter.limits()),
38            memory_hints: MemoryHints::Performance,
39            trace: wgpu::Trace::Off,
40        })
41        .await
42        .expect("Failed to get device");
43
44    // Get physical pixel dimensiosn inside the window
45    let size = window.inner_size();
46    // Make the dimensions at least size 1, otherwise wgpu would panic
47    let width = size.width.max(1);
48    let height = size.height.max(1);
49    let surface_config = surface.get_default_config(&adapter, width, height).unwrap();
50
51    #[cfg(not(target_arch = "wasm32"))]
52    surface.configure(&device, &surface_config);
53
54    let render_pipelines = vec![];
55
56    let mut gfx = Graphics {
57        window: window.clone(),
58        _instance: instance,
59        surface,
60        surface_config,
61        _adapter: adapter,
62        device,
63        queue,
64        render_pipelines,
65    };
66
67    let render_pipeline = user_app.borrow_mut().create_pipeline(&mut gfx);
68
69    gfx.render_pipelines.push(render_pipeline);
70
71    let _ = proxy.send_event(gfx);
72}
73
74#[derive(Debug)]
75pub struct Graphics {
76    pub window: Rc<Window>,
77    pub _instance: Instance,
78    pub surface: Surface<'static>,
79    pub surface_config: SurfaceConfiguration,
80    pub _adapter: Adapter,
81    pub device: Device,
82    pub queue: Queue,
83    pub render_pipelines: Vec<RenderPipeline>,
84}
85
86impl Graphics {
87    pub fn resize(&mut self, new_size: PhysicalSize<u32>) {
88        self.surface_config.width = new_size.width.max(1);
89        self.surface_config.height = new_size.height.max(1);
90        self.surface.configure(&self.device, &self.surface_config);
91    }
92}