diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 579aceea52..59386f7a27 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -11,7 +11,7 @@ use clip::{ClipSource, ClipStore, ClipWorkItem}; use clip_scroll_tree::{CoordinateSystemId}; use euclid::{TypedTransform3D, vec3}; use glyph_rasterizer::GlyphFormat; -use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle}; +use gpu_cache::{GpuCache, GpuCacheAddress}; use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex, ZBufferId, ZBufferIdGenerator}; use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, RasterizationSpace}; use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance}; @@ -677,7 +677,12 @@ impl AlphaBatchBuilder { let kind = BatchKind::Brush( BrushBatchKind::Image(ImageBufferKind::Texture2DArray) ); - let (uv_rect_address, textures) = surface.resolve(render_tasks); + let (uv_rect_address, textures) = surface + .resolve( + render_tasks, + ctx.resource_cache, + gpu_cache, + ); let key = BatchKey::new( kind, non_segmented_blend_mode, @@ -696,7 +701,7 @@ impl AlphaBatchBuilder { edge_flags: EdgeAaSegmentMask::empty(), brush_flags: BrushFlags::empty(), user_data: [ - uv_rect_address.as_int(gpu_cache), + uv_rect_address.as_int(), (BrushImageSourceKind::Color as i32) << 16 | RasterizationSpace::Screen as i32, picture.extra_gpu_data_handle.as_int(gpu_cache), @@ -742,11 +747,11 @@ impl AlphaBatchBuilder { // Retrieve the UV rect addresses for shadow/content. let cache_task_id = surface.resolve_render_task_id(); let shadow_uv_rect_address = render_tasks[cache_task_id] - .get_texture_handle() - .as_int(gpu_cache); + .get_texture_address(gpu_cache) + .as_int(); let content_uv_rect_address = render_tasks[secondary_id] - .get_texture_handle() - .as_int(gpu_cache); + .get_texture_address(gpu_cache) + .as_int(); // Get the GPU cache address of the extra data handle. let extra_data_address = gpu_cache.get_address(&picture.extra_gpu_data_handle); @@ -933,8 +938,8 @@ impl AlphaBatchBuilder { ); let uv_rect_address = render_tasks[cache_task_id] - .get_texture_handle() - .as_int(gpu_cache); + .get_texture_address(gpu_cache) + .as_int(); let instance = BrushInstance { picture_address: task_address, @@ -1077,8 +1082,14 @@ impl AlphaBatchBuilder { deferred_resolves, ) } - ImageSource::Cache { ref item, .. } => { - item.clone() + ImageSource::Cache { ref handle, .. } => { + let rt_handle = handle + .as_ref() + .expect("bug: render task handle not allocated"); + let rt_cache_entry = ctx + .resource_cache + .get_cached_render_task(rt_handle); + ctx.resource_cache.get_texture_cache_item(&rt_cache_entry.handle) } }; @@ -1296,7 +1307,6 @@ impl BrushPrimitive { ) -> Option<(BrushBatchKind, BatchTextures, [i32; 3])> { match self.kind { BrushKind::Image { request, ref source, .. } => { - let cache_item = match *source { ImageSource::Default => { resolve_image( @@ -1306,8 +1316,13 @@ impl BrushPrimitive { deferred_resolves, ) } - ImageSource::Cache { ref item, .. } => { - item.clone() + ImageSource::Cache { ref handle, .. } => { + let rt_handle = handle + .as_ref() + .expect("bug: render task handle not allocated"); + let rt_cache_entry = resource_cache + .get_cached_render_task(rt_handle); + resource_cache.get_texture_cache_item(&rt_cache_entry.handle) } }; @@ -1477,20 +1492,27 @@ impl AlphaBatchHelpers for PrimitiveStore { impl PictureSurface { // Retrieve the uv rect handle, and texture for a picture surface. - fn resolve<'a>( - &'a self, - render_tasks: &'a RenderTaskTree, - ) -> (&'a GpuCacheHandle, BatchTextures) { + fn resolve( + &self, + render_tasks: &RenderTaskTree, + resource_cache: &ResourceCache, + gpu_cache: &GpuCache, + ) -> (GpuCacheAddress, BatchTextures) { match *self { - PictureSurface::TextureCache(ref cache_item) => { + PictureSurface::TextureCache(ref handle) => { + let rt_cache_entry = resource_cache + .get_cached_render_task(handle); + let cache_item = resource_cache + .get_texture_cache_item(&rt_cache_entry.handle); + ( - &cache_item.uv_rect_handle, + gpu_cache.get_address(&cache_item.uv_rect_handle), BatchTextures::color(cache_item.texture_id), ) } PictureSurface::RenderTask(task_id) => { ( - render_tasks[task_id].get_texture_handle(), + render_tasks[task_id].get_texture_address(gpu_cache), BatchTextures::render_target_cache(), ) } @@ -1690,14 +1712,22 @@ impl ClipBatcher { }); } ClipSource::BoxShadow(ref info) => { - debug_assert_ne!(info.cache_item.texture_id, SourceTexture::Invalid); + let rt_handle = info + .cache_handle + .as_ref() + .expect("bug: render task handle not allocated"); + let rt_cache_entry = resource_cache + .get_cached_render_task(rt_handle); + let cache_item = resource_cache + .get_texture_cache_item(&rt_cache_entry.handle); + debug_assert_ne!(cache_item.texture_id, SourceTexture::Invalid); self.box_shadows - .entry(info.cache_item.texture_id) + .entry(cache_item.texture_id) .or_insert(Vec::new()) .push(ClipMaskInstance { clip_data_address: gpu_address, - resource_address: gpu_cache.get_address(&info.cache_item.uv_rect_handle), + resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle), ..instance }); } diff --git a/webrender/src/box_shadow.rs b/webrender/src/box_shadow.rs index 4ccfd5e39b..15e639f970 100644 --- a/webrender/src/box_shadow.rs +++ b/webrender/src/box_shadow.rs @@ -10,7 +10,7 @@ use gpu_cache::GpuCacheHandle; use gpu_types::BoxShadowStretchMode; use prim_store::{BrushKind, BrushPrimitive, PrimitiveContainer}; use prim_store::ScrollNodeAndClipChain; -use resource_cache::CacheItem; +use render_task::RenderTaskCacheEntryHandle; use util::RectHelpers; #[derive(Debug)] @@ -25,7 +25,7 @@ pub struct BoxShadowClipSource { // The current cache key (in device-pixels), and handles // to the cached clip region and blurred texture. pub cache_key: Option<(DeviceIntSize, BoxShadowCacheKey)>, - pub cache_item: CacheItem, + pub cache_handle: Option, pub clip_data_handle: GpuCacheHandle, // Local-space size of the required render task size. diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index 6a90c7fb98..1f6c92a305 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -14,14 +14,17 @@ use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks}; use gpu_types::{BoxShadowStretchMode, ClipScrollNodeIndex}; use prim_store::{ClipData, ImageMaskData}; use render_task::to_cache_size; -use resource_cache::{CacheItem, ImageRequest, ResourceCache}; +use resource_cache::{ImageRequest, ResourceCache}; use util::{LayerToWorldFastTransform, MaxRect, calculate_screen_bounding_rect}; use util::{extract_inner_rect_safe, pack_as_float}; use std::sync::Arc; -pub type ClipStore = FreeList; -pub type ClipSourcesHandle = FreeListHandle; -pub type ClipSourcesWeakHandle = WeakFreeListHandle; +#[derive(Debug)] +pub enum ClipStoreMarker {} + +pub type ClipStore = FreeList; +pub type ClipSourcesHandle = FreeListHandle; +pub type ClipSourcesWeakHandle = WeakFreeListHandle; #[derive(Debug)] pub struct LineDecorationClipSource { @@ -237,7 +240,7 @@ impl ClipSource { clip_mode, stretch_mode_x, stretch_mode_y, - cache_item: CacheItem::invalid(), + cache_handle: None, cache_key: None, clip_data_handle: GpuCacheHandle::new(), minimal_shadow_rect, diff --git a/webrender/src/frame_builder.rs b/webrender/src/frame_builder.rs index 6e4b516449..4bc98e2585 100644 --- a/webrender/src/frame_builder.rs +++ b/webrender/src/frame_builder.rs @@ -392,7 +392,7 @@ impl FrameBuilder { let gpu_cache_frame_id = gpu_cache.end_frame(gpu_cache_profile); - render_tasks.build(); + render_tasks.write_task_data(); resource_cache.end_frame(); diff --git a/webrender/src/freelist.rs b/webrender/src/freelist.rs index dcb10fd194..e1a97255e6 100644 --- a/webrender/src/freelist.rs +++ b/webrender/src/freelist.rs @@ -17,14 +17,14 @@ struct Epoch(u32); #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct FreeListHandle { +pub struct FreeListHandle { index: u32, epoch: Epoch, - _marker: PhantomData, + _marker: PhantomData, } -impl FreeListHandle { - pub fn weak(&self) -> WeakFreeListHandle { +impl FreeListHandle { + pub fn weak(&self) -> WeakFreeListHandle { WeakFreeListHandle { index: self.index, epoch: self.epoch, @@ -33,7 +33,7 @@ impl FreeListHandle { } } -impl Clone for WeakFreeListHandle { +impl Clone for WeakFreeListHandle { fn clone(&self) -> Self { WeakFreeListHandle { index: self.index, @@ -46,10 +46,10 @@ impl Clone for WeakFreeListHandle { #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct WeakFreeListHandle { +pub struct WeakFreeListHandle { index: u32, epoch: Epoch, - _marker: PhantomData, + _marker: PhantomData, } #[cfg_attr(feature = "capture", derive(Serialize))] @@ -62,31 +62,34 @@ struct Slot { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct FreeList { +pub struct FreeList { slots: Vec>, free_list_head: Option, active_count: usize, + _marker: PhantomData, } -pub enum UpsertResult { +pub enum UpsertResult { Updated(T), - Inserted(FreeListHandle), + Inserted(FreeListHandle), } -impl FreeList { +impl FreeList { pub fn new() -> Self { FreeList { slots: Vec::new(), free_list_head: None, active_count: 0, + _marker: PhantomData, } } - pub fn recycle(self) -> FreeList { + pub fn recycle(self) -> FreeList { FreeList { slots: recycle_vec(self.slots), free_list_head: None, active_count: 0, + _marker: PhantomData, } } @@ -97,16 +100,16 @@ impl FreeList { } #[allow(dead_code)] - pub fn get(&self, id: &FreeListHandle) -> &T { + pub fn get(&self, id: &FreeListHandle) -> &T { self.slots[id.index as usize].value.as_ref().unwrap() } #[allow(dead_code)] - pub fn get_mut(&mut self, id: &FreeListHandle) -> &mut T { + pub fn get_mut(&mut self, id: &FreeListHandle) -> &mut T { self.slots[id.index as usize].value.as_mut().unwrap() } - pub fn get_opt(&self, id: &WeakFreeListHandle) -> Option<&T> { + pub fn get_opt(&self, id: &WeakFreeListHandle) -> Option<&T> { let slot = &self.slots[id.index as usize]; if slot.epoch == id.epoch { slot.value.as_ref() @@ -115,7 +118,7 @@ impl FreeList { } } - pub fn get_opt_mut(&mut self, id: &WeakFreeListHandle) -> Option<&mut T> { + pub fn get_opt_mut(&mut self, id: &WeakFreeListHandle) -> Option<&mut T> { let slot = &mut self.slots[id.index as usize]; if slot.epoch == id.epoch { slot.value.as_mut() @@ -128,7 +131,7 @@ impl FreeList { // handle is a valid entry, update the value and return the // previous data. If the provided handle is invalid, then // insert the data into a new slot and return the new handle. - pub fn upsert(&mut self, id: &WeakFreeListHandle, data: T) -> UpsertResult { + pub fn upsert(&mut self, id: &WeakFreeListHandle, data: T) -> UpsertResult { if self.slots[id.index as usize].epoch == id.epoch { let slot = &mut self.slots[id.index as usize]; let result = UpsertResult::Updated(slot.value.take().unwrap()); @@ -139,7 +142,7 @@ impl FreeList { } } - pub fn insert(&mut self, item: T) -> FreeListHandle { + pub fn insert(&mut self, item: T) -> FreeListHandle { self.active_count += 1; match self.free_list_head { @@ -176,7 +179,7 @@ impl FreeList { } } - pub fn free(&mut self, id: FreeListHandle) -> T { + pub fn free(&mut self, id: FreeListHandle) -> T { self.active_count -= 1; let slot = &mut self.slots[id.index as usize]; slot.next = self.free_list_head; diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index 90180c9e13..efae1f15a5 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -11,9 +11,8 @@ use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState}; use gpu_cache::{GpuCacheHandle}; use prim_store::{PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect}; use prim_store::{PrimitiveMetadata, ScrollNodeAndClipChain}; -use render_task::{ClearMode, RenderTask}; +use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle}; use render_task::{RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation}; -use resource_cache::CacheItem; use scene::{FilterOpHelpers, SceneProperties}; use std::mem; use tiling::RenderTargetKind; @@ -48,7 +47,7 @@ pub enum PictureCompositeMode { #[derive(Debug)] pub enum PictureSurface { RenderTask(RenderTaskId), - TextureCache(CacheItem), + TextureCache(RenderTaskCacheEntryHandle), } // A unique identifier for a Picture. Once we start @@ -323,7 +322,7 @@ impl PicturePrimitive { // relevant transforms haven't changed from frame to frame. let surface = if pic_state_for_children.has_non_root_coord_system { let picture_task = RenderTask::new_picture( - RenderTaskLocation::Dynamic(None, device_rect.size), + RenderTaskLocation::Dynamic(None, Some(device_rect.size)), prim_index, device_rect.origin, pic_state_for_children.tasks, @@ -372,11 +371,12 @@ impl PicturePrimitive { frame_state.gpu_cache, frame_state.render_tasks, None, + false, |render_tasks| { let child_tasks = mem::replace(&mut pic_state_for_children.tasks, Vec::new()); let picture_task = RenderTask::new_picture( - RenderTaskLocation::Dynamic(None, device_rect.size), + RenderTaskLocation::Dynamic(None, Some(device_rect.size)), prim_index, device_rect.origin, child_tasks, @@ -396,7 +396,7 @@ impl PicturePrimitive { pic_state.tasks.push(render_task_id); - (render_task_id, false) + render_task_id } ); @@ -426,7 +426,7 @@ impl PicturePrimitive { .unwrap(); let mut picture_task = RenderTask::new_picture( - RenderTaskLocation::Dynamic(None, device_rect.size), + RenderTaskLocation::Dynamic(None, Some(device_rect.size)), prim_index, device_rect.origin, pic_state_for_children.tasks, @@ -453,7 +453,7 @@ impl PicturePrimitive { } Some(PictureCompositeMode::MixBlend(..)) => { let picture_task = RenderTask::new_picture( - RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size), + RenderTaskLocation::Dynamic(None, Some(prim_screen_rect.clipped.size)), prim_index, prim_screen_rect.clipped.origin, pic_state_for_children.tasks, @@ -487,7 +487,7 @@ impl PicturePrimitive { }; let picture_task = RenderTask::new_picture( - RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size), + RenderTaskLocation::Dynamic(None, Some(prim_screen_rect.clipped.size)), prim_index, prim_screen_rect.clipped.origin, pic_state_for_children.tasks, @@ -501,7 +501,7 @@ impl PicturePrimitive { } Some(PictureCompositeMode::Blit) | None => { let picture_task = RenderTask::new_picture( - RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size), + RenderTaskLocation::Dynamic(None, Some(prim_screen_rect.clipped.size)), prim_index, prim_screen_rect.clipped.origin, pic_state_for_children.tasks, diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index e7d6b950af..ca8c0abef6 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -21,9 +21,9 @@ use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuData use gpu_types::{ClipChainRectIndex}; use picture::{PictureCompositeMode, PictureId, PicturePrimitive}; use render_task::{BlitSource, RenderTask, RenderTaskCacheKey}; -use render_task::{RenderTaskCacheKeyKind, RenderTaskId}; +use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskCacheEntryHandle}; use renderer::{MAX_VERTEX_TEXTURE_WIDTH}; -use resource_cache::{CacheItem, ImageProperties, ImageRequest}; +use resource_cache::{ImageProperties, ImageRequest}; use segment::SegmentBuilder; use std::{mem, usize}; use std::sync::Arc; @@ -400,7 +400,7 @@ pub enum ImageSource { // via a render task. Cache { size: DeviceIntSize, - item: CacheItem, + handle: Option, }, } @@ -1209,7 +1209,7 @@ impl PrimitiveStore { ImageSource::Cache { // Size in device-pixels we need to allocate in render task cache. size: texel_rect.size, - item: CacheItem::invalid(), + handle: None, } } None => { @@ -1227,11 +1227,11 @@ impl PrimitiveStore { // time through, and any time the render task output has been // evicted from the texture cache. match image_cpu.source { - ImageSource::Cache { size, ref mut item } => { + ImageSource::Cache { size, ref mut handle } => { let key = image_cpu.key; // Request a pre-rendered image task. - *item = frame_state.resource_cache.request_render_task( + *handle = Some(frame_state.resource_cache.request_render_task( RenderTaskCacheKey { size, kind: RenderTaskCacheKeyKind::Image(key), @@ -1239,6 +1239,7 @@ impl PrimitiveStore { frame_state.gpu_cache, frame_state.render_tasks, None, + image_properties.descriptor.is_opaque, |render_tasks| { // We need to render the image cache this frame, // so will need access to the source texture. @@ -1271,9 +1272,9 @@ impl PrimitiveStore { // Pass the image opacity, so that the cached render task // item inherits the same opacity properties. - (target_to_cache_task_id, image_properties.descriptor.is_opaque) + target_to_cache_task_id } - ); + )); } ImageSource::Default => { // Normal images just reference the source texture each frame. @@ -1314,7 +1315,7 @@ impl PrimitiveStore { *source = ImageSource::Cache { // Size in device-pixels we need to allocate in render task cache. size: rect.size, - item: CacheItem::invalid(), + handle: None, }; } @@ -1325,14 +1326,14 @@ impl PrimitiveStore { // time through, and any time the render task output has been // evicted from the texture cache. match *source { - ImageSource::Cache { size, ref mut item } => { + ImageSource::Cache { size, ref mut handle } => { let image_cache_key = ImageCacheKey { request, texel_rect: sub_rect, }; // Request a pre-rendered image task. - *item = frame_state.resource_cache.request_render_task( + *handle = Some(frame_state.resource_cache.request_render_task( RenderTaskCacheKey { size, kind: RenderTaskCacheKeyKind::Image(image_cache_key), @@ -1340,6 +1341,7 @@ impl PrimitiveStore { frame_state.gpu_cache, frame_state.render_tasks, None, + image_properties.descriptor.is_opaque, |render_tasks| { // We need to render the image cache this frame, // so will need access to the source texture. @@ -1370,10 +1372,9 @@ impl PrimitiveStore { // Pass the image opacity, so that the cached render task // item inherits the same opacity properties. - (target_to_cache_task_id, image_properties.descriptor.is_opaque) + target_to_cache_task_id } - ); - + )); } ImageSource::Default => { // Normal images just reference the source texture each frame. diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index f43d7b0f0e..95b43f765d 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -11,7 +11,7 @@ use clip_scroll_tree::CoordinateSystemId; use device::TextureFilter; #[cfg(feature = "pathfinder")] use euclid::{TypedPoint2D, TypedVector2D}; -use freelist::{FreeList, FreeListHandle}; +use freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; use glyph_rasterizer::GpuGlyphCacheKey; use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle}; use gpu_types::{ImageSource, RasterizationSpace}; @@ -120,12 +120,18 @@ impl RenderTaskTree { pass.add_render_task(id, task.get_dynamic_size(), task.target_kind()); } + pub fn prepare_for_render(&mut self) { + for task in &mut self.tasks { + task.prepare_for_render(); + } + } + pub fn get_task_address(&self, id: RenderTaskId) -> RenderTaskAddress { debug_assert_eq!(self.frame_id, id.1); RenderTaskAddress(id.0) } - pub fn build(&mut self) { + pub fn write_task_data(&mut self) { for task in &self.tasks { self.task_data.push(task.write_task_data()); } @@ -158,7 +164,7 @@ impl ops::IndexMut for RenderTaskTree { #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum RenderTaskLocation { Fixed(DeviceIntRect), - Dynamic(Option<(DeviceIntPoint, RenderTargetIndex)>, DeviceIntSize), + Dynamic(Option<(DeviceIntPoint, RenderTargetIndex)>, Option), TextureCache(SourceTexture, i32, DeviceIntRect), } @@ -312,7 +318,7 @@ impl RenderTask { pub fn new_readback(screen_rect: DeviceIntRect) -> Self { RenderTask { children: Vec::new(), - location: RenderTaskLocation::Dynamic(None, screen_rect.size), + location: RenderTaskLocation::Dynamic(None, Some(screen_rect.size)), kind: RenderTaskKind::Readback(screen_rect), clear_mode: ClearMode::Transparent, saved_index: None, @@ -336,7 +342,7 @@ impl RenderTask { RenderTask { children, - location: RenderTaskLocation::Dynamic(None, size), + location: RenderTaskLocation::Dynamic(None, Some(size)), kind: RenderTaskKind::Blit(BlitTask { source, }), @@ -379,7 +385,7 @@ impl RenderTask { // Request a cacheable render task with a blurred, minimal // sized box-shadow rect. - info.cache_item = resource_cache.request_render_task( + info.cache_handle = Some(resource_cache.request_render_task( RenderTaskCacheKey { size: cache_size, kind: RenderTaskCacheKeyKind::BoxShadow(cache_key), @@ -387,6 +393,7 @@ impl RenderTask { gpu_cache, render_tasks, None, + false, |render_tasks| { // Draw the rounded rect. let mask_task = RenderTask::new_rounded_rect_mask( @@ -408,9 +415,9 @@ impl RenderTask { let root_task_id = render_tasks.add(blur_render_task); children.push(root_task_id); - (root_task_id, false) + root_task_id } - ); + )); } ClipSource::Rectangle(..) | ClipSource::RoundedRectangle(..) | @@ -423,7 +430,7 @@ impl RenderTask { RenderTask { children, - location: RenderTaskLocation::Dynamic(None, outer_rect.size), + location: RenderTaskLocation::Dynamic(None, Some(outer_rect.size)), kind: RenderTaskKind::CacheMask(CacheMaskTask { actual_rect: outer_rect, clips, @@ -440,7 +447,7 @@ impl RenderTask { ) -> Self { RenderTask { children: Vec::new(), - location: RenderTaskLocation::Dynamic(None, size), + location: RenderTaskLocation::Dynamic(None, Some(size)), kind: RenderTaskKind::ClipRegion(ClipRegionTask { clip_data_address, }), @@ -498,7 +505,7 @@ impl RenderTask { let blur_task_v = RenderTask { children: vec![downscaling_src_task_id], - location: RenderTaskLocation::Dynamic(None, adjusted_blur_target_size), + location: RenderTaskLocation::Dynamic(None, Some(adjusted_blur_target_size)), kind: RenderTaskKind::VerticalBlur(BlurTask { blur_std_deviation: adjusted_blur_std_deviation, target_kind, @@ -512,7 +519,7 @@ impl RenderTask { RenderTask { children: vec![blur_task_v_id], - location: RenderTaskLocation::Dynamic(None, adjusted_blur_target_size), + location: RenderTaskLocation::Dynamic(None, Some(adjusted_blur_target_size)), kind: RenderTaskKind::HorizontalBlur(BlurTask { blur_std_deviation: adjusted_blur_std_deviation, target_kind, @@ -530,7 +537,7 @@ impl RenderTask { ) -> Self { RenderTask { children: vec![src_task_id], - location: RenderTaskLocation::Dynamic(None, target_size), + location: RenderTaskLocation::Dynamic(None, Some(target_size)), kind: RenderTaskKind::Scaling(target_kind), clear_mode: match target_kind { RenderTargetKind::Color => ClearMode::Transparent, @@ -632,14 +639,14 @@ impl RenderTask { } } - pub fn get_texture_handle(&self) -> &GpuCacheHandle { + pub fn get_texture_address(&self, gpu_cache: &GpuCache) -> GpuCacheAddress { match self.kind { RenderTaskKind::Picture(ref info) => { - &info.uv_rect_handle + gpu_cache.get_address(&info.uv_rect_handle) } RenderTaskKind::VerticalBlur(ref info) | RenderTaskKind::HorizontalBlur(ref info) => { - &info.uv_rect_handle + gpu_cache.get_address(&info.uv_rect_handle) } RenderTaskKind::ClipRegion(..) | RenderTaskKind::Readback(..) | @@ -655,7 +662,10 @@ impl RenderTask { pub fn get_dynamic_size(&self) -> DeviceIntSize { match self.location { RenderTaskLocation::Fixed(..) => DeviceIntSize::zero(), - RenderTaskLocation::Dynamic(_, size) => size, + RenderTaskLocation::Dynamic(_, Some(size)) => size, + RenderTaskLocation::Dynamic(_, None) => { + panic!("bug: render task must have assigned size by now"); + } RenderTaskLocation::TextureCache(_, _, rect) => rect.size, } } @@ -680,6 +690,7 @@ impl RenderTask { // to mark a task as unused explicitly. This // would allow us to restore this debug check. RenderTaskLocation::Dynamic(Some((origin, target_index)), size) => { + let size = size.expect("bug: must be assigned a size by now"); (DeviceIntRect::new(origin, size), target_index) } RenderTaskLocation::Dynamic(None, _) => { @@ -749,7 +760,14 @@ impl RenderTask { } } - pub fn prepare_for_render( + // Optionally, prepare the render task for drawing. This is executed + // after all resource cache items (textures and glyphs) have been + // resolved and can be queried. It also allows certain render tasks + // to defer calculating an exact size until now, if desired. + pub fn prepare_for_render(&mut self) { + } + + pub fn write_gpu_blocks( &mut self, gpu_cache: &mut GpuCache, ) { @@ -867,21 +885,30 @@ pub struct RenderTaskCacheKey { pub kind: RenderTaskCacheKeyKind, } +#[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct RenderTaskCacheEntry { + pending_render_task_id: Option, + user_data: Option<[f32; 3]>, + is_opaque: bool, pub handle: TextureCacheHandle, } +#[derive(Debug)] +pub enum RenderTaskCacheMarker {} + // A cache of render tasks that are stored in the texture // cache for usage across frames. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct RenderTaskCache { - map: FastHashMap>, - cache_entries: FreeList, + map: FastHashMap>, + cache_entries: FreeList, } +pub type RenderTaskCacheEntryHandle = WeakFreeListHandle; + impl RenderTaskCache { pub fn new() -> Self { RenderTaskCache { @@ -927,6 +954,77 @@ impl RenderTaskCache { } } + pub fn update( + &mut self, + gpu_cache: &mut GpuCache, + texture_cache: &mut TextureCache, + render_tasks: &mut RenderTaskTree, + ) { + // Iterate the list of render task cache entries, + // and allocate / update the texture cache location + // if the entry has been evicted or not yet allocated. + for (_, handle) in &self.map { + let entry = self.cache_entries.get_mut(handle); + + if let Some(pending_render_task_id) = entry.pending_render_task_id.take() { + let render_task = &mut render_tasks[pending_render_task_id]; + let target_kind = render_task.target_kind(); + + // Find out what size to alloc in the texture cache. + let size = match render_task.location { + RenderTaskLocation::Fixed(..) | + RenderTaskLocation::TextureCache(..) => { + panic!("BUG: dynamic task was expected"); + } + RenderTaskLocation::Dynamic(_, None) => { + panic!("BUG: must have assigned size by now"); + } + RenderTaskLocation::Dynamic(_, Some(size)) => size, + }; + + // Select the right texture page to allocate from. + let image_format = match target_kind { + RenderTargetKind::Color => ImageFormat::BGRA8, + RenderTargetKind::Alpha => ImageFormat::R8, + }; + + let descriptor = ImageDescriptor::new( + size.width as u32, + size.height as u32, + image_format, + entry.is_opaque, + false, + ); + + // Allocate space in the texture cache, but don't supply + // and CPU-side data to be uploaded. + texture_cache.update( + &mut entry.handle, + descriptor, + TextureFilter::Linear, + None, + entry.user_data.unwrap_or([0.0; 3]), + None, + gpu_cache, + None, + ); + + // Get the allocation details in the texture cache, and store + // this in the render task. The renderer will draw this + // task into the appropriate layer and rect of the texture + // cache on this frame. + let (texture_id, texture_layer, uv_rect) = + texture_cache.get_cache_location(&entry.handle); + + render_task.location = RenderTaskLocation::TextureCache( + texture_id, + texture_layer, + uv_rect.to_i32() + ); + } + } + } + pub fn request_render_task( &mut self, key: RenderTaskCacheKey, @@ -934,9 +1032,10 @@ impl RenderTaskCache { gpu_cache: &mut GpuCache, render_tasks: &mut RenderTaskTree, user_data: Option<[f32; 3]>, + is_opaque: bool, mut f: F, - ) -> Result - where F: FnMut(&mut RenderTaskTree) -> Result<(RenderTaskId, bool), ()> { + ) -> Result + where F: FnMut(&mut RenderTaskTree) -> Result { // Get the texture cache handle for this cache key, // or create one. let cache_entries = &mut self.cache_entries; @@ -945,74 +1044,37 @@ impl RenderTaskCache { .or_insert_with(|| { let entry = RenderTaskCacheEntry { handle: TextureCacheHandle::new(), + pending_render_task_id: None, + user_data, + is_opaque, }; cache_entries.insert(entry) }); let cache_entry = cache_entries.get_mut(entry_handle); - // Check if this texture cache handle is valid. - if texture_cache.request(&cache_entry.handle, gpu_cache) { - // Invoke user closure to get render task chain - // to draw this into the texture cache. - let (render_task_id, is_opaque) = try!(f(render_tasks)); - let render_task = &mut render_tasks[render_task_id]; - - // Select the right texture page to allocate from. - let image_format = match render_task.target_kind() { - RenderTargetKind::Color => ImageFormat::BGRA8, - RenderTargetKind::Alpha => ImageFormat::R8, - }; + if cache_entry.pending_render_task_id.is_none() { + // Check if this texture cache handle is valid. + if texture_cache.request(&cache_entry.handle, gpu_cache) { + // Invoke user closure to get render task chain + // to draw this into the texture cache. + let render_task_id = try!(f(render_tasks)); - // Find out what size to alloc in the texture cache. - let size = match render_task.location { - RenderTaskLocation::Fixed(..) | - RenderTaskLocation::TextureCache(..) => { - panic!("BUG: dynamic task was expected"); - } - RenderTaskLocation::Dynamic(_, size) => size, - }; - - // TODO(gw): Support color tasks in the texture cache, - // and perhaps consider if we can determine - // if some tasks are opaque as an optimization. - let descriptor = ImageDescriptor::new( - size.width as u32, - size.height as u32, - image_format, - is_opaque, - false, - ); - - // Allocate space in the texture cache, but don't supply - // and CPU-side data to be uploaded. - texture_cache.update( - &mut cache_entry.handle, - descriptor, - TextureFilter::Linear, - None, - user_data.unwrap_or([0.0; 3]), - None, - gpu_cache, - None, - ); - - // Get the allocation details in the texture cache, and store - // this in the render task. The renderer will draw this - // task into the appropriate layer and rect of the texture - // cache on this frame. - let (texture_id, texture_layer, uv_rect) = - texture_cache.get_cache_location(&cache_entry.handle); - - render_task.location = RenderTaskLocation::TextureCache( - texture_id, - texture_layer, - uv_rect.to_i32() - ); + cache_entry.pending_render_task_id = Some(render_task_id); + cache_entry.user_data = user_data; + cache_entry.is_opaque = is_opaque; + } } - // Finally, return the texture cache handle that we know - // is now up to date. - Ok(texture_cache.get(&cache_entry.handle)) + Ok(entry_handle.weak()) + } + + pub fn get_cache_entry( + &self, + handle: &RenderTaskCacheEntryHandle, + ) -> &RenderTaskCacheEntry { + self.cache_entries + .get_opt(handle) + .expect("bug: invalid render task cache handle") } #[allow(dead_code)] diff --git a/webrender/src/resource_cache.rs b/webrender/src/resource_cache.rs index d5f12f11a1..ba469e0282 100644 --- a/webrender/src/resource_cache.rs +++ b/webrender/src/resource_cache.rs @@ -27,7 +27,8 @@ use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle}; use internal_types::{FastHashMap, FastHashSet, SourceTexture, TextureUpdateList}; use profiler::{ResourceProfileCounters, TextureCacheProfileCounters}; use render_backend::FrameId; -use render_task::{RenderTaskCache, RenderTaskCacheKey, RenderTaskId, RenderTaskTree}; +use render_task::{RenderTaskCache, RenderTaskCacheKey, RenderTaskId}; +use render_task::{RenderTaskCacheEntry, RenderTaskCacheEntryHandle, RenderTaskTree}; use std::collections::hash_map::Entry::{self, Occupied, Vacant}; use std::cmp; use std::fmt::Debug; @@ -346,14 +347,16 @@ impl ResourceCache { gpu_cache: &mut GpuCache, render_tasks: &mut RenderTaskTree, user_data: Option<[f32; 3]>, + is_opaque: bool, mut f: F, - ) -> CacheItem where F: FnMut(&mut RenderTaskTree) -> (RenderTaskId, bool) { + ) -> RenderTaskCacheEntryHandle where F: FnMut(&mut RenderTaskTree) -> RenderTaskId { self.cached_render_tasks.request_render_task( key, &mut self.texture_cache, gpu_cache, render_tasks, user_data, + is_opaque, |render_task_tree| Ok(f(render_task_tree)) ).expect("Failed to request a render task from the resource cache!") } @@ -841,6 +844,17 @@ impl ResourceCache { } } + pub fn get_cached_render_task( + &self, + handle: &RenderTaskCacheEntryHandle, + ) -> &RenderTaskCacheEntry { + self.cached_render_tasks.get_cache_entry(handle) + } + + pub fn get_texture_cache_item(&self, handle: &TextureCacheHandle) -> CacheItem { + self.texture_cache.get(handle) + } + pub fn get_image_properties(&self, image_key: ImageKey) -> Option { let image_template = &self.resources.image_templates.get(image_key); @@ -917,6 +931,12 @@ impl ResourceCache { // Apply any updates of new / updated images (incl. blobs) to the texture cache. self.update_texture_cache(gpu_cache); + render_tasks.prepare_for_render(); + self.cached_render_tasks.update( + gpu_cache, + &mut self.texture_cache, + render_tasks, + ); self.texture_cache.end_frame(texture_cache_profile); } diff --git a/webrender/src/texture_cache.rs b/webrender/src/texture_cache.rs index 3b259cee08..115ea23f19 100644 --- a/webrender/src/texture_cache.rs +++ b/webrender/src/texture_cache.rs @@ -83,6 +83,9 @@ enum EntryKind { }, } +#[derive(Debug)] +pub enum CacheEntryMarker {} + // Stores information related to a single entry in the texture // cache. This is stored for each item whether it's in the shared // cache or a standalone texture. @@ -163,7 +166,7 @@ impl CacheEntry { } } -type WeakCacheEntryHandle = WeakFreeListHandle; +type WeakCacheEntryHandle = WeakFreeListHandle; // A texture cache handle is a weak reference to a cache entry. // If the handle has not been inserted into the cache yet, the @@ -240,17 +243,17 @@ pub struct TextureCache { // Maintains the list of all current items in // the texture cache. - entries: FreeList, + entries: FreeList, // A list of the strong handles of items that were // allocated in the standalone texture pool. Used // for evicting old standalone textures. - standalone_entry_handles: Vec>, + standalone_entry_handles: Vec>, // A list of the strong handles of items that were // allocated in the shared texture cache. Used // for evicting old cache items. - shared_entry_handles: Vec>, + shared_entry_handles: Vec>, } impl TextureCache { diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index e68b946699..c689abfd7e 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -833,6 +833,7 @@ impl RenderPass { None } RenderTaskLocation::Dynamic(ref mut origin, size) => { + let size = size.expect("bug: size must be assigned by now"); let alloc_size = DeviceUintSize::new(size.width as u32, size.height as u32); let (alloc_origin, target_index) = match target_kind { RenderTargetKind::Color => color.allocate(alloc_size), @@ -854,7 +855,7 @@ impl RenderPass { // Give the render task an opportunity to add any // information to the GPU cache, if appropriate. - task.prepare_for_render(gpu_cache); + task.write_gpu_blocks(gpu_cache); (target_kind, texture_target) };