Skip to content

Commit cddf354

Browse files
committed
core: Put Character::Bitmap's data behind a Gc
This adds a new `BitmapCharacter` struct to hold the data as fields
1 parent 4727fc6 commit cddf354

File tree

6 files changed

+112
-102
lines changed

6 files changed

+112
-102
lines changed

core/src/avm1/globals/bitmap_data.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,10 +1538,10 @@ fn load_bitmap<'gc>(
15381538
.library_for_movie(movie)
15391539
.and_then(|l| l.character_by_export_name(name));
15401540

1541-
let Some((_id, Character::Bitmap { compressed, .. })) = character else {
1541+
let Some((_id, Character::Bitmap(bitmap))) = character else {
15421542
return Ok(Value::Undefined);
15431543
};
1544-
let bitmap = compressed.decode().unwrap();
1544+
let bitmap = bitmap.compressed().decode().unwrap();
15451545

15461546
let transparency = true;
15471547
let bitmap_data = BitmapData::new_with_pixels(

core/src/avm2/globals/flash/display/bitmap.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,14 @@ pub fn bitmap_allocator<'gc>(
4444
.avm2_class_registry()
4545
.class_symbol(class)
4646
{
47-
if let Some(Character::Bitmap {
48-
compressed,
49-
avm2_bitmapdata_class: _,
50-
handle: _,
51-
}) = activation
47+
if let Some(Character::Bitmap(bitmap)) = activation
5248
.context
5349
.library
5450
.library_for_movie_mut(movie)
5551
.character_by_id(symbol)
5652
.cloned()
5753
{
58-
let new_bitmap_data = fill_bitmap_data_from_symbol(activation, &compressed);
54+
let new_bitmap_data = fill_bitmap_data_from_symbol(activation, bitmap.compressed());
5955
let bitmap_data_obj = BitmapDataObject::from_bitmap_data_internal(
6056
activation,
6157
BitmapDataWrapper::dummy(activation.gc()),

core/src/avm2/globals/flash/display/bitmap_data.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,9 @@ pub fn init<'gc>(
114114
.cloned()
115115
});
116116

117-
let new_bitmap_data = if let Some(Character::Bitmap {
118-
compressed,
119-
avm2_bitmapdata_class: _,
120-
handle: _,
121-
}) = character
122-
{
117+
let new_bitmap_data = if let Some(Character::Bitmap(bitmap)) = character {
123118
// Instantiating BitmapData from an Animate-style bitmap asset
124-
fill_bitmap_data_from_symbol(activation, &compressed)
119+
fill_bitmap_data_from_symbol(activation, bitmap.compressed())
125120
} else {
126121
if character.is_some() {
127122
//TODO: Determine if mismatched symbols will still work as a

core/src/character.rs

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ use crate::display_object::{
66
Avm1Button, Avm2Button, BitmapClass, EditText, Graphic, MorphShape, MovieClip, Text, Video,
77
};
88
use crate::font::Font;
9-
use gc_arena::{Collect, Gc, GcCell};
10-
use ruffle_render::bitmap::{BitmapHandle, BitmapSize};
9+
use gc_arena::barrier::unlock;
10+
use gc_arena::lock::Lock;
11+
use gc_arena::{Collect, Gc, Mutation};
12+
use ruffle_render::backend::RenderBackend;
13+
use ruffle_render::bitmap::{Bitmap as RenderBitmap, BitmapHandle, BitmapSize};
14+
use ruffle_render::error::Error as RenderError;
1115
use swf::DefineBitsLossless;
1216

1317
#[derive(Clone, Collect, Debug)]
@@ -16,16 +20,7 @@ pub enum Character<'gc> {
1620
EditText(EditText<'gc>),
1721
Graphic(Graphic<'gc>),
1822
MovieClip(MovieClip<'gc>),
19-
Bitmap {
20-
#[collect(require_static)]
21-
compressed: CompressedBitmap,
22-
/// A lazily constructed GPU handle, used when performing fills with this bitmap
23-
#[collect(require_static)]
24-
handle: OnceCell<BitmapHandle>,
25-
/// The bitmap class set by `SymbolClass` - this is used when we instantaite
26-
/// a `Bitmap` displayobject.
27-
avm2_bitmapdata_class: GcCell<'gc, BitmapClass<'gc>>,
28-
},
23+
Bitmap(Gc<'gc, BitmapCharacter<'gc>>),
2924
Avm1Button(Avm1Button<'gc>),
3025
Avm2Button(Avm2Button<'gc>),
3126
Font(Font<'gc>),
@@ -36,6 +31,56 @@ pub enum Character<'gc> {
3631
BinaryData(Gc<'gc, BinaryData>),
3732
}
3833

34+
#[derive(Collect, Debug)]
35+
#[collect(no_drop)]
36+
pub struct BitmapCharacter<'gc> {
37+
#[collect(require_static)]
38+
compressed: CompressedBitmap,
39+
/// A lazily constructed GPU handle, used when performing fills with this bitmap
40+
#[collect(require_static)]
41+
handle: OnceCell<BitmapHandle>,
42+
/// The bitmap class set by `SymbolClass` - this is used when we instantaite
43+
/// a `Bitmap` displayobject.
44+
avm2_class: Lock<BitmapClass<'gc>>,
45+
}
46+
47+
impl<'gc> BitmapCharacter<'gc> {
48+
pub fn new(compressed: CompressedBitmap) -> Self {
49+
Self {
50+
compressed,
51+
handle: OnceCell::default(),
52+
avm2_class: Lock::new(BitmapClass::NoSubclass),
53+
}
54+
}
55+
56+
pub fn compressed(&self) -> &CompressedBitmap {
57+
&self.compressed
58+
}
59+
60+
pub fn avm2_class(&self) -> BitmapClass<'gc> {
61+
self.avm2_class.get()
62+
}
63+
64+
pub fn set_avm2_class(this: Gc<'gc, Self>, bitmap_class: BitmapClass<'gc>, mc: &Mutation<'gc>) {
65+
unlock!(Gc::write(mc, this), Self, avm2_class).set(bitmap_class);
66+
}
67+
68+
pub fn bitmap_handle(
69+
&self,
70+
backend: &mut dyn RenderBackend,
71+
) -> Result<BitmapHandle, RenderError> {
72+
// FIXME - use `OnceCell::get_or_try_init` when stabilized.
73+
if let Some(handle) = self.handle.get() {
74+
return Ok(handle.clone());
75+
}
76+
let decoded = self.compressed.decode()?;
77+
let new_handle = backend.register_bitmap(decoded)?;
78+
// FIXME - do we ever want to release this handle, to avoid taking up GPU memory?
79+
self.handle.set(new_handle.clone()).unwrap();
80+
Ok(new_handle)
81+
}
82+
}
83+
3984
/// Holds a bitmap from an SWF tag, plus the decoded width/height.
4085
/// We avoid decompressing the image until it's actually needed - some pathological SWFS
4186
/// like 'House' have thousands of highly-compressed (mostly empty) bitmaps, which can
@@ -64,7 +109,7 @@ impl CompressedBitmap {
64109
},
65110
}
66111
}
67-
pub fn decode(&self) -> Result<ruffle_render::bitmap::Bitmap, ruffle_render::error::Error> {
112+
pub fn decode(&self) -> Result<RenderBitmap, RenderError> {
68113
match self {
69114
CompressedBitmap::Jpeg {
70115
data,

core/src/display_object/movie_clip.rs

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::backend::audio::{AudioManager, SoundInstanceHandle};
1414
use crate::backend::navigator::Request;
1515
use crate::backend::ui::MouseCursor;
1616
use crate::binary_data::BinaryData;
17-
use crate::character::{Character, CompressedBitmap};
17+
use crate::character::{BitmapCharacter, Character, CompressedBitmap};
1818
use crate::context::{ActionType, RenderContext, UpdateContext};
1919
use crate::display_object::container::{dispatch_removed_event, ChildContainer};
2020
use crate::display_object::interactive::{
@@ -41,7 +41,7 @@ use bitflags::bitflags;
4141
use core::fmt;
4242
use gc_arena::barrier::unlock;
4343
use gc_arena::lock::{Lock, RefLock};
44-
use gc_arena::{Collect, Gc, GcCell, GcWeak, Mutation};
44+
use gc_arena::{Collect, Gc, GcWeak, Mutation};
4545
use ruffle_macros::istr;
4646
use ruffle_render::perspective_projection::PerspectiveProjection;
4747
use smallvec::SmallVec;
@@ -3167,20 +3167,19 @@ impl<'gc, 'a> MovieClipShared<'gc> {
31673167
version: u8,
31683168
) -> Result<(), Error> {
31693169
let define_bits_lossless = reader.read_define_bits_lossless(version)?;
3170-
let bitmap = Character::Bitmap {
3171-
compressed: CompressedBitmap::Lossless(DefineBitsLossless {
3170+
let bitmap = Gc::new(
3171+
context.gc(),
3172+
BitmapCharacter::new(CompressedBitmap::Lossless(DefineBitsLossless {
31723173
id: define_bits_lossless.id,
31733174
format: define_bits_lossless.format,
31743175
width: define_bits_lossless.width,
31753176
height: define_bits_lossless.height,
31763177
version: define_bits_lossless.version,
31773178
data: Cow::Owned(define_bits_lossless.data.into_owned()),
3178-
}),
3179-
handle: Default::default(),
3180-
avm2_bitmapdata_class: GcCell::new(context.gc(), BitmapClass::NoSubclass),
3181-
};
3179+
})),
3180+
);
31823181
self.library_mut(context)
3183-
.register_character(define_bits_lossless.id, bitmap);
3182+
.register_character(define_bits_lossless.id, Character::Bitmap(bitmap));
31843183
Ok(())
31853184
}
31863185

@@ -3298,19 +3297,16 @@ impl<'gc, 'a> MovieClipShared<'gc> {
32983297
let jpeg_data =
32993298
ruffle_render::utils::glue_tables_to_jpeg(jpeg_data, jpeg_tables).into_owned();
33003299
let (width, height) = ruffle_render::utils::decode_define_bits_jpeg_dimensions(&jpeg_data)?;
3301-
library.register_character(
3302-
id,
3303-
Character::Bitmap {
3304-
compressed: CompressedBitmap::Jpeg {
3305-
data: jpeg_data,
3306-
alpha: None,
3307-
width,
3308-
height,
3309-
},
3310-
handle: Default::default(),
3311-
avm2_bitmapdata_class: GcCell::new(mc, BitmapClass::NoSubclass),
3312-
},
3313-
);
3300+
let bitmap = Character::Bitmap(Gc::new(
3301+
mc,
3302+
BitmapCharacter::new(CompressedBitmap::Jpeg {
3303+
data: jpeg_data,
3304+
alpha: None,
3305+
width,
3306+
height,
3307+
}),
3308+
));
3309+
library.register_character(id, bitmap);
33143310
Ok(())
33153311
}
33163312

@@ -3322,16 +3318,15 @@ impl<'gc, 'a> MovieClipShared<'gc> {
33223318
) -> Result<(), Error> {
33233319
let (id, jpeg_data) = reader.read_define_bits_jpeg_2()?;
33243320
let (width, height) = ruffle_render::utils::decode_define_bits_jpeg_dimensions(jpeg_data)?;
3325-
let bitmap = Character::Bitmap {
3326-
compressed: CompressedBitmap::Jpeg {
3321+
let bitmap = Character::Bitmap(Gc::new(
3322+
context.gc(),
3323+
BitmapCharacter::new(CompressedBitmap::Jpeg {
33273324
data: jpeg_data.to_owned(),
33283325
alpha: None,
33293326
width,
33303327
height,
3331-
},
3332-
handle: Default::default(),
3333-
avm2_bitmapdata_class: GcCell::new(context.gc(), BitmapClass::NoSubclass),
3334-
};
3328+
}),
3329+
));
33353330
self.library_mut(context).register_character(id, bitmap);
33363331
Ok(())
33373332
}
@@ -3345,16 +3340,16 @@ impl<'gc, 'a> MovieClipShared<'gc> {
33453340
) -> Result<(), Error> {
33463341
let jpeg = reader.read_define_bits_jpeg_3(version)?;
33473342
let (width, height) = ruffle_render::utils::decode_define_bits_jpeg_dimensions(jpeg.data)?;
3348-
let bitmap = Character::Bitmap {
3349-
compressed: CompressedBitmap::Jpeg {
3343+
3344+
let bitmap = Character::Bitmap(Gc::new(
3345+
context.gc(),
3346+
BitmapCharacter::new(CompressedBitmap::Jpeg {
33503347
data: jpeg.data.to_owned(),
33513348
alpha: Some(jpeg.alpha_data.to_owned()),
33523349
width,
33533350
height,
3354-
},
3355-
handle: Default::default(),
3356-
avm2_bitmapdata_class: GcCell::new(context.gc(), BitmapClass::NoSubclass),
3357-
};
3351+
}),
3352+
));
33583353
self.library_mut(context)
33593354
.register_character(jpeg.id, bitmap);
33603355
Ok(())
@@ -4136,15 +4131,16 @@ impl<'gc, 'a> MovieClip<'gc> {
41364131
.library
41374132
.library_for_movie_mut(movie.clone());
41384133

4139-
let Some(Character::Bitmap {
4140-
avm2_bitmapdata_class,
4141-
..
4142-
}) = library.character_by_id(id)
4134+
let Some(&Character::Bitmap(bitmap)) =
4135+
library.character_by_id(id)
41434136
else {
41444137
unreachable!();
41454138
};
4146-
*avm2_bitmapdata_class.write(activation.context.gc_context) =
4147-
bitmap_class;
4139+
BitmapCharacter::set_avm2_class(
4140+
bitmap,
4141+
bitmap_class,
4142+
activation.gc(),
4143+
);
41484144
} else {
41494145
tracing::error!("Associated class {:?} for symbol {} must extend flash.display.Bitmap or BitmapData, does neither", class_object.inner_class_definition().name(), id);
41504146
}

core/src/library.rs

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,11 @@ impl<'gc> MovieLibrary<'gc> {
253253
mc: &Mutation<'gc>,
254254
) -> Option<DisplayObject<'gc>> {
255255
match character {
256-
Character::Bitmap {
257-
compressed,
258-
avm2_bitmapdata_class,
259-
handle: _,
260-
} => {
261-
let bitmap = compressed.decode().unwrap();
256+
Character::Bitmap(bitmap) => {
257+
let avm2_class = bitmap.avm2_class();
258+
let bitmap = bitmap.compressed().decode().unwrap();
262259
let bitmap = Bitmap::new(mc, id, bitmap, self.swf.clone());
263-
bitmap.set_avm2_bitmapdata_class(mc, *avm2_bitmapdata_class.read());
260+
bitmap.set_avm2_bitmapdata_class(mc, avm2_class);
264261
Some(bitmap.instantiate(mc))
265262
}
266263
Character::EditText(edit_text) => Some(edit_text.instantiate(mc)),
@@ -373,44 +370,25 @@ pub struct MovieLibrarySource<'a, 'gc> {
373370

374371
impl ruffle_render::bitmap::BitmapSource for MovieLibrarySource<'_, '_> {
375372
fn bitmap_size(&self, id: u16) -> Option<ruffle_render::bitmap::BitmapSize> {
376-
if let Some(Character::Bitmap { compressed, .. }) = self.library.characters.get(&id) {
377-
Some(compressed.size())
373+
if let Some(Character::Bitmap(bitmap)) = self.library.characters.get(&id) {
374+
Some(bitmap.compressed().size())
378375
} else {
379376
None
380377
}
381378
}
382379

383380
fn bitmap_handle(&self, id: u16, backend: &mut dyn RenderBackend) -> Option<BitmapHandle> {
384-
let Some(Character::Bitmap {
385-
compressed,
386-
handle,
387-
avm2_bitmapdata_class: _,
388-
}) = self.library.characters.get(&id)
389-
else {
381+
let Some(Character::Bitmap(bitmap)) = self.library.characters.get(&id) else {
390382
return None;
391383
};
392384

393-
// FIXME - use `OnceCell::get_or_try_init` when stabilized.
394-
if let Some(handle) = handle.get() {
395-
return Some(handle.clone());
396-
}
397-
let decoded = match compressed.decode() {
398-
Ok(decoded) => decoded,
399-
Err(e) => {
400-
tracing::error!("Failed to decode bitmap character {id:?}: {e:?}");
401-
return None;
402-
}
403-
};
404-
let new_handle = match backend.register_bitmap(decoded) {
405-
Ok(handle) => handle,
385+
match bitmap.bitmap_handle(backend) {
386+
Ok(handle) => Some(handle),
406387
Err(e) => {
407-
tracing::error!("Failed to register bitmap character {id:?}: {e:?}");
408-
return None;
388+
tracing::error!("Failed to register bitmap character {id}: {e}");
389+
None
409390
}
410-
};
411-
// FIXME - do we ever want to release this handle, to avoid taking up GPU memory?
412-
handle.set(new_handle.clone()).unwrap();
413-
Some(new_handle)
391+
}
414392
}
415393
}
416394

0 commit comments

Comments
 (0)