core: Free render backend resources on `BitmapData.dispose`
Currently, all three render backends hold on texture-related resources indefinitely (`register_bitmap` pushes to a `Vec`, and never removes anything). As a result, the resources used by the render backend (which may include GPU memory) will grow over time, even if the corresponding `BitmapData` has been deallocated. This commit adds a new `unregister_bitmap` method, which is called from `BitmapData.dispose`. All render backs are changed to now use an `FnvHashMap<BitmapHandle, _>` instead of a `Vec`, allowing us to remove individual entries. Currently, we only call `unregister_bitmap in response to `BitmapData.dispose` - when `BitmapData` is freed by the garbage collector, `unregister_bitmap` is *not* called. This will be addressed in a future PR.
This commit is contained in:
parent
4d1bf7e00c
commit
a79aa08f08
|
@ -3088,6 +3088,7 @@ dependencies = [
|
||||||
name = "ruffle_render_canvas"
|
name = "ruffle_render_canvas"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"ruffle_core",
|
"ruffle_core",
|
||||||
|
@ -3110,6 +3111,7 @@ name = "ruffle_render_webgl"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
"fnv",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"ruffle_core",
|
"ruffle_core",
|
||||||
|
@ -3126,6 +3128,7 @@ dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"clap",
|
"clap",
|
||||||
"enum-map",
|
"enum-map",
|
||||||
|
"fnv",
|
||||||
"futures",
|
"futures",
|
||||||
"image",
|
"image",
|
||||||
"log",
|
"log",
|
||||||
|
|
|
@ -405,7 +405,7 @@ pub fn dispose<'gc>(
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some(bitmap_data) = this.as_bitmap_data_object() {
|
if let Some(bitmap_data) = this.as_bitmap_data_object() {
|
||||||
if !bitmap_data.disposed() {
|
if !bitmap_data.disposed() {
|
||||||
bitmap_data.dispose(activation.context.gc_context);
|
bitmap_data.dispose(&mut activation.context);
|
||||||
return Ok(Value::Undefined);
|
return Ok(Value::Undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::add_field_accessors;
|
use crate::add_field_accessors;
|
||||||
use crate::avm1::{Object, ScriptObject, TObject};
|
use crate::avm1::{Object, ScriptObject, TObject};
|
||||||
|
use crate::context::UpdateContext;
|
||||||
use crate::impl_custom_object;
|
use crate::impl_custom_object;
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
|
|
||||||
|
@ -54,9 +55,11 @@ impl<'gc> BitmapDataObject<'gc> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispose(&self, gc_context: MutationContext<'gc, '_>) {
|
pub fn dispose(&self, context: &mut UpdateContext<'_, 'gc, '_>) {
|
||||||
self.bitmap_data().write(gc_context).dispose();
|
self.bitmap_data()
|
||||||
self.0.write(gc_context).disposed = true;
|
.write(context.gc_context)
|
||||||
|
.dispose(context.renderer);
|
||||||
|
self.0.write(context.gc_context).disposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,9 @@ pub trait RenderBackend: Downcast {
|
||||||
|
|
||||||
fn get_bitmap_pixels(&mut self, bitmap: BitmapHandle) -> Option<Bitmap>;
|
fn get_bitmap_pixels(&mut self, bitmap: BitmapHandle) -> Option<Bitmap>;
|
||||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error>;
|
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error>;
|
||||||
|
// Frees memory used by the bitmap. After this call, `handle` can no longer
|
||||||
|
// be used.
|
||||||
|
fn unregister_bitmap(&mut self, handle: BitmapHandle) -> Result<(), Error>;
|
||||||
fn update_texture(
|
fn update_texture(
|
||||||
&mut self,
|
&mut self,
|
||||||
bitmap: BitmapHandle,
|
bitmap: BitmapHandle,
|
||||||
|
@ -177,6 +180,9 @@ impl RenderBackend for NullRenderer {
|
||||||
fn register_bitmap(&mut self, _bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
fn register_bitmap(&mut self, _bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
||||||
Ok(BitmapHandle(0))
|
Ok(BitmapHandle(0))
|
||||||
}
|
}
|
||||||
|
fn unregister_bitmap(&mut self, _bitmap: BitmapHandle) -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn update_texture(
|
fn update_texture(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -168,11 +168,18 @@ impl<'gc> BitmapData<'gc> {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispose(&mut self) {
|
pub fn dispose(&mut self, renderer: &mut dyn RenderBackend) {
|
||||||
self.width = 0;
|
self.width = 0;
|
||||||
self.height = 0;
|
self.height = 0;
|
||||||
self.pixels.clear();
|
self.pixels.clear();
|
||||||
self.dirty = true;
|
if let Some(handle) = self.bitmap_handle {
|
||||||
|
if let Err(e) = renderer.unregister_bitmap(handle) {
|
||||||
|
log::warn!("Failed to unregister bitmap {:?}: {:?}", handle, e);
|
||||||
|
}
|
||||||
|
self.bitmap_handle = None;
|
||||||
|
}
|
||||||
|
// There's no longer a handle to update
|
||||||
|
self.dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitmap_handle(&mut self, renderer: &mut dyn RenderBackend) -> Option<BitmapHandle> {
|
pub fn bitmap_handle(&mut self, renderer: &mut dyn RenderBackend) -> Option<BitmapHandle> {
|
||||||
|
|
|
@ -10,6 +10,7 @@ js-sys = "0.3.57"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
ruffle_web_common = { path = "../../web/common" }
|
ruffle_web_common = { path = "../../web/common" }
|
||||||
wasm-bindgen = "=0.2.80"
|
wasm-bindgen = "=0.2.80"
|
||||||
|
fnv = "1.0.7"
|
||||||
|
|
||||||
[dependencies.ruffle_core]
|
[dependencies.ruffle_core]
|
||||||
path = "../../core"
|
path = "../../core"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use fnv::FnvHashMap;
|
||||||
use ruffle_core::backend::render::{
|
use ruffle_core::backend::render::{
|
||||||
swf, Bitmap, BitmapFormat, BitmapHandle, BitmapSource, Color, NullBitmapSource, RenderBackend,
|
swf, Bitmap, BitmapFormat, BitmapHandle, BitmapSource, Color, NullBitmapSource, RenderBackend,
|
||||||
ShapeHandle, Transform,
|
ShapeHandle, Transform,
|
||||||
|
@ -21,11 +22,12 @@ pub struct WebCanvasRenderBackend {
|
||||||
context: CanvasRenderingContext2d,
|
context: CanvasRenderingContext2d,
|
||||||
color_matrix: Element,
|
color_matrix: Element,
|
||||||
shapes: Vec<ShapeData>,
|
shapes: Vec<ShapeData>,
|
||||||
bitmaps: Vec<BitmapData>,
|
bitmaps: FnvHashMap<BitmapHandle, BitmapData>,
|
||||||
viewport_width: u32,
|
viewport_width: u32,
|
||||||
viewport_height: u32,
|
viewport_height: u32,
|
||||||
rect: Path2d,
|
rect: Path2d,
|
||||||
mask_state: MaskState,
|
mask_state: MaskState,
|
||||||
|
next_bitmap_handle: BitmapHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Canvas-drawable shape data extracted from an SWF file.
|
/// Canvas-drawable shape data extracted from an SWF file.
|
||||||
|
@ -237,11 +239,12 @@ impl WebCanvasRenderBackend {
|
||||||
color_matrix,
|
color_matrix,
|
||||||
context,
|
context,
|
||||||
shapes: vec![],
|
shapes: vec![],
|
||||||
bitmaps: vec![],
|
bitmaps: Default::default(),
|
||||||
viewport_width: 0,
|
viewport_width: 0,
|
||||||
viewport_height: 0,
|
viewport_height: 0,
|
||||||
rect,
|
rect,
|
||||||
mask_state: MaskState::DrawContent,
|
mask_state: MaskState::DrawContent,
|
||||||
|
next_bitmap_handle: BitmapHandle(0),
|
||||||
};
|
};
|
||||||
Ok(renderer)
|
Ok(renderer)
|
||||||
}
|
}
|
||||||
|
@ -369,7 +372,7 @@ impl RenderBackend for WebCanvasRenderBackend {
|
||||||
|
|
||||||
self.set_transform(&transform.matrix);
|
self.set_transform(&transform.matrix);
|
||||||
self.set_color_filter(transform);
|
self.set_color_filter(transform);
|
||||||
if let Some(bitmap) = self.bitmaps.get(bitmap.0) {
|
if let Some(bitmap) = self.bitmaps.get(&bitmap) {
|
||||||
let _ = self
|
let _ = self
|
||||||
.context
|
.context
|
||||||
.draw_image_with_html_canvas_element(&bitmap.canvas, 0.0, 0.0);
|
.draw_image_with_html_canvas_element(&bitmap.canvas, 0.0, 0.0);
|
||||||
|
@ -590,17 +593,23 @@ impl RenderBackend for WebCanvasRenderBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_bitmap_pixels(&mut self, bitmap: BitmapHandle) -> Option<Bitmap> {
|
fn get_bitmap_pixels(&mut self, bitmap: BitmapHandle) -> Option<Bitmap> {
|
||||||
let bitmap = &self.bitmaps[bitmap.0];
|
let bitmap = &self.bitmaps[&bitmap];
|
||||||
bitmap.get_pixels()
|
bitmap.get_pixels()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
||||||
let handle = BitmapHandle(self.bitmaps.len());
|
let handle = self.next_bitmap_handle;
|
||||||
|
self.next_bitmap_handle = BitmapHandle(self.next_bitmap_handle.0 + 1);
|
||||||
let bitmap_data = BitmapData::new(bitmap)?;
|
let bitmap_data = BitmapData::new(bitmap)?;
|
||||||
self.bitmaps.push(bitmap_data);
|
self.bitmaps.insert(handle, bitmap_data);
|
||||||
Ok(handle)
|
Ok(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unregister_bitmap(&mut self, bitmap: BitmapHandle) -> Result<(), Error> {
|
||||||
|
self.bitmaps.remove(&bitmap);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn update_texture(
|
fn update_texture(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: BitmapHandle,
|
handle: BitmapHandle,
|
||||||
|
@ -610,8 +619,10 @@ impl RenderBackend for WebCanvasRenderBackend {
|
||||||
) -> Result<BitmapHandle, Error> {
|
) -> Result<BitmapHandle, Error> {
|
||||||
// TODO: Could be optimized to a single put_image_data call
|
// TODO: Could be optimized to a single put_image_data call
|
||||||
// in case it is already stored as a canvas+context.
|
// in case it is already stored as a canvas+context.
|
||||||
self.bitmaps[handle.0] =
|
self.bitmaps.insert(
|
||||||
BitmapData::new(Bitmap::new(width, height, BitmapFormat::Rgba, rgba))?;
|
handle,
|
||||||
|
BitmapData::new(Bitmap::new(width, height, BitmapFormat::Rgba, rgba))?,
|
||||||
|
);
|
||||||
Ok(handle)
|
Ok(handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -647,7 +658,7 @@ fn draw_commands_to_path2d(commands: &[DrawCommand], is_closed: bool) -> Path2d
|
||||||
fn swf_shape_to_canvas_commands(
|
fn swf_shape_to_canvas_commands(
|
||||||
shape: &DistilledShape,
|
shape: &DistilledShape,
|
||||||
bitmap_source: &dyn BitmapSource,
|
bitmap_source: &dyn BitmapSource,
|
||||||
bitmaps: &[BitmapData],
|
bitmaps: &FnvHashMap<BitmapHandle, BitmapData>,
|
||||||
context: &CanvasRenderingContext2d,
|
context: &CanvasRenderingContext2d,
|
||||||
) -> ShapeData {
|
) -> ShapeData {
|
||||||
use ruffle_core::shape_utils::DrawPath;
|
use ruffle_core::shape_utils::DrawPath;
|
||||||
|
@ -710,7 +721,7 @@ fn swf_shape_to_canvas_commands(
|
||||||
} => {
|
} => {
|
||||||
if let Some(bitmap) = bitmap_source
|
if let Some(bitmap) = bitmap_source
|
||||||
.bitmap(*id)
|
.bitmap(*id)
|
||||||
.and_then(|bitmap| bitmaps.get(bitmap.handle.0))
|
.and_then(|bitmap| bitmaps.get(&bitmap.handle))
|
||||||
{
|
{
|
||||||
let repeat = if !*is_repeating {
|
let repeat = if !*is_repeating {
|
||||||
// NOTE: The WebGL backend does clamping in this case, just like
|
// NOTE: The WebGL backend does clamping in this case, just like
|
||||||
|
|
|
@ -12,6 +12,7 @@ ruffle_render_common_tess = { path = "../common_tess" }
|
||||||
ruffle_web_common = { path = "../../web/common" }
|
ruffle_web_common = { path = "../../web/common" }
|
||||||
wasm-bindgen = "=0.2.80"
|
wasm-bindgen = "=0.2.80"
|
||||||
bytemuck = { version = "1.9.1", features = ["derive"] }
|
bytemuck = { version = "1.9.1", features = ["derive"] }
|
||||||
|
fnv = "1.0.7"
|
||||||
|
|
||||||
[dependencies.ruffle_core]
|
[dependencies.ruffle_core]
|
||||||
path = "../../core"
|
path = "../../core"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use fnv::FnvHashMap;
|
||||||
use ruffle_core::backend::render::{
|
use ruffle_core::backend::render::{
|
||||||
Bitmap, BitmapFormat, BitmapHandle, BitmapSource, Color, NullBitmapSource, RenderBackend,
|
Bitmap, BitmapFormat, BitmapHandle, BitmapSource, Color, NullBitmapSource, RenderBackend,
|
||||||
ShapeHandle, Transform,
|
ShapeHandle, Transform,
|
||||||
|
@ -9,7 +10,6 @@ use ruffle_render_common_tess::{
|
||||||
Gradient as TessGradient, GradientType, ShapeTessellator, Vertex as TessVertex,
|
Gradient as TessGradient, GradientType, ShapeTessellator, Vertex as TessVertex,
|
||||||
};
|
};
|
||||||
use ruffle_web_common::JsResult;
|
use ruffle_web_common::JsResult;
|
||||||
use std::collections::HashMap;
|
|
||||||
use wasm_bindgen::{JsCast, JsValue};
|
use wasm_bindgen::{JsCast, JsValue};
|
||||||
use web_sys::{
|
use web_sys::{
|
||||||
HtmlCanvasElement, OesVertexArrayObject, WebGl2RenderingContext as Gl2, WebGlBuffer,
|
HtmlCanvasElement, OesVertexArrayObject, WebGl2RenderingContext as Gl2, WebGlBuffer,
|
||||||
|
@ -75,7 +75,6 @@ pub struct WebGlRenderBackend {
|
||||||
|
|
||||||
shape_tessellator: ShapeTessellator,
|
shape_tessellator: ShapeTessellator,
|
||||||
|
|
||||||
textures: Vec<Texture>,
|
|
||||||
meshes: Vec<Mesh>,
|
meshes: Vec<Mesh>,
|
||||||
|
|
||||||
color_quad_shape: ShapeHandle,
|
color_quad_shape: ShapeHandle,
|
||||||
|
@ -95,7 +94,13 @@ pub struct WebGlRenderBackend {
|
||||||
renderbuffer_height: i32,
|
renderbuffer_height: i32,
|
||||||
view_matrix: [[f32; 4]; 4],
|
view_matrix: [[f32; 4]; 4],
|
||||||
|
|
||||||
bitmap_registry: HashMap<BitmapHandle, Bitmap>,
|
bitmap_registry: FnvHashMap<BitmapHandle, RegistryData>,
|
||||||
|
next_bitmap_handle: BitmapHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RegistryData {
|
||||||
|
bitmap: Bitmap,
|
||||||
|
texture_wrapper: Texture,
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_GRADIENT_COLORS: usize = 15;
|
const MAX_GRADIENT_COLORS: usize = 15;
|
||||||
|
@ -233,7 +238,6 @@ impl WebGlRenderBackend {
|
||||||
meshes: vec![],
|
meshes: vec![],
|
||||||
color_quad_shape: ShapeHandle(0),
|
color_quad_shape: ShapeHandle(0),
|
||||||
bitmap_quad_shape: ShapeHandle(1),
|
bitmap_quad_shape: ShapeHandle(1),
|
||||||
textures: vec![],
|
|
||||||
renderbuffer_width: 1,
|
renderbuffer_width: 1,
|
||||||
renderbuffer_height: 1,
|
renderbuffer_height: 1,
|
||||||
view_matrix: [[0.0; 4]; 4],
|
view_matrix: [[0.0; 4]; 4],
|
||||||
|
@ -247,7 +251,8 @@ impl WebGlRenderBackend {
|
||||||
blend_func: (Gl::ONE, Gl::ONE_MINUS_SRC_ALPHA),
|
blend_func: (Gl::ONE, Gl::ONE_MINUS_SRC_ALPHA),
|
||||||
mult_color: None,
|
mult_color: None,
|
||||||
add_color: None,
|
add_color: None,
|
||||||
bitmap_registry: HashMap::new(),
|
bitmap_registry: Default::default(),
|
||||||
|
next_bitmap_handle: BitmapHandle(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
let color_quad_mesh = renderer.build_quad_mesh(&renderer.color_program)?;
|
let color_quad_mesh = renderer.build_quad_mesh(&renderer.color_program)?;
|
||||||
|
@ -821,7 +826,8 @@ impl RenderBackend for WebGlRenderBackend {
|
||||||
|
|
||||||
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
|
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||||
self.set_stencil_state();
|
self.set_stencil_state();
|
||||||
if let Some(bitmap) = self.textures.get(bitmap.0) {
|
if let Some(entry) = self.bitmap_registry.get(&bitmap) {
|
||||||
|
let bitmap = &entry.texture_wrapper;
|
||||||
let texture = &bitmap.texture;
|
let texture = &bitmap.texture;
|
||||||
// Adjust the quad draw to use the target bitmap.
|
// Adjust the quad draw to use the target bitmap.
|
||||||
let mesh = &self.meshes[self.bitmap_quad_shape.0];
|
let mesh = &self.meshes[self.bitmap_quad_shape.0];
|
||||||
|
@ -1019,8 +1025,8 @@ impl RenderBackend for WebGlRenderBackend {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
DrawType::Bitmap(bitmap) => {
|
DrawType::Bitmap(bitmap) => {
|
||||||
let texture = if let Some(texture) = self.textures.get(bitmap.handle.0) {
|
let texture = if let Some(entry) = self.bitmap_registry.get(&bitmap.handle) {
|
||||||
texture
|
&entry.texture_wrapper
|
||||||
} else {
|
} else {
|
||||||
// Bitmap not registered
|
// Bitmap not registered
|
||||||
continue;
|
continue;
|
||||||
|
@ -1168,7 +1174,7 @@ impl RenderBackend for WebGlRenderBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_bitmap_pixels(&mut self, bitmap: BitmapHandle) -> Option<Bitmap> {
|
fn get_bitmap_pixels(&mut self, bitmap: BitmapHandle) -> Option<Bitmap> {
|
||||||
self.bitmap_registry.get(&bitmap).cloned()
|
self.bitmap_registry.get(&bitmap).map(|e| e.bitmap.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
||||||
|
@ -1203,20 +1209,30 @@ impl RenderBackend for WebGlRenderBackend {
|
||||||
self.gl
|
self.gl
|
||||||
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MAG_FILTER, Gl::LINEAR as i32);
|
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MAG_FILTER, Gl::LINEAR as i32);
|
||||||
|
|
||||||
let handle = BitmapHandle(self.textures.len());
|
let handle = self.next_bitmap_handle;
|
||||||
|
self.next_bitmap_handle = BitmapHandle(self.next_bitmap_handle.0 + 1);
|
||||||
let width = bitmap.width();
|
let width = bitmap.width();
|
||||||
let height = bitmap.height();
|
let height = bitmap.height();
|
||||||
self.bitmap_registry.insert(handle, bitmap);
|
self.bitmap_registry.insert(
|
||||||
|
handle,
|
||||||
self.textures.push(Texture {
|
RegistryData {
|
||||||
width,
|
bitmap,
|
||||||
height,
|
texture_wrapper: Texture {
|
||||||
texture,
|
width,
|
||||||
});
|
height,
|
||||||
|
texture,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Ok(handle)
|
Ok(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unregister_bitmap(&mut self, bitmap: BitmapHandle) -> Result<(), Error> {
|
||||||
|
self.bitmap_registry.remove(&bitmap);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn update_texture(
|
fn update_texture(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: BitmapHandle,
|
handle: BitmapHandle,
|
||||||
|
@ -1224,8 +1240,8 @@ impl RenderBackend for WebGlRenderBackend {
|
||||||
height: u32,
|
height: u32,
|
||||||
rgba: Vec<u8>,
|
rgba: Vec<u8>,
|
||||||
) -> Result<BitmapHandle, Error> {
|
) -> Result<BitmapHandle, Error> {
|
||||||
let texture = if let Some(texture) = self.textures.get(handle.0) {
|
let texture = if let Some(entry) = self.bitmap_registry.get(&handle) {
|
||||||
texture
|
&entry.texture_wrapper
|
||||||
} else {
|
} else {
|
||||||
return Err("update_texture: Bitmap is not regsitered".into());
|
return Err("update_texture: Bitmap is not regsitered".into());
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,7 @@ bytemuck = { version = "1.9.1", features = ["derive"] }
|
||||||
raw-window-handle = "0.4"
|
raw-window-handle = "0.4"
|
||||||
clap = { version = "3.2.2", features = ["derive"], optional = true }
|
clap = { version = "3.2.2", features = ["derive"], optional = true }
|
||||||
enum-map = "2.4.0"
|
enum-map = "2.4.0"
|
||||||
|
fnv = "1.0.7"
|
||||||
|
|
||||||
# desktop
|
# desktop
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.futures]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.futures]
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::target::{RenderTarget, RenderTargetFrame, SwapChainTarget};
|
||||||
use crate::utils::{create_buffer_with_data, format_list, get_backend_names};
|
use crate::utils::{create_buffer_with_data, format_list, get_backend_names};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use enum_map::Enum;
|
use enum_map::Enum;
|
||||||
|
use fnv::FnvHashMap;
|
||||||
use ruffle_core::backend::render::{
|
use ruffle_core::backend::render::{
|
||||||
Bitmap, BitmapHandle, BitmapSource, Color, RenderBackend, ShapeHandle, Transform,
|
Bitmap, BitmapHandle, BitmapSource, Color, RenderBackend, ShapeHandle, Transform,
|
||||||
};
|
};
|
||||||
|
@ -32,7 +33,6 @@ pub mod clap;
|
||||||
use crate::bitmaps::BitmapSamplers;
|
use crate::bitmaps::BitmapSamplers;
|
||||||
use crate::globals::Globals;
|
use crate::globals::Globals;
|
||||||
use crate::uniform_buffer::UniformBuffer;
|
use crate::uniform_buffer::UniformBuffer;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
pub use wgpu;
|
pub use wgpu;
|
||||||
|
|
||||||
|
@ -149,12 +149,17 @@ pub struct WgpuRenderBackend<T: RenderTarget> {
|
||||||
meshes: Vec<Mesh>,
|
meshes: Vec<Mesh>,
|
||||||
mask_state: MaskState,
|
mask_state: MaskState,
|
||||||
shape_tessellator: ShapeTessellator,
|
shape_tessellator: ShapeTessellator,
|
||||||
textures: Vec<Texture>,
|
|
||||||
num_masks: u32,
|
num_masks: u32,
|
||||||
quad_vbo: wgpu::Buffer,
|
quad_vbo: wgpu::Buffer,
|
||||||
quad_ibo: wgpu::Buffer,
|
quad_ibo: wgpu::Buffer,
|
||||||
quad_tex_transforms: wgpu::Buffer,
|
quad_tex_transforms: wgpu::Buffer,
|
||||||
bitmap_registry: HashMap<BitmapHandle, Bitmap>,
|
bitmap_registry: FnvHashMap<BitmapHandle, RegistryData>,
|
||||||
|
next_bitmap_handle: BitmapHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RegistryData {
|
||||||
|
bitmap: Bitmap,
|
||||||
|
texture_wrapper: Texture,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -481,7 +486,6 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
|
||||||
current_frame: None,
|
current_frame: None,
|
||||||
meshes: Vec::new(),
|
meshes: Vec::new(),
|
||||||
shape_tessellator: ShapeTessellator::new(),
|
shape_tessellator: ShapeTessellator::new(),
|
||||||
textures: Vec::new(),
|
|
||||||
|
|
||||||
num_masks: 0,
|
num_masks: 0,
|
||||||
mask_state: MaskState::NoMask,
|
mask_state: MaskState::NoMask,
|
||||||
|
@ -489,7 +493,8 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
|
||||||
quad_vbo,
|
quad_vbo,
|
||||||
quad_ibo,
|
quad_ibo,
|
||||||
quad_tex_transforms,
|
quad_tex_transforms,
|
||||||
bitmap_registry: HashMap::new(),
|
bitmap_registry: Default::default(),
|
||||||
|
next_bitmap_handle: BitmapHandle(0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,8 +663,11 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TessDrawType::Bitmap(bitmap) => {
|
TessDrawType::Bitmap(bitmap) => {
|
||||||
let texture = self.textures.get(bitmap.bitmap.0).unwrap();
|
let entry = self.bitmap_registry.get(&bitmap.bitmap).unwrap();
|
||||||
let texture_view = texture.texture.create_view(&Default::default());
|
let texture_view = entry
|
||||||
|
.texture_wrapper
|
||||||
|
.texture
|
||||||
|
.create_view(&Default::default());
|
||||||
|
|
||||||
// TODO: Extract to function?
|
// TODO: Extract to function?
|
||||||
let mut texture_transform = [[0.0; 4]; 4];
|
let mut texture_transform = [[0.0; 4]; 4];
|
||||||
|
@ -952,7 +960,8 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
|
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||||
if let Some(texture) = self.textures.get(bitmap.0) {
|
if let Some(entry) = self.bitmap_registry.get(&bitmap) {
|
||||||
|
let texture = &entry.texture_wrapper;
|
||||||
let frame = if let Some(frame) = &mut self.current_frame {
|
let frame = if let Some(frame) = &mut self.current_frame {
|
||||||
frame.get()
|
frame.get()
|
||||||
} else {
|
} else {
|
||||||
|
@ -1320,7 +1329,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_bitmap_pixels(&mut self, bitmap: BitmapHandle) -> Option<Bitmap> {
|
fn get_bitmap_pixels(&mut self, bitmap: BitmapHandle) -> Option<Bitmap> {
|
||||||
self.bitmap_registry.get(&bitmap).cloned()
|
self.bitmap_registry.get(&bitmap).map(|e| e.bitmap.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
||||||
|
@ -1361,7 +1370,8 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
extent,
|
extent,
|
||||||
);
|
);
|
||||||
|
|
||||||
let handle = BitmapHandle(self.textures.len());
|
let handle = self.next_bitmap_handle;
|
||||||
|
self.next_bitmap_handle = BitmapHandle(self.next_bitmap_handle.0 + 1);
|
||||||
let width = bitmap.width();
|
let width = bitmap.width();
|
||||||
let height = bitmap.height();
|
let height = bitmap.height();
|
||||||
|
|
||||||
|
@ -1391,17 +1401,27 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
label: create_debug_label!("Bitmap {} bind group", handle.0).as_deref(),
|
label: create_debug_label!("Bitmap {} bind group", handle.0).as_deref(),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.bitmap_registry.insert(handle, bitmap);
|
self.bitmap_registry.insert(
|
||||||
self.textures.push(Texture {
|
handle,
|
||||||
width,
|
RegistryData {
|
||||||
height,
|
bitmap,
|
||||||
texture,
|
texture_wrapper: Texture {
|
||||||
bind_group,
|
width,
|
||||||
});
|
height,
|
||||||
|
texture,
|
||||||
|
bind_group,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Ok(handle)
|
Ok(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unregister_bitmap(&mut self, handle: BitmapHandle) -> Result<(), Error> {
|
||||||
|
self.bitmap_registry.remove(&handle);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn update_texture(
|
fn update_texture(
|
||||||
&mut self,
|
&mut self,
|
||||||
handle: BitmapHandle,
|
handle: BitmapHandle,
|
||||||
|
@ -1409,8 +1429,8 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
height: u32,
|
height: u32,
|
||||||
rgba: Vec<u8>,
|
rgba: Vec<u8>,
|
||||||
) -> Result<BitmapHandle, Error> {
|
) -> Result<BitmapHandle, Error> {
|
||||||
let texture = if let Some(texture) = self.textures.get(handle.0) {
|
let texture = if let Some(entry) = self.bitmap_registry.get(&handle) {
|
||||||
&texture.texture
|
&entry.texture_wrapper.texture
|
||||||
} else {
|
} else {
|
||||||
return Err("update_texture: Bitmap not registered".into());
|
return Err("update_texture: Bitmap not registered".into());
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue