Skip to main content

engvis_renderer/
gpu.rs

1use std::sync::Arc;
2use winit::event_loop::ActiveEventLoop;
3use winit::window::Window;
4
5pub struct GpuContext {
6    pub device: wgpu::Device,
7    pub queue: wgpu::Queue,
8    pub surface: wgpu::Surface<'static>,
9    pub config: wgpu::SurfaceConfiguration,
10    pub adapter: wgpu::Adapter,
11    pub instance: wgpu::Instance,
12}
13
14pub struct GpuResources {
15    pub context: GpuContext,
16    pub surface_format: wgpu::TextureFormat,
17}
18
19impl GpuResources {
20    pub async fn new(window: Arc<Window>) -> Self {
21        let instance = wgpu::Instance::default();
22        let surface = instance.create_surface(window.clone()).unwrap();
23
24        let adapter = instance
25            .request_adapter(&wgpu::RequestAdapterOptions {
26                power_preference: wgpu::PowerPreference::HighPerformance,
27                compatible_surface: Some(&surface),
28                force_fallback_adapter: false,
29            })
30            .await
31            .unwrap();
32
33        // Request POLYGON_MODE_LINE for wireframe rendering
34        let required_features = adapter
35            .features()
36            .intersection(wgpu::Features::POLYGON_MODE_LINE);
37
38        let (device, queue) = adapter
39            .request_device(&wgpu::DeviceDescriptor {
40                required_features,
41                required_limits: wgpu::Limits::default(),
42                label: Some("engvis device"),
43                experimental_features: wgpu::ExperimentalFeatures::disabled(),
44                memory_hints: wgpu::MemoryHints::default(),
45                trace: wgpu::Trace::Off,
46            })
47            .await
48            .unwrap();
49
50        let surface_caps = surface.get_capabilities(&adapter);
51        let surface_format = surface_caps
52            .formats
53            .iter()
54            .find(|f| matches!(f, wgpu::TextureFormat::Bgra8UnormSrgb))
55            .copied()
56            .unwrap_or(surface_caps.formats[0]);
57        let size = window.inner_size();
58
59        let config = wgpu::SurfaceConfiguration {
60            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
61            format: surface_format,
62            width: size.width,
63            height: size.height,
64            present_mode: surface_caps.present_modes[0],
65            alpha_mode: surface_caps.alpha_modes[0],
66            view_formats: vec![],
67            desired_maximum_frame_latency: 2,
68        };
69        surface.configure(&device, &config);
70
71        let context = GpuContext {
72            device,
73            queue,
74            surface,
75            config,
76            adapter,
77            instance,
78        };
79
80        Self {
81            context,
82            surface_format,
83        }
84    }
85
86    pub fn resize(&mut self, width: u32, height: u32) {
87        if width == 0 || height == 0 {
88            return;
89        }
90        self.context.config.width = width;
91        self.context.config.height = height;
92        self.context
93            .surface
94            .configure(&self.context.device, &self.context.config);
95    }
96
97    pub fn get_current_texture(&self) -> Option<wgpu::SurfaceTexture> {
98        self.context.surface.get_current_texture().ok()
99    }
100}
101
102pub async fn create_window_and_gpu(
103    event_loop: &ActiveEventLoop,
104    title: &str,
105    width: u32,
106    height: u32,
107) -> (Arc<Window>, GpuResources) {
108    let window = event_loop
109        .create_window(
110            Window::default_attributes()
111                .with_title(title)
112                .with_visible(true)
113                .with_inner_size(winit::dpi::LogicalSize::new(width, height)),
114        )
115        .unwrap();
116
117    let window = Arc::new(window);
118    let gpu = GpuResources::new(window.clone()).await;
119
120    (window, gpu)
121}