diff --git a/render/wgpu/src/backend.rs b/render/wgpu/src/backend.rs index a592d029b..751ff7aa1 100644 --- a/render/wgpu/src/backend.rs +++ b/render/wgpu/src/backend.rs @@ -1,3 +1,4 @@ +use crate::commands::CommandRenderer; use crate::descriptors::DescriptorsTargetData; use crate::frame::Frame; use crate::target::RenderTargetFrame; @@ -756,14 +757,16 @@ impl RenderBackend for WgpuRenderBackend { &self.descriptors.onscreen.pipelines, &self.descriptors, UniformBuffer::new(&mut self.uniform_buffers_storage), - self.quad_vbo.slice(..), - self.quad_ibo.slice(..), - &self.meshes, render_pass, &mut uniform_encoder, - &self.bitmap_registry, ); - commands.execute(&mut frame); + commands.execute(&mut CommandRenderer::new( + &mut frame, + &self.meshes, + &self.bitmap_registry, + self.quad_vbo.slice(..), + self.quad_ibo.slice(..), + )); // If we have an sRGB surface, copy from our linear intermediate buffer to the sRGB surface. let copy_encoder = if let Some(copy_srgb_bind_group) = &self.copy_srgb_bind_group { @@ -774,6 +777,8 @@ impl RenderBackend for WgpuRenderBackend { copy_srgb_bind_group, self.target.width() as f32, self.target.height() as f32, + self.quad_vbo.slice(..), + self.quad_ibo.slice(..), )) } else { None @@ -1072,14 +1077,16 @@ impl RenderBackend for WgpuRenderBackend { &self.descriptors.offscreen.pipelines, &self.descriptors, UniformBuffer::new(&mut self.uniform_buffers_storage), - self.quad_vbo.slice(..), - self.quad_ibo.slice(..), - &self.meshes, render_pass, &mut uniform_encoder, - &self.bitmap_registry, ); - commands.execute(&mut frame); + commands.execute(&mut CommandRenderer::new( + &mut frame, + &self.meshes, + &self.bitmap_registry, + self.quad_vbo.slice(..), + self.quad_ibo.slice(..), + )); frame.finish(); target.submit( diff --git a/render/wgpu/src/commands.rs b/render/wgpu/src/commands.rs new file mode 100644 index 000000000..13b38a3dc --- /dev/null +++ b/render/wgpu/src/commands.rs @@ -0,0 +1,189 @@ +use crate::frame::Frame; +use crate::pipelines::BlendMode as ActualBlendMode; +use crate::{ColorAdjustments, DrawType, MaskState, Mesh, RegistryData}; +use fnv::FnvHashMap; +use ruffle_render::backend::ShapeHandle; +use ruffle_render::bitmap::BitmapHandle; +use ruffle_render::commands::CommandHandler; +use ruffle_render::transform::Transform; +use swf::{BlendMode, Color}; + +pub struct CommandRenderer<'a, 'b> { + frame: &'b mut Frame<'a>, + bitmap_registry: &'a FnvHashMap, + meshes: &'a Vec, + quad_vertices: wgpu::BufferSlice<'a>, + quad_indices: wgpu::BufferSlice<'a>, + blend_modes: Vec, +} + +impl<'a, 'b> CommandRenderer<'a, 'b> { + pub fn new( + frame: &'b mut Frame<'a>, + meshes: &'a Vec, + bitmap_registry: &'a FnvHashMap, + quad_vertices: wgpu::BufferSlice<'a>, + quad_indices: wgpu::BufferSlice<'a>, + ) -> Self { + Self { + frame, + bitmap_registry, + meshes, + quad_vertices, + quad_indices, + blend_modes: vec![BlendMode::Normal], + } + } +} + +impl<'a, 'b> CommandHandler for CommandRenderer<'a, 'b> { + fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) { + if let Some(entry) = self.bitmap_registry.get(&bitmap) { + let texture = &entry.texture_wrapper; + + self.frame.apply_transform( + &(transform.matrix + * ruffle_render::matrix::Matrix { + a: texture.width as f32, + d: texture.height as f32, + ..Default::default() + }), + ColorAdjustments::from(transform.color_transform), + ); + + self.frame.draw_bitmap( + self.quad_vertices, + self.quad_indices, + 6, + &texture.bind_group, + false, + smoothing, + ); + } + } + + fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) { + self.frame.apply_transform( + &transform.matrix, + ColorAdjustments::from(transform.color_transform), + ); + + let mesh = &self.meshes[shape.0]; + let mask_state = self.frame.mask_state(); + for draw in &mesh.draws { + let num_indices = if mask_state != MaskState::DrawMaskStencil + && mask_state != MaskState::ClearMaskStencil + { + draw.num_indices + } else { + // Omit strokes when drawing a mask stencil. + draw.num_mask_indices + }; + if num_indices == 0 { + continue; + } + + match &draw.draw_type { + DrawType::Color => { + self.frame.draw_color( + draw.vertex_buffer.slice(..), + draw.index_buffer.slice(..), + num_indices, + ); + } + DrawType::Gradient { bind_group, .. } => { + self.frame.draw_gradient( + draw.vertex_buffer.slice(..), + draw.index_buffer.slice(..), + num_indices, + bind_group, + ); + } + DrawType::Bitmap { + is_repeating, + is_smoothed, + bind_group, + .. + } => { + self.frame.draw_bitmap( + draw.vertex_buffer.slice(..), + draw.index_buffer.slice(..), + num_indices, + bind_group, + *is_repeating, + *is_smoothed, + ); + } + } + } + } + + fn draw_rect(&mut self, color: Color, matrix: &ruffle_render::matrix::Matrix) { + self.frame.apply_transform( + &matrix, + ColorAdjustments { + mult_color: [ + f32::from(color.r) / 255.0, + f32::from(color.g) / 255.0, + f32::from(color.b) / 255.0, + f32::from(color.a) / 255.0, + ], + add_color: [0.0, 0.0, 0.0, 0.0], + }, + ); + + self.frame + .draw_color(self.quad_vertices, self.quad_indices, 6); + } + + fn push_mask(&mut self) { + debug_assert!( + self.frame.mask_state() == MaskState::NoMask + || self.frame.mask_state() == MaskState::DrawMaskedContent + ); + self.frame.set_mask_state(MaskState::DrawMaskStencil); + self.frame.set_mask_count(self.frame.num_masks() + 1); + } + + fn activate_mask(&mut self) { + debug_assert!( + self.frame.num_masks() > 0 && self.frame.mask_state() == MaskState::DrawMaskStencil + ); + self.frame.set_mask_state(MaskState::DrawMaskedContent); + } + + fn deactivate_mask(&mut self) { + debug_assert!( + self.frame.num_masks() > 0 && self.frame.mask_state() == MaskState::DrawMaskedContent + ); + self.frame.set_mask_state(MaskState::ClearMaskStencil); + } + + fn pop_mask(&mut self) { + debug_assert!( + self.frame.num_masks() > 0 && self.frame.mask_state() == MaskState::ClearMaskStencil + ); + let num_masks = self.frame.num_masks() - 1; + self.frame.set_mask_count(num_masks); + if num_masks == 0 { + self.frame.set_mask_state(MaskState::NoMask); + } else { + self.frame.set_mask_state(MaskState::DrawMaskedContent); + }; + } + + fn push_blend_mode(&mut self, blend: BlendMode) { + self.blend_modes.push(blend); + self.frame.set_blend_mode(blend.into()); + } + + fn pop_blend_mode(&mut self) { + self.blend_modes.pop(); + self.frame.set_blend_mode( + self.blend_modes + .last() + .map(|b| ActualBlendMode::from(*b)) + .unwrap_or(ActualBlendMode::Normal), + ); + } +} diff --git a/render/wgpu/src/frame.rs b/render/wgpu/src/frame.rs index f446dd1f9..51f5e784e 100644 --- a/render/wgpu/src/frame.rs +++ b/render/wgpu/src/frame.rs @@ -1,16 +1,7 @@ use crate::pipelines::BlendMode as ActualBlendMode; use crate::target::RenderTargetFrame; use crate::Pipelines; -use crate::{ - ColorAdjustments, Descriptors, DrawType, Globals, MaskState, Mesh, RegistryData, Transforms, - UniformBuffer, -}; -use fnv::FnvHashMap; -use ruffle_render::backend::ShapeHandle; -use ruffle_render::bitmap::BitmapHandle; -use ruffle_render::commands::CommandHandler; -use ruffle_render::transform::Transform; -use swf::{BlendMode, Color}; +use crate::{ColorAdjustments, Descriptors, Globals, MaskState, Transforms, UniformBuffer}; pub struct Frame<'a> { pipelines: &'a Pipelines, @@ -20,26 +11,16 @@ pub struct Frame<'a> { num_masks: u32, uniform_encoder: &'a mut wgpu::CommandEncoder, render_pass: wgpu::RenderPass<'a>, - blend_modes: Vec, blend_mode: ActualBlendMode, - bitmap_registry: &'a FnvHashMap, - quad_vertices: wgpu::BufferSlice<'a>, - quad_indices: wgpu::BufferSlice<'a>, - meshes: &'a Vec, } impl<'a> Frame<'a> { - #[allow(clippy::too_many_arguments)] pub fn new( pipelines: &'a Pipelines, descriptors: &'a Descriptors, uniform_buffers: UniformBuffer<'a, Transforms>, - quad_vertices: wgpu::BufferSlice<'a>, - quad_indices: wgpu::BufferSlice<'a>, - meshes: &'a Vec, render_pass: wgpu::RenderPass<'a>, uniform_encoder: &'a mut wgpu::CommandEncoder, - bitmap_registry: &'a FnvHashMap, ) -> Self { Self { pipelines, @@ -49,15 +30,11 @@ impl<'a> Frame<'a> { num_masks: 0, uniform_encoder, render_pass, - blend_modes: vec![BlendMode::Normal], blend_mode: ActualBlendMode::Normal, - bitmap_registry, - quad_vertices, - quad_indices, - meshes, } } + #[allow(clippy::too_many_arguments)] pub fn swap_srgb( &mut self, globals: &Globals, @@ -65,6 +42,8 @@ impl<'a> Frame<'a> { copy_srgb_bind_group: &wgpu::BindGroup, width: f32, height: f32, + quad_vertices: wgpu::BufferSlice<'a>, + quad_indices: wgpu::BufferSlice<'a>, ) -> wgpu::CommandBuffer { let mut copy_encoder = self.descriptors @@ -115,8 +94,8 @@ impl<'a> Frame<'a> { .get_bind_group(false, false), &[], ); - render_pass.set_vertex_buffer(0, self.quad_vertices); - render_pass.set_index_buffer(self.quad_indices, wgpu::IndexFormat::Uint32); + render_pass.set_vertex_buffer(0, quad_vertices); + render_pass.set_index_buffer(quad_indices, wgpu::IndexFormat::Uint32); render_pass.draw_indexed(0..6, 0, 0..1); drop(render_pass); @@ -127,7 +106,7 @@ impl<'a> Frame<'a> { self.uniform_buffers.finish() } - fn draw_color( + pub fn draw_color( &mut self, vertices: wgpu::BufferSlice<'a>, indices: wgpu::BufferSlice<'a>, @@ -146,7 +125,7 @@ impl<'a> Frame<'a> { self.render_pass.draw_indexed(0..num_indices, 0, 0..1); } - fn draw_gradient( + pub fn draw_gradient( &mut self, vertices: wgpu::BufferSlice<'a>, indices: wgpu::BufferSlice<'a>, @@ -167,7 +146,7 @@ impl<'a> Frame<'a> { self.render_pass.draw_indexed(0..num_indices, 0, 0..1); } - fn draw_bitmap( + pub fn draw_bitmap( &mut self, vertices: wgpu::BufferSlice<'a>, indices: wgpu::BufferSlice<'a>, @@ -197,7 +176,7 @@ impl<'a> Frame<'a> { self.render_pass.draw_indexed(0..num_indices, 0, 0..1); } - fn apply_transform( + pub fn apply_transform( &mut self, matrix: &ruffle_render::matrix::Matrix, color_adjustments: ColorAdjustments, @@ -226,150 +205,26 @@ impl<'a> Frame<'a> { }, ); } -} -impl<'a> CommandHandler for Frame<'a> { - fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) { - if let Some(entry) = self.bitmap_registry.get(&bitmap) { - let texture = &entry.texture_wrapper; - - self.apply_transform( - &(transform.matrix - * ruffle_render::matrix::Matrix { - a: texture.width as f32, - d: texture.height as f32, - ..Default::default() - }), - ColorAdjustments::from(transform.color_transform), - ); - - self.draw_bitmap( - self.quad_vertices, - self.quad_indices, - 6, - &texture.bind_group, - false, - smoothing, - ); - } + pub fn set_mask_state(&mut self, state: MaskState) { + self.mask_state = state; } - fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) { - self.apply_transform( - &transform.matrix, - ColorAdjustments::from(transform.color_transform), - ); + pub fn set_mask_count(&mut self, num: u32) { + self.num_masks = num; - let mesh = &self.meshes[shape.0]; - for draw in &mesh.draws { - let num_indices = if self.mask_state != MaskState::DrawMaskStencil - && self.mask_state != MaskState::ClearMaskStencil - { - draw.num_indices - } else { - // Omit strokes when drawing a mask stencil. - draw.num_mask_indices - }; - if num_indices == 0 { - continue; - } - - match &draw.draw_type { - DrawType::Color => { - self.draw_color( - draw.vertex_buffer.slice(..), - draw.index_buffer.slice(..), - num_indices, - ); - } - DrawType::Gradient { bind_group, .. } => { - self.draw_gradient( - draw.vertex_buffer.slice(..), - draw.index_buffer.slice(..), - num_indices, - bind_group, - ); - } - DrawType::Bitmap { - is_repeating, - is_smoothed, - bind_group, - .. - } => { - self.draw_bitmap( - draw.vertex_buffer.slice(..), - draw.index_buffer.slice(..), - num_indices, - bind_group, - *is_repeating, - *is_smoothed, - ); - } - } - } - } - - fn draw_rect(&mut self, color: Color, matrix: &ruffle_render::matrix::Matrix) { - self.apply_transform( - &matrix, - ColorAdjustments { - mult_color: [ - f32::from(color.r) / 255.0, - f32::from(color.g) / 255.0, - f32::from(color.b) / 255.0, - f32::from(color.a) / 255.0, - ], - add_color: [0.0, 0.0, 0.0, 0.0], - }, - ); - - self.draw_color(self.quad_vertices, self.quad_indices, 6); - } - - fn push_mask(&mut self) { - debug_assert!( - self.mask_state == MaskState::NoMask || self.mask_state == MaskState::DrawMaskedContent - ); - self.num_masks += 1; - self.mask_state = MaskState::DrawMaskStencil; - - self.render_pass.set_stencil_reference(self.num_masks - 1); - } - - fn activate_mask(&mut self) { - debug_assert!(self.num_masks > 0 && self.mask_state == MaskState::DrawMaskStencil); - self.mask_state = MaskState::DrawMaskedContent; self.render_pass.set_stencil_reference(self.num_masks); } - fn deactivate_mask(&mut self) { - debug_assert!(self.num_masks > 0 && self.mask_state == MaskState::DrawMaskedContent); - self.mask_state = MaskState::ClearMaskStencil; - self.render_pass.set_stencil_reference(self.num_masks); + pub fn set_blend_mode(&mut self, blend_mode: ActualBlendMode) { + self.blend_mode = blend_mode; } - fn pop_mask(&mut self) { - debug_assert!(self.num_masks > 0 && self.mask_state == MaskState::ClearMaskStencil); - self.num_masks -= 1; - self.mask_state = if self.num_masks == 0 { - MaskState::NoMask - } else { - self.render_pass.set_stencil_reference(self.num_masks); - MaskState::DrawMaskedContent - }; + pub fn mask_state(&self) -> MaskState { + self.mask_state } - fn push_blend_mode(&mut self, blend: BlendMode) { - self.blend_modes.push(blend); - self.blend_mode = blend.into(); - } - - fn pop_blend_mode(&mut self) { - self.blend_modes.pop(); - self.blend_mode = self - .blend_modes - .last() - .map(|b| ActualBlendMode::from(*b)) - .unwrap_or(ActualBlendMode::Normal); + pub fn num_masks(&self) -> u32 { + self.num_masks } } diff --git a/render/wgpu/src/lib.rs b/render/wgpu/src/lib.rs index 197ba96c1..d6d50f4a4 100644 --- a/render/wgpu/src/lib.rs +++ b/render/wgpu/src/lib.rs @@ -26,6 +26,7 @@ mod uniform_buffer; pub mod backend; #[cfg(feature = "clap")] pub mod clap; +mod commands; pub mod descriptors; mod frame; mod layouts; @@ -59,7 +60,7 @@ struct TextureTransforms { #[repr(C)] #[derive(Copy, Clone, Debug, Pod, Zeroable)] -struct ColorAdjustments { +pub struct ColorAdjustments { mult_color: [f32; 4], add_color: [f32; 4], }