Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions webrender/src/frame_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ impl FrameBuilder {
.set(self.prim_store.prim_count());

resource_cache.begin_frame(stamp);
gpu_cache.begin_frame(stamp.frame_id());
gpu_cache.begin_frame(stamp);

let mut transform_palette = TransformPalette::new();
clip_scroll_tree.update_tree(
Expand Down Expand Up @@ -492,11 +492,11 @@ impl FrameBuilder {
}
}

let gpu_cache_frame_id = gpu_cache.end_frame(gpu_cache_profile);
let gpu_cache_frame_id = gpu_cache.end_frame(gpu_cache_profile).frame_id();

render_tasks.write_task_data(device_pixel_scale);

resource_cache.end_frame();
resource_cache.end_frame(texture_cache_profile);

Frame {
window_size: self.window_size,
Expand Down
2 changes: 1 addition & 1 deletion webrender/src/glyph_rasterizer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ mod test_glyph_rasterizer {
let workers = Arc::new(worker.unwrap());
let mut glyph_rasterizer = GlyphRasterizer::new(workers).unwrap();
let mut glyph_cache = GlyphCache::new();
let mut gpu_cache = GpuCache::new();
let mut gpu_cache = GpuCache::new_for_testing();
let mut texture_cache = TextureCache::new_for_testing(2048, 1024);
let mut render_task_cache = RenderTaskCache::new();
let mut render_task_tree = RenderTaskTree::new(FrameId::INVALID);
Expand Down
83 changes: 53 additions & 30 deletions webrender/src/gpu_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@
//! address in the GPU cache of a given resource slot
//! for this frame.

use api::{DebugFlags, PremultipliedColorF, TexelRect};
use api::{DebugFlags, DocumentId, PremultipliedColorF, IdNamespace, TexelRect};
use api::{VoidPtrToSizeFn};
use euclid::TypedRect;
use internal_types::{FastHashMap};
use profiler::GpuCacheProfileCounters;
use render_backend::FrameId;
use render_backend::{FrameStamp, FrameId};
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
use std::{mem, u16, u32};
use std::num::NonZeroU32;
Expand Down Expand Up @@ -411,7 +412,7 @@ struct Texture {
// Linked list of currently occupied blocks. This
// makes it faster to iterate blocks looking for
// candidates to be evicted from the cache.
occupied_list_head: Option<BlockIndex>,
occupied_list_heads: FastHashMap<DocumentId, BlockIndex>,
// Pending blocks that have been written this frame
// and will need to be sent to the GPU.
pending_blocks: Vec<GpuBlockData>,
Expand Down Expand Up @@ -447,7 +448,7 @@ impl Texture {
free_lists: FreeBlockLists::new(),
pending_blocks: Vec::new(),
updates: Vec::new(),
occupied_list_head: None,
occupied_list_heads: FastHashMap::default(),
allocated_block_count: 0,
reached_reclaim_threshold: None,
debug_commands: Vec::new(),
Expand All @@ -474,8 +475,9 @@ impl Texture {
&mut self,
pending_block_index: Option<usize>,
block_count: usize,
frame_id: FrameId,
frame_stamp: FrameStamp
) -> CacheLocation {
debug_assert!(frame_stamp.is_valid());
// Find the appropriate free list to use based on the block size.
let (alloc_size, free_list) = self.free_lists
.get_actual_block_count_and_free_list(block_count);
Expand All @@ -498,7 +500,7 @@ impl Texture {
for i in 0 .. items_per_row {
let address = GpuCacheAddress::new(i * alloc_size, row_index);
let block_index = BlockIndex::new(self.blocks.len());
let block = Block::new(address, prev_block_index, frame_id, self.base_epoch);
let block = Block::new(address, prev_block_index, frame_stamp.frame_id(), self.base_epoch);
self.blocks.push(block);
prev_block_index = Some(block_index);
}
Expand All @@ -514,9 +516,9 @@ impl Texture {
*free_list = block.next;

// Add the block to the occupied linked list.
block.next = self.occupied_list_head;
block.last_access_time = frame_id;
self.occupied_list_head = Some(free_block_index);
block.next = self.occupied_list_heads.get(&frame_stamp.document_id()).cloned();
block.last_access_time = frame_stamp.frame_id();
self.occupied_list_heads.insert(frame_stamp.document_id(), free_block_index);
self.allocated_block_count += alloc_size;

if let Some(pending_block_index) = pending_block_index {
Expand Down Expand Up @@ -549,11 +551,12 @@ impl Texture {

// Run through the list of occupied cache blocks and evict
// any old blocks that haven't been referenced for a while.
fn evict_old_blocks(&mut self, frame_id: FrameId) {
fn evict_old_blocks(&mut self, frame_stamp: FrameStamp) {
debug_assert!(frame_stamp.is_valid());
// Prune any old items from the list to make room.
// Traverse the occupied linked list and see
// which items have not been used for a long time.
let mut current_block = self.occupied_list_head;
let mut current_block = self.occupied_list_heads.get(&frame_stamp.document_id()).map(|x| *x);
let mut prev_block: Option<BlockIndex> = None;

while let Some(index) = current_block {
Expand All @@ -566,7 +569,7 @@ impl Texture {
// If this resource has not been used in the last
// few frames, free it from the texture and mark
// as empty.
if block.last_access_time + FRAMES_BEFORE_EVICTION < frame_id {
if block.last_access_time + FRAMES_BEFORE_EVICTION < frame_stamp.frame_id() {
should_unlink = true;

// Get the row metadata from the address.
Expand Down Expand Up @@ -600,7 +603,14 @@ impl Texture {
self.blocks[prev_block.get()].next = next_block;
}
None => {
self.occupied_list_head = next_block;
match next_block {
Some(next_block) => {
self.occupied_list_heads.insert(frame_stamp.document_id(), next_block);
}
None => {
self.occupied_list_heads.remove(&frame_stamp.document_id());
}
}
}
}
} else {
Expand All @@ -627,7 +637,7 @@ impl Texture {
#[must_use]
pub struct GpuDataRequest<'a> {
handle: &'a mut GpuCacheHandle,
frame_id: FrameId,
frame_stamp: FrameStamp,
start_index: usize,
max_block_count: usize,
texture: &'a mut Texture,
Expand All @@ -653,7 +663,7 @@ impl<'a> Drop for GpuDataRequest<'a> {
debug_assert!(block_count <= self.max_block_count);

let location = self.texture
.push_data(Some(self.start_index), block_count, self.frame_id);
.push_data(Some(self.start_index), block_count, self.frame_stamp);
self.handle.location = Some(location);
}
}
Expand All @@ -663,8 +673,8 @@ impl<'a> Drop for GpuDataRequest<'a> {
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct GpuCache {
/// Current frame ID.
frame_id: FrameId,
/// Current FrameId.
now: FrameStamp,
/// CPU-side texture allocator.
texture: Texture,
/// Number of blocks requested this frame that don't
Expand All @@ -681,14 +691,26 @@ impl GpuCache {
pub fn new() -> Self {
let debug_flags = DebugFlags::empty();
GpuCache {
frame_id: FrameId::INVALID,
now: FrameStamp::INVALID,
texture: Texture::new(Epoch(0), debug_flags),
saved_block_count: 0,
debug_flags,
pending_clear: false,
}
}

/// Creates a GpuCache and sets it up with a valid `FrameStamp`, which
/// is useful for avoiding panics when instantiating the `GpuCache`
/// directly from unit test code.
#[allow(dead_code)]
pub fn new_for_testing() -> Self {
let mut cache = Self::new();
let mut now = FrameStamp::first(DocumentId(IdNamespace(1), 1));
now.advance();
cache.begin_frame(now);
cache
}

/// Drops everything in the GPU cache. Must not be called once gpu cache entries
/// for the next frame have already been requested.
pub fn clear(&mut self) {
Expand All @@ -701,10 +723,10 @@ impl GpuCache {
}

/// Begin a new frame.
pub fn begin_frame(&mut self, frame_id: FrameId) {
pub fn begin_frame(&mut self, stamp: FrameStamp) {
debug_assert!(self.texture.pending_blocks.is_empty());
self.frame_id = frame_id;
self.texture.evict_old_blocks(self.frame_id);
self.now = stamp;
self.texture.evict_old_blocks(self.now);
self.saved_block_count = 0;
}

Expand All @@ -731,19 +753,20 @@ impl GpuCache {
if let Some(block) = self.texture.blocks.get_mut(location.block_index.get()) {
if block.epoch == location.epoch {
max_block_count = self.texture.rows[block.address.v as usize].block_count_per_item;
if block.last_access_time != self.frame_id {
if block.last_access_time != self.now.frame_id() {
// Mark last access time to avoid evicting this block.
block.last_access_time = self.frame_id;
block.last_access_time = self.now.frame_id();
self.saved_block_count += max_block_count;
}
return None;
}
}
}

debug_assert!(self.now.is_valid());
Some(GpuDataRequest {
handle,
frame_id: self.frame_id,
frame_stamp: self.now,
start_index: self.texture.pending_blocks.len(),
texture: &mut self.texture,
max_block_count,
Expand All @@ -760,7 +783,7 @@ impl GpuCache {
let start_index = self.texture.pending_blocks.len();
self.texture.pending_blocks.extend_from_slice(blocks);
let location = self.texture
.push_data(Some(start_index), blocks.len(), self.frame_id);
.push_data(Some(start_index), blocks.len(), self.now);
GpuCacheHandle {
location: Some(location),
}
Expand All @@ -770,7 +793,7 @@ impl GpuCache {
// will be resolved by the render thread via the
// external image callback.
pub fn push_deferred_per_frame_blocks(&mut self, block_count: usize) -> GpuCacheHandle {
let location = self.texture.push_data(None, block_count, self.frame_id);
let location = self.texture.push_data(None, block_count, self.now);
GpuCacheHandle {
location: Some(location),
}
Expand All @@ -781,7 +804,7 @@ impl GpuCache {
pub fn end_frame(
&mut self,
profile_counters: &mut GpuCacheProfileCounters,
) -> FrameId {
) -> FrameStamp {
profile_counters
.allocated_rows
.set(self.texture.rows.len());
Expand All @@ -801,7 +824,7 @@ impl GpuCache {
self.texture.reached_reclaim_threshold = None;
}

self.frame_id
self.now
}

/// Returns true if utilization has been low enough for long enough that we
Expand All @@ -816,7 +839,7 @@ impl GpuCache {
let clear = self.pending_clear;
self.pending_clear = false;
GpuCacheUpdateList {
frame_id: self.frame_id,
frame_id: self.now.frame_id(),
clear,
height: self.texture.height,
debug_commands: mem::replace(&mut self.texture.debug_commands, Vec::new()),
Expand All @@ -839,7 +862,7 @@ impl GpuCache {
let location = id.location.expect("handle not requested or allocated!");
let block = &self.texture.blocks[location.block_index.get()];
debug_assert_eq!(block.epoch, location.epoch);
debug_assert_eq!(block.last_access_time, self.frame_id);
debug_assert_eq!(block.last_access_time, self.now.frame_id());
block.address
}

Expand Down
25 changes: 22 additions & 3 deletions webrender/src/render_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,15 @@ impl ::std::ops::Sub<usize> for FrameId {
pub struct FrameStamp {
id: FrameId,
time: SystemTime,
document_id: DocumentId,
}

impl Eq for FrameStamp {}

impl PartialEq for FrameStamp {
fn eq(&self, other: &Self) -> bool {
// We should not be checking equality unless the documents are the same
debug_assert!(self.document_id == other.document_id);
self.id == other.id
}
}
Expand All @@ -175,11 +178,24 @@ impl FrameStamp {
self.time
}

/// Gets the DocumentId in this stamp.
pub fn document_id(&self) -> DocumentId {
self.document_id
}

pub fn is_valid(&self) -> bool {
// If any fields are their default values, the whole struct should equal INVALID
debug_assert!((self.time != UNIX_EPOCH && self.id != FrameId(0) && self.document_id != DocumentId::INVALID) ||
*self == Self::INVALID);
self.document_id != DocumentId::INVALID
}

/// Returns a FrameStamp corresponding to the first frame.
pub fn first() -> Self {
pub fn first(document_id: DocumentId) -> Self {
FrameStamp {
id: FrameId::first(),
time: SystemTime::now(),
document_id: document_id,
}
}

Expand All @@ -193,6 +209,7 @@ impl FrameStamp {
pub const INVALID: FrameStamp = FrameStamp {
id: FrameId(0),
time: UNIX_EPOCH,
document_id: DocumentId::INVALID,
};
}

Expand Down Expand Up @@ -332,6 +349,7 @@ struct Document {

impl Document {
pub fn new(
id: DocumentId,
window_size: DeviceIntSize,
layer: DocumentLayer,
default_device_pixel_ratio: f32,
Expand All @@ -349,7 +367,7 @@ impl Document {
device_pixel_ratio: default_device_pixel_ratio,
},
clip_scroll_tree: ClipScrollTree::new(),
stamp: FrameStamp::first(),
stamp: FrameStamp::first(id),
frame_builder: None,
output_pipelines: FastHashSet::default(),
hit_tester: None,
Expand Down Expand Up @@ -980,6 +998,7 @@ impl RenderBackend {
}
ApiMsg::AddDocument(document_id, initial_size, layer) => {
let document = Document::new(
document_id,
initial_size,
layer,
self.default_device_pixel_ratio,
Expand Down Expand Up @@ -1743,7 +1762,7 @@ impl RenderBackend {
removed_pipelines: Vec::new(),
view: view.clone(),
clip_scroll_tree: ClipScrollTree::new(),
stamp: FrameStamp::first(),
stamp: FrameStamp::first(id),
frame_builder: Some(FrameBuilder::empty()),
output_pipelines: FastHashSet::default(),
dynamic_properties: SceneProperties::new(),
Expand Down
4 changes: 2 additions & 2 deletions webrender/src/resource_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1610,7 +1610,6 @@ impl ResourceCache {
&mut self.texture_cache,
render_tasks,
);
self.texture_cache.end_frame(texture_cache_profile);
}

fn rasterize_missing_blob_images(&mut self) {
Expand Down Expand Up @@ -1767,9 +1766,10 @@ impl ResourceCache {
}
}

pub fn end_frame(&mut self) {
pub fn end_frame(&mut self, texture_cache_profile: &mut TextureCacheProfileCounters) {
debug_assert_eq!(self.state, State::QueryResources);
self.state = State::Idle;
self.texture_cache.end_frame(texture_cache_profile);
}

pub fn set_debug_flags(&mut self, flags: DebugFlags) {
Expand Down
Loading