diff --git a/examples/hdr-gstreamer-wgpu/src/main.rs b/examples/hdr-gstreamer-wgpu/src/main.rs index 10d2759..79f153d 100644 --- a/examples/hdr-gstreamer-wgpu/src/main.rs +++ b/examples/hdr-gstreamer-wgpu/src/main.rs @@ -22,6 +22,23 @@ impl App { } } +pub trait HdrTextureFormatExt { + fn is_hdr_format(&self) -> bool; +} + +impl HdrTextureFormatExt for wgpu::TextureFormat { + fn is_hdr_format(&self) -> bool { + matches!( + self, + wgpu::TextureFormat::Rgba16Float + // | wgpu::TextureFormat::Rg11b10float + // | wgpu::TextureFormat::R11g11b10float + | wgpu::TextureFormat::Rgb10a2Unorm + | wgpu::TextureFormat::Rgba32Float + ) + } +} + pub struct State { window: Arc, gst: Video, @@ -62,7 +79,14 @@ impl State { .await .context("Failed to request wgpu device")?; let surface_caps = surface.get_capabilities(&adapter); - let surface_format = surface_caps.formats.last().unwrap().clone(); + dbg!(&surface_caps); + let surface_format = surface_caps + .formats + .iter() + .rev() // float one comes first + .find(|f| f.is_hdr_format()) + .expect("HDR format not supported") + .clone(); let size = window.inner_size(); let config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, @@ -72,7 +96,7 @@ impl State { present_mode: surface_caps.present_modes[0], alpha_mode: surface_caps.alpha_modes[0], view_formats: vec![], - desired_maximum_frame_latency: 3, // calculate upto 5 frames ahead + desired_maximum_frame_latency: 2, // calculate upto 5 frames ahead }; surface.configure(&device, &config); @@ -148,13 +172,13 @@ impl State { mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgb10a2Unorm, + format: surface_format, usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, label: Some("Jello Video Texture"), view_formats: &[], }); - /// Todo: Use a better sampler + // TODO: Use a better sampler let sampler = device.create_sampler(&wgpu::SamplerDescriptor { label: Some("texture_sampler"), address_mode_u: wgpu::AddressMode::ClampToEdge, @@ -183,6 +207,7 @@ impl State { label: Some("Jello Texture Bind Group"), }); let gst = Video::new().context("Failed to create Video")?; + // surface.configure(&device, &config); Ok(Self { window, @@ -214,7 +239,7 @@ impl State { return Ok(()); } - self.copy_next_frame_to_texture(&self.surface_texture) + self.copy_next_frame_to_texture() .inspect_err(|e| { tracing::error!("Failed to copy video frame to texture: {e:?}"); }) @@ -254,15 +279,15 @@ impl State { render_pass.set_pipeline(&self.pipeline); render_pass.set_bind_group(0, &self.bind_group, &[]); render_pass.draw(0..3, 0..1); - drop(render_pass); + self.queue.submit(std::iter::once(encoder.finish())); output.present(); self.window.request_redraw(); Ok(()) } - pub fn copy_next_frame_to_texture(&self, texture: &wgpu::Texture) -> Result<()> { + pub fn copy_next_frame_to_texture(&mut self) -> Result<()> { let frame = self .gst .appsink @@ -280,6 +305,18 @@ impl State { .get::("height") .context("Failed to get height from caps")?; + if self.config.width != width as u32 || self.config.height != height as u32 { + tracing::info!( + "Resizing surface from {}x{} to {}x{}", + self.config.width, + self.config.height, + width, + height + ); + self.resize(width as u32, height as u32); + } + + let texture = &self.surface_texture; let buffer = frame.buffer().context("Failed to get buffer from sample")?; let map = buffer .map_readable() @@ -299,6 +336,7 @@ impl State { }, texture.size(), ); + Ok(()) } } @@ -338,7 +376,10 @@ impl ApplicationHandler for App { match event { WindowEvent::CloseRequested => event_loop.exit(), - WindowEvent::Resized(size) => state.resize(size.width, size.height), + WindowEvent::Resized(size) => { + tracing::info!("Window resized to {size:?}"); + state.resize(size.width, size.height) + } WindowEvent::RedrawRequested => { // dbg!("RedrawRequested"); // if state.gst.poll() { @@ -418,6 +459,8 @@ impl Video { .map_err(|_| { anyhow::anyhow!("Failed to downcast video-sink appsink to gst_app::AppSink") })?; + // appsink.set_property("max-buffers", 10u32); + appsink.set_property("max-bytes", 10 * 4096 * 2160u64); appsink.set_callbacks( gst_app::AppSinkCallbacks::builder() .new_sample(|_appsink| Ok(gst::FlowSuccess::Ok))