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 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}