// This is free and unencumbered software released into the public domain. // Anyone is free to copy, modify, publish, use, compile, sell, or // distribute this software, either in source code form or as a compiled // binary, for any purpose, commercial or non-commercial, and by any // means. // In jurisdictions that recognize copyright laws, the author or authors // of this software dedicate any and all copyright interest in the // software to the public domain. We make this dedication for the benefit // of the public at large and to the detriment of our heirs and // successors. We intend this dedication to be an overt act of // relinquishment in perpetuity of all present and future rights to this // software under copyright law. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // For more information, please refer to [http://unlicense.org] use egui_winit::winit; use egui_latest_wgpu_backend::{RenderPass, ScreenDescriptor}; use winit::event::Event::*; use winit::event_loop::ControlFlow; const INITIAL_WIDTH: u32 = 1920; const INITIAL_HEIGHT: u32 = 1080; fn main() { let event_loop = winit::event_loop::EventLoop::new(); let window = winit::window::WindowBuilder::new() .with_decorations(true) .with_resizable(true) .with_transparent(false) .with_title("egui-wgpu_winit example") .with_inner_size(winit::dpi::PhysicalSize { width: INITIAL_WIDTH, height: INITIAL_HEIGHT, }) .build(&event_loop) .unwrap(); let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY); let surface = unsafe { instance.create_surface(&window) }; let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::HighPerformance, compatible_surface: Some(&surface), force_fallback_adapter: false, })) .unwrap(); let (device, queue) = pollster::block_on(adapter.request_device( &wgpu::DeviceDescriptor { features: wgpu::Features::default(), limits: wgpu::Limits::default(), label: None, }, None, )) .unwrap(); let size = window.inner_size(); let surface_format = surface.get_supported_formats(&adapter)[0]; println!( "surface_formats: {:?}", surface.get_supported_formats(&adapter) ); let mut surface_config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format: surface_format, width: size.width as u32, height: size.height as u32, present_mode: wgpu::PresentMode::Mailbox, alpha_mode: wgpu::CompositeAlphaMode::Auto, }; surface.configure(&device, &surface_config); // We use the `egui-winit` crate to handle integration with wgpu, and create the runtime context let mut state = egui_winit::State::new(&event_loop); let context = egui::Context::default(); // We use the egui_wgpu_backend crate as the render backend. let mut egui_rpass = RenderPass::new(&device, surface_format, 1); // Display the demo application that ships with egui. let mut demo_app = egui_demo_lib::DemoWindows::default(); event_loop.run(move |event, _, control_flow| { match event { RedrawRequested(..) => { let output_frame = match surface.get_current_texture() { Ok(frame) => frame, Err(wgpu::SurfaceError::Outdated) => { // This error occurs when the app is minimized on Windows. // Silently return here to prevent spamming the console with: // "The underlying surface has changed, and therefore the swap chain must be updated" return; } Err(e) => { eprintln!("Dropped frame with error: {}", e); return; } }; let output_view = output_frame .texture .create_view(&wgpu::TextureViewDescriptor::default()); // Begin to draw the UI frame. let input = state.take_egui_input(&window); context.begin_frame(input); // Draw the demo application. demo_app.ui(&context); // End the UI frame. We could now handle the output and draw the UI with the backend. let output = context.end_frame(); let paint_jobs = context.tessellate(output.shapes); state.handle_platform_output(&window, &context, output.platform_output); let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("encoder"), }); // Upload all resources for the GPU. let screen_descriptor = ScreenDescriptor { physical_width: surface_config.width, physical_height: surface_config.height, scale_factor: window.scale_factor() as f32, }; egui_rpass .add_textures(&device, &queue, &output.textures_delta) .unwrap(); egui_rpass.remove_textures(output.textures_delta).unwrap(); egui_rpass.update_buffers(&device, &queue, &paint_jobs, &screen_descriptor); // Record all render passes. egui_rpass .execute( &mut encoder, &output_view, &paint_jobs, &screen_descriptor, Some(wgpu::Color::BLACK), ) .unwrap(); // Submit the commands. queue.submit(std::iter::once(encoder.finish())); // Redraw egui output_frame.present(); } MainEventsCleared => { window.request_redraw(); } WindowEvent { event, .. } => { // Pass the winit events to the platform integration. let exclusive = state.on_event(&context, &event); // state.on_event returns true when the event has already been handled by egui and shouldn't be passed further if !exclusive { match event { winit::event::WindowEvent::Resized(size) => { // Resize with 0 width and height is used by winit to signal a minimize event on Windows. // See: https://github.com/rust-windowing/winit/issues/208 // This solves an issue where the app would panic when minimizing on Windows. if size.width > 0 && size.height > 0 { surface_config.width = size.width; surface_config.height = size.height; surface.configure(&device, &surface_config); } } winit::event::WindowEvent::CloseRequested => { *control_flow = ControlFlow::Exit; } _ => (), } } } _ => (), } }); }