diff --git a/Cargo.lock b/Cargo.lock index 611a5ddd6..66b3f528c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3489,6 +3489,7 @@ dependencies = [ name = "ruffle_render_canvas" version = "0.1.0" dependencies = [ + "downcast-rs", "fnv", "gc-arena", "js-sys", @@ -3505,6 +3506,7 @@ name = "ruffle_render_webgl" version = "0.1.0" dependencies = [ "bytemuck", + "downcast-rs", "fnv", "gc-arena", "js-sys", diff --git a/core/src/avm1/object/bitmap_data.rs b/core/src/avm1/object/bitmap_data.rs index 845e05c4f..81046f228 100644 --- a/core/src/avm1/object/bitmap_data.rs +++ b/core/src/avm1/object/bitmap_data.rs @@ -57,9 +57,7 @@ impl<'gc> BitmapDataObject<'gc> { } pub fn dispose(&self, context: &mut UpdateContext<'_, 'gc, '_>) { - self.bitmap_data() - .write(context.gc_context) - .dispose(context.renderer); + self.bitmap_data().write(context.gc_context).dispose(); } } diff --git a/core/src/avm2/globals/flash/display/bitmapdata.rs b/core/src/avm2/globals/flash/display/bitmapdata.rs index d74759f93..3680ae6ed 100644 --- a/core/src/avm2/globals/flash/display/bitmapdata.rs +++ b/core/src/avm2/globals/flash/display/bitmapdata.rs @@ -818,9 +818,7 @@ pub fn dispose<'gc>( if let Some(bitmap_data) = this.and_then(|this| this.as_bitmap_data()) { // Don't check if we've already disposed this BitmapData - 'BitmapData.dispose()' can be called // multiple times - bitmap_data - .write(activation.context.gc_context) - .dispose(activation.context.renderer); + bitmap_data.write(activation.context.gc_context).dispose(); } Ok(Value::Undefined) } diff --git a/core/src/avm2/object/context3d_object.rs b/core/src/avm2/object/context3d_object.rs index 02b3e494a..20336a4df 100644 --- a/core/src/avm2/object/context3d_object.rs +++ b/core/src/avm2/object/context3d_object.rs @@ -273,7 +273,7 @@ impl<'gc> Context3DObject<'gc> { if context3d.should_render() { let handle = context3d.bitmap_handle(); context.commands.render_bitmap( - handle, + &handle, // FIXME - apply x and y translation from Stage3D &Transform::default(), false, diff --git a/core/src/bitmap/bitmap_data.rs b/core/src/bitmap/bitmap_data.rs index 59f644041..08d44f27c 100644 --- a/core/src/bitmap/bitmap_data.rs +++ b/core/src/bitmap/bitmap_data.rs @@ -217,14 +217,11 @@ impl<'gc> BitmapData<'gc> { self.disposed } - pub fn dispose(&mut self, renderer: &mut dyn RenderBackend) { + pub fn dispose(&mut self) { self.width = 0; self.height = 0; self.pixels.clear(); - if let Some(handle) = self.bitmap_handle { - renderer.unregister_bitmap(handle); - self.bitmap_handle = None; - } + self.bitmap_handle = None; // There's no longer a handle to update self.dirty = false; self.disposed = true; @@ -245,7 +242,7 @@ impl<'gc> BitmapData<'gc> { self.bitmap_handle = bitmap_handle.ok(); } - self.bitmap_handle + self.bitmap_handle.clone() } pub fn transparency(&self) -> bool { @@ -914,7 +911,7 @@ impl<'gc> BitmapData<'gc> { let handle = self.bitmap_handle(context.renderer).unwrap(); if self.dirty() { if let Err(e) = context.renderer.update_texture( - handle, + &handle, self.width(), self.height(), self.pixels_rgba(), @@ -1028,7 +1025,7 @@ impl<'gc> BitmapData<'gc> { bitmap_data.update_dirty_texture(&mut render_context); let bitmap_handle = bitmap_data.bitmap_handle(render_context.renderer).unwrap(); render_context.commands.render_bitmap( - bitmap_handle, + &bitmap_handle, render_context.transform_stack.transform(), smoothing, ); diff --git a/core/src/display_object/bitmap.rs b/core/src/display_object/bitmap.rs index 60801da87..f98d9b651 100644 --- a/core/src/display_object/bitmap.rs +++ b/core/src/display_object/bitmap.rs @@ -140,7 +140,7 @@ impl<'gc> Bitmap<'gc> { #[allow(dead_code)] pub fn bitmap_handle(self) -> Option { - self.0.read().bitmap_handle + self.0.read().bitmap_handle.clone() } pub fn width(self) -> u16 { @@ -306,7 +306,7 @@ impl<'gc> TDisplayObject<'gc> for Bitmap<'gc> { } let bitmap_data = self.0.read(); - if let Some(bitmap_handle) = bitmap_data.bitmap_handle { + if let Some(bitmap_handle) = &bitmap_data.bitmap_handle { if let Some(inner_bitmap_data) = bitmap_data.bitmap_data { if let Ok(mut bd) = inner_bitmap_data.try_write(context.gc_context) { bd.update_dirty_texture(context); @@ -316,7 +316,7 @@ impl<'gc> TDisplayObject<'gc> for Bitmap<'gc> { } context.commands.render_bitmap( - bitmap_handle, + &bitmap_handle, context.transform_stack.transform(), bitmap_data.smoothing, ); diff --git a/core/src/display_object/video.rs b/core/src/display_object/video.rs index 76a41844c..218b5b829 100644 --- a/core/src/display_object/video.rs +++ b/core/src/display_object/video.rs @@ -467,7 +467,7 @@ impl<'gc> TDisplayObject<'gc> for Video<'gc> { context .commands - .render_bitmap(bitmap.handle, &transform, smoothing); + .render_bitmap(&bitmap.handle, &transform, smoothing); } else { log::warn!("Video has no decoded frame to render."); } diff --git a/core/src/drawing.rs b/core/src/drawing.rs index ab6b01df5..c4b77358e 100644 --- a/core/src/drawing.rs +++ b/core/src/drawing.rs @@ -409,7 +409,7 @@ impl BitmapSource for Drawing { }) } fn bitmap_handle(&self, id: u16, _backend: &mut dyn RenderBackend) -> Option { - self.bitmaps.get(id as usize).map(|bm| bm.handle) + self.bitmaps.get(id as usize).map(|bm| bm.handle.clone()) } } diff --git a/render/canvas/Cargo.toml b/render/canvas/Cargo.toml index 8e6dff4ea..3bb90dd5c 100644 --- a/render/canvas/Cargo.toml +++ b/render/canvas/Cargo.toml @@ -14,6 +14,7 @@ fnv = "1.0.7" ruffle_render = { path = "..", features = ["web"] } gc-arena = { git = "https://github.com/ruffle-rs/gc-arena" } swf = { path = "../../swf" } +downcast-rs = "1.2.0" [dependencies.web-sys] version = "0.3.60" diff --git a/render/canvas/src/lib.rs b/render/canvas/src/lib.rs index 34b2c2c23..23c1db4ce 100644 --- a/render/canvas/src/lib.rs +++ b/render/canvas/src/lib.rs @@ -1,6 +1,8 @@ #![allow(clippy::uninlined_format_args)] -use fnv::FnvHashMap; +use std::sync::Arc; + +use downcast_rs::Downcast; use gc_arena::MutationContext; use ruffle_render::backend::null::NullBitmapSource; use ruffle_render::backend::{ @@ -28,12 +30,10 @@ pub struct WebCanvasRenderBackend { context: CanvasRenderingContext2d, color_matrix: Element, shapes: Vec, - bitmaps: FnvHashMap, viewport_width: u32, viewport_height: u32, rect: Path2d, mask_state: MaskState, - next_bitmap_handle: BitmapHandle, blend_modes: Vec, // This is currnetly unused - we just store it to report @@ -135,6 +135,7 @@ struct CanvasBitmap { } #[allow(dead_code)] +#[derive(Debug)] struct BitmapData { bitmap: Bitmap, image_data: ImageData, @@ -142,6 +143,12 @@ struct BitmapData { context: CanvasRenderingContext2d, } +impl ruffle_render::bitmap::BitmapHandleImpl for BitmapData {} + +fn as_bitmap_data(handle: &BitmapHandle) -> &BitmapData { + handle.as_any().downcast_ref::().unwrap() +} + impl BitmapData { /// Puts the image data into a newly created , and caches it. fn new(bitmap: Bitmap) -> Result { @@ -175,6 +182,19 @@ impl BitmapData { context, }) } + + fn update_pixels(&self, bitmap: Bitmap) -> Result<(), JsValue> { + let bitmap = bitmap.to_rgba(); + let image_data = + ImageData::new_with_u8_clamped_array(Clamped(bitmap.data()), bitmap.width()) + .into_js_result()?; + self.canvas.set_width(bitmap.width()); + self.canvas.set_height(bitmap.height()); + self.context + .put_image_data(&image_data, 0.0, 0.0) + .into_js_result()?; + Ok(()) + } } impl WebCanvasRenderBackend { @@ -269,13 +289,11 @@ impl WebCanvasRenderBackend { color_matrix, context, shapes: vec![], - bitmaps: Default::default(), viewport_width: 0, viewport_height: 0, viewport_scale_factor: 1.0, rect, mask_state: MaskState::DrawContent, - next_bitmap_handle: BitmapHandle(0), blend_modes: vec![BlendMode::Normal], }; Ok(renderer) @@ -440,31 +458,20 @@ impl RenderBackend for WebCanvasRenderBackend { } fn register_bitmap(&mut self, bitmap: Bitmap) -> Result { - let handle = self.next_bitmap_handle; - self.next_bitmap_handle = BitmapHandle(self.next_bitmap_handle.0 + 1); let bitmap_data = BitmapData::new(bitmap).map_err(Error::JavascriptError)?; - self.bitmaps.insert(handle, bitmap_data); - Ok(handle) - } - - fn unregister_bitmap(&mut self, bitmap: BitmapHandle) { - self.bitmaps.remove(&bitmap); + Ok(BitmapHandle(Arc::new(bitmap_data))) } fn update_texture( &mut self, - handle: BitmapHandle, + handle: &BitmapHandle, width: u32, height: u32, rgba: Vec, ) -> Result<(), Error> { - // TODO: Could be optimized to a single put_image_data call - // in case it is already stored as a canvas+context. - self.bitmaps.insert( - handle, - BitmapData::new(Bitmap::new(width, height, BitmapFormat::Rgba, rgba)) - .map_err(Error::JavascriptError)?, - ); + let data = as_bitmap_data(handle); + data.update_pixels(Bitmap::new(width, height, BitmapFormat::Rgba, rgba)) + .map_err(Error::JavascriptError)?; Ok(()) } @@ -481,8 +488,8 @@ impl RenderBackend for WebCanvasRenderBackend { } } -impl CommandHandler for WebCanvasRenderBackend { - fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) { +impl<'a> CommandHandler<'a> for WebCanvasRenderBackend { + fn render_bitmap(&mut self, bitmap: &BitmapHandle, transform: &Transform, smoothing: bool) { if self.mask_state == MaskState::ClearMask { return; } @@ -491,11 +498,10 @@ impl CommandHandler for WebCanvasRenderBackend { self.set_transform(&transform.matrix); self.set_color_filter(transform); - if let Some(bitmap) = self.bitmaps.get(&bitmap) { - let _ = self - .context - .draw_image_with_html_canvas_element(&bitmap.canvas, 0.0, 0.0); - } + let bitmap = as_bitmap_data(bitmap); + let _ = self + .context + .draw_image_with_html_canvas_element(&bitmap.canvas, 0.0, 0.0); self.clear_color_filter(); } @@ -1149,10 +1155,8 @@ fn create_bitmap_pattern( bitmap_source: &dyn BitmapSource, backend: &mut WebCanvasRenderBackend, ) -> Option { - if let Some(bitmap) = bitmap_source - .bitmap_handle(id, backend) - .and_then(|handle| backend.bitmaps.get(&handle)) - { + if let Some(handle) = bitmap_source.bitmap_handle(id, backend) { + let bitmap = as_bitmap_data(&handle); let repeat = if !is_repeating { // NOTE: The WebGL backend does clamping in this case, just like // Flash Player, but CanvasPattern has no such option... diff --git a/render/src/backend.rs b/render/src/backend.rs index 3758628ce..4abda4212 100644 --- a/render/src/backend.rs +++ b/render/src/backend.rs @@ -47,12 +47,9 @@ pub trait RenderBackend: Downcast { fn submit_frame(&mut self, clear: swf::Color, commands: CommandList); fn register_bitmap(&mut self, bitmap: Bitmap) -> Result; - // Frees memory used by the bitmap. After this call, `handle` can no longer - // be used. - fn unregister_bitmap(&mut self, handle: BitmapHandle); fn update_texture( &mut self, - bitmap: BitmapHandle, + bitmap: &BitmapHandle, width: u32, height: u32, rgba: Vec, diff --git a/render/src/backend/null.rs b/render/src/backend/null.rs index 0b71e12e5..378adb1e8 100644 --- a/render/src/backend/null.rs +++ b/render/src/backend/null.rs @@ -1,5 +1,7 @@ +use std::sync::Arc; + use crate::backend::{RenderBackend, ShapeHandle, ViewportDimensions}; -use crate::bitmap::{Bitmap, BitmapHandle, BitmapSize, BitmapSource}; +use crate::bitmap::{Bitmap, BitmapHandle, BitmapHandleImpl, BitmapSize, BitmapSource}; use crate::commands::CommandList; use crate::error::Error; use crate::shape_utils::DistilledShape; @@ -28,6 +30,9 @@ impl NullRenderer { Self { dimensions } } } +#[derive(Clone, Debug)] +struct NullBitmapHandle; +impl BitmapHandleImpl for NullBitmapHandle {} impl RenderBackend for NullRenderer { fn viewport_dimensions(&self) -> ViewportDimensions { @@ -66,13 +71,12 @@ impl RenderBackend for NullRenderer { fn submit_frame(&mut self, _clear: Color, _commands: CommandList) {} fn register_bitmap(&mut self, _bitmap: Bitmap) -> Result { - Ok(BitmapHandle(0)) + Ok(BitmapHandle(Arc::new(NullBitmapHandle))) } - fn unregister_bitmap(&mut self, _bitmap: BitmapHandle) {} fn update_texture( &mut self, - _bitmap: BitmapHandle, + _bitmap: &BitmapHandle, _width: u32, _height: u32, _rgba: Vec, diff --git a/render/src/bitmap.rs b/render/src/bitmap.rs index 6ae9043fa..e6de76135 100644 --- a/render/src/bitmap.rs +++ b/render/src/bitmap.rs @@ -1,8 +1,17 @@ +use std::fmt::Debug; +use std::sync::Arc; + +use downcast_rs::{impl_downcast, Downcast}; + use crate::backend::RenderBackend; -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -pub struct BitmapHandle(pub usize); +#[derive(Clone, Debug)] +pub struct BitmapHandle(pub Arc); +pub trait BitmapHandleImpl: Downcast + Debug {} +impl_downcast!(BitmapHandleImpl); + +/// Info returned by the `register_bitmap` methods. #[derive(Clone, Debug)] pub struct BitmapInfo { pub handle: BitmapHandle, diff --git a/render/src/commands.rs b/render/src/commands.rs index 0a63b52f8..39717201a 100644 --- a/render/src/commands.rs +++ b/render/src/commands.rs @@ -4,8 +4,8 @@ use crate::matrix::Matrix; use crate::transform::Transform; use swf::{BlendMode, Color}; -pub trait CommandHandler { - fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool); +pub trait CommandHandler<'a> { + fn render_bitmap(&mut self, bitmap: &'a BitmapHandle, transform: &Transform, smoothing: bool); fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform); fn draw_rect(&mut self, color: Color, matrix: &Matrix); fn push_mask(&mut self); @@ -25,33 +25,33 @@ impl CommandList { Self::default() } - pub fn execute(self, handler: &mut impl CommandHandler) { - for command in self.0 { + pub fn execute<'a>(&'a self, handler: &mut impl CommandHandler<'a>) { + for command in &self.0 { match command { Command::RenderBitmap { bitmap, transform, smoothing, - } => handler.render_bitmap(bitmap, &transform, smoothing), + } => handler.render_bitmap(bitmap, &transform, *smoothing), Command::RenderShape { shape, transform } => { - handler.render_shape(shape, &transform) + handler.render_shape(*shape, &transform) } - Command::DrawRect { color, matrix } => handler.draw_rect(color, &matrix), + Command::DrawRect { color, matrix } => handler.draw_rect(color.clone(), &matrix), Command::PushMask => handler.push_mask(), Command::ActivateMask => handler.activate_mask(), Command::DeactivateMask => handler.deactivate_mask(), Command::PopMask => handler.pop_mask(), - Command::PushBlendMode(blend) => handler.push_blend_mode(blend), + Command::PushBlendMode(blend) => handler.push_blend_mode(*blend), Command::PopBlendMode => handler.pop_blend_mode(), } } } } -impl CommandHandler for CommandList { - fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) { +impl<'a> CommandHandler<'a> for CommandList { + fn render_bitmap(&mut self, bitmap: &'a BitmapHandle, transform: &Transform, smoothing: bool) { self.0.push(Command::RenderBitmap { - bitmap, + bitmap: bitmap.clone(), transform: transform.clone(), smoothing, }); diff --git a/render/webgl/Cargo.toml b/render/webgl/Cargo.toml index 6e2c65690..993f7509b 100644 --- a/render/webgl/Cargo.toml +++ b/render/webgl/Cargo.toml @@ -16,6 +16,7 @@ gc-arena = { git = "https://github.com/ruffle-rs/gc-arena" } fnv = "1.0.7" swf = { path = "../../swf" } thiserror = "1.0" +downcast-rs = "1.2.0" [dependencies.web-sys] version = "0.3.60" diff --git a/render/webgl/src/lib.rs b/render/webgl/src/lib.rs index 38e7c69ed..b82a5faa8 100644 --- a/render/webgl/src/lib.rs +++ b/render/webgl/src/lib.rs @@ -2,13 +2,14 @@ #![allow(clippy::uninlined_format_args)] use bytemuck::{Pod, Zeroable}; -use fnv::FnvHashMap; + +use downcast_rs::Downcast; use gc_arena::MutationContext; use ruffle_render::backend::null::NullBitmapSource; use ruffle_render::backend::{ Context3D, Context3DCommand, RenderBackend, ShapeHandle, ViewportDimensions, }; -use ruffle_render::bitmap::{Bitmap, BitmapFormat, BitmapHandle, BitmapSource}; +use ruffle_render::bitmap::{Bitmap, BitmapFormat, BitmapHandle, BitmapHandleImpl, BitmapSource}; use ruffle_render::commands::{CommandHandler, CommandList}; use ruffle_render::error::Error as BitmapError; use ruffle_render::shape_utils::DistilledShape; @@ -17,6 +18,7 @@ use ruffle_render::tessellator::{ }; use ruffle_render::transform::Transform; use ruffle_web_common::{JsError, JsResult}; +use std::sync::Arc; use swf::{BlendMode, Color}; use thiserror::Error; use wasm_bindgen::{JsCast, JsValue}; @@ -140,14 +142,12 @@ pub struct WebGlRenderBackend { renderbuffer_height: i32, view_matrix: [[f32; 4]; 4], - bitmap_registry: FnvHashMap, - next_bitmap_handle: BitmapHandle, - // This is currently unused - we just hold on to it // to expose via `get_viewport_dimensions` viewport_scale_factor: f64, } +#[derive(Debug)] struct RegistryData { gl: Gl, bitmap: Bitmap, @@ -160,6 +160,12 @@ impl Drop for RegistryData { } } +impl BitmapHandleImpl for RegistryData {} + +fn as_registry_data(handle: &BitmapHandle) -> &RegistryData { + handle.as_any().downcast_ref::().unwrap() +} + const MAX_GRADIENT_COLORS: usize = 15; impl WebGlRenderBackend { @@ -311,8 +317,6 @@ impl WebGlRenderBackend { blend_modes: vec![], mult_color: None, add_color: None, - bitmap_registry: Default::default(), - next_bitmap_handle: BitmapHandle(0), viewport_scale_factor: 1.0, }; @@ -404,8 +408,7 @@ impl WebGlRenderBackend { draw_type: if program.program == self.bitmap_program.program { DrawType::Bitmap(BitmapDraw { matrix: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], - handle: BitmapHandle(0), - + handle: None, is_smoothed: true, is_repeating: false, }) @@ -668,7 +671,7 @@ impl WebGlRenderBackend { TessDrawType::Bitmap(bitmap) => Draw { draw_type: DrawType::Bitmap(BitmapDraw { matrix: bitmap.matrix, - handle: bitmap_source.bitmap_handle(bitmap.bitmap_id, self).unwrap(), + handle: bitmap_source.bitmap_handle(bitmap.bitmap_id, self), is_smoothed: bitmap.is_smoothed, is_repeating: bitmap.is_repeating, }), @@ -1024,36 +1027,21 @@ impl RenderBackend for WebGlRenderBackend { self.gl .tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MAG_FILTER, Gl::LINEAR as i32); - let handle = self.next_bitmap_handle; - self.next_bitmap_handle = BitmapHandle(self.next_bitmap_handle.0 + 1); - self.bitmap_registry.insert( - handle, - RegistryData { - gl: self.gl.clone(), - bitmap, - texture, - }, - ); - - Ok(handle) - } - - fn unregister_bitmap(&mut self, bitmap: BitmapHandle) { - self.bitmap_registry.remove(&bitmap); + Ok(BitmapHandle(Arc::new(RegistryData { + gl: self.gl.clone(), + bitmap, + texture, + }))) } fn update_texture( &mut self, - handle: BitmapHandle, + handle: &BitmapHandle, width: u32, height: u32, rgba: Vec, ) -> Result<(), BitmapError> { - let texture = if let Some(entry) = self.bitmap_registry.get(&handle) { - &entry.texture - } else { - return Err(BitmapError::UnknownHandle(handle)); - }; + let texture = &as_registry_data(handle).texture; self.gl.bind_texture(Gl::TEXTURE_2D, Some(&texture)); @@ -1088,97 +1076,95 @@ impl RenderBackend for WebGlRenderBackend { } } -impl CommandHandler for WebGlRenderBackend { - fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) { +impl<'a> CommandHandler<'a> for WebGlRenderBackend { + fn render_bitmap(&mut self, bitmap: &'a BitmapHandle, transform: &Transform, smoothing: bool) { self.set_stencil_state(); - if let Some(entry) = self.bitmap_registry.get(&bitmap) { - // Adjust the quad draw to use the target bitmap. - let mesh = &self.meshes[self.bitmap_quad_shape.0]; - let draw = &mesh.draws[0]; - let bitmap_matrix = if let DrawType::Bitmap(BitmapDraw { matrix, .. }) = &draw.draw_type - { - matrix - } else { - unreachable!() - }; + let entry = as_registry_data(bitmap); + // Adjust the quad draw to use the target bitmap. + let mesh = &self.meshes[self.bitmap_quad_shape.0]; + let draw = &mesh.draws[0]; + let bitmap_matrix = if let DrawType::Bitmap(BitmapDraw { matrix, .. }) = &draw.draw_type { + matrix + } else { + unreachable!() + }; - // Scale the quad to the bitmap's dimensions. - let matrix = transform.matrix - * ruffle_render::matrix::Matrix::scale( - entry.bitmap.width() as f32, - entry.bitmap.height() as f32, - ); + // Scale the quad to the bitmap's dimensions. + let matrix = transform.matrix + * ruffle_render::matrix::Matrix::scale( + entry.bitmap.width() as f32, + entry.bitmap.height() as f32, + ); - let world_matrix = [ - [matrix.a, matrix.b, 0.0, 0.0], - [matrix.c, matrix.d, 0.0, 0.0], - [0.0, 0.0, 1.0, 0.0], - [ - matrix.tx.to_pixels() as f32, - matrix.ty.to_pixels() as f32, - 0.0, - 1.0, - ], - ]; + let world_matrix = [ + [matrix.a, matrix.b, 0.0, 0.0], + [matrix.c, matrix.d, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.0], + [ + matrix.tx.to_pixels() as f32, + matrix.ty.to_pixels() as f32, + 0.0, + 1.0, + ], + ]; - let mult_color = transform.color_transform.mult_rgba_normalized(); - let add_color = transform.color_transform.add_rgba_normalized(); + let mult_color = transform.color_transform.mult_rgba_normalized(); + let add_color = transform.color_transform.add_rgba_normalized(); - self.bind_vertex_array(Some(&draw.vao)); + self.bind_vertex_array(Some(&draw.vao)); - let program = &self.bitmap_program; + let program = &self.bitmap_program; - // Set common render state, while minimizing unnecessary state changes. - // TODO: Using designated layout specifiers in WebGL2/OpenGL ES 3, we could guarantee that uniforms - // are in the same location between shaders, and avoid changing them unless necessary. - if program as *const ShaderProgram != self.active_program { - self.gl.use_program(Some(&program.program)); - self.active_program = program as *const ShaderProgram; + // Set common render state, while minimizing unnecessary state changes. + // TODO: Using designated layout specifiers in WebGL2/OpenGL ES 3, we could guarantee that uniforms + // are in the same location between shaders, and avoid changing them unless necessary. + if program as *const ShaderProgram != self.active_program { + self.gl.use_program(Some(&program.program)); + self.active_program = program as *const ShaderProgram; - program.uniform_matrix4fv(&self.gl, ShaderUniform::ViewMatrix, &self.view_matrix); + program.uniform_matrix4fv(&self.gl, ShaderUniform::ViewMatrix, &self.view_matrix); - self.mult_color = None; - self.add_color = None; - } - - program.uniform_matrix4fv(&self.gl, ShaderUniform::WorldMatrix, &world_matrix); - if Some(mult_color) != self.mult_color { - program.uniform4fv(&self.gl, ShaderUniform::MultColor, &mult_color); - self.mult_color = Some(mult_color); - } - if Some(add_color) != self.add_color { - program.uniform4fv(&self.gl, ShaderUniform::AddColor, &add_color); - self.add_color = Some(add_color); - } - - program.uniform_matrix3fv(&self.gl, ShaderUniform::TextureMatrix, bitmap_matrix); - - // Bind texture. - self.gl.active_texture(Gl::TEXTURE0); - self.gl.bind_texture(Gl::TEXTURE_2D, Some(&entry.texture)); - program.uniform1i(&self.gl, ShaderUniform::BitmapTexture, 0); - - // Set texture parameters. - let filter = if smoothing { - Gl::LINEAR as i32 - } else { - Gl::NEAREST as i32 - }; - self.gl - .tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MAG_FILTER, filter); - self.gl - .tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MIN_FILTER, filter); - - let wrap = Gl::CLAMP_TO_EDGE as i32; - self.gl - .tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_WRAP_S, wrap); - self.gl - .tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_WRAP_T, wrap); - - // Draw the triangles. - self.gl - .draw_elements_with_i32(Gl::TRIANGLES, draw.num_indices, Gl::UNSIGNED_INT, 0); + self.mult_color = None; + self.add_color = None; } + + program.uniform_matrix4fv(&self.gl, ShaderUniform::WorldMatrix, &world_matrix); + if Some(mult_color) != self.mult_color { + program.uniform4fv(&self.gl, ShaderUniform::MultColor, &mult_color); + self.mult_color = Some(mult_color); + } + if Some(add_color) != self.add_color { + program.uniform4fv(&self.gl, ShaderUniform::AddColor, &add_color); + self.add_color = Some(add_color); + } + + program.uniform_matrix3fv(&self.gl, ShaderUniform::TextureMatrix, bitmap_matrix); + + // Bind texture. + self.gl.active_texture(Gl::TEXTURE0); + self.gl.bind_texture(Gl::TEXTURE_2D, Some(&entry.texture)); + program.uniform1i(&self.gl, ShaderUniform::BitmapTexture, 0); + + // Set texture parameters. + let filter = if smoothing { + Gl::LINEAR as i32 + } else { + Gl::NEAREST as i32 + }; + self.gl + .tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MAG_FILTER, filter); + self.gl + .tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MIN_FILTER, filter); + + let wrap = Gl::CLAMP_TO_EDGE as i32; + self.gl + .tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_WRAP_S, wrap); + self.gl + .tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_WRAP_T, wrap); + + // Draw the triangles. + self.gl + .draw_elements_with_i32(Gl::TRIANGLES, draw.num_indices, Gl::UNSIGNED_INT, 0); } fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) { @@ -1281,12 +1267,7 @@ impl CommandHandler for WebGlRenderBackend { ); } DrawType::Bitmap(bitmap) => { - let texture = if let Some(entry) = self.bitmap_registry.get(&bitmap.handle) { - &entry.texture - } else { - // Bitmap not registered - continue; - }; + let texture = &as_registry_data(&bitmap.handle.as_ref().unwrap()).texture; program.uniform_matrix3fv( &self.gl, @@ -1485,7 +1466,7 @@ impl From for Gradient { #[derive(Clone, Debug)] struct BitmapDraw { matrix: [[f32; 3]; 3], - handle: BitmapHandle, + handle: Option, is_repeating: bool, is_smoothed: bool, } diff --git a/render/wgpu/src/backend.rs b/render/wgpu/src/backend.rs index 5103858a5..6615db03d 100644 --- a/render/wgpu/src/backend.rs +++ b/render/wgpu/src/backend.rs @@ -5,10 +5,9 @@ use crate::target::RenderTargetFrame; use crate::target::TextureTarget; use crate::uniform_buffer::BufferStorage; use crate::{ - format_list, get_backend_names, BufferDimensions, Descriptors, Error, Globals, RenderTarget, - SwapChainTarget, Texture, TextureOffscreen, Transforms, + as_texture, format_list, get_backend_names, BufferDimensions, Descriptors, Error, Globals, + RenderTarget, SwapChainTarget, Texture, TextureOffscreen, Transforms, }; -use fnv::FnvHashMap; use gc_arena::MutationContext; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use ruffle_render::backend::{Context3D, Context3DCommand}; @@ -34,8 +33,6 @@ pub struct WgpuRenderBackend { surface: Surface, meshes: Vec, shape_tessellator: ShapeTessellator, - bitmap_registry: FnvHashMap, - next_bitmap_handle: BitmapHandle, // This is currently unused - we just store it to report in // `get_viewport_dimensions` viewport_scale_factor: f64, @@ -156,9 +153,6 @@ impl WgpuRenderBackend { surface, meshes: Vec::new(), shape_tessellator: ShapeTessellator::new(), - - bitmap_registry: Default::default(), - next_bitmap_handle: BitmapHandle(0), viewport_scale_factor: 1.0, }) } @@ -221,19 +215,6 @@ impl WgpuRenderBackend { pub fn device(&self) -> &wgpu::Device { &self.descriptors.device } - - pub fn bitmap_registry(&self) -> &FnvHashMap { - &self.bitmap_registry - } - - fn raw_register_bitmap(&mut self, data: Texture) -> BitmapHandle { - let handle = self.next_bitmap_handle; - self.next_bitmap_handle.0 += 1; - if self.bitmap_registry.insert(handle, data).is_some() { - panic!("Overwrote existing bitmap {:?}", handle); - } - handle - } } impl RenderBackend for WgpuRenderBackend { @@ -283,14 +264,14 @@ impl RenderBackend for WgpuRenderBackend { usage: wgpu::TextureUsages::COPY_SRC, }); - let handle = self.raw_register_bitmap(Texture { + let handle = BitmapHandle(Arc::new(Texture { bind_linear: Default::default(), bind_nearest: Default::default(), - texture: dummy_texture, - texture_offscreen: None, + texture: Arc::new(dummy_texture), + texture_offscreen: Default::default(), width: 0, height: 0, - }); + })); Ok(Box::new(WgpuContext3D::new( self.descriptors.clone(), handle, @@ -307,14 +288,7 @@ impl RenderBackend for WgpuRenderBackend { .as_any_mut() .downcast_mut::() .unwrap(); - if let Some(new_registry_data) = context.present(commands, mc) { - // Update the registry with the new texture, which will later - // be rendered by `Stage` - *self - .bitmap_registry - .get_mut(&context.bitmap_handle()) - .unwrap() = new_registry_data; - } + context.present(commands, mc); Ok(()) } @@ -385,7 +359,6 @@ impl RenderBackend for WgpuRenderBackend { &mut self.globals, &mut self.uniform_buffers_storage, &self.meshes, - &self.bitmap_registry, commands, ); @@ -444,34 +417,26 @@ impl RenderBackend for WgpuRenderBackend { extent, ); - let handle = self.raw_register_bitmap(Texture { - texture, + let handle = BitmapHandle(Arc::new(Texture { + texture: Arc::new(texture), bind_linear: Default::default(), bind_nearest: Default::default(), - texture_offscreen: None, - width: extent.width, - height: extent.height, - }); + texture_offscreen: Default::default(), + width: bitmap.width(), + height: bitmap.height(), + })); Ok(handle) } - fn unregister_bitmap(&mut self, handle: BitmapHandle) { - self.bitmap_registry.remove(&handle); - } - fn update_texture( &mut self, - handle: BitmapHandle, + handle: &BitmapHandle, width: u32, height: u32, rgba: Vec, ) -> Result<(), BitmapError> { - let texture = if let Some(entry) = self.bitmap_registry.get(&handle) { - &entry.texture - } else { - return Err(BitmapError::UnknownHandle(handle)); - }; + let texture = as_texture(handle); let extent = wgpu::Extent3d { width, @@ -481,7 +446,7 @@ impl RenderBackend for WgpuRenderBackend { self.descriptors.queue.write_texture( wgpu::ImageCopyTexture { - texture, + texture: &texture.texture, mip_level: 0, origin: Default::default(), aspect: wgpu::TextureAspect::All, @@ -505,16 +470,7 @@ impl RenderBackend for WgpuRenderBackend { height: u32, commands: CommandList, ) -> Result { - // We need ownership of `Texture` to access the non-`Clone` - // `wgpu` fields. At the end of this method, we re-insert - // `texture` into the map. - // - // This means that the target texture will be inaccessible - // while the callback `f` is a problem. This would only be - // an issue if a caller tried to render the target texture - // to itself, which probably isn't supported by Flash. If it - // is, then we could change `TextureTarget` to use an `Rc` - let mut texture = self.bitmap_registry.remove(&handle).unwrap(); + let texture = as_texture(&handle); let extent = wgpu::Extent3d { width, @@ -531,7 +487,7 @@ impl RenderBackend for WgpuRenderBackend { // many buffers / depth textures rendered at once, we could // try storing this data in an LRU cache, evicting entries // as needed. - let mut texture_offscreen = texture.texture_offscreen.unwrap_or_else(|| { + let texture_offscreen = texture.texture_offscreen.get_or_init(|| { let buffer_dimensions = BufferDimensions::new(width as usize, height as usize); let buffer_label = create_debug_label!("Render target buffer"); let buffer = self @@ -545,7 +501,7 @@ impl RenderBackend for WgpuRenderBackend { mapped_at_creation: false, }); TextureOffscreen { - buffer, + buffer: Arc::new(buffer), buffer_dimensions, surface: Surface::new( &self.descriptors, @@ -559,10 +515,10 @@ impl RenderBackend for WgpuRenderBackend { let mut target = TextureTarget { size: extent, - texture: texture.texture, + texture: texture.texture.clone(), format: wgpu::TextureFormat::Rgba8Unorm, - buffer: texture_offscreen.buffer, - buffer_dimensions: texture_offscreen.buffer_dimensions, + buffer: texture_offscreen.buffer.clone(), + buffer_dimensions: texture_offscreen.buffer_dimensions.clone(), }; let (old_width, old_height) = self.globals.resolution(); @@ -579,7 +535,6 @@ impl RenderBackend for WgpuRenderBackend { &mut self.globals, &mut self.uniform_buffers_storage, &self.meshes, - &self.bitmap_registry, commands, ); target.submit( @@ -602,11 +557,6 @@ impl RenderBackend for WgpuRenderBackend { }); self.globals.set_resolution(old_width, old_height); - texture_offscreen.buffer = target.buffer; - texture_offscreen.buffer_dimensions = target.buffer_dimensions; - texture.texture_offscreen = Some(texture_offscreen); - texture.texture = target.texture; - self.bitmap_registry.insert(handle, texture); Ok(image.unwrap()) } diff --git a/render/wgpu/src/commands.rs b/render/wgpu/src/commands.rs index d2be913cb..cbc184b9d 100644 --- a/render/wgpu/src/commands.rs +++ b/render/wgpu/src/commands.rs @@ -1,8 +1,7 @@ use crate::frame::Frame; use crate::mesh::{DrawType, Mesh}; use crate::pipelines::BlendMode as ActualBlendMode; -use crate::{ColorAdjustments, MaskState, Texture}; -use fnv::FnvHashMap; +use crate::{as_texture, ColorAdjustments, MaskState}; use ruffle_render::backend::ShapeHandle; use ruffle_render::bitmap::BitmapHandle; use ruffle_render::commands::CommandHandler; @@ -11,7 +10,6 @@ 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>, @@ -23,13 +21,11 @@ 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, @@ -39,32 +35,32 @@ impl<'a, 'b> CommandRenderer<'a, 'b> { } } -impl<'a, 'b> CommandHandler for CommandRenderer<'a, 'b> { - fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) { - if let Some(texture) = self.bitmap_registry.get(&bitmap) { - 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), - ); - let descriptors = self.frame.descriptors(); - let bind = texture.bind_group( - smoothing, - &descriptors.device, - &descriptors.bind_layouts.bitmap, - &descriptors.quad, - bitmap, - &descriptors.bitmap_samplers, - ); +impl<'a, 'b> CommandHandler<'a> for CommandRenderer<'a, 'b> { + fn render_bitmap(&mut self, bitmap: &'a BitmapHandle, transform: &Transform, smoothing: bool) { + let texture = as_texture(bitmap); - self.frame.prep_bitmap(&bind.bind_group); + 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), + ); + let descriptors = self.frame.descriptors(); + let bind = texture.bind_group( + smoothing, + &descriptors.device, + &descriptors.bind_layouts.bitmap, + &descriptors.quad, + bitmap.clone(), + &descriptors.bitmap_samplers, + ); - self.frame.draw(self.quad_vertices, self.quad_indices, 6); - } + self.frame.prep_bitmap(&bind.bind_group); + + self.frame.draw(self.quad_vertices, self.quad_indices, 6); } fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) { diff --git a/render/wgpu/src/context3d/mod.rs b/render/wgpu/src/context3d/mod.rs index 47995c5cd..40973915f 100644 --- a/render/wgpu/src/context3d/mod.rs +++ b/render/wgpu/src/context3d/mod.rs @@ -177,14 +177,11 @@ impl WgpuContext3D { } } // Executes all of the given `commands` in response to a `Context3D.present` call. - // If we needed to re-create the target Texture due to a `ConfigureBackBuffer` command, - // then we return the new Texture. - // If we re-used the same Texture, then we return `None`. pub(crate) fn present<'gc>( &mut self, commands: Vec>, mc: MutationContext<'gc, '_>, - ) -> Option { + ) { let mut render_command_encoder = self.descriptors .device @@ -216,10 +213,6 @@ impl WgpuContext3D { // `clear_color`, which may be `None` even if we've seen a `Clear` command. let mut seen_clear_command = false; - // If we execute any `ConfigureBackBuffer` commands, this will store the newly-create - // Texture. - let mut recreated_texture = None; - for command in &commands { match command { Context3DCommand::Clear { @@ -293,14 +286,14 @@ impl WgpuContext3D { finish_render_pass!(render_pass); self.texture_view = Some(wgpu_texture.create_view(&Default::default())); - recreated_texture = Some(Texture { - texture: wgpu_texture, + self.raw_texture_handle = BitmapHandle(Arc::new(Texture { + texture: Arc::new(wgpu_texture), bind_linear: Default::default(), bind_nearest: Default::default(), - texture_offscreen: None, + texture_offscreen: Default::default(), width: *width, height: *height, - }); + })); } Context3DCommand::UploadToIndexBuffer { buffer, @@ -514,8 +507,6 @@ impl WgpuContext3D { self.buffer_staging_belt.recall(); self.compiled_pipeline = compiled_pipeline; - - recreated_texture } } @@ -548,7 +539,7 @@ pub struct VertexAttributeInfo { impl Context3D for WgpuContext3D { fn bitmap_handle(&self) -> BitmapHandle { - self.raw_texture_handle + self.raw_texture_handle.clone() } fn should_render(&self) -> bool { // If this is None, we haven't called configureBackBuffer yet. diff --git a/render/wgpu/src/lib.rs b/render/wgpu/src/lib.rs index 0424aa23d..416a1fd56 100644 --- a/render/wgpu/src/lib.rs +++ b/render/wgpu/src/lib.rs @@ -1,5 +1,7 @@ #![allow(clippy::uninlined_format_args)] +use std::sync::Arc; + use crate::bitmaps::BitmapSamplers; use crate::descriptors::Quad; use crate::globals::Globals; @@ -13,7 +15,7 @@ use bytemuck::{Pod, Zeroable}; use descriptors::Descriptors; use enum_map::Enum; use once_cell::sync::OnceCell; -use ruffle_render::bitmap::BitmapHandle; +use ruffle_render::bitmap::{BitmapHandle, BitmapHandleImpl}; use ruffle_render::color_transform::ColorTransform; use ruffle_render::tessellator::{Gradient as TessGradient, GradientType, Vertex as TessVertex}; pub use wgpu; @@ -41,6 +43,12 @@ mod mesh; mod shaders; mod surface; +impl BitmapHandleImpl for Texture {} + +pub fn as_texture(handle: &BitmapHandle) -> &Texture { + handle.0.as_any().downcast_ref().unwrap() +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Enum)] pub enum MaskState { NoMask, @@ -186,10 +194,10 @@ impl From for GradientStorage { #[derive(Debug)] pub struct Texture { - texture: wgpu::Texture, + texture: Arc, bind_linear: OnceCell, bind_nearest: OnceCell, - texture_offscreen: Option, + texture_offscreen: OnceCell, width: u32, height: u32, } @@ -215,7 +223,7 @@ impl Texture { samplers.get_sampler(false, smoothed), &quad.texture_transforms, self.texture.create_view(&Default::default()), - create_debug_label!("Bitmap {} bind group (smoothed: {})", handle.0, smoothed), + create_debug_label!("Bitmap {:?} bind group (smoothed: {})", handle.0, smoothed), ) }) } @@ -223,7 +231,7 @@ impl Texture { #[derive(Debug)] struct TextureOffscreen { - buffer: wgpu::Buffer, + buffer: Arc, buffer_dimensions: BufferDimensions, surface: Surface, } diff --git a/render/wgpu/src/mesh.rs b/render/wgpu/src/mesh.rs index d6079b4d5..991eb4774 100644 --- a/render/wgpu/src/mesh.rs +++ b/render/wgpu/src/mesh.rs @@ -1,10 +1,11 @@ use crate::backend::WgpuRenderBackend; use crate::target::RenderTarget; use crate::{ - create_buffer_with_data, Descriptors, GradientStorage, GradientUniforms, Texture, + as_texture, create_buffer_with_data, Descriptors, GradientStorage, GradientUniforms, TextureTransforms, Vertex, }; +use ruffle_render::backend::RenderBackend; use ruffle_render::bitmap::BitmapSource; use ruffle_render::tessellator::{Bitmap, Draw as LyonDraw, DrawType as TessDrawType, Gradient}; use swf::CharacterId; @@ -32,7 +33,7 @@ impl Draw { draw_id: usize, ) -> Self { let vertices: Vec<_> = draw.vertices.into_iter().map(Vertex::from).collect(); - let descriptors = backend.descriptors(); + let descriptors = backend.descriptors().clone(); let vertex_buffer = create_buffer_with_data( &descriptors.device, bytemuck::cast_slice(&vertices), @@ -63,23 +64,20 @@ impl Draw { num_indices: index_count, num_mask_indices: draw.mask_index_count, }, - TessDrawType::Bitmap(bitmap) => { - let bitmap_handle = source.bitmap_handle(bitmap.bitmap_id, backend).unwrap(); - let texture = &backend.bitmap_registry()[&bitmap_handle]; - Draw { - draw_type: DrawType::bitmap( - &backend.descriptors(), - bitmap, - texture, - shape_id, - draw_id, - ), - vertex_buffer, - index_buffer, - num_indices: index_count, - num_mask_indices: draw.mask_index_count, - } - } + TessDrawType::Bitmap(bitmap) => Draw { + draw_type: DrawType::bitmap( + &descriptors, + bitmap, + shape_id, + draw_id, + source, + backend, + ), + vertex_buffer, + index_buffer, + num_indices: index_count, + num_mask_indices: draw.mask_index_count, + }, } } } @@ -189,12 +187,14 @@ impl DrawType { pub fn bitmap( descriptors: &Descriptors, bitmap: Bitmap, - texture: &Texture, shape_id: CharacterId, draw_id: usize, + source: &dyn BitmapSource, + backend: &mut dyn RenderBackend, ) -> Self { + let handle = source.bitmap_handle(bitmap.bitmap_id, backend).unwrap(); + let texture = as_texture(&handle); let texture_view = texture.texture.create_view(&Default::default()); - let texture_transforms = create_texture_transforms( &descriptors.device, &bitmap.matrix, diff --git a/render/wgpu/src/surface.rs b/render/wgpu/src/surface.rs index 0c2d7b61c..4a13fbb4e 100644 --- a/render/wgpu/src/surface.rs +++ b/render/wgpu/src/surface.rs @@ -7,11 +7,10 @@ use crate::surface::Surface::{Direct, DirectSrgb, Resolve, ResolveSrgb}; use crate::uniform_buffer::BufferStorage; use crate::utils::remove_srgb; use crate::{ - create_buffer_with_data, ColorAdjustments, Descriptors, Globals, Pipelines, Texture, - TextureTransforms, Transforms, UniformBuffer, + create_buffer_with_data, ColorAdjustments, Descriptors, Globals, Pipelines, TextureTransforms, + Transforms, UniformBuffer, }; -use fnv::FnvHashMap; -use ruffle_render::bitmap::BitmapHandle; + use ruffle_render::commands::CommandList; use std::sync::Arc; @@ -387,7 +386,6 @@ impl Surface { globals: &mut Globals, uniform_buffers_storage: &mut BufferStorage, meshes: &Vec, - bitmap_registry: &FnvHashMap, commands: CommandList, ) -> Vec { let label = create_debug_label!("Draw encoder"); @@ -445,7 +443,6 @@ impl Surface { commands.execute(&mut CommandRenderer::new( &mut frame, meshes, - bitmap_registry, descriptors.quad.vertices.slice(..), descriptors.quad.indices.slice(..), )); diff --git a/render/wgpu/src/target.rs b/render/wgpu/src/target.rs index a907d6dc8..6b8d5910f 100644 --- a/render/wgpu/src/target.rs +++ b/render/wgpu/src/target.rs @@ -2,6 +2,7 @@ use crate::utils::BufferDimensions; use crate::Error; use ruffle_render::utils::unmultiply_alpha_rgba; use std::fmt::Debug; +use std::sync::Arc; pub trait RenderTargetFrame: Debug { fn into_view(self) -> wgpu::TextureView; @@ -136,9 +137,9 @@ impl RenderTarget for SwapChainTarget { #[derive(Debug)] pub struct TextureTarget { pub size: wgpu::Extent3d, - pub texture: wgpu::Texture, + pub texture: Arc, pub format: wgpu::TextureFormat, - pub buffer: wgpu::Buffer, + pub buffer: Arc, pub buffer_dimensions: BufferDimensions, } @@ -197,9 +198,9 @@ impl TextureTarget { }); Ok(Self { size, - texture, + texture: Arc::new(texture), format, - buffer, + buffer: Arc::new(buffer), buffer_dimensions, }) } diff --git a/render/wgpu/src/utils.rs b/render/wgpu/src/utils.rs index 642b6501b..6d67f4b92 100644 --- a/render/wgpu/src/utils.rs +++ b/render/wgpu/src/utils.rs @@ -88,7 +88,7 @@ pub fn create_buffer_with_data( } // Based off wgpu example 'capture' -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct BufferDimensions { pub width: usize, pub height: usize, diff --git a/video/software/src/backend.rs b/video/software/src/backend.rs index c9679d966..cf2e52aa6 100644 --- a/video/software/src/backend.rs +++ b/video/software/src/backend.rs @@ -78,12 +78,12 @@ impl VideoBackend for SoftwareVideoBackend { .ok_or(Error::VideoStreamIsNotRegistered)?; let frame = stream.decoder.decode_frame(encoded_frame)?; - let handle = if let Some(bitmap) = stream.bitmap { + let handle = if let Some(bitmap) = stream.bitmap.clone() { renderer.update_texture( - bitmap, + &bitmap, frame.width.into(), frame.height.into(), - frame.rgba.clone(), + frame.rgba, )?; bitmap } else { @@ -95,7 +95,7 @@ impl VideoBackend for SoftwareVideoBackend { ); renderer.register_bitmap(bitmap)? }; - stream.bitmap = Some(handle); + stream.bitmap = Some(handle.clone()); Ok(BitmapInfo { handle,