wgpu_examples/hello_windows/
mod.rs
1#![cfg_attr(target_arch = "wasm32", allow(dead_code))]
2
3use std::{collections::HashMap, sync::Arc};
4use winit::{
5 event::{Event, WindowEvent},
6 event_loop::EventLoop,
7 window::{Window, WindowId},
8};
9
10struct ViewportDesc {
11 window: Arc<Window>,
12 background: wgpu::Color,
13 surface: wgpu::Surface<'static>,
14}
15
16struct Viewport {
17 desc: ViewportDesc,
18 config: wgpu::SurfaceConfiguration,
19}
20
21impl ViewportDesc {
22 fn new(window: Arc<Window>, background: wgpu::Color, instance: &wgpu::Instance) -> Self {
23 let surface = instance.create_surface(window.clone()).unwrap();
24 Self {
25 window,
26 background,
27 surface,
28 }
29 }
30
31 fn build(self, adapter: &wgpu::Adapter, device: &wgpu::Device) -> Viewport {
32 let size = self.window.inner_size();
33 let config = self
34 .surface
35 .get_default_config(adapter, size.width, size.height)
36 .unwrap();
37 self.surface.configure(device, &config);
38 Viewport { desc: self, config }
39 }
40}
41
42impl Viewport {
43 fn resize(&mut self, device: &wgpu::Device, size: winit::dpi::PhysicalSize<u32>) {
44 self.config.width = size.width;
45 self.config.height = size.height;
46 self.desc.surface.configure(device, &self.config);
47 }
48 fn get_current_texture(&mut self) -> wgpu::SurfaceTexture {
49 self.desc
50 .surface
51 .get_current_texture()
52 .expect("Failed to acquire next swap chain texture")
53 }
54}
55
56async fn run(event_loop: EventLoop<()>, viewports: Vec<(Arc<Window>, wgpu::Color)>) {
57 let instance = wgpu::Instance::default();
58 let viewports: Vec<_> = viewports
59 .into_iter()
60 .map(|(window, color)| ViewportDesc::new(window, color, &instance))
61 .collect();
62 let adapter = instance
63 .request_adapter(&wgpu::RequestAdapterOptions {
64 compatible_surface: viewports.first().map(|desc| &desc.surface),
66 ..Default::default()
67 })
68 .await
69 .expect("Failed to find an appropriate adapter");
70
71 let (device, queue) = adapter
73 .request_device(&wgpu::DeviceDescriptor {
74 label: None,
75 required_features: wgpu::Features::empty(),
76 required_limits: wgpu::Limits::downlevel_defaults(),
77 memory_hints: wgpu::MemoryHints::MemoryUsage,
78 trace: wgpu::Trace::Off,
79 })
80 .await
81 .expect("Failed to create device");
82
83 let mut viewports: HashMap<WindowId, Viewport> = viewports
84 .into_iter()
85 .map(|desc| (desc.window.id(), desc.build(&adapter, &device)))
86 .collect();
87
88 event_loop
89 .run(move |event, target| {
90 let _ = (&instance, &adapter);
94
95 if let Event::WindowEvent { window_id, event } = event {
96 match event {
97 WindowEvent::Resized(new_size) => {
98 if let Some(viewport) = viewports.get_mut(&window_id) {
100 viewport.resize(&device, new_size);
101 viewport.desc.window.request_redraw();
103 }
104 }
105 WindowEvent::RedrawRequested => {
106 if let Some(viewport) = viewports.get_mut(&window_id) {
107 let frame = viewport.get_current_texture();
108 let view = frame
109 .texture
110 .create_view(&wgpu::TextureViewDescriptor::default());
111 let mut encoder =
112 device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
113 label: None,
114 });
115 {
116 let _rpass =
117 encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
118 label: None,
119 color_attachments: &[Some(
120 wgpu::RenderPassColorAttachment {
121 view: &view,
122 depth_slice: None,
123 resolve_target: None,
124 ops: wgpu::Operations {
125 load: wgpu::LoadOp::Clear(
126 viewport.desc.background,
127 ),
128 store: wgpu::StoreOp::Store,
129 },
130 },
131 )],
132 depth_stencil_attachment: None,
133 timestamp_writes: None,
134 occlusion_query_set: None,
135 });
136 }
137
138 queue.submit(Some(encoder.finish()));
139 viewport.desc.window.pre_present_notify();
140 frame.present();
141 }
142 }
143 WindowEvent::CloseRequested => {
144 viewports.remove(&window_id);
145 if viewports.is_empty() {
146 target.exit();
147 }
148 }
149 _ => {}
150 }
151 }
152 })
153 .unwrap();
154}
155
156pub fn main() {
157 #[cfg(not(target_arch = "wasm32"))]
158 {
159 const WINDOW_SIZE: u32 = 128;
160 const WINDOW_PADDING: u32 = 16;
161 const WINDOW_TITLEBAR: u32 = 32;
162 const WINDOW_OFFSET: u32 = WINDOW_SIZE + WINDOW_PADDING;
163 const ROWS: u32 = 4;
164 const COLUMNS: u32 = 4;
165
166 let event_loop = EventLoop::new().unwrap();
167 let mut viewports = Vec::with_capacity((ROWS * COLUMNS) as usize);
168 for row in 0..ROWS {
169 for column in 0..COLUMNS {
170 let window = winit::window::WindowBuilder::new()
171 .with_title(format!("x{column}y{row}"))
172 .with_inner_size(winit::dpi::PhysicalSize::new(WINDOW_SIZE, WINDOW_SIZE))
173 .build(&event_loop)
174 .unwrap();
175 let window = Arc::new(window);
176 window.set_outer_position(winit::dpi::PhysicalPosition::new(
177 WINDOW_PADDING + column * WINDOW_OFFSET,
178 WINDOW_PADDING + row * (WINDOW_OFFSET + WINDOW_TITLEBAR),
179 ));
180 fn frac(index: u32, max: u32) -> f64 {
181 index as f64 / max as f64
182 }
183 viewports.push((
184 window,
185 wgpu::Color {
186 r: frac(row, ROWS),
187 g: 0.5 - frac(row * column, ROWS * COLUMNS) * 0.5,
188 b: frac(column, COLUMNS),
189 a: 1.0,
190 },
191 ))
192 }
193 }
194
195 env_logger::init();
196 pollster::block_on(run(event_loop, viewports));
197 }
198 #[cfg(target_arch = "wasm32")]
199 {
200 std::panic::set_hook(Box::new(console_error_panic_hook::hook));
201 panic!("wasm32 is not supported")
202 }
203}