From 175bd9a090a86e1b2ddefe9257b0e8dc32f7bee3 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 5 Apr 2018 14:46:48 +0200 Subject: [PATCH] Support sampling from the render task cache in brush images. --- webrender/src/batch.rs | 22 ++++-- webrender/src/display_list_flattener.rs | 31 +++++---- webrender/src/prim_store.rs | 91 +++++++++++++++++++++++-- 3 files changed, 119 insertions(+), 25 deletions(-) diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 583d403748..87e3571efd 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -1258,13 +1258,21 @@ impl BrushPrimitive { cached_gradients: &[CachedGradient], ) -> Option<(BrushBatchKind, BatchTextures, [i32; 3])> { match self.kind { - BrushKind::Image { request, .. } => { - let cache_item = resolve_image( - request, - resource_cache, - gpu_cache, - deferred_resolves, - ); + BrushKind::Image { request, ref source, .. } => { + + let cache_item = match *source { + ImageSource::Default => { + resolve_image( + request, + resource_cache, + gpu_cache, + deferred_resolves, + ) + } + ImageSource::Cache { ref item, .. } => { + item.clone() + } + }; if cache_item.texture_id == SourceTexture::Invalid { None diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index e78a3f387d..c4a7156762 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -2183,17 +2183,33 @@ impl<'a> DisplayListFlattener<'a> { tile: tile_offset, }; + let sub_rect = sub_rect.map(|texel_rect| { + DeviceIntRect::new( + DeviceIntPoint::new( + texel_rect.uv0.x as i32, + texel_rect.uv0.y as i32, + ), + DeviceIntSize::new( + (texel_rect.uv1.x - texel_rect.uv0.x) as i32, + (texel_rect.uv1.y - texel_rect.uv0.y) as i32, + ), + ) + }); + // See if conditions are met to run through the new // image brush shader, which supports segments. if tile_spacing == LayerSize::zero() && stretch_size == info.rect.size && - sub_rect.is_none() && tile_offset.is_none() { let prim = BrushPrimitive::new( BrushKind::Image { request, current_epoch: Epoch::invalid(), alpha_type, + stretch_size, + tile_spacing, + source: ImageSource::Default, + sub_rect, }, None, ); @@ -2213,18 +2229,7 @@ impl<'a> DisplayListFlattener<'a> { source: ImageSource::Default, key: ImageCacheKey { request, - texel_rect: sub_rect.map(|texel_rect| { - DeviceIntRect::new( - DeviceIntPoint::new( - texel_rect.uv0.x as i32, - texel_rect.uv0.y as i32, - ), - DeviceIntSize::new( - (texel_rect.uv1.x - texel_rect.uv0.x) as i32, - (texel_rect.uv1.y - texel_rect.uv0.y) as i32, - ), - ) - }), + texel_rect: sub_rect, }, }; diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index b3b924ec84..c1457822c2 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -213,6 +213,10 @@ pub enum BrushKind { request: ImageRequest, current_epoch: Epoch, alpha_type: AlphaType, + stretch_size: LayerSize, + tile_spacing: LayerSize, + source: ImageSource, + sub_rect: Option, }, YuvImage { yuv_key: [ImageKey; 3], @@ -1300,11 +1304,12 @@ impl PrimitiveStore { let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0]; match brush.kind { - BrushKind::Image { request, ref mut current_epoch, .. } => { + BrushKind::Image { request, sub_rect, ref mut current_epoch, ref mut source, .. } => { let image_properties = frame_state .resource_cache .get_image_properties(request.key); + // Set if we need to request the source image from the cache this frame. if let Some(image_properties) = image_properties { // See if this image has been updated since we last hit this code path. // If so, we need to update the opacity. @@ -1312,12 +1317,88 @@ impl PrimitiveStore { *current_epoch = image_properties.epoch; metadata.opacity.is_opaque = image_properties.descriptor.is_opaque; } + + // Work out whether this image is a normal / simple type, or if + // we need to pre-render it to the render task cache. + if let Some(rect) = sub_rect { + *source = ImageSource::Cache { + // Size in device-pixels we need to allocate in render task cache. + size: rect.size, + item: CacheItem::invalid(), + }; + } + + let mut request_source_image = false; + + // Every frame, for cached items, we need to request the render + // task cache item. The closure will be invoked on the first + // time through, and any time the render task output has been + // evicted from the texture cache. + match *source { + ImageSource::Cache { size, ref mut item } => { + let image_cache_key = ImageCacheKey { + request, + texel_rect: sub_rect, + }; + + // Request a pre-rendered image task. + *item = frame_state.resource_cache.request_render_task( + RenderTaskCacheKey { + size, + kind: RenderTaskCacheKeyKind::Image(image_cache_key), + }, + frame_state.gpu_cache, + frame_state.render_tasks, + None, + |render_tasks| { + // We need to render the image cache this frame, + // so will need access to the source texture. + request_source_image = true; + + // Create a task to blit from the texture cache to + // a normal transient render task surface. This will + // copy only the sub-rect, if specified. + let cache_to_target_task = RenderTask::new_blit( + size, + BlitSource::Image { key: image_cache_key }, + ); + let cache_to_target_task_id = render_tasks.add(cache_to_target_task); + + // Create a task to blit the rect from the child render + // task above back into the right spot in the persistent + // render target cache. + let target_to_cache_task = RenderTask::new_blit( + size, + BlitSource::RenderTask { + task_id: cache_to_target_task_id, + }, + ); + let target_to_cache_task_id = render_tasks.add(target_to_cache_task); + + // Hook this into the render task tree at the right spot. + pic_state.tasks.push(target_to_cache_task_id); + + // 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) + } + ); + + } + ImageSource::Default => { + // Normal images just reference the source texture each frame. + request_source_image = true; + } + } + + if request_source_image { + frame_state.resource_cache.request_image( + request, + frame_state.gpu_cache, + ); + } } - frame_state.resource_cache.request_image( - request, - frame_state.gpu_cache, - ); } BrushKind::YuvImage { format, yuv_key, image_rendering, .. } => { let channel_num = format.get_plane_num();