diff --git a/wgpu/examples/hello-windows/README.md b/wgpu/examples/hello-windows/README.md new file mode 100644 index 0000000000..e450713337 --- /dev/null +++ b/wgpu/examples/hello-windows/README.md @@ -0,0 +1,13 @@ +# hello-windows + +This example renders a set of 16 windows, with a differently colored background + +## To Run + +``` +cargo run --example hello-windows +``` + +## Screenshots + +![16 windows](./screenshot.png) diff --git a/wgpu/examples/hello-windows/main.rs b/wgpu/examples/hello-windows/main.rs new file mode 100644 index 0000000000..731dcdf8d5 --- /dev/null +++ b/wgpu/examples/hello-windows/main.rs @@ -0,0 +1,208 @@ +use std::collections::HashMap; +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::{Window, WindowId}, +}; + +struct ViewportDesc { + window: Window, + background: wgpu::Color, + surface: wgpu::Surface, +} + +struct Viewport { + desc: ViewportDesc, + sc_desc: wgpu::SwapChainDescriptor, + swap_chain: wgpu::SwapChain, +} + +impl ViewportDesc { + fn new(window: Window, background: wgpu::Color, instance: &wgpu::Instance) -> Self { + let surface = unsafe { instance.create_surface(&window) }; + Self { + window, + background, + surface, + } + } + + fn build(self, device: &wgpu::Device, swapchain_format: wgpu::TextureFormat) -> Viewport { + let size = self.window.inner_size(); + + let sc_desc = wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: swapchain_format, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Fifo, + }; + + let swap_chain = device.create_swap_chain(&self.surface, &sc_desc); + + Viewport { + desc: self, + sc_desc, + swap_chain, + } + } +} + +impl Viewport { + fn resize(&mut self, device: &wgpu::Device, size: winit::dpi::PhysicalSize) { + self.sc_desc.width = size.width; + self.sc_desc.height = size.height; + self.swap_chain = device.create_swap_chain(&self.desc.surface, &self.sc_desc); + } + fn get_current_frame(&mut self) -> wgpu::SwapChainTexture { + self.swap_chain + .get_current_frame() + .expect("Failed to acquire next swap chain texture") + .output + } +} + +async fn run( + event_loop: EventLoop<()>, + viewports: Vec<(Window, wgpu::Color)>, + swapchain_format: wgpu::TextureFormat, +) { + let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); + let viewports: Vec<_> = viewports + .into_iter() + .map(|(window, color)| ViewportDesc::new(window, color, &instance)) + .collect(); + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::Default, + // Request an adapter which can render to our surface + compatible_surface: viewports.first().map(|desc| &desc.surface), + }) + .await + .expect("Failed to find an appropiate adapter"); + + // Create the logical device and command queue + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + features: wgpu::Features::empty(), + limits: wgpu::Limits::default(), + shader_validation: true, + }, + None, + ) + .await + .expect("Failed to create device"); + + let mut viewports: HashMap = viewports + .into_iter() + .map(|desc| (desc.window.id(), desc.build(&device, swapchain_format))) + .collect(); + + event_loop.run(move |event, _, control_flow| { + // Have the closure take ownership of the resources. + // `event_loop.run` never returns, therefore we must do this to ensure + // the resources are properly cleaned up. + let _ = (&instance, &adapter); + + *control_flow = ControlFlow::Wait; + match event { + Event::WindowEvent { + window_id, + event: WindowEvent::Resized(size), + .. + } => { + // Recreate the swap chain with the new size + if let Some(viewport) = viewports.get_mut(&window_id) { + viewport.resize(&device, size); + } + } + Event::RedrawRequested(window_id) => { + if let Some(viewport) = viewports.get_mut(&window_id) { + let frame = viewport.get_current_frame(); + let mut encoder = device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + { + let _rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(viewport.desc.background), + store: true, + }, + }], + depth_stencil_attachment: None, + }); + } + + queue.submit(Some(encoder.finish())); + } + } + Event::WindowEvent { + window_id, + event: WindowEvent::CloseRequested, + .. + } => { + viewports.remove(&window_id); + if viewports.is_empty() { + *control_flow = ControlFlow::Exit + } + } + _ => {} + } + }); +} + +fn main() { + #[cfg(not(target_arch = "wasm32"))] + { + const WINDOW_SIZE: u32 = 128; + const WINDOW_PADDING: u32 = 16; + const WINDOW_TITLEBAR: u32 = 32; + const WINDOW_OFFSET: u32 = WINDOW_SIZE + WINDOW_PADDING; + const ROWS: u32 = 4; + const COLUMNS: u32 = 4; + + let event_loop = EventLoop::new(); + let mut viewports = Vec::with_capacity((ROWS * COLUMNS) as usize); + for row in 0..ROWS { + for column in 0..COLUMNS { + let window = winit::window::WindowBuilder::new() + .with_title(format!("x{}y{}", column, row)) + .with_inner_size(winit::dpi::PhysicalSize::new(WINDOW_SIZE, WINDOW_SIZE)) + .build(&event_loop) + .unwrap(); + window.set_outer_position(winit::dpi::PhysicalPosition::new( + WINDOW_PADDING + column * WINDOW_OFFSET, + WINDOW_PADDING + row * (WINDOW_OFFSET + WINDOW_TITLEBAR), + )); + fn frac(index: u32, max: u32) -> f64 { + index as f64 / max as f64 + } + viewports.push(( + window, + wgpu::Color { + r: frac(row, ROWS), + g: 0.5 - frac(row * column, ROWS * COLUMNS) * 0.5, + b: frac(column, COLUMNS), + a: 1.0, + }, + )) + } + } + + subscriber::initialize_default_subscriber(None); + // Temporarily avoid srgb formats for the swapchain on the web + futures::executor::block_on(run( + event_loop, + viewports, + wgpu::TextureFormat::Bgra8UnormSrgb, + )); + } + #[cfg(target_arch = "wasm32")] + { + std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + panic!("wasm32 is not supported") + } +} diff --git a/wgpu/examples/hello-windows/screenshot.png b/wgpu/examples/hello-windows/screenshot.png new file mode 100644 index 0000000000..202a3c54c8 Binary files /dev/null and b/wgpu/examples/hello-windows/screenshot.png differ