@@ -52,6 +52,7 @@ use record::ApiRecordingReceiver;
52
52
use render_backend:: RenderBackend ;
53
53
use scene_builder:: { SceneBuilder , LowPrioritySceneBuilder } ;
54
54
use shade:: Shaders ;
55
+ use smallvec:: SmallVec ;
55
56
use render_task:: { RenderTask , RenderTaskKind , RenderTaskTree } ;
56
57
use resource_cache:: ResourceCache ;
57
58
use util:: drain_filter;
@@ -786,13 +787,38 @@ impl SourceTextureResolver {
786
787
assert ! ( self . saved_textures. is_empty( ) ) ;
787
788
}
788
789
789
- fn end_frame ( & mut self ) {
790
+ fn end_frame ( & mut self , device : & mut Device , frame_id : FrameId ) {
790
791
// return the cached targets to the pool
791
792
self . end_pass ( None , None ) ;
792
793
// return the global alpha texture
793
794
self . render_target_pool . extend ( self . shared_alpha_texture . take ( ) ) ;
794
795
// return the saved targets as well
795
796
self . render_target_pool . extend ( self . saved_textures . drain ( ..) ) ;
797
+
798
+ // GC the render target pool.
799
+ //
800
+ // We use a simple scheme whereby we drop any texture that hasn't been used
801
+ // in the last 30 frames. This should generally prevent any sustained build-
802
+ // up of unused textures, unless we don't generate frames for a long period.
803
+ // This can happen when the window is minimized, and we probably want to
804
+ // flush all the WebRender caches in that case [1].
805
+ //
806
+ // [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1494099
807
+ self . retain_targets ( device, |texture| texture. used_recently ( frame_id, 30 ) ) ;
808
+ }
809
+
810
+ /// Drops all targets from the render target pool that do not satisfy the predicate.
811
+ pub fn retain_targets < F : Fn ( & Texture ) -> bool > ( & mut self , device : & mut Device , f : F ) {
812
+ // We can't just use retain() because `Texture` requires manual cleanup.
813
+ let mut tmp = SmallVec :: < [ Texture ; 8 ] > :: new ( ) ;
814
+ for target in self . render_target_pool . drain ( ..) {
815
+ if f ( & target) {
816
+ tmp. push ( target) ;
817
+ } else {
818
+ device. delete_texture ( target) ;
819
+ }
820
+ }
821
+ self . render_target_pool . extend ( tmp) ;
796
822
}
797
823
798
824
fn end_pass (
@@ -1985,17 +2011,27 @@ impl Renderer {
1985
2011
}
1986
2012
ResultMsg :: UpdateResources {
1987
2013
updates,
1988
- cancel_rendering ,
2014
+ memory_pressure ,
1989
2015
} => {
1990
2016
self . pending_texture_updates . push ( updates) ;
1991
2017
self . device . begin_frame ( ) ;
1992
2018
self . update_texture_cache ( ) ;
2019
+
2020
+ // Flush the render target pool on memory pressure.
2021
+ //
2022
+ // This needs to be separate from the block below because
2023
+ // the device module asserts if we delete textures while
2024
+ // not in a frame.
2025
+ if memory_pressure {
2026
+ self . texture_resolver . retain_targets ( & mut self . device , |_| false ) ;
2027
+ }
2028
+
1993
2029
self . device . end_frame ( ) ;
1994
2030
// If we receive a `PublishDocument` message followed by this one
1995
2031
// within the same update we need to cancel the frame because we
1996
2032
// might have deleted the resources in use in the frame due to a
1997
2033
// memory pressure event.
1998
- if cancel_rendering {
2034
+ if memory_pressure {
1999
2035
self . active_documents . clear ( ) ;
2000
2036
}
2001
2037
}
@@ -3884,7 +3920,7 @@ impl Renderer {
3884
3920
) ;
3885
3921
}
3886
3922
3887
- self . texture_resolver . end_frame ( ) ;
3923
+ self . texture_resolver . end_frame ( & mut self . device , frame_id ) ;
3888
3924
3889
3925
#[ cfg( feature = "debug_renderer" ) ]
3890
3926
{
0 commit comments