|
| 1 | +//! Repro for various issues with queue presentation |
| 2 | +//! |
| 3 | +//! The 2 current bugs being tested are presentation after no usage of surface texture |
| 4 | +//! and queue destruction immediately after present |
| 5 | +
|
| 6 | +use std::sync::Arc; |
| 7 | + |
| 8 | +use winit::application::ApplicationHandler; |
| 9 | +use winit::event::WindowEvent; |
| 10 | +use winit::event_loop::{ActiveEventLoop, EventLoop}; |
| 11 | +use winit::window::{Window, WindowId}; |
| 12 | + |
| 13 | +fn main() { |
| 14 | + env_logger::init(); |
| 15 | + let event_loop = EventLoop::new().unwrap(); |
| 16 | + event_loop.set_control_flow(winit::event_loop::ControlFlow::Poll); |
| 17 | + let mut app = App::default(); |
| 18 | + event_loop.run_app(&mut app).unwrap(); |
| 19 | +} |
| 20 | + |
| 21 | +#[derive(Default)] |
| 22 | +struct App { |
| 23 | + state: Option<State>, |
| 24 | +} |
| 25 | + |
| 26 | +struct State { |
| 27 | + window: Arc<Window>, |
| 28 | + instance: wgpu::Instance, |
| 29 | + device: wgpu::Device, |
| 30 | + queue: Option<wgpu::Queue>, |
| 31 | + surface: wgpu::Surface<'static>, |
| 32 | + surface_config: wgpu::SurfaceConfiguration, |
| 33 | +} |
| 34 | + |
| 35 | +impl ApplicationHandler for App { |
| 36 | + fn resumed(&mut self, event_loop: &ActiveEventLoop) { |
| 37 | + if self.state.is_some() { |
| 38 | + return; |
| 39 | + } |
| 40 | + let window = Arc::new( |
| 41 | + event_loop |
| 42 | + .create_window(Window::default_attributes().with_title("Presentation bugs")) |
| 43 | + .unwrap(), |
| 44 | + ); |
| 45 | + self.state = Some(State::new(window)); |
| 46 | + } |
| 47 | + |
| 48 | + fn window_event( |
| 49 | + &mut self, |
| 50 | + event_loop: &ActiveEventLoop, |
| 51 | + _window_id: WindowId, |
| 52 | + event: WindowEvent, |
| 53 | + ) { |
| 54 | + let Some(state) = &mut self.state else { return }; |
| 55 | + match event { |
| 56 | + WindowEvent::CloseRequested => event_loop.exit(), |
| 57 | + WindowEvent::Resized(size) if size.width > 0 && size.height > 0 => { |
| 58 | + state.surface_config.width = size.width; |
| 59 | + state.surface_config.height = size.height; |
| 60 | + state |
| 61 | + .surface |
| 62 | + .configure(&state.device, &state.surface_config); |
| 63 | + } |
| 64 | + WindowEvent::RedrawRequested => { |
| 65 | + let frame = match state.surface.get_current_texture() { |
| 66 | + wgpu::CurrentSurfaceTexture::Success(f) => f, |
| 67 | + wgpu::CurrentSurfaceTexture::Suboptimal(_) |
| 68 | + | wgpu::CurrentSurfaceTexture::Outdated => { |
| 69 | + state |
| 70 | + .surface |
| 71 | + .configure(&state.device, &state.surface_config); |
| 72 | + return; |
| 73 | + } |
| 74 | + wgpu::CurrentSurfaceTexture::Lost => { |
| 75 | + state.surface = |
| 76 | + state.instance.create_surface(state.window.clone()).unwrap(); |
| 77 | + state |
| 78 | + .surface |
| 79 | + .configure(&state.device, &state.surface_config); |
| 80 | + return; |
| 81 | + } |
| 82 | + _ => return, |
| 83 | + }; |
| 84 | + let Some(queue) = state.queue.take() else { |
| 85 | + return; |
| 86 | + }; |
| 87 | + // Immediately present the surface texture (with nothing on it) and then drop the queue, which should cause a full wait. |
| 88 | + queue.present(frame); |
| 89 | + event_loop.exit(); |
| 90 | + } |
| 91 | + _ => {} |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { |
| 96 | + if let Some(state) = &self.state { |
| 97 | + state.window.request_redraw(); |
| 98 | + } |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +impl State { |
| 103 | + fn new(window: Arc<Window>) -> Self { |
| 104 | + let size = window.inner_size(); |
| 105 | + let width = size.width.max(1); |
| 106 | + let height = size.height.max(1); |
| 107 | + |
| 108 | + let mut instance_desc = wgpu::InstanceDescriptor::new_without_display_handle_from_env(); |
| 109 | + instance_desc.flags |= wgpu::InstanceFlags::advanced_debugging(); |
| 110 | + let instance = wgpu::Instance::new(instance_desc); |
| 111 | + let surface = instance.create_surface(window.clone()).unwrap(); |
| 112 | + let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { |
| 113 | + compatible_surface: Some(&surface), |
| 114 | + ..Default::default() |
| 115 | + })) |
| 116 | + .expect("No adapter"); |
| 117 | + |
| 118 | + println!("Adapter: {:?}", adapter.get_info().name); |
| 119 | + |
| 120 | + let (device, queue) = |
| 121 | + pollster::block_on(adapter.request_device(&Default::default())).unwrap(); |
| 122 | + |
| 123 | + let surface_format = surface.get_capabilities(&adapter).formats[0]; |
| 124 | + let surface_config = wgpu::SurfaceConfiguration { |
| 125 | + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, |
| 126 | + format: surface_format, |
| 127 | + width, |
| 128 | + height, |
| 129 | + present_mode: wgpu::PresentMode::AutoVsync, |
| 130 | + alpha_mode: wgpu::CompositeAlphaMode::Auto, |
| 131 | + view_formats: vec![], |
| 132 | + desired_maximum_frame_latency: 2, |
| 133 | + }; |
| 134 | + surface.configure(&device, &surface_config); |
| 135 | + |
| 136 | + State { |
| 137 | + window, |
| 138 | + instance, |
| 139 | + device, |
| 140 | + queue: Some(queue), |
| 141 | + surface, |
| 142 | + surface_config, |
| 143 | + } |
| 144 | + } |
| 145 | +} |
0 commit comments