Skip to content

Commit 43e8d85

Browse files
author
bors-servo
authored
Auto merge of #3124 - bholley:texture_memory, r=gw3583
Add memory reporters and eviction for cached textures Reviewed by Glenn in https://bugzilla.mozilla.org/show_bug.cgi?id=1493196 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/3124) <!-- Reviewable:end -->
2 parents 8ef886d + cce3bc2 commit 43e8d85

File tree

5 files changed

+104
-7
lines changed

5 files changed

+104
-7
lines changed

webrender/src/device/gl.rs

+17
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,23 @@ 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+
496+
/// Returns the number of bytes (generally in GPU memory) that this texture
497+
/// consumes.
498+
pub fn size_in_bytes(&self) -> usize {
499+
assert!(self.layer_count > 0 || self.width + self.height == 0);
500+
let bpp = self.format.bytes_per_pixel() as usize;
501+
let w = self.width as usize;
502+
let h = self.height as usize;
503+
let count = self.layer_count as usize;
504+
bpp * w * h * count
505+
}
506+
490507
#[cfg(feature = "replay")]
491508
pub fn into_external(mut self) -> ExternalTexture {
492509
let ext = ExternalTexture {

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

+70-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(
@@ -896,6 +922,21 @@ impl SourceTextureResolver {
896922
}
897923
}
898924
}
925+
926+
fn report_memory(&self) -> MemoryReport {
927+
let mut report = MemoryReport::default();
928+
929+
// We're reporting GPU memory rather than heap-allocations, so we don't
930+
// use size_of_op.
931+
for t in self.cache_texture_map.iter() {
932+
report.texture_cache_textures += t.size_in_bytes();
933+
}
934+
for t in self.render_target_pool.iter() {
935+
report.render_target_textures += t.size_in_bytes();
936+
}
937+
938+
report
939+
}
899940
}
900941

901942
#[derive(Debug, Copy, Clone, PartialEq)]
@@ -1970,17 +2011,27 @@ impl Renderer {
19702011
}
19712012
ResultMsg::UpdateResources {
19722013
updates,
1973-
cancel_rendering,
2014+
memory_pressure,
19742015
} => {
19752016
self.pending_texture_updates.push(updates);
19762017
self.device.begin_frame();
19772018
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+
19782029
self.device.end_frame();
19792030
// If we receive a `PublishDocument` message followed by this one
19802031
// within the same update we need to cancel the frame because we
19812032
// might have deleted the resources in use in the frame due to a
19822033
// memory pressure event.
1983-
if cancel_rendering {
2034+
if memory_pressure {
19842035
self.active_documents.clear();
19852036
}
19862037
}
@@ -3869,7 +3920,7 @@ impl Renderer {
38693920
);
38703921
}
38713922

3872-
self.texture_resolver.end_frame();
3923+
self.texture_resolver.end_frame(&mut self.device, frame_id);
38733924

38743925
#[cfg(feature = "debug_renderer")]
38753926
{
@@ -4176,15 +4227,30 @@ impl Renderer {
41764227
/// Collects a memory report.
41774228
pub fn report_memory(&self) -> MemoryReport {
41784229
let mut report = MemoryReport::default();
4230+
4231+
// GPU cache CPU memory.
41794232
if let CacheBus::PixelBuffer{ref cpu_blocks, ..} = self.gpu_cache_texture.bus {
41804233
report.gpu_cache_cpu_mirror += self.size_of(cpu_blocks.as_ptr());
41814234
}
41824235

4236+
// GPU cache GPU memory.
4237+
report.gpu_cache_textures += self.gpu_cache_texture.texture.size_in_bytes();
4238+
4239+
// Render task CPU memory.
41834240
for (_id, doc) in &self.active_documents {
41844241
report.render_tasks += self.size_of(doc.frame.render_tasks.tasks.as_ptr());
41854242
report.render_tasks += self.size_of(doc.frame.render_tasks.task_data.as_ptr());
41864243
}
41874244

4245+
// Vertex data GPU memory.
4246+
report.vertex_data_textures += self.prim_header_f_texture.texture.size_in_bytes();
4247+
report.vertex_data_textures += self.prim_header_i_texture.texture.size_in_bytes();
4248+
report.vertex_data_textures += self.transforms_texture.texture.size_in_bytes();
4249+
report.vertex_data_textures += self.render_task_texture.texture.size_in_bytes();
4250+
4251+
// Texture cache and render target GPU memory.
4252+
report += self.texture_resolver.report_memory();
4253+
41884254
report
41894255
}
41904256

webrender_api/src/api.rs

+14
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,9 @@ impl PipelineId {
751751
#[repr(C)]
752752
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
753753
pub struct MemoryReport {
754+
//
755+
// CPU Memory.
756+
//
754757
pub primitive_stores: usize,
755758
pub clip_stores: usize,
756759
pub gpu_cache_metadata: usize,
@@ -760,6 +763,13 @@ pub struct MemoryReport {
760763
pub fonts: usize,
761764
pub images: usize,
762765
pub rasterized_blobs: usize,
766+
//
767+
// GPU memory.
768+
//
769+
pub gpu_cache_textures: usize,
770+
pub vertex_data_textures: usize,
771+
pub render_target_textures: usize,
772+
pub texture_cache_textures: usize,
763773
}
764774

765775
impl ::std::ops::AddAssign for MemoryReport {
@@ -773,6 +783,10 @@ impl ::std::ops::AddAssign for MemoryReport {
773783
self.fonts += other.fonts;
774784
self.images += other.images;
775785
self.rasterized_blobs += other.rasterized_blobs;
786+
self.gpu_cache_textures += other.gpu_cache_textures;
787+
self.vertex_data_textures += other.vertex_data_textures;
788+
self.render_target_textures += other.render_target_textures;
789+
self.texture_cache_textures += other.texture_cache_textures;
776790
}
777791
}
778792

0 commit comments

Comments
 (0)