wgpu_examples/hello_windows/
mod.rs1#![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 experimental_features: wgpu::ExperimentalFeatures::disabled(),
78 memory_hints: wgpu::MemoryHints::MemoryUsage,
79 trace: wgpu::Trace::Off,
80 })
81 .await
82 .expect("Failed to create device");
83
84 let mut viewports: HashMap<WindowId, Viewport> = viewports
85 .into_iter()
86 .map(|desc| (desc.window.id(), desc.build(&adapter, &device)))
87 .collect();
88
89 event_loop
90 .run(move |event, target| {
91 let _ = (&instance, &adapter);
95
96 if let Event::WindowEvent { window_id, event } = event {
97 match event {
98 WindowEvent::Resized(new_size) => {
99 if let Some(viewport) = viewports.get_mut(&window_id) {
101 viewport.resize(&device, new_size);
102 viewport.desc.window.request_redraw();
104 }
105 }
106 WindowEvent::RedrawRequested => {
107 if let Some(viewport) = viewports.get_mut(&window_id) {
108 let frame = viewport.get_current_texture();
109 let view = frame
110 .texture
111 .create_view(&wgpu::TextureViewDescriptor::default());
112 let mut encoder =
113 device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
114 label: None,
115 });
116 {
117 let _rpass =
118 encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
119 label: None,
120 color_attachments: &[Some(
121 wgpu::RenderPassColorAttachment {
122 view: &view,
123 depth_slice: None,
124 resolve_target: None,
125 ops: wgpu::Operations {
126 load: wgpu::LoadOp::Clear(
127 viewport.desc.background,
128 ),
129 store: wgpu::StoreOp::Store,
130 },
131 },
132 )],
133 depth_stencil_attachment: None,
134 timestamp_writes: None,
135 occlusion_query_set: None,
136 multiview_mask: None,
137 });
138 }
139
140 queue.submit(Some(encoder.finish()));
141 viewport.desc.window.pre_present_notify();
142 frame.present();
143 }
144 }
145 WindowEvent::CloseRequested => {
146 viewports.remove(&window_id);
147 if viewports.is_empty() {
148 target.exit();
149 }
150 }
151 _ => {}
152 }
153 }
154 })
155 .unwrap();
156}
157
158pub fn main() {
159 #[cfg(not(target_arch = "wasm32"))]
160 {
161 const WINDOW_SIZE: u32 = 128;
162 const WINDOW_PADDING: u32 = 16;
163 const WINDOW_TITLEBAR: u32 = 32;
164 const WINDOW_OFFSET: u32 = WINDOW_SIZE + WINDOW_PADDING;
165 const ROWS: u32 = 4;
166 const COLUMNS: u32 = 4;
167
168 let event_loop = EventLoop::new().unwrap();
169 let mut viewports = Vec::with_capacity((ROWS * COLUMNS) as usize);
170 for row in 0..ROWS {
171 for column in 0..COLUMNS {
172 let window = winit::window::WindowBuilder::new()
173 .with_title(format!("x{column}y{row}"))
174 .with_inner_size(winit::dpi::PhysicalSize::new(WINDOW_SIZE, WINDOW_SIZE))
175 .build(&event_loop)
176 .unwrap();
177 let window = Arc::new(window);
178 window.set_outer_position(winit::dpi::PhysicalPosition::new(
179 WINDOW_PADDING + column * WINDOW_OFFSET,
180 WINDOW_PADDING + row * (WINDOW_OFFSET + WINDOW_TITLEBAR),
181 ));
182 fn frac(index: u32, max: u32) -> f64 {
183 index as f64 / max as f64
184 }
185 viewports.push((
186 window,
187 wgpu::Color {
188 r: frac(row, ROWS),
189 g: 0.5 - frac(row * column, ROWS * COLUMNS) * 0.5,
190 b: frac(column, COLUMNS),
191 a: 1.0,
192 },
193 ))
194 }
195 }
196
197 env_logger::init();
198 pollster::block_on(run(event_loop, viewports));
199 }
200 #[cfg(target_arch = "wasm32")]
201 {
202 std::panic::set_hook(Box::new(console_error_panic_hook::hook));
203 panic!("wasm32 is not supported")
204 }
205}