diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index d88ff71ca9..00ac0f6350 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -15,10 +15,10 @@ use gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance}; use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette}; use internal_types::{FastHashMap, SavedTargetIndex, TextureSource}; use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureSurface}; -use prim_store::{BrushKind, BrushPrimitive, DeferredResolve, PrimitiveTemplateKind, PrimitiveDataStore}; +use prim_store::{DeferredResolve, PrimitiveTemplateKind, PrimitiveDataStore}; use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveInstanceKind}; use prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex}; -use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex, PrimitiveDetails}; +use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex}; use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree}; use renderer::{BlendMode, ImageBufferKind, ShaderColorMode}; use renderer::BLOCKS_PER_UV_RECT; @@ -902,13 +902,13 @@ impl AlphaBatchBuilder { PrimitiveInstanceKind::Picture { pic_index } => pic_index, PrimitiveInstanceKind::LineDecoration { .. } | PrimitiveInstanceKind::TextRun { .. } | - PrimitiveInstanceKind::LegacyPrimitive { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::Rectangle { .. } | PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::Image { .. } | PrimitiveInstanceKind::LinearGradient { .. } | + PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::Clear => { unreachable!(); } @@ -1400,104 +1400,6 @@ impl AlphaBatchBuilder { } } } - ( - PrimitiveInstanceKind::LegacyPrimitive { prim_index }, - PrimitiveTemplateKind::Unused, - ) => { - let prim = &ctx.prim_store.primitives[prim_index.0]; - - // If the primitive is internally decomposed into multiple sub-primitives we may not - // use some of the per-primitive data and get it from each sub-primitive instead. - let is_multiple_primitives = match prim.details { - PrimitiveDetails::Brush(ref brush) => { - match brush.kind { - BrushKind::RadialGradient { visible_tiles_range, .. } => !visible_tiles_range.is_empty(), - } - } - }; - - let specified_blend_mode = BlendMode::PremultipliedAlpha; - - match prim.details { - PrimitiveDetails::Brush(ref brush) => { - let non_segmented_blend_mode = if !brush.opacity.is_opaque || - prim_instance.clip_task_index != ClipTaskIndex::INVALID || - transform_kind == TransformedRectKind::Complex - { - specified_blend_mode - } else { - BlendMode::None - }; - - let prim_cache_address = if is_multiple_primitives { - GpuCacheAddress::invalid() - } else { - gpu_cache.get_address(&brush.gpu_location) - }; - - let prim_header = PrimitiveHeader { - local_rect: prim.local_rect, - local_clip_rect: prim_instance.combined_local_clip_rect, - task_address, - specific_prim_address: prim_cache_address, - clip_task_address, - transform_id, - }; - - if prim_instance.is_chased() { - println!("\ttask target {:?}", self.target_rect); - println!("\t{:?}", prim_header); - } - - match brush.kind { - BrushKind::RadialGradient { ref stops_handle, visible_tiles_range, .. } if !visible_tiles_range.is_empty() => { - let visible_tiles = &ctx.scratch.gradient_tiles[visible_tiles_range]; - - add_gradient_tiles( - visible_tiles, - stops_handle, - BrushBatchKind::RadialGradient, - specified_blend_mode, - bounding_rect, - clip_task_address, - gpu_cache, - &mut self.batch_list, - &prim_header, - prim_headers, - z_id, - ); - } - _ => { - if let Some(params) = brush.get_batch_params( - gpu_cache, - ) { - let prim_header_index = prim_headers.push(&prim_header, z_id, params.prim_user_data); - if prim_instance.is_chased() { - println!("\t{:?} {:?}, task relative bounds {:?}", - params.batch_kind, prim_header_index, bounding_rect); - } - - self.add_segmented_prim_to_batch( - brush.segment_desc.as_ref().map(|desc| desc.segments.as_slice()), - brush.opacity, - ¶ms, - specified_blend_mode, - non_segmented_blend_mode, - prim_header_index, - clip_task_address, - bounding_rect, - transform_kind, - render_tasks, - z_id, - prim_instance.clip_task_index, - ctx, - ); - } - } - } - } - } - } ( PrimitiveInstanceKind::ImageBorder { .. }, PrimitiveTemplateKind::ImageBorder { request, brush_segments, .. } @@ -1964,6 +1866,89 @@ impl AlphaBatchBuilder { ); } } + ( + PrimitiveInstanceKind::RadialGradient { visible_tiles_range, .. }, + PrimitiveTemplateKind::RadialGradient { stops_handle, ref brush_segments, .. } + ) => { + let specified_blend_mode = BlendMode::PremultipliedAlpha; + + let mut prim_header = PrimitiveHeader { + local_rect: prim_data.prim_rect, + local_clip_rect: prim_instance.combined_local_clip_rect, + task_address, + specific_prim_address: GpuCacheAddress::invalid(), + clip_task_address, + transform_id, + }; + + if visible_tiles_range.is_empty() { + let non_segmented_blend_mode = if !prim_data.opacity.is_opaque || + prim_instance.clip_task_index != ClipTaskIndex::INVALID || + transform_kind == TransformedRectKind::Complex + { + specified_blend_mode + } else { + BlendMode::None + }; + + let batch_params = BrushBatchParameters::shared( + BrushBatchKind::RadialGradient, + BatchTextures::no_texture(), + [ + stops_handle.as_int(gpu_cache), + 0, + 0, + ], + 0, + ); + + prim_header.specific_prim_address = gpu_cache.get_address(&prim_data.gpu_cache_handle); + + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + batch_params.prim_user_data, + ); + + let segments = if brush_segments.is_empty() { + None + } else { + Some(brush_segments.as_slice()) + }; + + self.add_segmented_prim_to_batch( + segments, + prim_data.opacity, + &batch_params, + specified_blend_mode, + non_segmented_blend_mode, + prim_header_index, + clip_task_address, + bounding_rect, + transform_kind, + render_tasks, + z_id, + prim_instance.clip_task_index, + ctx, + ); + } else { + let visible_tiles = &ctx.scratch.gradient_tiles[*visible_tiles_range]; + + add_gradient_tiles( + visible_tiles, + stops_handle, + BrushBatchKind::RadialGradient, + specified_blend_mode, + bounding_rect, + clip_task_address, + gpu_cache, + &mut self.batch_list, + &prim_header, + prim_headers, + z_id, + ); + } + } _ => { unreachable!(); } @@ -2295,28 +2280,6 @@ impl BrushBatchParameters { } } -impl BrushPrimitive { - fn get_batch_params( - &self, - gpu_cache: &mut GpuCache, - ) -> Option { - match self.kind { - BrushKind::RadialGradient { ref stops_handle, .. } => { - Some(BrushBatchParameters::shared( - BrushBatchKind::RadialGradient, - BatchTextures::no_texture(), - [ - stops_handle.as_int(gpu_cache), - 0, - 0, - ], - 0, - )) - } - } - } -} - impl PrimitiveInstance { pub fn is_cacheable( &self, @@ -2337,7 +2300,6 @@ impl PrimitiveInstance { _ => unreachable!(), } } - PrimitiveInstanceKind::LegacyPrimitive { .. } | PrimitiveInstanceKind::Picture { .. } | PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::LineDecoration { .. } | @@ -2345,6 +2307,7 @@ impl PrimitiveInstance { PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::Rectangle { .. } | PrimitiveInstanceKind::LinearGradient { .. } | + PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::Clear => { return true; } diff --git a/webrender/src/border.rs b/webrender/src/border.rs index cc16a826b8..c22a428f6f 100644 --- a/webrender/src/border.rs +++ b/webrender/src/border.rs @@ -11,7 +11,7 @@ use euclid::vec2; use display_list_flattener::DisplayListFlattener; use gpu_types::{BorderInstance, BorderSegment, BrushFlags}; use prim_store::{BorderSegmentInfo, BrushSegment, NinePatchDescriptor}; -use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain}; +use prim_store::{EdgeAaSegmentMask, ScrollNodeAndClipChain, PrimitiveKeyKind}; use util::{lerp, RectHelpers}; // Using 2048 as the maximum radius in device space before which we @@ -117,6 +117,18 @@ pub struct NormalBorderAu { pub do_aa: bool, } +impl NormalBorderAu { + // Construct a border based upon self with color + pub fn with_color(&self, color: ColorU) -> Self { + let mut b = self.clone(); + b.left.color = color; + b.right.color = color; + b.top.color = color; + b.bottom.color = color; + b + } +} + impl From for NormalBorderAu { fn from(border: NormalBorder) -> Self { NormalBorderAu { @@ -217,9 +229,9 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll, info, Vec::new(), - PrimitiveContainer::NormalBorder { - border, - widths, + PrimitiveKeyKind::NormalBorder { + border: border.into(), + widths: widths.to_au(), }, ); } diff --git a/webrender/src/box_shadow.rs b/webrender/src/box_shadow.rs index 7e9170bb9a..eaaa4fd71b 100644 --- a/webrender/src/box_shadow.rs +++ b/webrender/src/box_shadow.rs @@ -8,8 +8,7 @@ use clip::ClipItemKey; use display_list_flattener::DisplayListFlattener; use gpu_cache::GpuCacheHandle; use gpu_types::BoxShadowStretchMode; -use prim_store::PrimitiveContainer; -use prim_store::ScrollNodeAndClipChain; +use prim_store::{ScrollNodeAndClipChain, PrimitiveKeyKind}; use render_task::RenderTaskCacheEntryHandle; use util::RectHelpers; @@ -73,7 +72,7 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayoutPrimitiveInfo, box_offset: &LayoutVector2D, - color: &ColorF, + color: ColorF, mut blur_radius: f32, spread_radius: f32, border_radius: BorderRadius, @@ -149,8 +148,8 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll, &LayoutPrimitiveInfo::with_clip_rect(final_prim_rect, prim_info.clip_rect), clips, - PrimitiveContainer::Rectangle { - color: *color, + PrimitiveKeyKind::Rectangle { + color: color.into(), }, ); } else { @@ -172,8 +171,8 @@ impl<'a> DisplayListFlattener<'a> { // Draw the box-shadow as a solid rect, using a box-shadow // clip mask item. - let prim = PrimitiveContainer::Rectangle { - color: *color, + let prim = PrimitiveKeyKind::Rectangle { + color: color.into(), }; // Create the box-shadow clip item. diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index 8b7f63cf85..efa17f972d 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -5,7 +5,7 @@ use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter, ClipAndScrollInfo}; use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize}; -use api::{DisplayItemRef, ExtendMode, ExternalScrollId}; +use api::{DisplayItemRef, ExtendMode, ExternalScrollId, AuHelpers}; use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, RasterSpace, GradientStop}; use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint, ColorDepth}; use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D}; @@ -13,24 +13,23 @@ use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId}; use api::{PropertyBinding, ReferenceFrame, ScrollFrameDisplayItem, ScrollSensitivity}; use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect}; use api::{ClipMode, TransformStyle, YuvColorSpace, YuvData}; +use app_units::Au; use clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore, ClipItemSceneData}; use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex}; use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig}; use glyph_rasterizer::FontInstance; -use gpu_cache::GpuCacheHandle; use hit_test::{HitTestingItem, HitTestingRun}; use image::simplify_repeated_primitive; use internal_types::{FastHashMap, FastHashSet}; use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PrimitiveList}; -use prim_store::{BrushKind, BrushPrimitive, PrimitiveInstance, PrimitiveDataInterner, PrimitiveKeyKind}; +use prim_store::{PrimitiveInstance, PrimitiveDataInterner, PrimitiveKeyKind, RadialGradientParams}; use prim_store::{PrimitiveKey, PrimitiveSceneData, PrimitiveInstanceKind, GradientStopKey, NinePatchDescriptor}; -use prim_store::{PrimitiveContainer, PrimitiveDataHandle, PrimitiveStore, PrimitiveStoreStats, BrushSegmentDescriptor}; -use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, GradientTileRange}; +use prim_store::{PrimitiveDataHandle, PrimitiveStore, PrimitiveStoreStats, LineDecorationCacheKey}; +use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, get_line_decoration_sizes}; use render_backend::{DocumentView}; use resource_cache::{FontInstanceMap, ImageRequest}; use scene::{Scene, ScenePipeline, StackingContextHelpers}; use scene_builder::DocumentResources; -use smallvec::SmallVec; use spatial_node::{StickyFrameInfo}; use std::{f32, mem}; use std::collections::vec_deque::VecDeque; @@ -575,12 +574,12 @@ impl<'a> DisplayListFlattener<'a> { &prim_info, info.wavy_line_thickness, info.orientation, - &info.color, + info.color, info.style, ); } SpecificDisplayItem::Gradient(ref info) => { - if let Some(prim) = self.create_linear_gradient_prim( + if let Some(prim_key_kind) = self.create_linear_gradient_prim( &prim_info, info.gradient.start_point, info.gradient.end_point, @@ -595,12 +594,12 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll, &prim_info, Vec::new(), - prim, + prim_key_kind, ); } } SpecificDisplayItem::RadialGradient(ref info) => { - let brush_kind = self.create_brush_kind_for_radial_gradient( + let prim_key_kind = self.create_radial_gradient_prim( &prim_info, info.gradient.center, info.gradient.start_offset * info.gradient.radius.width, @@ -610,9 +609,15 @@ impl<'a> DisplayListFlattener<'a> { info.gradient.extend_mode, info.tile_size, info.tile_spacing, + pipeline_id, + None, + ); + self.add_primitive( + clip_and_scroll, + &prim_info, + Vec::new(), + prim_key_kind, ); - let prim = PrimitiveContainer::Brush(BrushPrimitive::new(brush_kind, None)); - self.add_primitive(clip_and_scroll, &prim_info, Vec::new(), prim); } SpecificDisplayItem::BoxShadow(ref box_shadow_info) => { let bounds = box_shadow_info @@ -624,7 +629,7 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll, &prim_info, &box_shadow_info.offset, - &box_shadow_info.color, + box_shadow_info.color, box_shadow_info.blur_radius, box_shadow_info.spread_radius, box_shadow_info.border_radius, @@ -838,16 +843,9 @@ impl<'a> DisplayListFlattener<'a> { info: &LayoutPrimitiveInfo, clip_chain_id: ClipChainId, spatial_node_index: SpatialNodeIndex, - container: PrimitiveContainer, + prim_key_kind: PrimitiveKeyKind, ) -> PrimitiveInstance { - // Build a primitive key, and optionally an old - // style PrimitiveDetails structure from the - // source primitive container. - let mut info = info.clone(); - let (prim_key_kind, prim_details) = container.build( - &mut info, - ); - + // Build a primitive key. let prim_key = PrimitiveKey::new( info.is_backface_visible, info.rect, @@ -871,24 +869,7 @@ impl<'a> DisplayListFlattener<'a> { } }); - // If we are building an old style primitive, add it to - // the prim store, and create a primitive index for it. - // For an interned primitive, use the primitive key to - // create a matching primitive instance kind. - let instance_kind = match prim_details { - Some(prim_details) => { - let prim_index = self.prim_store.add_primitive( - &info.rect, - &info.clip_rect, - prim_details, - ); - - PrimitiveInstanceKind::LegacyPrimitive { prim_index } - } - None => { - prim_key.to_instance_kind(&mut self.prim_store) - } - }; + let instance_kind = prim_key.to_instance_kind(&mut self.prim_store); PrimitiveInstance::new( instance_kind, @@ -941,12 +922,12 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll: ScrollNodeAndClipChain, info: &LayoutPrimitiveInfo, clip_items: Vec, - container: PrimitiveContainer, + key_kind: PrimitiveKeyKind, ) { // If a shadow context is not active, then add the primitive // directly to the parent picture. if self.pending_shadow_items.is_empty() { - if container.is_visible() { + if key_kind.is_visible() { let clip_chain_id = self.build_clip_chain( clip_items, clip_and_scroll.spatial_node_index, @@ -956,7 +937,7 @@ impl<'a> DisplayListFlattener<'a> { info, clip_chain_id, clip_and_scroll.spatial_node_index, - container, + key_kind, ); self.register_chase_primitive_by_rect( &info.rect, @@ -973,7 +954,7 @@ impl<'a> DisplayListFlattener<'a> { self.pending_shadow_items.push_back(ShadowItem::Primitive(PendingPrimitive { clip_and_scroll, info: *info, - container, + key_kind, })); } } @@ -1559,7 +1540,7 @@ impl<'a> DisplayListFlattener<'a> { &info, pending_primitive.clip_and_scroll.clip_chain_id, pending_primitive.clip_and_scroll.spatial_node_index, - pending_primitive.container.create_shadow( + pending_primitive.key_kind.create_shadow( &pending_shadow.shadow, ), ); @@ -1630,12 +1611,12 @@ impl<'a> DisplayListFlattener<'a> { ShadowItem::Primitive(pending_primitive) => { // For a normal primitive, if it has alpha > 0, then we add this // as a normal primitive to the parent picture. - if pending_primitive.container.is_visible() { + if pending_primitive.key_kind.is_visible() { let prim_instance = self.create_primitive( &pending_primitive.info, pending_primitive.clip_and_scroll.clip_chain_id, pending_primitive.clip_and_scroll.spatial_node_index, - pending_primitive.container, + pending_primitive.key_kind, ); self.register_chase_primitive_by_rect( &pending_primitive.info.rect, @@ -1689,8 +1670,8 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll, info, Vec::new(), - PrimitiveContainer::Rectangle { - color, + PrimitiveKeyKind::Rectangle { + color: color.into(), }, ); } @@ -1704,7 +1685,7 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll, info, Vec::new(), - PrimitiveContainer::Clear, + PrimitiveKeyKind::Clear, ); } @@ -1714,21 +1695,69 @@ impl<'a> DisplayListFlattener<'a> { info: &LayoutPrimitiveInfo, wavy_line_thickness: f32, orientation: LineOrientation, - color: &ColorF, + color: ColorF, style: LineStyle, ) { - let container = PrimitiveContainer::LineDecoration { - color: *color, - style, + // For line decorations, we can construct the render task cache key + // here during scene building, since it doesn't depend on device + // pixel ratio or transform. + let mut info = info.clone(); + + let size = get_line_decoration_sizes( + &info.rect.size, orientation, + style, wavy_line_thickness, - }; + ); + + let cache_key = size.map(|(inline_size, block_size)| { + let size = match orientation { + LineOrientation::Horizontal => LayoutSize::new(inline_size, block_size), + LineOrientation::Vertical => LayoutSize::new(block_size, inline_size), + }; + + // If dotted, adjust the clip rect to ensure we don't draw a final + // partial dot. + if style == LineStyle::Dotted { + let clip_size = match orientation { + LineOrientation::Horizontal => { + LayoutSize::new( + inline_size * (info.rect.size.width / inline_size).floor(), + info.rect.size.height, + ) + } + LineOrientation::Vertical => { + LayoutSize::new( + info.rect.size.width, + inline_size * (info.rect.size.height / inline_size).floor(), + ) + } + }; + let clip_rect = LayoutRect::new( + info.rect.origin, + clip_size, + ); + info.clip_rect = clip_rect + .intersection(&info.clip_rect) + .unwrap_or(LayoutRect::zero()); + } + + LineDecorationCacheKey { + style, + orientation, + wavy_line_thickness: Au::from_f32_px(wavy_line_thickness), + size: size.to_au(), + } + }); self.add_primitive( clip_and_scroll, - info, + &info, Vec::new(), - container, + PrimitiveKeyKind::LineDecoration { + cache_key, + color: color.into(), + }, ); } @@ -1755,7 +1784,7 @@ impl<'a> DisplayListFlattener<'a> { let prim = match border.source { NinePatchBorderSource::Image(image_key) => { - PrimitiveContainer::ImageBorder { + PrimitiveKeyKind::ImageBorder { request: ImageRequest { key: image_key, rendering: ImageRendering::Auto, @@ -1781,7 +1810,7 @@ impl<'a> DisplayListFlattener<'a> { } } NinePatchBorderSource::RadialGradient(gradient) => { - let brush_kind = self.create_brush_kind_for_radial_gradient( + self.create_radial_gradient_prim( &info, gradient.center, gradient.start_offset * gradient.radius.width, @@ -1791,16 +1820,8 @@ impl<'a> DisplayListFlattener<'a> { gradient.extend_mode, LayoutSize::new(border.height as f32, border.width as f32), LayoutSize::zero(), - ); - - let segments = nine_patch.create_segments(&info.rect); - - let descriptor = BrushSegmentDescriptor { - segments: SmallVec::from_vec(segments), - }; - - PrimitiveContainer::Brush( - BrushPrimitive::new(brush_kind, Some(descriptor)) + pipeline_id, + Some(Box::new(nine_patch)), ) } }; @@ -1834,7 +1855,7 @@ impl<'a> DisplayListFlattener<'a> { mut tile_spacing: LayoutSize, pipeline_id: PipelineId, nine_patch: Option>, - ) -> Option { + ) -> Option { let mut prim_rect = info.rect; simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect); @@ -1876,19 +1897,19 @@ impl<'a> DisplayListFlattener<'a> { (start_point, end_point) }; - Some(PrimitiveContainer::LinearGradient { + Some(PrimitiveKeyKind::LinearGradient { extend_mode, - start_point: sp, - end_point: ep, - stretch_size, - tile_spacing, + start_point: sp.into(), + end_point: ep.into(), + stretch_size: stretch_size.into(), + tile_spacing: tile_spacing.into(), stops, reverse_stops, nine_patch, }) } - pub fn create_brush_kind_for_radial_gradient( + pub fn create_radial_gradient_prim( &mut self, info: &LayoutPrimitiveInfo, center: LayoutPoint, @@ -1899,21 +1920,38 @@ impl<'a> DisplayListFlattener<'a> { extend_mode: ExtendMode, stretch_size: LayoutSize, mut tile_spacing: LayoutSize, - ) -> BrushKind { + pipeline_id: PipelineId, + nine_patch: Option>, + ) -> PrimitiveKeyKind { let mut prim_rect = info.rect; simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect); - BrushKind::RadialGradient { - stops_range: stops, - extend_mode, - center, + // TODO(gw): It seems like we should be able to look this up once in + // flatten_root() and pass to all children here to avoid + // some hash lookups? + let display_list = self.scene.get_display_list_for_pipeline(pipeline_id); + + let params = RadialGradientParams { start_radius, end_radius, ratio_xy, - stops_handle: GpuCacheHandle::new(), - stretch_size, - tile_spacing, - visible_tiles_range: GradientTileRange::empty(), + }; + + let stops = display_list.get(stops).map(|stop| { + GradientStopKey { + offset: stop.offset, + color: stop.color.into(), + } + }).collect(); + + PrimitiveKeyKind::RadialGradient { + extend_mode, + center: center.into(), + params, + stretch_size: stretch_size.into(), + tile_spacing: tile_spacing.into(), + nine_patch, + stops, } } @@ -1977,10 +2015,10 @@ impl<'a> DisplayListFlattener<'a> { // primitive template. let glyphs = display_list.get(glyph_range).collect(); - PrimitiveContainer::TextRun { + PrimitiveKeyKind::TextRun { glyphs, font, - offset, + offset: offset.to_au(), shadow: false, } }; @@ -2029,11 +2067,11 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll, &info, Vec::new(), - PrimitiveContainer::Image { + PrimitiveKeyKind::Image { key: image_key, - tile_spacing, - stretch_size, - color, + tile_spacing: tile_spacing.into(), + stretch_size: stretch_size.into(), + color: color.into(), sub_rect, image_rendering, alpha_type, @@ -2061,7 +2099,7 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll, info, Vec::new(), - PrimitiveContainer::YuvImage { + PrimitiveKeyKind::YuvImage { color_depth, yuv_key, format, @@ -2200,7 +2238,7 @@ impl FlattenedStackingContext { struct PendingPrimitive { clip_and_scroll: ScrollNodeAndClipChain, info: LayoutPrimitiveInfo, - container: PrimitiveContainer, + key_kind: PrimitiveKeyKind, } /// As shadows are pushed, they are stored as pending diff --git a/webrender/src/frame_builder.rs b/webrender/src/frame_builder.rs index f19ae7a103..0b93afe330 100644 --- a/webrender/src/frame_builder.rs +++ b/webrender/src/frame_builder.rs @@ -338,7 +338,7 @@ impl FrameBuilder { let mut profile_counters = FrameProfileCounters::new(); profile_counters .total_primitives - .set(self.prim_store.prim_count()); + .set(self.prim_store.prim_count); resource_cache.begin_frame(stamp); gpu_cache.begin_frame(stamp.frame_id()); diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index 93a1037471..30b74396fe 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -441,12 +441,12 @@ impl TileCache { } } } - PrimitiveInstanceKind::LegacyPrimitive { .. } | PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::LineDecoration { .. } | PrimitiveInstanceKind::Clear | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::LinearGradient { .. } | + PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::ImageBorder { .. } => { // These don't contribute dependencies } diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 61c3da5890..4b14feabf5 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -2,11 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipMode, ColorF, PictureRect, ColorU, LayoutPrimitiveInfo}; +use api::{AlphaType, BorderRadius, ClipMode, ColorF, PictureRect, ColorU}; use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, ExtendMode, DeviceRect, LayoutSideOffsetsAu}; -use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, ItemRange, TileOffset, RepeatMode}; +use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, TileOffset, RepeatMode}; use api::{RasterSpace, LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, LayoutToWorldTransform}; -use api::{LayoutVector2D, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat}; +use api::{PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat}; use api::{DeviceIntSideOffsets, WorldPixel, BoxShadowClipMode, NormalBorder, WorldRect, LayoutToWorldScale}; use api::{PicturePixel, RasterPixel, ColorDepth, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers, LayoutVector2DAu}; use app_units::Au; @@ -298,11 +298,6 @@ pub struct DeferredResolve { pub rendering: ImageRendering, } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct PrimitiveIndex(pub usize); - #[derive(Debug, Copy, Clone, PartialEq)] pub struct ClipTaskIndex(pub u32); @@ -406,6 +401,15 @@ pub enum PrimitiveKeyKind { reverse_stops: bool, nine_patch: Option>, }, + RadialGradient { + extend_mode: ExtendMode, + center: PointKey, + params: RadialGradientParams, + stretch_size: SizeKey, + stops: Vec, + tile_spacing: SizeKey, + nine_patch: Option>, + }, } /// A hashable gradient stop that can be used in primitive keys. @@ -525,7 +529,7 @@ impl From> for SideOffsetsKey { /// A hashable size for using as a key during primitive interning. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Copy, Debug, Clone, PartialEq)] pub struct SizeKey { w: f32, h: f32, @@ -555,6 +559,26 @@ impl From for SizeKey { } } +/// Hashable radial gradient parameters, for use during prim interning. +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Debug, Clone, PartialEq)] +pub struct RadialGradientParams { + pub start_radius: f32, + pub end_radius: f32, + pub ratio_xy: f32, +} + +impl Eq for RadialGradientParams {} + +impl hash::Hash for RadialGradientParams { + fn hash(&self, state: &mut H) { + self.start_radius.to_bits().hash(state); + self.end_radius.to_bits().hash(state); + self.ratio_xy.to_bits().hash(state); + } +} + /// A hashable point for using as a key during primitive interning. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -677,6 +701,11 @@ impl PrimitiveKey { visible_tiles_range: GradientTileRange::empty(), } } + PrimitiveKeyKind::RadialGradient { .. } => { + PrimitiveInstanceKind::RadialGradient { + visible_tiles_range: GradientTileRange::empty(), + } + } PrimitiveKeyKind::Unused => { // Should never be hit as this method should not be // called for old style primitives. @@ -748,6 +777,16 @@ pub enum PrimitiveTemplateKind { reverse_stops: bool, stops_handle: GpuCacheHandle, }, + RadialGradient { + extend_mode: ExtendMode, + center: LayoutPoint, + params: RadialGradientParams, + stretch_size: LayoutSize, + tile_spacing: LayoutSize, + brush_segments: Vec, + stops: Vec, + stops_handle: GpuCacheHandle, + }, Clear, Unused, } @@ -892,6 +931,40 @@ impl PrimitiveKeyKind { stops_handle: GpuCacheHandle::new(), } } + PrimitiveKeyKind::RadialGradient { + extend_mode, + params, + stretch_size, + tile_spacing, + nine_patch, + center, + stops, + .. + } => { + let mut brush_segments = Vec::new(); + + if let Some(ref nine_patch) = nine_patch { + brush_segments = nine_patch.create_segments(rect); + } + + let stops = stops.iter().map(|stop| { + GradientStop { + offset: stop.offset, + color: stop.color.into(), + } + }).collect(); + + PrimitiveTemplateKind::RadialGradient { + center: center.into(), + extend_mode, + params, + stretch_size: stretch_size.into(), + tile_spacing: tile_spacing.into(), + brush_segments, + stops_handle: GpuCacheHandle::new(), + stops, + } + } } } } @@ -1054,6 +1127,26 @@ impl PrimitiveTemplateKind { 0.0, ]); } + PrimitiveTemplateKind::RadialGradient { + center, + ref params, + extend_mode, + stretch_size, + .. + } => { + request.push([ + center.x, + center.y, + params.start_radius, + params.end_radius, + ]); + request.push([ + params.ratio_xy, + pack_as_float(extend_mode as u32), + stretch_size.width, + stretch_size.height, + ]); + } PrimitiveTemplateKind::Unused => {} } } @@ -1094,7 +1187,8 @@ impl PrimitiveTemplateKind { [0.0; 4], ); } - PrimitiveTemplateKind::LinearGradient { ref brush_segments, .. } => { + PrimitiveTemplateKind::LinearGradient { ref brush_segments, .. } | + PrimitiveTemplateKind::RadialGradient { ref brush_segments, .. } => { for segment in brush_segments { // has to match VECS_PER_SEGMENT request.write_segment( @@ -1156,7 +1250,7 @@ impl PrimitiveTemplate { GradientGpuBlockBuilder::build( reverse_stops, &mut request, - stops.iter().cloned(), + stops, ); } @@ -1173,6 +1267,18 @@ impl PrimitiveTemplate { PrimitiveOpacity::translucent() } } + PrimitiveTemplateKind::RadialGradient { ref mut stops_handle, ref stops, .. } => { + if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) { + GradientGpuBlockBuilder::build( + false, + &mut request, + stops, + ); + } + + //TODO: can we make it opaque in some cases? + PrimitiveOpacity::translucent() + } PrimitiveTemplateKind::ImageBorder { request, .. } => { let image_properties = frame_state .resource_cache @@ -1439,21 +1545,6 @@ pub struct BorderSegmentInfo { pub cache_key: BorderSegmentCacheKey, } -pub enum BrushKind { - RadialGradient { - stops_handle: GpuCacheHandle, - stops_range: ItemRange, - extend_mode: ExtendMode, - center: LayoutPoint, - start_radius: f32, - end_radius: f32, - ratio_xy: f32, - stretch_size: LayoutSize, - tile_spacing: LayoutSize, - visible_tiles_range: GradientTileRange, - }, -} - bitflags! { /// Each bit of the edge AA mask is: /// 0, when the edge of the primitive needs to be considered for AA @@ -1565,78 +1656,6 @@ impl BrushSegment { } } -pub type BrushSegmentVec = SmallVec<[BrushSegment; 1]>; - -#[derive(Debug)] -pub struct BrushSegmentDescriptor { - pub segments: BrushSegmentVec, -} - -pub struct BrushPrimitive { - pub kind: BrushKind, - pub opacity: PrimitiveOpacity, - pub segment_desc: Option, - pub gpu_location: GpuCacheHandle, -} - -impl BrushPrimitive { - pub fn new( - kind: BrushKind, - segment_desc: Option, - ) -> Self { - BrushPrimitive { - kind, - opacity: PrimitiveOpacity::translucent(), - segment_desc, - gpu_location: GpuCacheHandle::new(), - } - } - - fn write_gpu_blocks_if_required( - &mut self, - local_rect: LayoutRect, - gpu_cache: &mut GpuCache, - ) { - if let Some(mut request) = gpu_cache.request(&mut self.gpu_location) { - // has to match VECS_PER_SPECIFIC_BRUSH - match self.kind { - BrushKind::RadialGradient { stretch_size, center, start_radius, end_radius, ratio_xy, extend_mode, .. } => { - request.push([ - center.x, - center.y, - start_radius, - end_radius, - ]); - request.push([ - ratio_xy, - pack_as_float(extend_mode as u32), - stretch_size.width, - stretch_size.height, - ]); - } - } - - match self.segment_desc { - Some(ref segment_desc) => { - for segment in &segment_desc.segments { - // has to match VECS_PER_SEGMENT - request.write_segment( - segment.local_rect, - segment.extra_data, - ); - } - } - None => { - request.write_segment( - local_rect, - [0.0; 4], - ); - } - } - } - } -} - // Key that identifies a unique (partial) image that is being // stored in the render task cache. #[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)] @@ -1651,10 +1670,10 @@ pub struct ImageCacheKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct LineDecorationCacheKey { - style: LineStyle, - orientation: LineOrientation, - wavy_line_thickness: Au, - size: LayoutSizeAu, + pub style: LineStyle, + pub orientation: LineOrientation, + pub wavy_line_thickness: Au, + pub size: LayoutSizeAu, } // Where to find the texture data for an image primitive. @@ -1739,11 +1758,11 @@ impl GradientGpuBlockBuilder { } // Build the gradient data from the supplied stops, reversing them if necessary. - fn build( + fn build( reverse_stops: bool, request: &mut GpuDataRequest, - src_stops: I, - ) where I: IntoIterator { + src_stops: &[GradientStop], + ) { // Preconditions (should be ensured by DisplayListBuilder): // * we have at least two stops // * first stop has offset 0.0 @@ -2190,61 +2209,7 @@ pub struct NinePatchDescriptor { pub widths: SideOffsetsKey, } -pub enum PrimitiveContainer { - TextRun { - font: FontInstance, - offset: LayoutVector2D, - glyphs: Vec, - shadow: bool, - }, - Clear, - Brush(BrushPrimitive), - LineDecoration { - color: ColorF, - style: LineStyle, - orientation: LineOrientation, - wavy_line_thickness: f32, - }, - NormalBorder { - border: NormalBorder, - widths: LayoutSideOffsets, - }, - ImageBorder { - request: ImageRequest, - nine_patch: NinePatchDescriptor, - }, - Rectangle { - color: ColorF, - }, - YuvImage { - color_depth: ColorDepth, - yuv_key: [ImageKey; 3], - format: YuvFormat, - color_space: YuvColorSpace, - image_rendering: ImageRendering, - }, - Image { - key: ImageKey, - color: ColorF, - tile_spacing: LayoutSize, - stretch_size: LayoutSize, - sub_rect: Option, - image_rendering: ImageRendering, - alpha_type: AlphaType, - }, - LinearGradient { - extend_mode: ExtendMode, - start_point: LayoutPoint, - end_point: LayoutPoint, - stretch_size: LayoutSize, - tile_spacing: LayoutSize, - stops: Vec, - reverse_stops: bool, - nine_patch: Option>, - }, -} - -impl PrimitiveContainer { +impl PrimitiveKeyKind { // Return true if the primary primitive is visible. // Used to trivially reject non-visible primitives. // TODO(gw): Currently, primitives other than those @@ -2254,183 +2219,22 @@ impl PrimitiveContainer { // primitive types to use this. pub fn is_visible(&self) -> bool { match *self { - PrimitiveContainer::TextRun { ref font, .. } => { + PrimitiveKeyKind::TextRun { ref font, .. } => { font.color.a > 0 } - PrimitiveContainer::Brush(ref brush) => { - match brush.kind { - BrushKind::RadialGradient { .. } => { - true - } - } - } - PrimitiveContainer::NormalBorder { .. } | - PrimitiveContainer::ImageBorder { .. } | - PrimitiveContainer::YuvImage { .. } | - PrimitiveContainer::Image { .. } | - PrimitiveContainer::LinearGradient { .. } | - PrimitiveContainer::Clear => { + PrimitiveKeyKind::NormalBorder { .. } | + PrimitiveKeyKind::ImageBorder { .. } | + PrimitiveKeyKind::YuvImage { .. } | + PrimitiveKeyKind::Image { .. } | + PrimitiveKeyKind::LinearGradient { .. } | + PrimitiveKeyKind::RadialGradient { .. } | + PrimitiveKeyKind::Clear | + PrimitiveKeyKind::Unused => { true } - PrimitiveContainer::Rectangle { ref color, .. } | - PrimitiveContainer::LineDecoration { ref color, .. } => { - color.a > 0.0 - } - } - } - - /// Convert a source primitive container into a key, and optionally - /// an old style PrimitiveDetails structure. - pub fn build( - self, - info: &mut LayoutPrimitiveInfo, - ) -> (PrimitiveKeyKind, Option) { - match self { - PrimitiveContainer::TextRun { font, offset, glyphs, shadow, .. } => { - let key = PrimitiveKeyKind::TextRun { - font, - offset: offset.to_au(), - glyphs, - shadow, - }; - - (key, None) - } - PrimitiveContainer::LinearGradient { - extend_mode, - start_point, - end_point, - stretch_size, - tile_spacing, - stops, - reverse_stops, - nine_patch, - .. - } => { - let key = PrimitiveKeyKind::LinearGradient { - extend_mode, - start_point: start_point.into(), - end_point: end_point.into(), - stretch_size: stretch_size.into(), - tile_spacing: tile_spacing.into(), - stops, - reverse_stops, - nine_patch, - }; - - (key, None) - } - PrimitiveContainer::Clear => { - (PrimitiveKeyKind::Clear, None) - } - PrimitiveContainer::Rectangle { color, .. } => { - let key = PrimitiveKeyKind::Rectangle { - color: color.into(), - }; - - (key, None) - } - PrimitiveContainer::Image { alpha_type, key, stretch_size, color, tile_spacing, image_rendering, sub_rect, .. } => { - let key = PrimitiveKeyKind::Image { - key, - tile_spacing: tile_spacing.into(), - stretch_size: stretch_size.into(), - color: color.into(), - sub_rect, - image_rendering, - alpha_type, - }; - - (key, None) - } - PrimitiveContainer::YuvImage { color_depth, yuv_key, format, color_space, image_rendering, .. } => { - let key = PrimitiveKeyKind::YuvImage { - color_depth, - yuv_key, - format, - color_space, - image_rendering, - }; - - (key, None) - } - PrimitiveContainer::ImageBorder { request, nine_patch, .. } => { - let key = PrimitiveKeyKind::ImageBorder { - request, - nine_patch, - }; - - (key, None) - } - PrimitiveContainer::NormalBorder { border, widths, .. } => { - let key = PrimitiveKeyKind::NormalBorder { - border: border.into(), - widths: widths.to_au(), - }; - - (key, None) - } - PrimitiveContainer::LineDecoration { color, style, orientation, wavy_line_thickness } => { - // For line decorations, we can construct the render task cache key - // here during scene building, since it doesn't depend on device - // pixel ratio or transform. - - let size = get_line_decoration_sizes( - &info.rect.size, - orientation, - style, - wavy_line_thickness, - ); - - let cache_key = size.map(|(inline_size, block_size)| { - let size = match orientation { - LineOrientation::Horizontal => LayoutSize::new(inline_size, block_size), - LineOrientation::Vertical => LayoutSize::new(block_size, inline_size), - }; - - // If dotted, adjust the clip rect to ensure we don't draw a final - // partial dot. - if style == LineStyle::Dotted { - let clip_size = match orientation { - LineOrientation::Horizontal => { - LayoutSize::new( - inline_size * (info.rect.size.width / inline_size).floor(), - info.rect.size.height, - ) - } - LineOrientation::Vertical => { - LayoutSize::new( - info.rect.size.width, - inline_size * (info.rect.size.height / inline_size).floor(), - ) - } - }; - let clip_rect = LayoutRect::new( - info.rect.origin, - clip_size, - ); - info.clip_rect = clip_rect - .intersection(&info.clip_rect) - .unwrap_or(LayoutRect::zero()); - } - - LineDecorationCacheKey { - style, - orientation, - wavy_line_thickness: Au::from_f32_px(wavy_line_thickness), - size: size.to_au(), - } - }); - - let key = PrimitiveKeyKind::LineDecoration { - cache_key, - color: color.into(), - }; - - (key, None) - } - PrimitiveContainer::Brush(prim) => { - (PrimitiveKeyKind::Unused, Some(PrimitiveDetails::Brush(prim))) + PrimitiveKeyKind::Rectangle { ref color, .. } | + PrimitiveKeyKind::LineDecoration { ref color, .. } => { + color.a > 0 } } } @@ -2441,9 +2245,9 @@ impl PrimitiveContainer { pub fn create_shadow( &self, shadow: &Shadow, - ) -> PrimitiveContainer { + ) -> PrimitiveKeyKind { match *self { - PrimitiveContainer::TextRun { ref font, offset, ref glyphs, .. } => { + PrimitiveKeyKind::TextRun { ref font, offset, ref glyphs, .. } => { let mut font = FontInstance { color: shadow.color.into(), ..font.clone() @@ -2452,65 +2256,54 @@ impl PrimitiveContainer { font.disable_subpixel_aa(); } - PrimitiveContainer::TextRun { + PrimitiveKeyKind::TextRun { font, glyphs: glyphs.clone(), - offset: offset + shadow.offset, + offset: offset + shadow.offset.to_au(), shadow: true, } } - PrimitiveContainer::LineDecoration { style, orientation, wavy_line_thickness, .. } => { - PrimitiveContainer::LineDecoration { - color: shadow.color, - style, - orientation, - wavy_line_thickness, + PrimitiveKeyKind::LineDecoration { ref cache_key, .. } => { + PrimitiveKeyKind::LineDecoration { + color: shadow.color.into(), + cache_key: cache_key.clone(), } } - PrimitiveContainer::Rectangle { .. } => { - PrimitiveContainer::Rectangle { - color: shadow.color, + PrimitiveKeyKind::Rectangle { .. } => { + PrimitiveKeyKind::Rectangle { + color: shadow.color.into(), } } - PrimitiveContainer::NormalBorder { border, widths, .. } => { - let border = border.with_color(shadow.color); - PrimitiveContainer::NormalBorder { + PrimitiveKeyKind::NormalBorder { ref border, widths, .. } => { + let border = border.with_color(shadow.color.into()); + PrimitiveKeyKind::NormalBorder { border, widths, } } - PrimitiveContainer::Image { alpha_type, image_rendering, tile_spacing, stretch_size, key, sub_rect, .. } => { - PrimitiveContainer::Image { + PrimitiveKeyKind::Image { alpha_type, image_rendering, tile_spacing, stretch_size, key, sub_rect, .. } => { + PrimitiveKeyKind::Image { tile_spacing, stretch_size, key, sub_rect, image_rendering, alpha_type, - color: shadow.color, + color: shadow.color.into(), } } - PrimitiveContainer::Brush(..) | - PrimitiveContainer::ImageBorder { .. } | - PrimitiveContainer::YuvImage { .. } | - PrimitiveContainer::LinearGradient { .. } | - PrimitiveContainer::Clear => { + PrimitiveKeyKind::ImageBorder { .. } | + PrimitiveKeyKind::YuvImage { .. } | + PrimitiveKeyKind::LinearGradient { .. } | + PrimitiveKeyKind::RadialGradient { .. } | + PrimitiveKeyKind::Unused | + PrimitiveKeyKind::Clear => { panic!("bug: this prim is not supported in shadow contexts"); } } } } -pub enum PrimitiveDetails { - Brush(BrushPrimitive), -} - -pub struct Primitive { - pub local_rect: LayoutRect, - pub local_clip_rect: LayoutRect, - pub details: PrimitiveDetails, -} - /// Instance specific fields for an image primitive. These are /// currently stored in a separate array to avoid bloating the /// size of PrimitiveInstance. In the future, we should be able @@ -2541,11 +2334,6 @@ pub enum PrimitiveInstanceKind { Picture { pic_index: PictureIndex, }, - /// An old style, non-interned primitive. Uses prim_index to - /// access the primitive details in the prim_store. - LegacyPrimitive { - prim_index: PrimitiveIndex, - }, /// A run of glyphs, with associated font parameters. TextRun { run_index: TextRunIndex, @@ -2581,6 +2369,9 @@ pub enum PrimitiveInstanceKind { LinearGradient { visible_tiles_range: GradientTileRange, }, + RadialGradient { + visible_tiles_range: GradientTileRange, + }, /// Clear out a rect, used for special effects. Clear, } @@ -2757,7 +2548,6 @@ impl PrimitiveScratchBuffer { #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(Clone, Debug)] pub struct PrimitiveStoreStats { - primitive_count: usize, picture_count: usize, text_run_count: usize, opacity_binding_count: usize, @@ -2767,7 +2557,6 @@ pub struct PrimitiveStoreStats { impl PrimitiveStoreStats { pub fn empty() -> Self { PrimitiveStoreStats { - primitive_count: 0, picture_count: 0, text_run_count: 0, opacity_binding_count: 0, @@ -2777,7 +2566,6 @@ impl PrimitiveStoreStats { } pub struct PrimitiveStore { - pub primitives: Vec, pub pictures: Vec, pub text_runs: TextRunStorage, @@ -2788,22 +2576,25 @@ pub struct PrimitiveStore { /// List of animated opacity bindings for a primitive. pub opacity_bindings: OpacityBindingStorage, + + /// Total count of primitive instances contained in pictures. + /// This is used for profile counters only. + pub prim_count: usize, } impl PrimitiveStore { pub fn new(stats: &PrimitiveStoreStats) -> PrimitiveStore { PrimitiveStore { - primitives: Vec::with_capacity(stats.primitive_count), pictures: Vec::with_capacity(stats.picture_count), text_runs: TextRunStorage::new(stats.text_run_count), images: ImageInstanceStorage::new(stats.image_count), opacity_bindings: OpacityBindingStorage::new(stats.opacity_binding_count), + prim_count: 0, } } pub fn get_stats(&self) -> PrimitiveStoreStats { PrimitiveStoreStats { - primitive_count: self.primitives.len(), picture_count: self.pictures.len(), text_run_count: self.text_runs.len(), image_count: self.images.len(), @@ -2816,6 +2607,7 @@ impl PrimitiveStore { prim: PicturePrimitive, ) -> PictureIndex { let index = PictureIndex(self.pictures.len()); + self.prim_count += prim.prim_list.prim_instances.len(); self.pictures.push(prim); index } @@ -2867,25 +2659,6 @@ impl PrimitiveStore { } } - pub fn add_primitive( - &mut self, - local_rect: &LayoutRect, - local_clip_rect: &LayoutRect, - details: PrimitiveDetails, - ) -> PrimitiveIndex { - let prim_index = self.primitives.len(); - - let prim = Primitive { - local_rect: *local_rect, - local_clip_rect: *local_clip_rect, - details, - }; - - self.primitives.push(prim); - - PrimitiveIndex(prim_index) - } - pub fn get_opacity_binding( &self, opacity_binding_index: OpacityBindingIndex, @@ -2929,8 +2702,8 @@ impl PrimitiveStore { PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::YuvImage { .. } | - PrimitiveInstanceKind::LegacyPrimitive { .. } | PrimitiveInstanceKind::LinearGradient { .. } | + PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::LineDecoration { .. } => { // These prims don't support opacity collapse } @@ -3011,10 +2784,6 @@ impl PrimitiveStore { self.pictures[pic_index.0].requested_composite_mode = None; } - pub fn prim_count(&self) -> usize { - self.primitives.len() - } - pub fn prepare_prim_for_render( &mut self, prim_instance: &mut PrimitiveInstance, @@ -3023,7 +2792,6 @@ impl PrimitiveStore { pic_state: &mut PictureState, frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, - display_list: &BuiltDisplayList, plane_split_anchor: usize, resources: &mut FrameResources, scratch: &mut PrimitiveScratchBuffer, @@ -3060,12 +2828,12 @@ impl PrimitiveStore { PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::Rectangle { .. } | PrimitiveInstanceKind::LineDecoration { .. } | - PrimitiveInstanceKind::LegacyPrimitive { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::Image { .. } | PrimitiveInstanceKind::LinearGradient { .. } | + PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::Clear => { None } @@ -3121,15 +2889,12 @@ impl PrimitiveStore { PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::Image { .. } | PrimitiveInstanceKind::LinearGradient { .. } | + PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::LineDecoration { .. } => { let prim_data = &resources .prim_data_store[prim_instance.prim_data_handle]; (prim_data.prim_rect, prim_data.clip_rect) } - PrimitiveInstanceKind::LegacyPrimitive { prim_index } => { - let prim = &self.primitives[prim_index.0]; - (prim.local_rect, prim.local_clip_rect) - } }; // TODO(gw): Eventually we can move all the code handling below for @@ -3323,6 +3088,7 @@ impl PrimitiveStore { PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::Image { .. } | PrimitiveInstanceKind::LinearGradient { .. } | + PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::LineDecoration { .. } => { self.prepare_interned_prim_for_render( prim_instance, @@ -3334,19 +3100,6 @@ impl PrimitiveStore { scratch, ); } - PrimitiveInstanceKind::LegacyPrimitive { prim_index } => { - let prim_details = &mut self.primitives[prim_index.0].details; - - prim_instance.prepare_prim_for_render_inner( - prim_local_rect, - prim_details, - prim_context, - pic_context, - frame_state, - display_list, - scratch, - ); - } } true @@ -3362,12 +3115,6 @@ impl PrimitiveStore { resources: &mut FrameResources, scratch: &mut PrimitiveScratchBuffer, ) { - let display_list = &frame_context - .pipelines - .get(&pic_context.pipeline_id) - .expect("No display list?") - .display_list; - for (plane_split_anchor, prim_instance) in prim_list.prim_instances.iter_mut().enumerate() { prim_instance.bounding_rect = None; @@ -3438,7 +3185,6 @@ impl PrimitiveStore { pic_state, frame_context, frame_state, - display_list, plane_split_anchor, resources, scratch, @@ -3783,6 +3529,46 @@ impl PrimitiveStore { // for gradient primitives. SegmentInstanceIndex::UNUSED } + ( + PrimitiveInstanceKind::RadialGradient { ref mut visible_tiles_range, .. }, + PrimitiveTemplateKind::RadialGradient { ref params, extend_mode, stretch_size, tile_spacing, center, .. } + ) => { + if *tile_spacing != LayoutSize::zero() { + *visible_tiles_range = decompose_repeated_primitive( + &prim_instance.combined_local_clip_rect, + &prim_data.prim_rect, + &stretch_size, + &tile_spacing, + prim_context, + frame_state, + &pic_context.dirty_world_rect, + &mut scratch.gradient_tiles, + &mut |rect, mut request| { + request.push([ + center.x, + center.y, + params.start_radius, + params.end_radius, + ]); + request.push([ + params.ratio_xy, + pack_as_float(*extend_mode as u32), + stretch_size.width, + stretch_size.height, + ]); + request.write_segment(*rect, [0.0; 4]); + }, + ); + + if visible_tiles_range.is_empty() { + prim_instance.bounding_rect = None; + } + } + + // TODO(gw): Consider whether it's worth doing segment building + // for gradient primitives. + SegmentInstanceIndex::UNUSED + } _ => { unreachable!(); } @@ -4075,57 +3861,11 @@ impl PrimitiveInstance { PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::Clear | PrimitiveInstanceKind::LinearGradient { .. } | + PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::LineDecoration { .. } => { // These primitives don't support / need segments. return; } - PrimitiveInstanceKind::LegacyPrimitive { prim_index } => { - let prim = &mut prim_store.primitives[prim_index.0]; - match prim.details { - PrimitiveDetails::Brush(ref mut brush) => { - match brush.segment_desc { - Some(..) => { - // If we already have a segment descriptor, skip segment build. - return; - } - None => { - // If no segment descriptor built yet, see if it is a brush - // type that wants to be segmented. - let mut segments = BrushSegmentVec::new(); - - if write_brush_segment_description( - prim_local_rect, - prim_local_clip_rect, - prim_clip_chain, - &mut frame_state.segment_builder, - frame_state.clip_store, - resources, - ) { - frame_state.segment_builder.build(|segment| { - segments.push( - BrushSegment::new( - segment.rect, - segment.has_mask, - segment.edge_flags, - [0.0; 4], - BrushFlags::empty(), - ), - ); - }); - } - - if !segments.is_empty() { - brush.segment_desc = Some(BrushSegmentDescriptor { - segments, - }); - } - } - } - } - } - - return; - } }; if *segment_instance_index == SegmentInstanceIndex::INVALID { @@ -4265,18 +4005,21 @@ impl PrimitiveInstance { } } } - PrimitiveInstanceKind::LegacyPrimitive { prim_index } => { - let prim = &prim_store.primitives[prim_index.0]; - match prim.details { - PrimitiveDetails::Brush(ref brush) => { - match brush.segment_desc { - Some(ref description) => { - &description.segments - } - None => { - return false; - } + PrimitiveInstanceKind::RadialGradient { .. } => { + let prim_data = &resources.prim_data_store[self.prim_data_handle]; + + // TODO: This is quite messy - once we remove legacy primitives we + // can change this to be a tuple match on (instance, template) + match prim_data.kind { + PrimitiveTemplateKind::RadialGradient { ref brush_segments, .. } => { + if brush_segments.is_empty() { + return false; } + + brush_segments.as_slice() + } + _ => { + unreachable!(); } } } @@ -4349,101 +4092,6 @@ impl PrimitiveInstance { true } - fn prepare_prim_for_render_inner( - &mut self, - prim_local_rect: LayoutRect, - prim_details: &mut PrimitiveDetails, - prim_context: &PrimitiveContext, - pic_context: &PictureContext, - frame_state: &mut FrameBuildingState, - display_list: &BuiltDisplayList, - scratch: &mut PrimitiveScratchBuffer, - ) { - let mut is_tiled = false; - - match *prim_details { - PrimitiveDetails::Brush(ref mut brush) => { - brush.opacity = match brush.kind { - BrushKind::RadialGradient { - stops_range, - center, - start_radius, - end_radius, - ratio_xy, - extend_mode, - stretch_size, - tile_spacing, - ref mut stops_handle, - ref mut visible_tiles_range, - .. - } => { - if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) { - let src_stops = display_list.get(stops_range); - - GradientGpuBlockBuilder::build( - false, - &mut request, - src_stops, - ); - } - - if tile_spacing != LayoutSize::zero() { - is_tiled = true; - - *visible_tiles_range = decompose_repeated_primitive( - &self.combined_local_clip_rect, - &prim_local_rect, - &stretch_size, - &tile_spacing, - prim_context, - frame_state, - &pic_context.dirty_world_rect, - &mut scratch.gradient_tiles, - &mut |rect, mut request| { - request.push([ - center.x, - center.y, - start_radius, - end_radius, - ]); - request.push([ - ratio_xy, - pack_as_float(extend_mode as u32), - stretch_size.width, - stretch_size.height, - ]); - request.write_segment(*rect, [0.0; 4]); - }, - ); - - if visible_tiles_range.is_empty() { - self.bounding_rect = None; - } - } - - //TODO: can we make it opaque in some cases? - PrimitiveOpacity::translucent() - } - }; - } - } - - if is_tiled { - // we already requested each tile's gpu data. - return; - } - - // Mark this GPU resource as required for this frame. - match *prim_details { - PrimitiveDetails::Brush(ref mut brush) => { - brush.write_gpu_blocks_if_required( - prim_local_rect, - frame_state.gpu_cache, - ); - } - } - } - fn update_clip_task( &mut self, prim_local_rect: LayoutRect, @@ -4566,7 +4214,7 @@ pub fn get_raster_rects( /// Get the inline (horizontal) and block (vertical) sizes /// for a given line decoration. -fn get_line_decoration_sizes( +pub fn get_line_decoration_sizes( rect_size: &LayoutSize, orientation: LineOrientation, style: LineStyle, @@ -4632,12 +4280,10 @@ fn test_struct_sizes() { // test expectations and move on. // (b) You made a structure larger. This is not necessarily a problem, but should only // be done with care, and after checking if talos performance regresses badly. - assert_eq!(mem::size_of::(), 176, "PrimitiveContainer size changed"); assert_eq!(mem::size_of::(), 120, "PrimitiveInstance size changed"); assert_eq!(mem::size_of::(), 16, "PrimitiveInstanceKind size changed"); assert_eq!(mem::size_of::(), 176, "PrimitiveTemplate size changed"); assert_eq!(mem::size_of::(), 112, "PrimitiveTemplateKind size changed"); assert_eq!(mem::size_of::(), 152, "PrimitiveKey size changed"); assert_eq!(mem::size_of::(), 112, "PrimitiveKeyKind size changed"); - assert_eq!(mem::size_of::(), 200, "Primitive size changed"); } diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index 0fc3123afd..28fa06e9b6 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -49,7 +49,6 @@ use serde_json; use std::path::PathBuf; use std::sync::atomic::{AtomicUsize, Ordering}; use std::mem::replace; -use std::os::raw::c_void; use std::sync::mpsc::{channel, Sender, Receiver}; use std::time::{UNIX_EPOCH, SystemTime}; use std::u32; @@ -1369,18 +1368,12 @@ impl RenderBackend { serde_json::to_string(&debug_root).unwrap() } - fn size_of(&self, ptr: *const T) -> usize { - let op = self.size_of_op.as_ref().unwrap(); - unsafe { op(ptr as *const c_void) } - } - fn report_memory(&self) -> MemoryReport { let mut report = MemoryReport::default(); let op = self.size_of_op.unwrap(); report.gpu_cache_metadata = self.gpu_cache.malloc_size_of(op); for (_id, doc) in &self.documents { if let Some(ref fb) = doc.frame_builder { - report.primitive_stores += self.size_of(fb.prim_store.primitives.as_ptr()); report.clip_stores += fb.clip_store.malloc_size_of(op); } report.hit_testers += diff --git a/webrender/src/surface.rs b/webrender/src/surface.rs index 97947175fe..c4f39fb00e 100644 --- a/webrender/src/surface.rs +++ b/webrender/src/surface.rs @@ -236,14 +236,14 @@ impl SurfaceDescriptor { // a legacy primitive or picture, then fail to create a cache // descriptor. match prim_instance.kind { - PrimitiveInstanceKind::Picture { .. } | - PrimitiveInstanceKind::LegacyPrimitive { .. } => { + PrimitiveInstanceKind::Picture { .. } => { return None; } PrimitiveInstanceKind::Image { .. } | PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::LineDecoration { .. } | PrimitiveInstanceKind::LinearGradient { .. } | + PrimitiveInstanceKind::RadialGradient { .. } | PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::Rectangle { .. } | diff --git a/webrender_api/src/display_item.rs b/webrender_api/src/display_item.rs index 4700871042..6cadaf3218 100644 --- a/webrender_api/src/display_item.rs +++ b/webrender_api/src/display_item.rs @@ -274,16 +274,6 @@ pub struct NormalBorder { } impl NormalBorder { - // Construct a border based upon self with color - pub fn with_color(&self, color: ColorF) -> Self { - let mut b = *self; - b.left.color = color; - b.right.color = color; - b.top.color = color; - b.bottom.color = color; - b - } - fn can_disable_antialiasing(&self) -> bool { fn is_valid(style: BorderStyle) -> bool { style == BorderStyle::Solid || style == BorderStyle::None @@ -463,7 +453,7 @@ pub struct Shadow { pub blur_radius: f32, } -#[repr(u32)] +#[repr(u8)] #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)] pub enum ExtendMode { Clamp, diff --git a/wrench/reftests/gradient/premultiplied-radial-2.png b/wrench/reftests/gradient/premultiplied-radial-2.png index 01a551e6ea..9a4462c7af 100644 Binary files a/wrench/reftests/gradient/premultiplied-radial-2.png and b/wrench/reftests/gradient/premultiplied-radial-2.png differ