From a3d3230bafe3485d073b4d15e9a3c930f42d0c0d Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sun, 21 May 2023 02:34:09 +0200 Subject: [PATCH] desktop: Turn MovieView into a custom render target --- desktop/src/gui.rs | 1 + desktop/src/gui/controller.rs | 30 +++++--- desktop/src/gui/movie.rs | 129 ++++++++++++++++++++++++++-------- desktop/src/main.rs | 23 ++---- 4 files changed, 127 insertions(+), 56 deletions(-) diff --git a/desktop/src/gui.rs b/desktop/src/gui.rs index 1a1ac4a98..b34894e4c 100644 --- a/desktop/src/gui.rs +++ b/desktop/src/gui.rs @@ -7,6 +7,7 @@ use std::time::{Duration, Instant}; use winit::event_loop::EventLoopProxy; pub use controller::GuiController; +pub use movie::MovieView; /// The main controller for the Ruffle GUI. pub struct RuffleGui { diff --git a/desktop/src/gui/controller.rs b/desktop/src/gui/controller.rs index 6849ec97e..a6fee43ac 100644 --- a/desktop/src/gui/controller.rs +++ b/desktop/src/gui/controller.rs @@ -1,5 +1,5 @@ use crate::custom_event::RuffleEvent; -use crate::gui::movie::MovieView; +use crate::gui::movie::{MovieView, MovieViewRenderer}; use crate::gui::RuffleGui; use anyhow::anyhow; use egui::Context; @@ -25,7 +25,7 @@ pub struct GuiController { repaint_after: Duration, surface: wgpu::Surface, surface_format: wgpu::TextureFormat, - movie_view: MovieView, + movie_view_renderer: Arc, } impl GuiController { @@ -67,7 +67,8 @@ impl GuiController { .cloned() .expect("At least one format should be supported"); - let game_view = MovieView::new(&descriptors.device, surface_format); + let movie_view_renderer = + Arc::new(MovieViewRenderer::new(&descriptors.device, surface_format)); let egui_renderer = egui_wgpu::Renderer::new(&descriptors.device, surface_format, None, 1); let event_loop = event_loop.create_proxy(); let gui = RuffleGui::new(event_loop); @@ -82,7 +83,7 @@ impl GuiController { repaint_after: Duration::ZERO, surface, surface_format, - movie_view: game_view, + movie_view_renderer, }) } @@ -113,7 +114,17 @@ impl GuiController { response.consumed } - pub fn render(&mut self, movie: &wgpu::Texture) { + pub fn create_movie_view(&self) -> MovieView { + let size = self.window.inner_size(); + MovieView::new( + self.movie_view_renderer.clone(), + &self.descriptors.device, + size.width, + size.height, + ) + } + + pub fn render(&mut self, movie: &MovieView) { let surface_texture = self .surface .get_current_texture() @@ -166,17 +177,12 @@ impl GuiController { { let surface_view = surface_texture.texture.create_view(&Default::default()); - // First draw the movie - this also clears the surface - self.movie_view - .render(&self.descriptors.device, &mut encoder, movie, &surface_view); - - // Then any UI let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { color_attachments: &[Some(wgpu::RenderPassColorAttachment { view: &surface_view, resolve_target: None, ops: wgpu::Operations { - load: wgpu::LoadOp::Load, + load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), store: true, }, })], @@ -184,6 +190,8 @@ impl GuiController { label: Some("egui_render"), }); + movie.render(&self.movie_view_renderer, &mut render_pass); + self.egui_renderer .render(&mut render_pass, &clipped_primitives, &screen_descriptor); } diff --git a/desktop/src/gui/movie.rs b/desktop/src/gui/movie.rs index 12fd05f69..9f5a1e016 100644 --- a/desktop/src/gui/movie.rs +++ b/desktop/src/gui/movie.rs @@ -1,7 +1,10 @@ +use ruffle_render_wgpu::target::{RenderTarget, RenderTargetFrame}; use std::borrow::Cow; +use std::sync::Arc; use wgpu::util::DeviceExt; -pub struct MovieView { +#[derive(Debug)] +pub struct MovieViewRenderer { bind_group_layout: wgpu::BindGroupLayout, pipeline: wgpu::RenderPipeline, sampler: wgpu::Sampler, @@ -18,7 +21,7 @@ const BLIT_VERTICES: [[f32; 4]; 6] = [ [-1.0, 1.0, 0.0, 0.0], // tl ]; -impl MovieView { +impl MovieViewRenderer { pub fn new(device: &wgpu::Device, surface_format: wgpu::TextureFormat) -> Self { let module = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, @@ -113,45 +116,115 @@ impl MovieView { vertices, } } +} - pub fn render( - &self, +#[derive(Debug)] +pub struct MovieView { + renderer: Arc, + texture: wgpu::Texture, + bind_group: wgpu::BindGroup, +} + +impl MovieView { + pub fn new( + renderer: Arc, device: &wgpu::Device, - encoder: &mut wgpu::CommandEncoder, - movie: &wgpu::Texture, - surface_view: &wgpu::TextureView, - ) { - let movie_view = movie.create_view(&Default::default()); - let blit_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + width: u32, + height: u32, + ) -> Self { + let texture = device.create_texture(&wgpu::TextureDescriptor { label: None, - layout: &self.bind_group_layout, + size: wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }); + let view = texture.create_view(&Default::default()); + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &renderer.bind_group_layout, entries: &[ wgpu::BindGroupEntry { binding: 0, - resource: wgpu::BindingResource::TextureView(&movie_view), + resource: wgpu::BindingResource::TextureView(&view), }, wgpu::BindGroupEntry { binding: 1, - resource: wgpu::BindingResource::Sampler(&self.sampler), + resource: wgpu::BindingResource::Sampler(&renderer.sampler), }, ], }); - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: surface_view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), - store: true, - }, - })], - depth_stencil_attachment: None, - label: Some("egui_render"), - }); + Self { + renderer, + texture, + bind_group, + } + } - render_pass.set_pipeline(&self.pipeline); - render_pass.set_bind_group(0, &blit_bind_group, &[]); - render_pass.set_vertex_buffer(0, self.vertices.slice(..)); + pub fn render<'pass, 'global: 'pass>( + &'pass self, + renderer: &'global MovieViewRenderer, + render_pass: &mut wgpu::RenderPass<'pass>, + ) { + render_pass.set_pipeline(&renderer.pipeline); + render_pass.set_bind_group(0, &self.bind_group, &[]); + render_pass.set_vertex_buffer(0, renderer.vertices.slice(..)); render_pass.draw(0..6, 0..1); } } + +impl RenderTarget for MovieView { + type Frame = MovieViewFrame; + + fn resize(&mut self, device: &wgpu::Device, width: u32, height: u32) { + *self = MovieView::new(self.renderer.clone(), device, width, height); + } + + fn format(&self) -> wgpu::TextureFormat { + self.texture.format() + } + + fn width(&self) -> u32 { + self.texture.width() + } + + fn height(&self) -> u32 { + self.texture.height() + } + + fn get_next_texture(&mut self) -> Result { + Ok(MovieViewFrame( + self.texture.create_view(&Default::default()), + )) + } + + fn submit>( + &self, + _device: &wgpu::Device, + queue: &wgpu::Queue, + command_buffers: I, + _frame: Self::Frame, + ) -> wgpu::SubmissionIndex { + queue.submit(command_buffers) + } +} + +#[derive(Debug)] +pub struct MovieViewFrame(wgpu::TextureView); + +impl RenderTargetFrame for MovieViewFrame { + fn into_view(self) -> wgpu::TextureView { + self.0 + } + + fn view(&self) -> &wgpu::TextureView { + &self.0 + } +} diff --git a/desktop/src/main.rs b/desktop/src/main.rs index db6e27939..c0f96b29d 100644 --- a/desktop/src/main.rs +++ b/desktop/src/main.rs @@ -17,6 +17,7 @@ mod ui; use crate::custom_event::RuffleEvent; use crate::executor::GlutinAsyncExecutor; +use crate::gui::MovieView; use anyhow::{anyhow, Context, Error}; use clap::Parser; use gui::GuiController; @@ -33,7 +34,6 @@ use ruffle_render::backend::RenderBackend; use ruffle_render::quality::StageQuality; use ruffle_render_wgpu::backend::WgpuRenderBackend; use ruffle_render_wgpu::clap::{GraphicsBackend, PowerPreference}; -use ruffle_render_wgpu::target::TextureTarget; use std::cell::RefCell; use std::io::Read; use std::panic::PanicInfo; @@ -354,17 +354,9 @@ impl App { opt.power.into(), )?; - let viewport_size = window.inner_size(); - let renderer = WgpuRenderBackend::new( - gui.descriptors().clone(), - TextureTarget::new( - &gui.descriptors().device, - (viewport_size.width, viewport_size.height), - ) - .map_err(|e| anyhow!(e.to_string()))?, - ) - .map_err(|e| anyhow!(e.to_string())) - .context("Couldn't create wgpu rendering backend")?; + let renderer = WgpuRenderBackend::new(gui.descriptors().clone(), gui.create_movie_view()) + .map_err(|e| anyhow!(e.to_string())) + .context("Couldn't create wgpu rendering backend")?; RENDER_INFO.with(|i| *i.borrow_mut() = Some(renderer.debug_info().to_string())); builder = builder @@ -492,12 +484,9 @@ impl App { player.render(); let renderer = player .renderer_mut() - .downcast_mut::>() + .downcast_mut::>() .expect("Renderer must be correct type"); - self.gui - .lock() - .expect("Gui lock") - .render(&renderer.target().texture); + self.gui.lock().expect("Gui lock").render(renderer.target()); #[cfg(feature = "tracy")] tracing_tracy::client::Client::running() .expect("tracy client must be running")