From 5e8634e9eb111eee7981a22cb41c3f941cb8b325 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sat, 10 Apr 2021 16:24:12 +0200 Subject: [PATCH] examples/glupload: Update glutin to 0.26 with winit 0.24 Winit 0.19 uses uninitialized variables which is invalid since Rust 1.48, leading to a runtime panic [1]. Updating to the latest version resolves these issues but requires significant refactoring since the event loop now runs entirely within a closure. [1]: https://github.com/rust-windowing/winit/issues/1811 --- deny.toml | 5 ++ examples/Cargo.toml | 3 +- examples/src/bin/glupload.rs | 137 +++++++++++++++++------------------ 3 files changed, 74 insertions(+), 71 deletions(-) diff --git a/deny.toml b/deny.toml index 987451d21..369463599 100644 --- a/deny.toml +++ b/deny.toml @@ -30,6 +30,11 @@ name = "gstreamer-rs-lgpl-docs" multiple-versions = "deny" wildcards = "allow" highlight = "all" +skip-tree = [ + # Winit introduces quite a few duplicate (outdated!) dependencies together + # with its direct dependant glutin. + { name = "winit", version = "0.24" } +] [sources] unknown-registry = "deny" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 79ff3abf9..d3e0fd518 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -32,8 +32,7 @@ byte-slice-cast = "1" cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs", features=["use_glib"], optional = true } pango = { git = "https://github.com/gtk-rs/gtk-rs", optional = true } pangocairo = { git = "https://github.com/gtk-rs/gtk-rs", optional = true } -glutin = { version = "0.21", optional = true } -winit = { version = "0.19", optional = true } +glutin = { version = "0.26", optional = true } once_cell = "1.0" image = { version="0.23", optional = true } diff --git a/examples/src/bin/glupload.rs b/examples/src/bin/glupload.rs index f94f4d4da..a176fcd87 100644 --- a/examples/src/bin/glupload.rs +++ b/examples/src/bin/glupload.rs @@ -12,6 +12,7 @@ use gst_gl::prelude::*; use std::ffi::CStr; use std::mem; use std::ptr; +use std::sync; use std::sync::mpsc; use anyhow::Error; @@ -184,7 +185,7 @@ impl Gl { } } - fn resize(&self, size: glutin::dpi::PhysicalSize) { + fn resize(&self, size: glutin::dpi::PhysicalSize) { unsafe { self.gl .Viewport(0, 0, size.width as i32, size.height as i32); @@ -318,7 +319,7 @@ struct App { appsink: gst_app::AppSink, glupload: gst::Element, bus: gst::Bus, - events_loop: glutin::EventsLoop, + event_loop: glutin::event_loop::EventLoop<()>, windowed_context: glutin::WindowedContext, shared_context: gst_gl::GLContext, } @@ -332,11 +333,11 @@ impl App { .get_bus() .expect("Pipeline without bus. Shouldn't happen!"); - let events_loop = glutin::EventsLoop::new(); - let window = glutin::WindowBuilder::new().with_title("GL rendering"); + let event_loop = glutin::event_loop::EventLoop::new(); + let window = glutin::window::WindowBuilder::new().with_title("GL rendering"); let windowed_context = glutin::ContextBuilder::new() .with_vsync(true) - .build_windowed(window, &events_loop)?; + .build_windowed(window, &event_loop)?; let windowed_context = unsafe { windowed_context.make_current().map_err(|(_, err)| err)? }; @@ -345,10 +346,10 @@ impl App { let shared_context: gst_gl::GLContext; if cfg!(target_os = "linux") { - use glutin::os::unix::RawHandle; + use glutin::platform::unix::RawHandle; #[cfg(any(feature = "gst-gl-x11", feature = "gst-gl-wayland"))] - use glutin::os::unix::WindowExt; - use glutin::os::ContextTraitExt; + use glutin::platform::unix::WindowExtUnix; + use glutin::platform::ContextTraitExt; let api = App::map_gl_api(windowed_context.get_api()); @@ -368,7 +369,7 @@ impl App { }; #[cfg(feature = "gst-gl-wayland")] - if let Some(display) = inner_window.get_wayland_display() { + if let Some(display) = inner_window.wayland_display() { gl_display = Some( unsafe { gst_gl_wayland::GLDisplayWayland::with_display(display as usize) @@ -386,7 +387,7 @@ impl App { } #[cfg(feature = "gst-gl-x11")] RawHandle::Glx(glx_context) => { - let gl_display = if let Some(display) = inner_window.get_xlib_display() { + let gl_display = if let Some(display) = inner_window.xlib_display() { unsafe { gst_gl_x11::GLDisplayX11::with_display(display as usize) }.unwrap() } else { panic!("X11 window without X Display"); @@ -413,7 +414,7 @@ impl App { shared_context.fill_info()?; let gl_context = shared_context.clone(); - let events_proxy = events_loop.create_proxy(); + let event_proxy = sync::Mutex::new(event_loop.create_proxy()); #[allow(clippy::single_match)] bus.set_sync_handler(move |_, msg| { @@ -446,7 +447,9 @@ impl App { _ => (), } - let _ = events_proxy.wakeup(); + if let Err(e) = event_proxy.lock().unwrap().send_event(()) { + eprintln!("Failed to send BusEvent to event proxy: {}", e) + } gst::BusSyncReply::Pass }); @@ -459,7 +462,7 @@ impl App { appsink, glupload, bus, - events_loop, + event_loop, windowed_context, shared_context, }) @@ -467,9 +470,9 @@ impl App { fn setup( &self, - events_loop: &glutin::EventsLoop, + event_loop: &glutin::event_loop::EventLoop<()>, ) -> Result, Error> { - let events_proxy = events_loop.create_proxy(); + let events_proxy = event_loop.create_proxy(); let (sender, receiver) = mpsc::channel(); self.appsink.set_callbacks( gst_app::AppSinkCallbacks::builder() @@ -506,7 +509,7 @@ impl App { .map(|_| gst::FlowSuccess::Ok) .map_err(|_| gst::FlowError::Error)?; - let _ = events_proxy.wakeup(); + let _ = events_proxy.send_event(()); Ok(gst::FlowSuccess::Ok) }) @@ -595,13 +598,11 @@ impl App { Ok(()) } - - fn into_context(self: App) -> glutin::WindowedContext { - self.windowed_context - } } -fn main_loop(mut app: App) -> Result, Error> { +fn main_loop(app: App) -> Result<(), Error> { + let receiver = app.setup(&app.event_loop)?; + println!( "Pixel format of the window's GL context {:?}", app.windowed_context.get_pixel_format() @@ -609,42 +610,52 @@ fn main_loop(mut app: App) -> Result> = None; - let mut running = true; let mut gst_gl_context: Option = None; - let events_loop = &mut app.events_loop; - let windowed_context = &mut app.windowed_context; - let bus = &app.bus; - while running { - #[allow(clippy::single_match)] - events_loop.poll_events(|event| match event { - glutin::Event::WindowEvent { event, .. } => match event { - glutin::WindowEvent::CloseRequested - | glutin::WindowEvent::KeyboardInput { + let App { + bus, + event_loop, + glupload, + pipeline, + shared_context, + windowed_context, + .. + } = app; + + event_loop.run(move |event, _, cf| { + *cf = glutin::event_loop::ControlFlow::Wait; + + let mut needs_redraw = false; + match event { + glutin::event::Event::LoopDestroyed => { + pipeline.send_event(gst::event::Eos::new()); + pipeline.set_state(gst::State::Null).unwrap(); + } + glutin::event::Event::WindowEvent { event, .. } => match event { + glutin::event::WindowEvent::CloseRequested + | glutin::event::WindowEvent::KeyboardInput { input: - glutin::KeyboardInput { - state: glutin::ElementState::Released, - virtual_keycode: Some(glutin::VirtualKeyCode::Escape), + glutin::event::KeyboardInput { + state: glutin::event::ElementState::Released, + virtual_keycode: Some(glutin::event::VirtualKeyCode::Escape), .. }, .. - } => running = false, - glutin::WindowEvent::Resized(logical_size) => { - let dpi_factor = windowed_context.window().get_hidpi_factor(); - windowed_context.resize(logical_size.to_physical(dpi_factor)); - gl.resize(logical_size.to_physical(dpi_factor)); + } => *cf = glutin::event_loop::ControlFlow::Exit, + glutin::event::WindowEvent::Resized(physical_size) => { + windowed_context.resize(physical_size); + gl.resize(physical_size); } _ => (), }, + glutin::event::Event::RedrawRequested(_) => needs_redraw = true, _ => (), - }); + } // Handle all pending messages. Whenever there is a message we will // wake up the events loop above - App::handle_messages(&bus)?; + App::handle_messages(&bus).unwrap(); // get the last frame in channel if let Some(sample) = receiver.try_iter().last() { @@ -656,8 +667,7 @@ fn main_loop(mut app: App) -> Result() @@ -670,38 +680,27 @@ fn main_loop(mut app: App) -> Result().unwrap(); - sync_meta.wait(&app.shared_context); - if let Some(texture) = frame.get_texture_id(0) { - gl.draw_frame(texture as gl::types::GLuint); + if needs_redraw { + if let Some(frame) = curr_frame.as_ref() { + let sync_meta = frame.buffer().get_meta::().unwrap(); + sync_meta.wait(&shared_context); + if let Some(texture) = frame.get_texture_id(0) { + gl.draw_frame(texture as gl::types::GLuint); + } } + windowed_context.swap_buffers().unwrap(); } - windowed_context.swap_buffers()?; - } - - app.pipeline.send_event(gst::event::Eos::new()); - app.pipeline.set_state(gst::State::Null)?; - - Ok(app.into_context()) -} - -fn cleanup(_windowed_context: glutin::WindowedContext) { - // To ensure that the context stays alive longer than the pipeline or any reference - // inside GStreamer to the GL context, its display or anything else. See - // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/196 - // - // We might do any window/GL specific cleanup here as needed. + }) } fn example_main() { - match App::new().and_then(main_loop).map(cleanup) { - Ok(r) => r, - Err(e) => eprintln!("Error! {}", e), - } + App::new() + .and_then(main_loop) + .unwrap_or_else(|e| eprintln!("Error! {}", e)) } fn main() {