Skip to content

Commit cce3bc2

Browse files
committed
Basic eviction for render target textures.
1 parent d8f85be commit cce3bc2

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed

webrender/src/device/gl.rs

+6
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,12 @@ impl Texture {
487487
self.last_frame_used == frame_id
488488
}
489489

490+
/// Returns true if this texture was used within `threshold` frames of
491+
/// the current frame.
492+
pub fn used_recently(&self, current_frame_id: FrameId, threshold: usize) -> bool {
493+
self.last_frame_used + threshold >= current_frame_id
494+
}
495+
490496
/// Returns the number of bytes (generally in GPU memory) that this texture
491497
/// consumes.
492498
pub fn size_in_bytes(&self) -> usize {

webrender/src/internal_types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ pub enum ResultMsg {
151151
UpdateGpuCache(GpuCacheUpdateList),
152152
UpdateResources {
153153
updates: TextureUpdateList,
154-
cancel_rendering: bool,
154+
memory_pressure: bool,
155155
},
156156
PublishPipelineInfo(PipelineInfo),
157157
PublishDocument(

webrender/src/render_backend.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ impl RenderBackend {
747747
let pending_update = self.resource_cache.pending_updates();
748748
let msg = ResultMsg::UpdateResources {
749749
updates: pending_update,
750-
cancel_rendering: true,
750+
memory_pressure: true,
751751
};
752752
self.result_tx.send(msg).unwrap();
753753
self.notifier.wake_up();
@@ -1340,7 +1340,7 @@ impl RenderBackend {
13401340
self.result_tx.send(msg_update_gpu_cache).unwrap();
13411341
let msg_update_resources = ResultMsg::UpdateResources {
13421342
updates: self.resource_cache.pending_updates(),
1343-
cancel_rendering: false,
1343+
memory_pressure: false,
13441344
};
13451345
self.result_tx.send(msg_update_resources).unwrap();
13461346
// Save the texture/glyph/image caches.

webrender/src/renderer.rs

+40-4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use record::ApiRecordingReceiver;
5252
use render_backend::RenderBackend;
5353
use scene_builder::{SceneBuilder, LowPrioritySceneBuilder};
5454
use shade::Shaders;
55+
use smallvec::SmallVec;
5556
use render_task::{RenderTask, RenderTaskKind, RenderTaskTree};
5657
use resource_cache::ResourceCache;
5758
use util::drain_filter;
@@ -786,13 +787,38 @@ impl SourceTextureResolver {
786787
assert!(self.saved_textures.is_empty());
787788
}
788789

789-
fn end_frame(&mut self) {
790+
fn end_frame(&mut self, device: &mut Device, frame_id: FrameId) {
790791
// return the cached targets to the pool
791792
self.end_pass(None, None);
792793
// return the global alpha texture
793794
self.render_target_pool.extend(self.shared_alpha_texture.take());
794795
// return the saved targets as well
795796
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);
796822
}
797823

798824
fn end_pass(
@@ -1985,17 +2011,27 @@ impl Renderer {
19852011
}
19862012
ResultMsg::UpdateResources {
19872013
updates,
1988-
cancel_rendering,
2014+
memory_pressure,
19892015
} => {
19902016
self.pending_texture_updates.push(updates);
19912017
self.device.begin_frame();
19922018
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+
19932029
self.device.end_frame();
19942030
// If we receive a `PublishDocument` message followed by this one
19952031
// within the same update we need to cancel the frame because we
19962032
// might have deleted the resources in use in the frame due to a
19972033
// memory pressure event.
1998-
if cancel_rendering {
2034+
if memory_pressure {
19992035
self.active_documents.clear();
20002036
}
20012037
}
@@ -3884,7 +3920,7 @@ impl Renderer {
38843920
);
38853921
}
38863922

3887-
self.texture_resolver.end_frame();
3923+
self.texture_resolver.end_frame(&mut self.device, frame_id);
38883924

38893925
#[cfg(feature = "debug_renderer")]
38903926
{

0 commit comments

Comments
 (0)