mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[rs] Merge #553
553: Add hello-windows example r=kvark a=qthree # `hello-windows` ## Description This is demonstration of ability to create multiple windows with differently colored backgrounds. ## Screenshot  # `shared-textures` (old version) ## Description This is demonstration of ability to create multiple windows and share single texture across all of them. Available in ad3030ae8f61e3ea3f7b913cd03c366119d058fb commit. ## Screenshot  Co-authored-by: qthree <qthree3@gmail.com>
This commit is contained in:
13
wgpu/examples/hello-windows/README.md
Normal file
13
wgpu/examples/hello-windows/README.md
Normal file
@@ -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
|
||||
|
||||

|
||||
208
wgpu/examples/hello-windows/main.rs
Normal file
208
wgpu/examples/hello-windows/main.rs
Normal file
@@ -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<u32>) {
|
||||
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<WindowId, Viewport> = 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")
|
||||
}
|
||||
}
|
||||
BIN
wgpu/examples/hello-windows/screenshot.png
Normal file
BIN
wgpu/examples/hello-windows/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Reference in New Issue
Block a user