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"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"js-sys",
|
||||
"log",
|
||||
"ruffle_core",
|
||||
|
@ -3110,6 +3111,7 @@ name = "ruffle_render_webgl"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"fnv",
|
||||
"js-sys",
|
||||
"log",
|
||||
"ruffle_core",
|
||||
|
@ -3126,6 +3128,7 @@ dependencies = [
|
|||
"bytemuck",
|
||||
"clap",
|
||||
"enum-map",
|
||||
"fnv",
|
||||
"futures",
|
||||
"image",
|
||||
"log",
|
||||
|
|
|
@ -405,7 +405,7 @@ pub fn dispose<'gc>(
|
|||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some(bitmap_data) = this.as_bitmap_data_object() {
|
||||
if !bitmap_data.disposed() {
|
||||
bitmap_data.dispose(activation.context.gc_context);
|
||||
bitmap_data.dispose(&mut activation.context);
|
||||
return Ok(Value::Undefined);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::add_field_accessors;
|
||||
use crate::avm1::{Object, ScriptObject, TObject};
|
||||
use crate::context::UpdateContext;
|
||||
use crate::impl_custom_object;
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
|
||||
|
@ -54,9 +55,11 @@ impl<'gc> BitmapDataObject<'gc> {
|
|||
))
|
||||
}
|
||||
|
||||
pub fn dispose(&self, gc_context: MutationContext<'gc, '_>) {
|
||||
self.bitmap_data().write(gc_context).dispose();
|
||||
self.0.write(gc_context).disposed = true;
|
||||
pub fn dispose(&self, context: &mut UpdateContext<'_, 'gc, '_>) {
|
||||
self.bitmap_data()
|
||||
.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 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(
|
||||
&mut self,
|
||||
bitmap: BitmapHandle,
|
||||
|
@ -177,6 +180,9 @@ impl RenderBackend for NullRenderer {
|
|||
fn register_bitmap(&mut self, _bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
||||
Ok(BitmapHandle(0))
|
||||
}
|
||||
fn unregister_bitmap(&mut self, _bitmap: BitmapHandle) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_texture(
|
||||
&mut self,
|
||||
|
|
|
@ -168,11 +168,18 @@ impl<'gc> BitmapData<'gc> {
|
|||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub fn dispose(&mut self) {
|
||||
pub fn dispose(&mut self, renderer: &mut dyn RenderBackend) {
|
||||
self.width = 0;
|
||||
self.height = 0;
|
||||
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> {
|
||||
|
|
|
@ -10,6 +10,7 @@ js-sys = "0.3.57"
|
|||
log = "0.4"
|
||||
ruffle_web_common = { path = "../../web/common" }
|
||||
wasm-bindgen = "=0.2.80"
|
||||
fnv = "1.0.7"
|
||||
|
||||
[dependencies.ruffle_core]
|
||||
path = "../../core"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use fnv::FnvHashMap;
|
||||
use ruffle_core::backend::render::{
|
||||
swf, Bitmap, BitmapFormat, BitmapHandle, BitmapSource, Color, NullBitmapSource, RenderBackend,
|
||||
ShapeHandle, Transform,
|
||||
|
@ -21,11 +22,12 @@ pub struct WebCanvasRenderBackend {
|
|||
context: CanvasRenderingContext2d,
|
||||
color_matrix: Element,
|
||||
shapes: Vec<ShapeData>,
|
||||
bitmaps: Vec<BitmapData>,
|
||||
bitmaps: FnvHashMap<BitmapHandle, BitmapData>,
|
||||
viewport_width: u32,
|
||||
viewport_height: u32,
|
||||
rect: Path2d,
|
||||
mask_state: MaskState,
|
||||
next_bitmap_handle: BitmapHandle,
|
||||
}
|
||||
|
||||
/// Canvas-drawable shape data extracted from an SWF file.
|
||||
|
@ -237,11 +239,12 @@ impl WebCanvasRenderBackend {
|
|||
color_matrix,
|
||||
context,
|
||||
shapes: vec![],
|
||||
bitmaps: vec![],
|
||||
bitmaps: Default::default(),
|
||||
viewport_width: 0,
|
||||
viewport_height: 0,
|
||||
rect,
|
||||
mask_state: MaskState::DrawContent,
|
||||
next_bitmap_handle: BitmapHandle(0),
|
||||
};
|
||||
Ok(renderer)
|
||||
}
|
||||
|
@ -369,7 +372,7 @@ impl RenderBackend for WebCanvasRenderBackend {
|
|||
|
||||
self.set_transform(&transform.matrix);
|
||||
self.set_color_filter(transform);
|
||||
if let Some(bitmap) = self.bitmaps.get(bitmap.0) {
|
||||
if let Some(bitmap) = self.bitmaps.get(&bitmap) {
|
||||
let _ = self
|
||||
.context
|
||||
.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> {
|
||||
let bitmap = &self.bitmaps[bitmap.0];
|
||||
let bitmap = &self.bitmaps[&bitmap];
|
||||
bitmap.get_pixels()
|
||||
}
|
||||
|
||||
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)?;
|
||||
self.bitmaps.push(bitmap_data);
|
||||
self.bitmaps.insert(handle, bitmap_data);
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
fn unregister_bitmap(&mut self, bitmap: BitmapHandle) -> Result<(), Error> {
|
||||
self.bitmaps.remove(&bitmap);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_texture(
|
||||
&mut self,
|
||||
handle: BitmapHandle,
|
||||
|
@ -610,8 +619,10 @@ impl RenderBackend for WebCanvasRenderBackend {
|
|||
) -> Result<BitmapHandle, Error> {
|
||||
// TODO: Could be optimized to a single put_image_data call
|
||||
// in case it is already stored as a canvas+context.
|
||||
self.bitmaps[handle.0] =
|
||||
BitmapData::new(Bitmap::new(width, height, BitmapFormat::Rgba, rgba))?;
|
||||
self.bitmaps.insert(
|
||||
handle,
|
||||
BitmapData::new(Bitmap::new(width, height, BitmapFormat::Rgba, rgba))?,
|
||||
);
|
||||
Ok(handle)
|
||||
}
|
||||
}
|
||||
|
@ -647,7 +658,7 @@ fn draw_commands_to_path2d(commands: &[DrawCommand], is_closed: bool) -> Path2d
|
|||
fn swf_shape_to_canvas_commands(
|
||||
shape: &DistilledShape,
|
||||
bitmap_source: &dyn BitmapSource,
|
||||
bitmaps: &[BitmapData],
|
||||
bitmaps: &FnvHashMap<BitmapHandle, BitmapData>,
|
||||
context: &CanvasRenderingContext2d,
|
||||
) -> ShapeData {
|
||||
use ruffle_core::shape_utils::DrawPath;
|
||||
|
@ -710,7 +721,7 @@ fn swf_shape_to_canvas_commands(
|
|||
} => {
|
||||
if let Some(bitmap) = bitmap_source
|
||||
.bitmap(*id)
|
||||
.and_then(|bitmap| bitmaps.get(bitmap.handle.0))
|
||||
.and_then(|bitmap| bitmaps.get(&bitmap.handle))
|
||||
{
|
||||
let repeat = if !*is_repeating {
|
||||
// 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" }
|
||||
wasm-bindgen = "=0.2.80"
|
||||
bytemuck = { version = "1.9.1", features = ["derive"] }
|
||||
fnv = "1.0.7"
|
||||
|
||||
[dependencies.ruffle_core]
|
||||
path = "../../core"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use bytemuck::{Pod, Zeroable};
|
||||
use fnv::FnvHashMap;
|
||||
use ruffle_core::backend::render::{
|
||||
Bitmap, BitmapFormat, BitmapHandle, BitmapSource, Color, NullBitmapSource, RenderBackend,
|
||||
ShapeHandle, Transform,
|
||||
|
@ -9,7 +10,6 @@ use ruffle_render_common_tess::{
|
|||
Gradient as TessGradient, GradientType, ShapeTessellator, Vertex as TessVertex,
|
||||
};
|
||||
use ruffle_web_common::JsResult;
|
||||
use std::collections::HashMap;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{
|
||||
HtmlCanvasElement, OesVertexArrayObject, WebGl2RenderingContext as Gl2, WebGlBuffer,
|
||||
|
@ -75,7 +75,6 @@ pub struct WebGlRenderBackend {
|
|||
|
||||
shape_tessellator: ShapeTessellator,
|
||||
|
||||
textures: Vec<Texture>,
|
||||
meshes: Vec<Mesh>,
|
||||
|
||||
color_quad_shape: ShapeHandle,
|
||||
|
@ -95,7 +94,13 @@ pub struct WebGlRenderBackend {
|
|||
renderbuffer_height: i32,
|
||||
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;
|
||||
|
@ -233,7 +238,6 @@ impl WebGlRenderBackend {
|
|||
meshes: vec![],
|
||||
color_quad_shape: ShapeHandle(0),
|
||||
bitmap_quad_shape: ShapeHandle(1),
|
||||
textures: vec![],
|
||||
renderbuffer_width: 1,
|
||||
renderbuffer_height: 1,
|
||||
view_matrix: [[0.0; 4]; 4],
|
||||
|
@ -247,7 +251,8 @@ impl WebGlRenderBackend {
|
|||
blend_func: (Gl::ONE, Gl::ONE_MINUS_SRC_ALPHA),
|
||||
mult_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)?;
|
||||
|
@ -821,7 +826,8 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
|
||||
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||
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;
|
||||
// Adjust the quad draw to use the target bitmap.
|
||||
let mesh = &self.meshes[self.bitmap_quad_shape.0];
|
||||
|
@ -1019,8 +1025,8 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
);
|
||||
}
|
||||
DrawType::Bitmap(bitmap) => {
|
||||
let texture = if let Some(texture) = self.textures.get(bitmap.handle.0) {
|
||||
texture
|
||||
let texture = if let Some(entry) = self.bitmap_registry.get(&bitmap.handle) {
|
||||
&entry.texture_wrapper
|
||||
} else {
|
||||
// Bitmap not registered
|
||||
continue;
|
||||
|
@ -1168,7 +1174,7 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
}
|
||||
|
||||
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> {
|
||||
|
@ -1203,20 +1209,30 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
self.gl
|
||||
.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 height = bitmap.height();
|
||||
self.bitmap_registry.insert(handle, bitmap);
|
||||
|
||||
self.textures.push(Texture {
|
||||
width,
|
||||
height,
|
||||
texture,
|
||||
});
|
||||
self.bitmap_registry.insert(
|
||||
handle,
|
||||
RegistryData {
|
||||
bitmap,
|
||||
texture_wrapper: Texture {
|
||||
width,
|
||||
height,
|
||||
texture,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
fn unregister_bitmap(&mut self, bitmap: BitmapHandle) -> Result<(), Error> {
|
||||
self.bitmap_registry.remove(&bitmap);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_texture(
|
||||
&mut self,
|
||||
handle: BitmapHandle,
|
||||
|
@ -1224,8 +1240,8 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
height: u32,
|
||||
rgba: Vec<u8>,
|
||||
) -> Result<BitmapHandle, Error> {
|
||||
let texture = if let Some(texture) = self.textures.get(handle.0) {
|
||||
texture
|
||||
let texture = if let Some(entry) = self.bitmap_registry.get(&handle) {
|
||||
&entry.texture_wrapper
|
||||
} else {
|
||||
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"
|
||||
clap = { version = "3.2.2", features = ["derive"], optional = true }
|
||||
enum-map = "2.4.0"
|
||||
fnv = "1.0.7"
|
||||
|
||||
# desktop
|
||||
[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 bytemuck::{Pod, Zeroable};
|
||||
use enum_map::Enum;
|
||||
use fnv::FnvHashMap;
|
||||
use ruffle_core::backend::render::{
|
||||
Bitmap, BitmapHandle, BitmapSource, Color, RenderBackend, ShapeHandle, Transform,
|
||||
};
|
||||
|
@ -32,7 +33,6 @@ pub mod clap;
|
|||
use crate::bitmaps::BitmapSamplers;
|
||||
use crate::globals::Globals;
|
||||
use crate::uniform_buffer::UniformBuffer;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
pub use wgpu;
|
||||
|
||||
|
@ -149,12 +149,17 @@ pub struct WgpuRenderBackend<T: RenderTarget> {
|
|||
meshes: Vec<Mesh>,
|
||||
mask_state: MaskState,
|
||||
shape_tessellator: ShapeTessellator,
|
||||
textures: Vec<Texture>,
|
||||
num_masks: u32,
|
||||
quad_vbo: wgpu::Buffer,
|
||||
quad_ibo: 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)]
|
||||
|
@ -481,7 +486,6 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
|
|||
current_frame: None,
|
||||
meshes: Vec::new(),
|
||||
shape_tessellator: ShapeTessellator::new(),
|
||||
textures: Vec::new(),
|
||||
|
||||
num_masks: 0,
|
||||
mask_state: MaskState::NoMask,
|
||||
|
@ -489,7 +493,8 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
|
|||
quad_vbo,
|
||||
quad_ibo,
|
||||
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) => {
|
||||
let texture = self.textures.get(bitmap.bitmap.0).unwrap();
|
||||
let texture_view = texture.texture.create_view(&Default::default());
|
||||
let entry = self.bitmap_registry.get(&bitmap.bitmap).unwrap();
|
||||
let texture_view = entry
|
||||
.texture_wrapper
|
||||
.texture
|
||||
.create_view(&Default::default());
|
||||
|
||||
// TODO: Extract to function?
|
||||
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) {
|
||||
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 {
|
||||
frame.get()
|
||||
} else {
|
||||
|
@ -1320,7 +1329,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
}
|
||||
|
||||
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> {
|
||||
|
@ -1361,7 +1370,8 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
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 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(),
|
||||
});
|
||||
|
||||
self.bitmap_registry.insert(handle, bitmap);
|
||||
self.textures.push(Texture {
|
||||
width,
|
||||
height,
|
||||
texture,
|
||||
bind_group,
|
||||
});
|
||||
self.bitmap_registry.insert(
|
||||
handle,
|
||||
RegistryData {
|
||||
bitmap,
|
||||
texture_wrapper: Texture {
|
||||
width,
|
||||
height,
|
||||
texture,
|
||||
bind_group,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
fn unregister_bitmap(&mut self, handle: BitmapHandle) -> Result<(), Error> {
|
||||
self.bitmap_registry.remove(&handle);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_texture(
|
||||
&mut self,
|
||||
handle: BitmapHandle,
|
||||
|
@ -1409,8 +1429,8 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
height: u32,
|
||||
rgba: Vec<u8>,
|
||||
) -> Result<BitmapHandle, Error> {
|
||||
let texture = if let Some(texture) = self.textures.get(handle.0) {
|
||||
&texture.texture
|
||||
let texture = if let Some(entry) = self.bitmap_registry.get(&handle) {
|
||||
&entry.texture_wrapper.texture
|
||||
} else {
|
||||
return Err("update_texture: Bitmap not registered".into());
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue