From 58a1de7b021371b32a2728d6615c73a94f12242c Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Thu, 22 Feb 2018 12:40:31 +1000 Subject: [PATCH] Share gradient GPU cache entries for repeated gradient primitives. This is a potential fix for the intermittent failures here: https://github.com/servo/webrender/pull/2441#issuecomment-367211596 I still can't reproduce them locally. However, I could see that the GPU cache size in that test was getting dangerously close to the maximum size of the texture supported by the GL implementation. That would fit with the issues we're seeing on CI, where there seems to be items not being drawn, and they are affected even though the test in question doesn't draw any gradients. This is not a very elegant fix - however it will hopefully fix the issues we are seeing on CI for now. We can revisit this later to consider a better fix. --- webrender/src/batch.rs | 10 +++++++--- webrender/src/frame_builder.rs | 28 +++++++++++++++++++++++----- webrender/src/prim_store.rs | 25 +++++++++++++++++++++---- webrender/src/tiling.rs | 3 ++- 4 files changed, 53 insertions(+), 13 deletions(-) diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 048be35515..596283120f 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -18,7 +18,7 @@ use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveIn use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface}; use plane_split::{BspSplitter, Polygon, Splitter}; -use prim_store::{ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore}; +use prim_store::{CachedGradient, ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore}; use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PrimitiveRun}; use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree}; use renderer::{BlendMode, ImageBufferKind}; @@ -681,6 +681,7 @@ impl AlphaBatchBuilder { ctx.resource_cache, gpu_cache, deferred_resolves, + &ctx.cached_gradients, ) { self.add_brush_to_batch( brush, @@ -1312,6 +1313,7 @@ impl BrushPrimitive { resource_cache: &ResourceCache, gpu_cache: &mut GpuCache, deferred_resolves: &mut Vec, + cached_gradients: &[CachedGradient], ) -> Option<(BrushBatchKind, BatchTextures, [i32; 3])> { match self.kind { BrushKind::Line { .. } => { @@ -1358,7 +1360,8 @@ impl BrushPrimitive { [0; 3], )) } - BrushKind::RadialGradient { ref stops_handle, .. } => { + BrushKind::RadialGradient { gradient_index, .. } => { + let stops_handle = &cached_gradients[gradient_index.0].handle; Some(( BrushBatchKind::RadialGradient, BatchTextures::no_texture(), @@ -1369,7 +1372,8 @@ impl BrushPrimitive { ], )) } - BrushKind::LinearGradient { ref stops_handle, .. } => { + BrushKind::LinearGradient { gradient_index, .. } => { + let stops_handle = &cached_gradients[gradient_index.0].handle; Some(( BrushBatchKind::LinearGradient, BatchTextures::no_texture(), diff --git a/webrender/src/frame_builder.rs b/webrender/src/frame_builder.rs index f3023300bd..8aecebb038 100644 --- a/webrender/src/frame_builder.rs +++ b/webrender/src/frame_builder.rs @@ -18,12 +18,12 @@ use clip_scroll_tree::{ClipScrollTree, ClipChainIndex}; use euclid::{SideOffsets2D, vec2}; use frame::{FrameId, ClipIdToIndexMapper}; use glyph_rasterizer::FontInstance; -use gpu_cache::{GpuCache, GpuCacheHandle}; +use gpu_cache::GpuCache; use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, PictureType}; use hit_test::{HitTester, HitTestingItem, HitTestingRun}; use internal_types::{FastHashMap, FastHashSet}; use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface}; -use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor}; +use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient, CachedGradientIndex}; use prim_store::{ImageCacheKey, ImagePrimitiveCpu, ImageSource, PrimitiveContainer}; use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveRun, PrimitiveStore}; use prim_store::{ScrollNodeAndClipChain, TextRunPrimitiveCpu}; @@ -85,6 +85,7 @@ pub struct FrameBuilder { pub clip_store: ClipStore, hit_testing_runs: Vec, pub config: FrameBuilderConfig, + pub cached_gradients: Vec, // A stack of the current shadow primitives. // The sub-Vec stores a buffer of fast-path primitives to be appended on pop. @@ -123,6 +124,7 @@ pub struct FrameState<'a> { pub local_clip_rects: &'a mut Vec, pub resource_cache: &'a mut ResourceCache, pub gpu_cache: &'a mut GpuCache, + pub cached_gradients: &'a mut [CachedGradient], } pub struct PictureContext<'a> { @@ -172,6 +174,7 @@ impl FrameBuilder { FrameBuilder { hit_testing_runs: Vec::new(), shadow_prim_stack: Vec::new(), + cached_gradients: Vec::new(), pending_shadow_contents: Vec::new(), scrollbar_prims: Vec::new(), reference_frame_stack: Vec::new(), @@ -200,6 +203,7 @@ impl FrameBuilder { FrameBuilder { hit_testing_runs: recycle_vec(self.hit_testing_runs), shadow_prim_stack: recycle_vec(self.shadow_prim_stack), + cached_gradients: recycle_vec(self.cached_gradients), pending_shadow_contents: recycle_vec(self.pending_shadow_contents), scrollbar_prims: recycle_vec(self.scrollbar_prims), reference_frame_stack: recycle_vec(self.reference_frame_stack), @@ -1232,7 +1236,7 @@ impl FrameBuilder { } } - pub fn add_gradient_impl( + fn add_gradient_impl( &mut self, clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, @@ -1241,6 +1245,7 @@ impl FrameBuilder { stops: ItemRange, stops_count: usize, extend_mode: ExtendMode, + gradient_index: CachedGradientIndex, ) { // Try to ensure that if the gradient is specified in reverse, then so long as the stops // are also supplied in reverse that the rendered result will be equivalent. To do this, @@ -1262,13 +1267,13 @@ impl FrameBuilder { let prim = BrushPrimitive::new( BrushKind::LinearGradient { - stops_handle: GpuCacheHandle::new(), stops_range: stops, stops_count, extend_mode, reverse_stops, start_point: sp, end_point: ep, + gradient_index, }, None, ); @@ -1290,6 +1295,9 @@ impl FrameBuilder { tile_size: LayerSize, tile_spacing: LayerSize, ) { + let gradient_index = CachedGradientIndex(self.cached_gradients.len()); + self.cached_gradients.push(CachedGradient::new()); + let prim_infos = info.decompose( tile_size, tile_spacing, @@ -1305,6 +1313,7 @@ impl FrameBuilder { stops, stops_count, extend_mode, + gradient_index, ); } else { for prim_info in prim_infos { @@ -1316,6 +1325,7 @@ impl FrameBuilder { stops, stops_count, extend_mode, + gradient_index, ); } } @@ -1332,17 +1342,18 @@ impl FrameBuilder { ratio_xy: f32, stops: ItemRange, extend_mode: ExtendMode, + gradient_index: CachedGradientIndex, ) { let prim = BrushPrimitive::new( BrushKind::RadialGradient { stops_range: stops, extend_mode, - stops_handle: GpuCacheHandle::new(), start_center, end_center, start_radius, end_radius, ratio_xy, + gradient_index, }, None, ); @@ -1369,6 +1380,9 @@ impl FrameBuilder { tile_size: LayerSize, tile_spacing: LayerSize, ) { + let gradient_index = CachedGradientIndex(self.cached_gradients.len()); + self.cached_gradients.push(CachedGradient::new()); + let prim_infos = info.decompose( tile_size, tile_spacing, @@ -1386,6 +1400,7 @@ impl FrameBuilder { ratio_xy, stops, extend_mode, + gradient_index, ); } else { for prim_info in prim_infos { @@ -1399,6 +1414,7 @@ impl FrameBuilder { ratio_xy, stops, extend_mode, + gradient_index, ); } } @@ -1718,6 +1734,7 @@ impl FrameBuilder { local_clip_rects, resource_cache, gpu_cache, + cached_gradients: &mut self.cached_gradients, }; let pic_context = PictureContext { @@ -1886,6 +1903,7 @@ impl FrameBuilder { clip_scroll_tree, use_dual_source_blending, node_data: &node_data, + cached_gradients: &self.cached_gradients, }; pass.build( diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index e6ab6538a1..29a5695e3c 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -71,6 +71,21 @@ impl PrimitiveOpacity { } } +#[derive(Debug, Copy, Clone)] +pub struct CachedGradientIndex(pub usize); + +pub struct CachedGradient { + pub handle: GpuCacheHandle, +} + +impl CachedGradient { + pub fn new() -> CachedGradient { + CachedGradient { + handle: GpuCacheHandle::new(), + } + } +} + // Represents the local space rect of a list of // primitive runs. For most primitive runs, the // primitive runs are attached to the parent they @@ -205,9 +220,9 @@ pub enum BrushKind { image_rendering: ImageRendering, }, RadialGradient { + gradient_index: CachedGradientIndex, stops_range: ItemRange, extend_mode: ExtendMode, - stops_handle: GpuCacheHandle, start_center: LayerPoint, end_center: LayerPoint, start_radius: f32, @@ -215,9 +230,9 @@ pub enum BrushKind { ratio_xy: f32, }, LinearGradient { + gradient_index: CachedGradientIndex, stops_range: ItemRange, stops_count: usize, - stops_handle: GpuCacheHandle, extend_mode: ExtendMode, reverse_stops: bool, start_point: LayerPoint, @@ -1255,7 +1270,8 @@ impl PrimitiveStore { ); } } - BrushKind::RadialGradient { ref mut stops_handle, stops_range, .. } => { + BrushKind::RadialGradient { gradient_index, stops_range, .. } => { + let stops_handle = &mut frame_state.cached_gradients[gradient_index.0].handle; if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) { let gradient_builder = GradientGpuBlockBuilder::new( stops_range, @@ -1267,7 +1283,8 @@ impl PrimitiveStore { ); } } - BrushKind::LinearGradient { ref mut stops_handle, stops_range, reverse_stops, .. } => { + BrushKind::LinearGradient { gradient_index, stops_range, reverse_stops, .. } => { + let stops_handle = &mut frame_state.cached_gradients[gradient_index.0].handle; if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) { let gradient_builder = GradientGpuBlockBuilder::new( stops_range, diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index ba18a150f4..90e1d34271 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -16,7 +16,7 @@ use gpu_types::{ClipScrollNodeData, ClipScrollNodeIndex}; use gpu_types::{PrimitiveInstance}; use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; use picture::{PictureKind}; -use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveStore}; +use prim_store::{CachedGradient, PrimitiveIndex, PrimitiveKind, PrimitiveStore}; use prim_store::{BrushMaskKind, BrushKind, DeferredResolve, EdgeAaSegmentMask}; use profiler::FrameProfileCounters; use render_task::{BlitSource, RenderTaskAddress, RenderTaskId, RenderTaskKind}; @@ -46,6 +46,7 @@ pub struct RenderTargetContext<'a> { pub clip_scroll_tree: &'a ClipScrollTree, pub use_dual_source_blending: bool, pub node_data: &'a [ClipScrollNodeData], + pub cached_gradients: &'a [CachedGradient], } #[cfg_attr(feature = "capture", derive(Serialize))]