@@ -8,6 +8,17 @@ use ruffle_render::backend::RenderBackend;
88use ruffle_render:: bitmap:: {
99 Bitmap , BitmapFormat , BitmapHandle , PixelRegion , PixelSnapping , SyncHandle ,
1010} ;
11+ use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
12+
13+ static BITMAP_MEMORY_BYTES : AtomicUsize = AtomicUsize :: new ( 0 ) ;
14+
15+ /// Returns the current total bitmap memory in kilobytes,
16+ /// including both CPU-side BitmapData pixels and GPU-registered character bitmaps.
17+ pub fn bitmap_memory_kb ( ) -> i32 {
18+ let cpu_bytes = BITMAP_MEMORY_BYTES . load ( Ordering :: Relaxed ) ;
19+ let gpu_bytes = crate :: character:: registered_bitmap_memory_kb ( ) as usize * 1024 ;
20+ ( ( cpu_bytes + gpu_bytes) / 1024 ) as i32
21+ }
1122use ruffle_wstr:: WStr ;
1223use std:: cell:: Ref ;
1324use std:: fmt:: Debug ;
@@ -417,6 +428,7 @@ pub enum DirtyState {
417428}
418429
419430mod wrapper {
431+ use super :: BITMAP_MEMORY_BYTES ;
420432 use crate :: avm2:: object:: BitmapDataObject ;
421433 use crate :: context:: RenderContext ;
422434 use crate :: display_object:: DisplayObjectWeak ;
@@ -427,6 +439,7 @@ mod wrapper {
427439 use ruffle_render:: bitmap:: { BitmapHandle , PixelRegion , PixelSnapping } ;
428440 use ruffle_render:: commands:: CommandHandler ;
429441 use std:: cell:: Ref ;
442+ use std:: sync:: atomic:: Ordering ;
430443
431444 use super :: { BitmapRawData , DirtyState , copy_pixels_to_bitmapdata} ;
432445
@@ -494,9 +507,11 @@ mod wrapper {
494507 /// Clones the underlying data, producing a new `BitmapData`
495508 /// that has no GPU texture or associated display objects
496509 pub fn clone_data ( & self , renderer : & mut dyn RenderBackend ) -> BitmapRawData < ' gc > {
497- // Sync from the GPU to CPU, since our new BitmapData starts out
498- // with no GPU texture
499510 let data = self . sync ( renderer) . borrow ( ) ;
511+ BITMAP_MEMORY_BYTES . fetch_add (
512+ BitmapRawData :: pixel_byte_size ( data. width , data. height ) ,
513+ Ordering :: Relaxed ,
514+ ) ;
500515 BitmapRawData {
501516 pixels : data. pixels . clone ( ) ,
502517 width : data. width ,
@@ -506,7 +521,6 @@ mod wrapper {
506521 bitmap_handle : None ,
507522 avm2_object : None ,
508523 display_objects : vec ! [ ] ,
509- // We have no GPU texture, so there's no need to mark as dirty
510524 dirty_state : DirtyState :: Clean ,
511525 #[ cfg( feature = "egui" ) ]
512526 egui_texture : Default :: default ( ) ,
@@ -728,7 +742,12 @@ impl std::fmt::Debug for BitmapRawData<'_> {
728742}
729743
730744impl < ' gc > BitmapRawData < ' gc > {
745+ fn pixel_byte_size ( width : u32 , height : u32 ) -> usize {
746+ width as usize * height as usize * std:: mem:: size_of :: < Color > ( )
747+ }
748+
731749 pub fn new ( width : u32 , height : u32 , transparency : bool , fill_color : u32 ) -> Self {
750+ BITMAP_MEMORY_BYTES . fetch_add ( Self :: pixel_byte_size ( width, height) , Ordering :: Relaxed ) ;
732751 Self {
733752 pixels : vec ! [
734753 Color :: bgra_u32( fill_color) . to_premultiplied_alpha( transparency) ;
@@ -753,6 +772,7 @@ impl<'gc> BitmapRawData<'gc> {
753772 transparency : bool ,
754773 pixels : Vec < Color > ,
755774 ) -> Self {
775+ BITMAP_MEMORY_BYTES . fetch_add ( Self :: pixel_byte_size ( width, height) , Ordering :: Relaxed ) ;
756776 Self {
757777 pixels,
758778 width,
@@ -773,11 +793,14 @@ impl<'gc> BitmapRawData<'gc> {
773793 }
774794
775795 pub fn dispose ( & mut self ) {
796+ BITMAP_MEMORY_BYTES . fetch_sub (
797+ Self :: pixel_byte_size ( self . width , self . height ) ,
798+ Ordering :: Relaxed ,
799+ ) ;
776800 self . width = 0 ;
777801 self . height = 0 ;
778- self . pixels = Vec :: new ( ) ; // free the CPU pixel buffer
802+ self . pixels = Vec :: new ( ) ;
779803 self . bitmap_handle = None ;
780- // There's no longer a handle to update
781804 self . dirty_state = DirtyState :: Clean ;
782805 self . disposed = true ;
783806 }
0 commit comments