desktop: Turn MovieView into a custom render target
This commit is contained in:
parent
67fed1159c
commit
a3d3230baf
|
@ -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 {
|
||||
|
|
|
@ -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<MovieViewRenderer>,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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<MovieViewRenderer>,
|
||||
texture: wgpu::Texture,
|
||||
bind_group: wgpu::BindGroup,
|
||||
}
|
||||
|
||||
impl MovieView {
|
||||
pub fn new(
|
||||
renderer: Arc<MovieViewRenderer>,
|
||||
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<Self::Frame, wgpu::SurfaceError> {
|
||||
Ok(MovieViewFrame(
|
||||
self.texture.create_view(&Default::default()),
|
||||
))
|
||||
}
|
||||
|
||||
fn submit<I: IntoIterator<Item = wgpu::CommandBuffer>>(
|
||||
&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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::<WgpuRenderBackend<TextureTarget>>()
|
||||
.downcast_mut::<WgpuRenderBackend<MovieView>>()
|
||||
.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")
|
||||
|
|
Loading…
Reference in New Issue