From 5e25afb9c5089719335a2ea43e81a4c625d9b195 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 23 Oct 2017 09:46:47 -0400 Subject: [PATCH] Bug 1409736 - Update webrender to commit d741f472dd3d6c3441646f7bf4e714c71bea39b7. r=jrmuizel MozReview-Commit-ID: FhFX2PAHwU --HG-- extra : rebase_source : 34c2d4bedadc940cf4a16dbdd6e0755eee909889 --- gfx/doc/README.webrender | 2 +- gfx/webrender/Cargo.toml | 2 +- gfx/webrender/examples/basic.rs | 8 +- gfx/webrender/examples/blob.rs | 6 +- gfx/webrender/examples/common/boilerplate.rs | 16 +- gfx/webrender/res/brush_mask.glsl | 18 +- gfx/webrender/res/cs_blur.glsl | 24 +- gfx/webrender/src/border.rs | 26 ++- gfx/webrender/src/clip.rs | 24 +- gfx/webrender/src/frame.rs | 9 +- gfx/webrender/src/frame_builder.rs | 228 +++++++++++++++---- gfx/webrender/src/gpu_types.rs | 4 +- gfx/webrender/src/picture.rs | 141 ++++++++++-- gfx/webrender/src/prim_store.rs | 77 +++---- gfx/webrender/src/render_backend.rs | 68 ++---- gfx/webrender/src/render_task.rs | 29 ++- gfx/webrender/src/renderer.rs | 45 ++-- gfx/webrender/src/resource_cache.rs | 2 +- gfx/webrender/src/tiling.rs | 111 ++++++--- gfx/webrender_api/Cargo.toml | 3 +- gfx/webrender_api/src/api.rs | 9 +- gfx/webrender_api/src/color.rs | 1 - gfx/webrender_api/src/display_item.rs | 54 +++-- gfx/webrender_api/src/display_list.rs | 43 +++- gfx/webrender_api/src/image.rs | 2 +- gfx/webrender_api/src/lib.rs | 2 - gfx/webrender_bindings/Cargo.toml | 4 +- 27 files changed, 627 insertions(+), 331 deletions(-) diff --git a/gfx/doc/README.webrender b/gfx/doc/README.webrender index ae7d8df4e3e7..a13a493c798b 100644 --- a/gfx/doc/README.webrender +++ b/gfx/doc/README.webrender @@ -175,4 +175,4 @@ Troubleshooting tips: ------------------------------------------------------------------------------- The version of WebRender currently in the tree is: -7892f5364bc4d35c7a9b42949f0ace4cc54f8b3c +d741f472dd3d6c3441646f7bf4e714c71bea39b7 diff --git a/gfx/webrender/Cargo.toml b/gfx/webrender/Cargo.toml index e88b7a24f2fc..2989c5cd2add 100644 --- a/gfx/webrender/Cargo.toml +++ b/gfx/webrender/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webrender" -version = "0.52.1" +version = "0.53.0" authors = ["Glenn Watson "] license = "MPL-2.0" repository = "https://github.com/servo/webrender" diff --git a/gfx/webrender/examples/basic.rs b/gfx/webrender/examples/basic.rs index 6c32fc5c87e8..a9784842ce37 100644 --- a/gfx/webrender/examples/basic.rs +++ b/gfx/webrender/examples/basic.rs @@ -218,7 +218,11 @@ impl Example for App { rect: (75, 75).by(100, 100), repeat: false, }; - let complex = ComplexClipRegion::new((50, 50).to(150, 150), BorderRadius::uniform(20.0)); + let complex = ComplexClipRegion::new( + (50, 50).to(150, 150), + BorderRadius::uniform(20.0), + ClipMode::Clip + ); let id = builder.define_clip(None, bounds, vec![complex], Some(mask)); builder.push_clip_id(id); @@ -339,7 +343,7 @@ impl Example for App { color, blur_radius, spread_radius, - simple_border_radius, + BorderRadius::uniform(simple_border_radius), box_shadow_type, ); } diff --git a/gfx/webrender/examples/blob.rs b/gfx/webrender/examples/blob.rs index 4384d96151a5..919e7eb25da1 100644 --- a/gfx/webrender/examples/blob.rs +++ b/gfx/webrender/examples/blob.rs @@ -17,8 +17,8 @@ use std::collections::HashMap; use std::collections::hash_map::Entry; use std::sync::Arc; use std::sync::mpsc::{channel, Receiver, Sender}; -use webrender::api::{self, DisplayListBuilder, DocumentId, LayoutSize, PipelineId, RenderApi, - ResourceUpdates}; +use webrender::api::{self, DeviceUintRect, DisplayListBuilder, DocumentId, LayoutSize, PipelineId, + RenderApi, ResourceUpdates}; // This example shows how to implement a very basic BlobImageRenderer that can only render // a checkerboard pattern. @@ -145,7 +145,7 @@ impl api::BlobImageRenderer for CheckerboardRenderer { .insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap())); } - fn update(&mut self, key: api::ImageKey, cmds: api::BlobImageData) { + fn update(&mut self, key: api::ImageKey, cmds: api::BlobImageData, _dirty_rect: Option) { // Here, updating is just replacing the current version of the commands with // the new one (no incremental updates). self.image_cmds diff --git a/gfx/webrender/examples/common/boilerplate.rs b/gfx/webrender/examples/common/boilerplate.rs index 785f38d8d8b7..2822c0c8c5a7 100644 --- a/gfx/webrender/examples/common/boilerplate.rs +++ b/gfx/webrender/examples/common/boilerplate.rs @@ -22,12 +22,18 @@ impl Notifier { } impl RenderNotifier for Notifier { - fn new_frame_ready(&mut self) { + fn clone(&self) -> Box { + Box::new(Notifier { + window_proxy: self.window_proxy.clone(), + }) + } + + fn new_frame_ready(&self) { #[cfg(not(target_os = "android"))] self.window_proxy.wakeup_event_loop(); } - fn new_scroll_frame_ready(&mut self, _composite_needed: bool) { + fn new_scroll_frame_ready(&self, _composite_needed: bool) { #[cfg(not(target_os = "android"))] self.window_proxy.wakeup_event_loop(); } @@ -125,13 +131,11 @@ pub fn main_wrapper(example: &mut Example, options: Option 0.0) { + vec4 blur_region = aBlurRegion * uDevicePixelRatio; + src_rect = vec4(src_rect.xy + blur_region.xy, blur_region.zw); + target_rect = vec4(target_rect.xy + blur_region.xy, blur_region.zw); + } + + vec2 pos = target_rect.xy + target_rect.zw * aPosition.xy; + + vec2 uv0 = src_rect.xy / texture_size; + vec2 uv1 = (src_rect.xy + src_rect.zw) / texture_size; vUv.xy = mix(uv0, uv1, aPosition.xy); gl_Position = uTransform * vec4(pos, 0.0, 1.0); diff --git a/gfx/webrender/src/border.rs b/gfx/webrender/src/border.rs index 2a7440f1de83..627a748916f1 100644 --- a/gfx/webrender/src/border.rs +++ b/gfx/webrender/src/border.rs @@ -15,6 +15,7 @@ use util::{lerp, pack_as_float}; #[repr(u8)] #[derive(Debug, Copy, Clone, PartialEq)] pub enum BorderCornerInstance { + None, Single, // Single instance needed - corner styles are same or similar. Double, // Different corner styles. Draw two instances, one per style. } @@ -128,8 +129,8 @@ impl NormalBorderHelpers for NormalBorder { corner: BorderCorner, border_rect: &LayerRect, ) -> BorderCornerKind { - // If either width is zero, a corner isn't formed. - if width0 == 0.0 || width1 == 0.0 { + // If both widths are zero, a corner isn't formed. + if width0 == 0.0 && width1 == 0.0 { return BorderCornerKind::None; } @@ -139,9 +140,13 @@ impl NormalBorderHelpers for NormalBorder { } match (edge0.style, edge1.style) { - // If either edge is none or hidden, no corner is needed. - (BorderStyle::None, _) | (_, BorderStyle::None) => BorderCornerKind::None, - (BorderStyle::Hidden, _) | (_, BorderStyle::Hidden) => BorderCornerKind::None, + // If both edges are none or hidden, no corner is needed. + (BorderStyle::None, BorderStyle::None) | + (BorderStyle::None, BorderStyle::Hidden) | + (BorderStyle::Hidden, BorderStyle::None) | + (BorderStyle::Hidden, BorderStyle::Hidden) => { + BorderCornerKind::None + } // If both borders are solid, we can draw them with a simple rectangle if // both the colors match and there is no radius. @@ -429,16 +434,19 @@ impl FrameBuilder { let mut corner_instances = [BorderCornerInstance::Single; 4]; for (i, corner) in corners.iter().enumerate() { - match corner { - &BorderCornerKind::Mask(corner_data, corner_radius, widths, kind) => { + match *corner { + BorderCornerKind::Mask(corner_data, corner_radius, widths, kind) => { let clip_source = BorderCornerClipSource::new(corner_data, corner_radius, widths, kind); extra_clips.push(ClipSource::BorderCorner(clip_source)); } - &BorderCornerKind::Clip(instance_kind) => { + BorderCornerKind::Clip(instance_kind) => { corner_instances[i] = instance_kind; } - _ => {} + BorderCornerKind::Solid => {} + BorderCornerKind::None => { + corner_instances[i] = BorderCornerInstance::None; + } } } diff --git a/gfx/webrender/src/clip.rs b/gfx/webrender/src/clip.rs index 22738e674114..de8e20a45cd8 100644 --- a/gfx/webrender/src/clip.rs +++ b/gfx/webrender/src/clip.rs @@ -3,14 +3,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{BorderRadius, ComplexClipRegion, DeviceIntRect, ImageMask, ImageRendering, LayerPoint}; -use api::{LayerRect, LayerSize, LayerToWorldTransform, LayoutPoint, LayoutVector2D, LocalClip}; +use api::{ClipMode, LayerRect, LayerSize}; +use api::{LayerToWorldTransform, LayoutPoint, LayoutVector2D, LocalClip}; use border::BorderCornerClipSource; use ellipse::Ellipse; use freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks}; use prim_store::{ClipData, ImageMaskData}; use resource_cache::ResourceCache; -use std::ops::Not; use util::{extract_inner_rect_safe, TransformedRect}; const MAX_CLIP: f32 = 1000000.0; @@ -61,24 +61,6 @@ impl ClipRegion { } } -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum ClipMode { - Clip, // Pixels inside the region are visible. - ClipOut, // Pixels outside the region are visible. -} - -impl Not for ClipMode { - type Output = ClipMode; - - fn not(self) -> ClipMode { - match self { - ClipMode::Clip => ClipMode::ClipOut, - ClipMode::ClipOut => ClipMode::Clip, - } - } -} - #[derive(Debug)] pub enum ClipSource { Rectangle(LayerRect), @@ -105,7 +87,7 @@ impl From for ClipSources { clips.push(ClipSource::RoundedRectangle( complex.rect, complex.radii, - ClipMode::Clip, + complex.mode, )); } diff --git a/gfx/webrender/src/frame.rs b/gfx/webrender/src/frame.rs index 5d662a3b0166..d3567169d172 100644 --- a/gfx/webrender/src/frame.rs +++ b/gfx/webrender/src/frame.rs @@ -9,7 +9,7 @@ use api::{HitTestResult, ImageDisplayItem, ItemRange, LayerPoint, LayerPrimitive use api::{LayerSize, LayerToScrollTransform, LayerVector2D, LayoutSize, LayoutTransform}; use api::{LocalClip, PipelineId, ScrollClamping, ScrollEventPhase, ScrollLayerState}; use api::{ScrollLocation, ScrollPolicy, ScrollSensitivity, SpecificDisplayItem, StackingContext}; -use api::{TileOffset, TransformStyle, WorldPoint}; +use api::{ClipMode, TileOffset, TransformStyle, WorldPoint}; use clip::ClipRegion; use clip_scroll_tree::{ClipScrollTree, ScrollStates}; use euclid::rect; @@ -1151,7 +1151,12 @@ fn try_to_add_rectangle_splitting_on_clip( let inner_unclipped_rect = match &info.local_clip { &LocalClip::Rect(_) => return false, - &LocalClip::RoundedRect(_, ref region) => region.get_inner_rect_full(), + &LocalClip::RoundedRect(_, ref region) => { + if region.mode == ClipMode::ClipOut { + return false; + } + region.get_inner_rect_full() + } }; let inner_unclipped_rect = match inner_unclipped_rect { Some(rect) => rect, diff --git a/gfx/webrender/src/frame_builder.rs b/gfx/webrender/src/frame_builder.rs index 5268389cc01e..96ee8a05e648 100644 --- a/gfx/webrender/src/frame_builder.rs +++ b/gfx/webrender/src/frame_builder.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{BorderDetails, BorderDisplayItem, BorderRadius, BoxShadowClipMode, BuiltDisplayList}; -use api::{ComplexClipRegion, ClipAndScrollInfo, ClipId, ColorF}; +use api::{ClipMode, ComplexClipRegion, ClipAndScrollInfo, ClipId, ColorF, LayoutSize}; use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintRect, DeviceUintSize}; use api::{ExtendMode, FilterOp, FontInstance, FontRenderMode}; use api::{GlyphInstance, GlyphOptions, GradientStop, HitTestFlags, HitTestItem, HitTestResult}; @@ -14,7 +14,7 @@ use api::{ScrollSensitivity, Shadow, TileOffset, TransformStyle}; use api::{WorldPixel, WorldPoint, YuvColorSpace, YuvData, device_length}; use app_units::Au; use border::ImageBorderSegment; -use clip::{ClipMode, ClipRegion, ClipSource, ClipSources, ClipStore, Contains}; +use clip::{ClipRegion, ClipSource, ClipSources, ClipStore, Contains}; use clip_scroll_node::{ClipInfo, ClipScrollNode, NodeType}; use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId}; use euclid::{SideOffsets2D, TypedTransform3D, vec2, vec3}; @@ -29,7 +29,7 @@ use prim_store::{PrimitiveContainer, PrimitiveIndex}; use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu}; use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu}; use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters}; -use render_task::{AlphaRenderItem, ClipChain, RenderTask, RenderTaskId, RenderTaskLocation}; +use render_task::{AlphaRenderItem, ClearMode, ClipChain, RenderTask, RenderTaskId, RenderTaskLocation}; use render_task::RenderTaskTree; use resource_cache::ResourceCache; use scene::ScenePipeline; @@ -40,6 +40,9 @@ use tiling::{PackedLayer, PackedLayerIndex, PrimitiveFlags, PrimitiveRunCmd, Ren use tiling::{RenderTargetContext, ScrollbarPrimitive, StackingContext}; use util::{self, pack_as_float, RectHelpers, recycle_vec}; +// The blur shader samples BLUR_SAMPLE_SCALE * blur_radius surrounding texels. +const BLUR_SAMPLE_SCALE: f32 = 3.0; + /// Construct a polygon from stacking context boundaries. /// `anchor` here is an index that's going to be preserved in all the /// splits of the polygon. @@ -242,7 +245,7 @@ impl FrameBuilder { clip_sources.push(ClipSource::RoundedRectangle( region.rect, region.radii, - ClipMode::Clip, + region.mode, )); } @@ -557,7 +560,7 @@ impl FrameBuilder { clip_and_scroll: ClipAndScrollInfo, info: &LayerPrimitiveInfo, ) { - let prim = PicturePrimitive::new_shadow(shadow, RenderTargetKind::Color); + let prim = PicturePrimitive::new_text_shadow(shadow); // Create an empty shadow primitive. Insert it into // the draw lists immediately so that it will be drawn @@ -587,7 +590,7 @@ impl FrameBuilder { // is then used when blitting the shadow to the final location. let metadata = &mut self.prim_store.cpu_metadata[prim_index.0]; let prim = &self.prim_store.cpu_pictures[metadata.cpu_prim_index.0]; - let shadow = prim.as_shadow(); + let shadow = prim.as_text_shadow(); metadata.local_rect = metadata.local_rect.translate(&shadow.offset); } @@ -676,7 +679,7 @@ impl FrameBuilder { for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() { let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0]; let picture = &self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0]; - let shadow = picture.as_shadow(); + let shadow = picture.as_text_shadow(); if shadow.blur_radius == 0.0 { fast_shadow_prims.push((idx, shadow.clone())); } @@ -719,7 +722,7 @@ impl FrameBuilder { debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Picture); let picture = &mut self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0]; - let blur_radius = picture.as_shadow().blur_radius; + let blur_radius = picture.as_text_shadow().blur_radius; // Only run real blurs here (fast path zero blurs are handled above). if blur_radius > 0.0 { @@ -1183,7 +1186,7 @@ impl FrameBuilder { for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() { let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0]; let picture_prim = &self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0]; - let shadow = picture_prim.as_shadow(); + let shadow = picture_prim.as_text_shadow(); if shadow.blur_radius == 0.0 { let mut text_prim = prim.clone(); text_prim.font.color = shadow.color.into(); @@ -1238,7 +1241,7 @@ impl FrameBuilder { &mut self.prim_store.cpu_pictures[shadow_metadata.cpu_prim_index.0]; // Only run real blurs here (fast path zero blurs are handled above). - let blur_radius = picture_prim.as_shadow().blur_radius; + let blur_radius = picture_prim.as_text_shadow().blur_radius; if blur_radius > 0.0 { let shadow_rect = rect.inflate( blur_radius, @@ -1258,7 +1261,7 @@ impl FrameBuilder { color: &ColorF, blur_radius: f32, spread_radius: f32, - border_radius: f32, + border_radius: BorderRadius, clip_mode: BoxShadowClipMode, ) { if color.a == 0.0 { @@ -1274,15 +1277,11 @@ impl FrameBuilder { } }; - // Adjust the shadow box radius as per: - // https://drafts.csswg.org/css-backgrounds-3/#shadow-shape - let sharpness_scale = if border_radius < spread_radius { - let r = border_radius / spread_amount; - 1.0 + (r - 1.0) * (r - 1.0) * (r - 1.0) - } else { - 1.0 - }; - let shadow_radius = (border_radius + spread_amount * sharpness_scale).max(0.0); + let shadow_radius = adjust_border_radius_for_box_shadow( + border_radius, + spread_amount, + spread_radius + ); let shadow_rect = prim_info.rect .translate(box_offset) .inflate(spread_amount, spread_amount); @@ -1295,7 +1294,7 @@ impl FrameBuilder { // TODO(gw): Add a fast path for ClipOut + zero border radius! clips.push(ClipSource::RoundedRectangle( prim_info.rect, - BorderRadius::uniform(border_radius), + border_radius, ClipMode::ClipOut )); @@ -1303,14 +1302,18 @@ impl FrameBuilder { shadow_rect, LocalClip::RoundedRect( shadow_rect, - ComplexClipRegion::new(shadow_rect, BorderRadius::uniform(shadow_radius)), + ComplexClipRegion::new( + shadow_rect, + shadow_radius, + ClipMode::Clip, + ), ), ) } BoxShadowClipMode::Inset => { clips.push(ClipSource::RoundedRectangle( shadow_rect, - BorderRadius::uniform(shadow_radius), + shadow_radius, ClipMode::ClipOut )); @@ -1318,7 +1321,11 @@ impl FrameBuilder { prim_info.rect, LocalClip::RoundedRect( prim_info.rect, - ComplexClipRegion::new(prim_info.rect, BorderRadius::uniform(border_radius)), + ComplexClipRegion::new( + prim_info.rect, + border_radius, + ClipMode::Clip + ), ), ) } @@ -1333,17 +1340,11 @@ impl FrameBuilder { }), ); } else { - let shadow = Shadow { - blur_radius, - color: *color, - offset: LayerVector2D::zero(), - }; - let blur_offset = 2.0 * blur_radius; let mut extra_clips = vec![]; - let mut pic_prim = PicturePrimitive::new_shadow(shadow, RenderTargetKind::Alpha); + let mut blur_regions = vec![]; - let pic_info = match clip_mode { + match clip_mode { BoxShadowClipMode::Outset => { let brush_prim = BrushPrimitive { clip_mode: ClipMode::Clip, @@ -1362,16 +1363,72 @@ impl FrameBuilder { PrimitiveContainer::Brush(brush_prim), ); + let pic_rect = shadow_rect.inflate(blur_offset, blur_offset); + let blur_range = BLUR_SAMPLE_SCALE * blur_radius; + + let size = pic_rect.size; + + let tl = LayerSize::new( + blur_radius.max(border_radius.top_left.width), + blur_radius.max(border_radius.top_left.height) + ) * BLUR_SAMPLE_SCALE; + let tr = LayerSize::new( + blur_radius.max(border_radius.top_right.width), + blur_radius.max(border_radius.top_right.height) + ) * BLUR_SAMPLE_SCALE; + let br = LayerSize::new( + blur_radius.max(border_radius.bottom_right.width), + blur_radius.max(border_radius.bottom_right.height) + ) * BLUR_SAMPLE_SCALE; + let bl = LayerSize::new( + blur_radius.max(border_radius.bottom_left.width), + blur_radius.max(border_radius.bottom_left.height) + ) * BLUR_SAMPLE_SCALE; + + let max_width = tl.width.max(tr.width.max(bl.width.max(br.width))); + let max_height = tl.height.max(tr.height.max(bl.height.max(br.height))); + + // Apply a conservative test that if any of the blur regions below + // will overlap, we won't bother applying the region optimization + // and will just blur the entire thing. This should only happen + // in rare cases, where either the blur radius or border radius + // is very large, in which case there's no real point in trying + // to only blur a small region anyway. + if max_width < 0.5 * size.width && max_height < 0.5 * size.height { + blur_regions.push(LayerRect::from_floats(0.0, 0.0, tl.width, tl.height)); + blur_regions.push(LayerRect::from_floats(size.width - tr.width, 0.0, size.width, tr.height)); + blur_regions.push(LayerRect::from_floats(size.width - br.width, size.height - br.height, size.width, size.height)); + blur_regions.push(LayerRect::from_floats(0.0, size.height - bl.height, bl.width, size.height)); + + blur_regions.push(LayerRect::from_floats(0.0, tl.height, blur_range, size.height - bl.height)); + blur_regions.push(LayerRect::from_floats(size.width - blur_range, tr.height, size.width, size.height - br.height)); + blur_regions.push(LayerRect::from_floats(tl.width, 0.0, size.width - tr.width, blur_range)); + blur_regions.push(LayerRect::from_floats(bl.width, size.height - blur_range, size.width - br.width, size.height)); + } + + let mut pic_prim = PicturePrimitive::new_box_shadow( + blur_radius, + *color, + blur_regions, + BoxShadowClipMode::Outset, + ); + pic_prim.add_primitive(brush_prim_index, clip_and_scroll); extra_clips.push(ClipSource::RoundedRectangle( prim_info.rect, - BorderRadius::uniform(border_radius), + border_radius, ClipMode::ClipOut, )); - let pic_rect = shadow_rect.inflate(blur_offset, blur_offset); - LayerPrimitiveInfo::new(pic_rect) + let pic_info = LayerPrimitiveInfo::new(pic_rect); + + self.add_primitive( + clip_and_scroll, + &pic_info, + extra_clips, + PrimitiveContainer::Picture(pic_prim), + ); } BoxShadowClipMode::Inset => { let brush_prim = BrushPrimitive { @@ -1392,25 +1449,35 @@ impl FrameBuilder { PrimitiveContainer::Brush(brush_prim), ); + let pic_rect = prim_info.rect.inflate(blur_offset, blur_offset); + + // TODO(gw): Apply minimal blur regions for inset box shadows. + + let mut pic_prim = PicturePrimitive::new_box_shadow( + blur_radius, + *color, + blur_regions, + BoxShadowClipMode::Inset, + ); + pic_prim.add_primitive(brush_prim_index, clip_and_scroll); extra_clips.push(ClipSource::RoundedRectangle( prim_info.rect, - BorderRadius::uniform(border_radius), + border_radius, ClipMode::Clip, )); - let pic_rect = prim_info.rect.inflate(blur_offset, blur_offset); - LayerPrimitiveInfo::with_clip_rect(pic_rect, prim_info.rect) - } - }; + let pic_info = LayerPrimitiveInfo::with_clip_rect(pic_rect, prim_info.rect); - self.add_primitive( - clip_and_scroll, - &pic_info, - extra_clips, - PrimitiveContainer::Picture(pic_prim), - ); + self.add_primitive( + clip_and_scroll, + &pic_info, + extra_clips, + PrimitiveContainer::Picture(pic_prim), + ); + } + } } } @@ -1770,8 +1837,9 @@ impl FrameBuilder { let transform = scroll_node.world_content_transform; if !packed_layer.set_transform(transform) { + group.screen_bounding_rect = None; debug!("\t\tUnable to set transform {:?}", transform); - return; + continue; } // Here we move the viewport rectangle into the coordinate system @@ -2045,6 +2113,8 @@ impl FrameBuilder { current_task_id, render_tasks, RenderTargetKind::Color, + &[], + ClearMode::Transparent, ); let blur_render_task_id = render_tasks.add(blur_render_task); let item = AlphaRenderItem::HardwareComposite( @@ -2326,3 +2396,67 @@ impl FrameBuilder { } } } + +fn adjust_border_radius_for_box_shadow( + radius: BorderRadius, + spread_amount: f32, + spread_radius: f32, +) -> BorderRadius { + BorderRadius { + top_left: adjust_corner_for_box_shadow( + radius.top_left, + spread_radius, + spread_amount, + ), + top_right: adjust_corner_for_box_shadow( + radius.top_right, + spread_radius, + spread_amount, + ), + bottom_right: adjust_corner_for_box_shadow( + radius.bottom_right, + spread_radius, + spread_amount, + ), + bottom_left: adjust_corner_for_box_shadow( + radius.bottom_left, + spread_radius, + spread_amount, + ), + } +} + +fn adjust_corner_for_box_shadow( + corner: LayoutSize, + spread_amount: f32, + spread_radius: f32, +) -> LayoutSize { + LayoutSize::new( + adjust_radius_for_box_shadow( + corner.width, + spread_radius, + spread_amount + ), + adjust_radius_for_box_shadow( + corner.height, + spread_radius, + spread_amount + ), + ) +} + +fn adjust_radius_for_box_shadow( + border_radius: f32, + spread_amount: f32, + spread_radius: f32, +) -> f32 { + // Adjust the shadow box radius as per: + // https://drafts.csswg.org/css-backgrounds-3/#shadow-shape + let sharpness_scale = if border_radius < spread_radius { + let r = border_radius / spread_amount; + 1.0 + (r - 1.0) * (r - 1.0) * (r - 1.0) + } else { + 1.0 + }; + (border_radius + spread_amount * sharpness_scale).max(0.0) +} diff --git a/gfx/webrender/src/gpu_types.rs b/gfx/webrender/src/gpu_types.rs index b8e129a6f738..b8f3db7663f3 100644 --- a/gfx/webrender/src/gpu_types.rs +++ b/gfx/webrender/src/gpu_types.rs @@ -2,6 +2,7 @@ * 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::LayerRect; use gpu_cache::GpuCacheAddress; use render_task::RenderTaskAddress; use tiling::PackedLayerIndex; @@ -18,7 +19,7 @@ impl From for PackedLayerAddress { } #[repr(i32)] -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum BlurDirection { Horizontal = 0, Vertical, @@ -30,6 +31,7 @@ pub struct BlurInstance { pub task_address: RenderTaskAddress, pub src_task_address: RenderTaskAddress, pub blur_direction: BlurDirection, + pub region: LayerRect, } /// A clipping primitive drawn into the clipping mask. diff --git a/gfx/webrender/src/picture.rs b/gfx/webrender/src/picture.rs index c8cb49e49de6..d566fec66146 100644 --- a/gfx/webrender/src/picture.rs +++ b/gfx/webrender/src/picture.rs @@ -2,9 +2,12 @@ * 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::{ClipAndScrollInfo, Shadow}; -use prim_store::PrimitiveIndex; -use render_task::RenderTaskId; +use api::{ColorF, ClipAndScrollInfo, device_length, DeviceIntSize}; +use api::{BoxShadowClipMode, LayerRect, Shadow}; +use frame_builder::PrimitiveContext; +use gpu_cache::GpuDataRequest; +use prim_store::{PrimitiveIndex, PrimitiveMetadata}; +use render_task::{ClearMode, RenderTask, RenderTaskId, RenderTaskTree}; use tiling::RenderTargetKind; /* @@ -25,19 +28,23 @@ pub struct PrimitiveRun { } #[derive(Debug)] -pub enum CompositeOp { - Shadow(Shadow), - - // TODO(gw): Support other composite ops, such - // as blur, blend etc. +pub enum PictureKind { + TextShadow { + shadow: Shadow, + }, + BoxShadow { + blur_radius: f32, + color: ColorF, + blur_regions: Vec, + clip_mode: BoxShadowClipMode, + }, } #[derive(Debug)] pub struct PicturePrimitive { pub prim_runs: Vec, - pub composite_op: CompositeOp, pub render_task_id: Option, - pub kind: RenderTargetKind, + pub kind: PictureKind, // TODO(gw): Add a mode that specifies if this // picture should be rasterized in @@ -45,21 +52,38 @@ pub struct PicturePrimitive { } impl PicturePrimitive { - pub fn new_shadow( - shadow: Shadow, - kind: RenderTargetKind, - ) -> PicturePrimitive { + pub fn new_text_shadow(shadow: Shadow) -> PicturePrimitive { PicturePrimitive { prim_runs: Vec::new(), - composite_op: CompositeOp::Shadow(shadow), render_task_id: None, - kind, + kind: PictureKind::TextShadow { + shadow, + }, } } - pub fn as_shadow(&self) -> &Shadow { - match self.composite_op { - CompositeOp::Shadow(ref shadow) => shadow, + pub fn new_box_shadow( + blur_radius: f32, + color: ColorF, + blur_regions: Vec, + clip_mode: BoxShadowClipMode, + ) -> PicturePrimitive { + PicturePrimitive { + prim_runs: Vec::new(), + render_task_id: None, + kind: PictureKind::BoxShadow { + blur_radius, + color, + blur_regions, + clip_mode, + }, + } + } + + pub fn as_text_shadow(&self) -> &Shadow { + match self.kind { + PictureKind::TextShadow { ref shadow } => shadow, + PictureKind::BoxShadow { .. } => panic!("bug: not a text shadow") } } @@ -82,4 +106,83 @@ impl PicturePrimitive { clip_and_scroll, }); } + + pub fn prepare_for_render( + &mut self, + prim_index: PrimitiveIndex, + prim_metadata: &PrimitiveMetadata, + prim_context: &PrimitiveContext, + render_tasks: &mut RenderTaskTree, + ) { + // This is a shadow element. Create a render task that will + // render the text run to a target, and then apply a gaussian + // blur to that text run in order to build the actual primitive + // which will be blitted to the framebuffer. + let cache_width = + (prim_metadata.local_rect.size.width * prim_context.device_pixel_ratio).ceil() as i32; + let cache_height = + (prim_metadata.local_rect.size.height * prim_context.device_pixel_ratio).ceil() as i32; + let cache_size = DeviceIntSize::new(cache_width, cache_height); + + let (blur_radius, target_kind, blur_regions, clear_mode) = match self.kind { + PictureKind::TextShadow { ref shadow } => { + let dummy: &[LayerRect] = &[]; + (shadow.blur_radius, RenderTargetKind::Color, dummy, ClearMode::Transparent) + } + PictureKind::BoxShadow { blur_radius, clip_mode, ref blur_regions, .. } => { + let clear_mode = match clip_mode { + BoxShadowClipMode::Outset => ClearMode::One, + BoxShadowClipMode::Inset => ClearMode::Zero, + }; + (blur_radius, RenderTargetKind::Alpha, blur_regions.as_slice(), clear_mode) + } + }; + let blur_radius = device_length(blur_radius, prim_context.device_pixel_ratio); + + let picture_task = RenderTask::new_picture( + cache_size, + prim_index, + target_kind, + ); + let picture_task_id = render_tasks.add(picture_task); + let render_task = RenderTask::new_blur( + blur_radius, + picture_task_id, + render_tasks, + target_kind, + blur_regions, + clear_mode, + ); + self.render_task_id = Some(render_tasks.add(render_task)); + } + + pub fn write_gpu_blocks(&self, mut request: GpuDataRequest) { + match self.kind { + PictureKind::TextShadow { ref shadow } => { + request.push(shadow.color); + request.push([ + shadow.offset.x, + shadow.offset.y, + shadow.blur_radius, + 0.0, + ]); + } + PictureKind::BoxShadow { blur_radius, color, .. } => { + request.push(color); + request.push([ + 0.0, + 0.0, + blur_radius, + 0.0, + ]); + } + } + } + + pub fn target_kind(&self) -> RenderTargetKind { + match self.kind { + PictureKind::TextShadow { .. } => RenderTargetKind::Color, + PictureKind::BoxShadow { .. } => RenderTargetKind::Alpha, + } + } } diff --git a/gfx/webrender/src/prim_store.rs b/gfx/webrender/src/prim_store.rs index fc11ad1c9892..8178e5f0c0a5 100644 --- a/gfx/webrender/src/prim_store.rs +++ b/gfx/webrender/src/prim_store.rs @@ -2,13 +2,13 @@ * 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::{BorderRadius, BuiltDisplayList, ColorF, ComplexClipRegion, DeviceIntRect, DeviceIntSize}; +use api::{BorderRadius, BuiltDisplayList, ColorF, ComplexClipRegion, DeviceIntRect}; use api::{DevicePoint, ExtendMode, FontInstance, FontRenderMode, GlyphInstance, GlyphKey}; use api::{GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerRect}; -use api::{LayerSize, LayerVector2D, LineOrientation, LineStyle}; -use api::{TileOffset, YuvColorSpace, YuvFormat, device_length}; +use api::{ClipMode, LayerSize, LayerVector2D, LineOrientation, LineStyle}; +use api::{TileOffset, YuvColorSpace, YuvFormat}; use border::BorderCornerInstance; -use clip::{ClipMode, ClipSourcesHandle, ClipStore, Geometry}; +use clip::{ClipSourcesHandle, ClipStore, Geometry}; use frame_builder::PrimitiveContext; use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; @@ -167,17 +167,29 @@ impl ToGpuBlocks for RectanglePrimitive { #[derive(Debug)] pub struct BrushPrimitive { pub clip_mode: ClipMode, - pub radius: f32, + pub radius: BorderRadius, } impl ToGpuBlocks for BrushPrimitive { fn write_gpu_blocks(&self, mut request: GpuDataRequest) { request.push([ self.clip_mode as u32 as f32, - self.radius, + 0.0, 0.0, 0.0 ]); + request.push([ + self.radius.top_left.width, + self.radius.top_left.height, + self.radius.top_right.width, + self.radius.top_right.height, + ]); + request.push([ + self.radius.bottom_right.width, + self.radius.bottom_right.height, + self.radius.bottom_left.width, + self.radius.bottom_left.height, + ]); } } @@ -1037,46 +1049,20 @@ impl PrimitiveStore { prim_context: &PrimitiveContext, resource_cache: &mut ResourceCache, gpu_cache: &mut GpuCache, - // For some primitives, we need to mark dependencies as needed for rendering - // without spawning new tasks, since there will be another call to - // `prepare_prim_for_render_inner` specifically for this primitive later on. - render_tasks: Option<&mut RenderTaskTree>, + render_tasks: &mut RenderTaskTree, text_run_mode: TextRunMode, ) { let metadata = &mut self.cpu_metadata[prim_index.0]; match metadata.prim_kind { PrimitiveKind::Rectangle | PrimitiveKind::Border | PrimitiveKind::Line => {} PrimitiveKind::Picture => { - let picture = &mut self.cpu_pictures[metadata.cpu_prim_index.0]; - - // This is a shadow element. Create a render task that will - // render the text run to a target, and then apply a gaussian - // blur to that text run in order to build the actual primitive - // which will be blitted to the framebuffer. - let cache_width = - (metadata.local_rect.size.width * prim_context.device_pixel_ratio).ceil() as i32; - let cache_height = - (metadata.local_rect.size.height * prim_context.device_pixel_ratio).ceil() as i32; - let cache_size = DeviceIntSize::new(cache_width, cache_height); - let blur_radius = picture.as_shadow().blur_radius; - let blur_radius = device_length(blur_radius, prim_context.device_pixel_ratio); - - // ignore new tasks if we are in a dependency context - picture.render_task_id = render_tasks.map(|rt| { - let picture_task = RenderTask::new_picture( - cache_size, + self.cpu_pictures[metadata.cpu_prim_index.0] + .prepare_for_render( prim_index, - picture.kind, + metadata, + prim_context, + render_tasks ); - let picture_task_id = rt.add(picture_task); - let render_task = RenderTask::new_blur( - blur_radius, - picture_task_id, - rt, - picture.kind - ); - rt.add(render_task) - }); } PrimitiveKind::TextRun => { let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0]; @@ -1173,15 +1159,8 @@ impl PrimitiveStore { text.write_gpu_blocks(&mut request); } PrimitiveKind::Picture => { - let picture = &self.cpu_pictures[metadata.cpu_prim_index.0]; - let shadow = picture.as_shadow(); - request.push(shadow.color); - request.push([ - shadow.offset.x, - shadow.offset.y, - shadow.blur_radius, - 0.0, - ]); + self.cpu_pictures[metadata.cpu_prim_index.0] + .write_gpu_blocks(request); } PrimitiveKind::Brush => { let brush = &self.cpu_brushes[metadata.cpu_prim_index.0]; @@ -1342,7 +1321,7 @@ impl PrimitiveStore { prim_context, resource_cache, gpu_cache, - None, + render_tasks, TextRunMode::Shadow, ); } @@ -1365,7 +1344,7 @@ impl PrimitiveStore { prim_context, resource_cache, gpu_cache, - Some(render_tasks), + render_tasks, TextRunMode::Normal, ); diff --git a/gfx/webrender/src/render_backend.rs b/gfx/webrender/src/render_backend.rs index 00f176ec083b..c2d684f5f510 100644 --- a/gfx/webrender/src/render_backend.rs +++ b/gfx/webrender/src/render_backend.rs @@ -22,7 +22,8 @@ use resource_cache::ResourceCache; use scene::Scene; #[cfg(feature = "debugger")] use serde_json; -use std::sync::{Arc, Mutex}; +use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; +use std::sync::Arc; use std::sync::mpsc::Sender; use std::u32; use texture_cache::TextureCache; @@ -124,6 +125,9 @@ enum DocumentOp { Rendered(RendererFrame), } +/// The unique id for WR resource identification. +static NEXT_NAMESPACE_ID: AtomicUsize = ATOMIC_USIZE_INIT; + /// The render backend is responsible for transforming high level display lists into /// GPU-friendly work which is then submitted to the renderer in the form of a frame::Frame. /// @@ -133,7 +137,6 @@ pub struct RenderBackend { payload_rx: PayloadReceiver, payload_tx: PayloadSender, result_tx: Sender, - next_namespace_id: IdNamespace, default_device_pixel_ratio: f32, gpu_cache: GpuCache, @@ -142,7 +145,7 @@ pub struct RenderBackend { frame_config: FrameBuilderConfig, documents: FastHashMap, - notifier: Arc>>>, + notifier: Box, recorder: Option>, enable_render_on_scroll: bool, @@ -157,12 +160,15 @@ impl RenderBackend { default_device_pixel_ratio: f32, texture_cache: TextureCache, workers: Arc, - notifier: Arc>>>, + notifier: Box, frame_config: FrameBuilderConfig, recorder: Option>, blob_image_renderer: Option>, enable_render_on_scroll: bool, ) -> RenderBackend { + // The namespace_id should start from 1. + NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed); + let resource_cache = ResourceCache::new(texture_cache, workers, blob_image_renderer); register_thread_with_profiler("Backend".to_string()); @@ -177,7 +183,6 @@ impl RenderBackend { gpu_cache: GpuCache::new(), frame_config, documents: FastHashMap::default(), - next_namespace_id: IdNamespace(1), notifier, recorder, @@ -421,6 +426,10 @@ impl RenderBackend { } } + fn next_namespace_id(&self) -> IdNamespace { + IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32) + } + pub fn run(&mut self, mut profile_counters: BackendProfileCounters) { let mut frame_counter: u32 = 0; @@ -435,8 +444,7 @@ impl RenderBackend { msg } Err(..) => { - let notifier = self.notifier.lock(); - notifier.unwrap().as_mut().unwrap().shut_down(); + self.notifier.shut_down(); break; } }; @@ -463,9 +471,7 @@ impl RenderBackend { tx.send(glyph_indices).unwrap(); } ApiMsg::CloneApi(sender) => { - let namespace = self.next_namespace_id; - self.next_namespace_id = IdNamespace(namespace.0 + 1); - sender.send(namespace).unwrap(); + sender.send(self.next_namespace_id()).unwrap(); } ApiMsg::AddDocument(document_id, initial_size) => { let document = Document::new( @@ -504,8 +510,7 @@ impl RenderBackend { self.documents.remove(&document_id); } ApiMsg::ExternalEvent(evt) => { - let notifier = self.notifier.lock(); - notifier.unwrap().as_mut().unwrap().external_event(evt); + self.notifier.external_event(evt); } ApiMsg::ClearNamespace(namespace_id) => { self.resource_cache.clear_namespace(namespace_id); @@ -530,12 +535,7 @@ impl RenderBackend { // We use new_frame_ready to wake up the renderer and get the // resource updates processed, but the UpdateResources message // will cancel rendering the frame. - self.notifier - .lock() - .unwrap() - .as_mut() - .unwrap() - .new_frame_ready(); + self.notifier.new_frame_ready(); } ApiMsg::DebugCommand(option) => { let msg = match option { @@ -550,12 +550,10 @@ impl RenderBackend { _ => ResultMsg::DebugCommand(option), }; self.result_tx.send(msg).unwrap(); - let notifier = self.notifier.lock(); - notifier.unwrap().as_mut().unwrap().new_frame_ready(); + self.notifier.new_frame_ready(); } ApiMsg::ShutDown => { - let notifier = self.notifier.lock(); - notifier.unwrap().as_mut().unwrap().shut_down(); + self.notifier.shut_down(); break; } } @@ -582,31 +580,11 @@ impl RenderBackend { ) { self.publish_frame(document_id, frame, profile_counters); - // TODO(gw): This is kindof bogus to have to lock the notifier - // each time it's used. This is due to some nastiness - // in initialization order for Servo. Perhaps find a - // cleaner way to do this, or use the OnceMutex on crates.io? - let mut notifier = self.notifier.lock(); - notifier - .as_mut() - .unwrap() - .as_mut() - .unwrap() - .new_frame_ready(); + self.notifier.new_frame_ready(); } - fn notify_compositor_of_new_scroll_frame(&mut self, composite_needed: bool) { - // TODO(gw): This is kindof bogus to have to lock the notifier - // each time it's used. This is due to some nastiness - // in initialization order for Servo. Perhaps find a - // cleaner way to do this, or use the OnceMutex on crates.io? - let mut notifier = self.notifier.lock(); - notifier - .as_mut() - .unwrap() - .as_mut() - .unwrap() - .new_scroll_frame_ready(composite_needed); + fn notify_compositor_of_new_scroll_frame(&self, composite_needed: bool) { + self.notifier.new_scroll_frame_ready(composite_needed); } diff --git a/gfx/webrender/src/render_task.rs b/gfx/webrender/src/render_task.rs index 9d397ca7b7ae..1d48cf057c00 100644 --- a/gfx/webrender/src/render_task.rs +++ b/gfx/webrender/src/render_task.rs @@ -4,7 +4,7 @@ use api::{ClipId, DeviceIntLength, DeviceIntPoint, DeviceIntRect, DeviceIntSize}; use api::{FilterOp, MixBlendMode}; -use api::PipelineId; +use api::{LayerRect, PipelineId}; use clip::{ClipSource, ClipSourcesWeakHandle, ClipStore}; use clip_scroll_tree::CoordinateSystemId; use gpu_cache::GpuCacheHandle; @@ -264,6 +264,7 @@ pub struct PictureTask { pub struct BlurTask { pub blur_radius: DeviceIntLength, pub target_kind: RenderTargetKind, + pub regions: Vec, } #[derive(Debug)] @@ -282,12 +283,23 @@ pub enum RenderTaskKind { Alias(RenderTaskId), } +#[derive(Debug, Copy, Clone)] +pub enum ClearMode { + // Applicable to color and alpha targets. + Zero, + One, + + // Applicable to color targets only. + Transparent, +} + #[derive(Debug)] pub struct RenderTask { pub cache_key: Option, pub location: RenderTaskLocation, pub children: Vec, pub kind: RenderTaskKind, + pub clear_mode: ClearMode, } impl RenderTask { @@ -305,6 +317,7 @@ impl RenderTask { items: Vec::new(), frame_output_pipeline_id, }), + clear_mode: ClearMode::Transparent, } } @@ -321,6 +334,11 @@ impl RenderTask { prim_index: PrimitiveIndex, target_kind: RenderTargetKind, ) -> RenderTask { + let clear_mode = match target_kind { + RenderTargetKind::Color => ClearMode::Transparent, + RenderTargetKind::Alpha => ClearMode::One, + }; + RenderTask { cache_key: None, children: Vec::new(), @@ -329,6 +347,7 @@ impl RenderTask { prim_index, target_kind, }), + clear_mode, } } @@ -338,6 +357,7 @@ impl RenderTask { children: Vec::new(), location: RenderTaskLocation::Dynamic(None, screen_rect.size), kind: RenderTaskKind::Readback(screen_rect), + clear_mode: ClearMode::Transparent, } } @@ -420,6 +440,7 @@ impl RenderTask { geometry_kind, coordinate_system_id: prim_coordinate_system_id, }), + clear_mode: ClearMode::One, }) } @@ -443,6 +464,8 @@ impl RenderTask { src_task_id: RenderTaskId, render_tasks: &mut RenderTaskTree, target_kind: RenderTargetKind, + regions: &[LayerRect], + clear_mode: ClearMode, ) -> RenderTask { let blur_target_size = render_tasks.get(src_task_id).get_dynamic_size(); @@ -453,7 +476,9 @@ impl RenderTask { kind: RenderTaskKind::VerticalBlur(BlurTask { blur_radius, target_kind, + regions: regions.to_vec(), }), + clear_mode, }; let blur_task_v_id = render_tasks.add(blur_task_v); @@ -465,7 +490,9 @@ impl RenderTask { kind: RenderTaskKind::HorizontalBlur(BlurTask { blur_radius, target_kind, + regions: regions.to_vec(), }), + clear_mode, }; blur_task_h diff --git a/gfx/webrender/src/renderer.rs b/gfx/webrender/src/renderer.rs index d76ada08313e..24a785987a4a 100644 --- a/gfx/webrender/src/renderer.rs +++ b/gfx/webrender/src/renderer.rs @@ -55,7 +55,7 @@ use std::f32; use std::mem; use std::path::PathBuf; use std::rc::Rc; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread; use texture_cache::TextureCache; @@ -325,6 +325,11 @@ const DESC_BLUR: VertexDescriptor = VertexDescriptor { count: 1, kind: VertexAttributeKind::I32, }, + VertexAttribute { + name: "aBlurRegion", + count: 4, + kind: VertexAttributeKind::F32 + }, ], }; @@ -925,20 +930,14 @@ struct PrimitiveShader { } struct FileWatcher { - notifier: Arc>>>, + notifier: Box, result_tx: Sender, } impl FileWatcherHandler for FileWatcher { fn file_changed(&self, path: PathBuf) { self.result_tx.send(ResultMsg::RefreshShader(path)).ok(); - let mut notifier = self.notifier.lock(); - notifier - .as_mut() - .unwrap() - .as_mut() - .unwrap() - .new_frame_ready(); + self.notifier.new_frame_ready(); } } @@ -1132,8 +1131,6 @@ pub struct Renderer { ps_split_composite: LazilyCompiledShader, ps_composite: LazilyCompiledShader, - notifier: Arc>>>, - max_texture_size: u32, max_recorded_profiles: usize, @@ -1229,6 +1226,7 @@ impl Renderer { /// [rendereroptions]: struct.RendererOptions.html pub fn new( gl: Rc, + notifier: Box, mut options: RendererOptions, ) -> Result<(Renderer, RenderApiSender), RendererError> { let (api_tx, api_rx) = try!{ channel::msg_channel() }; @@ -1236,12 +1234,11 @@ impl Renderer { let (result_tx, result_rx) = channel(); let gl_type = gl.get_type(); - let notifier = Arc::new(Mutex::new(None)); let debug_server = DebugServer::new(api_tx.clone()); let file_watch_handler = FileWatcher { result_tx: result_tx.clone(), - notifier: Arc::clone(¬ifier), + notifier: notifier.clone(), }; let mut device = Device::new( @@ -1652,7 +1649,7 @@ impl Renderer { device.end_frame(); - let backend_notifier = Arc::clone(¬ifier); + let backend_notifier = notifier.clone(); let default_font_render_mode = match (options.enable_aa, options.enable_subpixel_aa) { (true, true) => FontRenderMode::Subpixel, @@ -1735,7 +1732,6 @@ impl Renderer { ps_split_composite, ps_composite, ps_line, - notifier, debug: debug_renderer, debug_flags, enable_batcher: options.enable_batcher, @@ -1794,15 +1790,6 @@ impl Renderer { (color_space as usize) } - /// Sets the new RenderNotifier. - /// - /// The RenderNotifier will be called when processing e.g. of a (scrolling) frame is done, - /// and therefore the screen should be updated. - pub fn set_render_notifier(&self, notifier: Box) { - let mut notifier_arc = self.notifier.lock().unwrap(); - *notifier_arc = Some(notifier); - } - /// Returns the Epoch of the current frame in a pipeline. pub fn current_epoch(&self, pipeline_id: PipelineId) -> Option { self.pipeline_epoch_map.get(&pipeline_id).cloned() @@ -2890,6 +2877,7 @@ impl Renderer { target: &AlphaRenderTarget, target_size: DeviceUintSize, projection: &Transform3D, + render_tasks: &RenderTaskTree, ) { self.gpu_profile.add_sampler(GPU_SAMPLER_TAG_ALPHA); @@ -2908,6 +2896,14 @@ impl Renderer { let clear_color = [1.0, 1.0, 1.0, 0.0]; self.device .clear_target_rect(Some(clear_color), None, target.used_rect()); + + let zero_color = [0.0, 0.0, 0.0, 0.0]; + for task_id in &target.zero_clears { + let task = render_tasks.get(*task_id); + let (rect, _) = task.get_target_rect(); + self.device + .clear_target_rect(Some(zero_color), None, rect); + } } // Draw any blurs for this target. @@ -3238,6 +3234,7 @@ impl Renderer { target, pass.max_alpha_target_size, &projection, + &frame.render_tasks, ); } diff --git a/gfx/webrender/src/resource_cache.rs b/gfx/webrender/src/resource_cache.rs index 14e989538442..30dcffec18aa 100644 --- a/gfx/webrender/src/resource_cache.rs +++ b/gfx/webrender/src/resource_cache.rs @@ -430,7 +430,7 @@ impl ResourceCache { self.blob_image_renderer .as_mut() .unwrap() - .update(image_key, mem::replace(blob, BlobImageData::new())); + .update(image_key, mem::replace(blob, BlobImageData::new()), dirty_rect); } ImageResource { diff --git a/gfx/webrender/src/tiling.rs b/gfx/webrender/src/tiling.rs index 255be5fd6c7a..7dd55fe5fcb3 100644 --- a/gfx/webrender/src/tiling.rs +++ b/gfx/webrender/src/tiling.rs @@ -21,7 +21,7 @@ use prim_store::{DeferredResolve, TextRunMode}; use profiler::FrameProfileCounters; use render_task::{AlphaRenderItem, ClipWorkItem, MaskGeometryKind, MaskSegment}; use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKey, RenderTaskKind}; -use render_task::{RenderTaskLocation, RenderTaskTree}; +use render_task::{BlurTask, ClearMode, RenderTaskLocation, RenderTaskTree}; use renderer::BlendMode; use renderer::ImageBufferKind; use resource_cache::{GlyphFetchResult, ResourceCache}; @@ -427,6 +427,7 @@ impl AlphaRenderItem { { let sub_index = i as i32; match *instance_kind { + BorderCornerInstance::None => {} BorderCornerInstance::Single => { batch.push(base_instance.build( sub_index, @@ -580,7 +581,7 @@ impl AlphaRenderItem { let textures = BatchTextures::render_target_cache(); let kind = BatchKind::Transformable( transform_kind, - TransformBatchKind::CacheImage(picture.kind), + TransformBatchKind::CacheImage(picture.target_kind()), ); let key = BatchKey::new(kind, blend_mode, textures); let batch = batch_list.get_suitable_batch(key, item_bounding_rect); @@ -1137,23 +1138,23 @@ impl RenderTarget for ColorRenderTarget { }); } } - RenderTaskKind::VerticalBlur(..) => { - // Find the child render task that we are applying - // a vertical blur on. - self.vertical_blurs.push(BlurInstance { - task_address: render_tasks.get_task_address(task_id), - src_task_address: render_tasks.get_task_address(task.children[0]), - blur_direction: BlurDirection::Vertical, - }); + RenderTaskKind::VerticalBlur(ref info) => { + info.add_instances( + &mut self.vertical_blurs, + task_id, + task.children[0], + BlurDirection::Vertical, + render_tasks, + ); } - RenderTaskKind::HorizontalBlur(..) => { - // Find the child render task that we are applying - // a horizontal blur on. - self.horizontal_blurs.push(BlurInstance { - task_address: render_tasks.get_task_address(task_id), - src_task_address: render_tasks.get_task_address(task.children[0]), - blur_direction: BlurDirection::Horizontal, - }); + RenderTaskKind::HorizontalBlur(ref info) => { + info.add_instances( + &mut self.horizontal_blurs, + task_id, + task.children[0], + BlurDirection::Horizontal, + render_tasks, + ); } RenderTaskKind::Picture(ref task_info) => { let prim_metadata = ctx.prim_store.get_metadata(task_info.prim_index); @@ -1244,6 +1245,7 @@ pub struct AlphaRenderTarget { // List of blur operations to apply for this render target. pub vertical_blurs: Vec, pub horizontal_blurs: Vec, + pub zero_clears: Vec, allocator: TextureAllocator, } @@ -1258,6 +1260,7 @@ impl RenderTarget for AlphaRenderTarget { rect_cache_prims: Vec::new(), vertical_blurs: Vec::new(), horizontal_blurs: Vec::new(), + zero_clears: Vec::new(), allocator: TextureAllocator::new(size.expect("bug: alpha targets need size")), } } @@ -1275,6 +1278,17 @@ impl RenderTarget for AlphaRenderTarget { clip_store: &ClipStore, ) { let task = render_tasks.get(task_id); + + match task.clear_mode { + ClearMode::Zero => { + self.zero_clears.push(task_id); + } + ClearMode::One => {} + ClearMode::Transparent => { + panic!("bug: invalid clear mode for alpha task"); + } + } + match task.kind { RenderTaskKind::Alias(..) => { panic!("BUG: add_task() called on invalidated task"); @@ -1283,23 +1297,23 @@ impl RenderTarget for AlphaRenderTarget { RenderTaskKind::Readback(..) => { panic!("Should not be added to alpha target!"); } - RenderTaskKind::VerticalBlur(..) => { - // Find the child render task that we are applying - // a vertical blur on. - self.vertical_blurs.push(BlurInstance { - task_address: render_tasks.get_task_address(task_id), - src_task_address: render_tasks.get_task_address(task.children[0]), - blur_direction: BlurDirection::Vertical, - }); + RenderTaskKind::VerticalBlur(ref info) => { + info.add_instances( + &mut self.vertical_blurs, + task_id, + task.children[0], + BlurDirection::Vertical, + render_tasks, + ); } - RenderTaskKind::HorizontalBlur(..) => { - // Find the child render task that we are applying - // a horizontal blur on. - self.horizontal_blurs.push(BlurInstance { - task_address: render_tasks.get_task_address(task_id), - src_task_address: render_tasks.get_task_address(task.children[0]), - blur_direction: BlurDirection::Horizontal, - }); + RenderTaskKind::HorizontalBlur(ref info) => { + info.add_instances( + &mut self.horizontal_blurs, + task_id, + task.children[0], + BlurDirection::Horizontal, + render_tasks, + ); } RenderTaskKind::Picture(ref task_info) => { let prim_metadata = ctx.prim_store.get_metadata(task_info.prim_index); @@ -1873,3 +1887,32 @@ fn resolve_image( None => (SourceTexture::Invalid, GpuCacheHandle::new()), } } + +impl BlurTask { + fn add_instances( + &self, + instances: &mut Vec, + task_id: RenderTaskId, + source_task_id: RenderTaskId, + blur_direction: BlurDirection, + render_tasks: &RenderTaskTree, + ) { + let instance = BlurInstance { + task_address: render_tasks.get_task_address(task_id), + src_task_address: render_tasks.get_task_address(source_task_id), + blur_direction, + region: LayerRect::zero(), + }; + + if self.regions.is_empty() { + instances.push(instance); + } else { + for region in &self.regions { + instances.push(BlurInstance { + region: *region, + ..instance + }); + } + } + } +} diff --git a/gfx/webrender_api/Cargo.toml b/gfx/webrender_api/Cargo.toml index 34975fb41dd2..20f526a2060b 100644 --- a/gfx/webrender_api/Cargo.toml +++ b/gfx/webrender_api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webrender_api" -version = "0.52.1" +version = "0.53.0" authors = ["Glenn Watson "] license = "MPL-2.0" repository = "https://github.com/servo/webrender" @@ -15,7 +15,6 @@ bitflags = "1.0" bincode = "0.9" byteorder = "1.0" euclid = "0.15" -heapsize = ">= 0.3.6, < 0.5" ipc-channel = {version = "0.9", optional = true} serde = { version = "1.0", features = ["rc", "derive"] } time = "0.1" diff --git a/gfx/webrender_api/src/api.rs b/gfx/webrender_api/src/api.rs index 9f01274fbfb0..91b07972fd67 100644 --- a/gfx/webrender_api/src/api.rs +++ b/gfx/webrender_api/src/api.rs @@ -873,10 +873,11 @@ pub struct DynamicProperties { } pub trait RenderNotifier: Send { - fn new_frame_ready(&mut self); - fn new_scroll_frame_ready(&mut self, composite_needed: bool); - fn external_event(&mut self, _evt: ExternalEvent) { + fn clone(&self) -> Box; + fn new_frame_ready(&self); + fn new_scroll_frame_ready(&self, composite_needed: bool); + fn external_event(&self, _evt: ExternalEvent) { unimplemented!() } - fn shut_down(&mut self) {} + fn shut_down(&self) {} } diff --git a/gfx/webrender_api/src/color.rs b/gfx/webrender_api/src/color.rs index aae7b1b587e3..3e30c30a0fcf 100644 --- a/gfx/webrender_api/src/color.rs +++ b/gfx/webrender_api/src/color.rs @@ -16,7 +16,6 @@ pub struct ColorF { pub b: f32, pub a: f32, } -known_heap_size!(0, ColorF); impl ColorF { /// Constructs a new `ColorF` from its components. diff --git a/gfx/webrender_api/src/display_item.rs b/gfx/webrender_api/src/display_item.rs index e5b8bfe4ddac..9f5761f02672 100644 --- a/gfx/webrender_api/src/display_item.rs +++ b/gfx/webrender_api/src/display_item.rs @@ -6,6 +6,7 @@ use {ColorF, FontInstanceKey, ImageKey, LayerPixel, LayoutPixel, LayoutPoint, La LayoutSize, LayoutTransform}; use {GlyphOptions, LayoutVector2D, PipelineId, PropertyBinding}; use euclid::{SideOffsets2D, TypedRect, TypedSideOffsets2D}; +use std::ops::Not; // NOTE: some of these structs have an "IMPLICIT" comment. // This indicates that the BuiltDisplayList will have serialized @@ -297,7 +298,7 @@ pub struct BoxShadowDisplayItem { pub color: ColorF, pub blur_radius: f32, pub spread_radius: f32, - pub border_radius: f32, + pub border_radius: BorderRadius, pub clip_mode: BoxShadowClipMode, } @@ -336,7 +337,6 @@ pub struct GradientStop { pub offset: f32, pub color: ColorF, } -known_heap_size!(0, GradientStop); #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct RadialGradient { @@ -376,8 +376,6 @@ pub enum ScrollPolicy { Fixed = 1, } -known_heap_size!(0, ScrollPolicy); - #[repr(u32)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub enum TransformStyle { @@ -547,12 +545,31 @@ impl LocalClip { ComplexClipRegion { rect: complex.rect.translate(offset), radii: complex.radii, + mode: complex.mode, }, ), } } } +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum ClipMode { + Clip, // Pixels inside the region are visible. + ClipOut, // Pixels outside the region are visible. +} + +impl Not for ClipMode { + type Output = ClipMode; + + fn not(self) -> ClipMode { + match self { + ClipMode::Clip => ClipMode::ClipOut, + ClipMode::ClipOut => ClipMode::Clip, + } + } +} + #[repr(C)] #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct ComplexClipRegion { @@ -560,6 +577,9 @@ pub struct ComplexClipRegion { pub rect: LayoutRect, /// Border radii of this rectangle. pub radii: BorderRadius, + /// Whether we are clipping inside or outside + /// the region. + pub mode: ClipMode, } impl BorderRadius { @@ -619,8 +639,12 @@ impl BorderRadius { impl ComplexClipRegion { /// Create a new complex clip region. - pub fn new(rect: LayoutRect, radii: BorderRadius) -> ComplexClipRegion { - ComplexClipRegion { rect, radii } + pub fn new( + rect: LayoutRect, + radii: BorderRadius, + mode: ClipMode, + ) -> ComplexClipRegion { + ComplexClipRegion { rect, radii, mode } } } @@ -672,21 +696,3 @@ impl ClipId { } } } - -macro_rules! define_empty_heap_size_of { - ($name:ident) => { - impl ::heapsize::HeapSizeOf for $name { - fn heap_size_of_children(&self) -> usize { 0 } - } - } -} - -define_empty_heap_size_of!(ClipAndScrollInfo); -define_empty_heap_size_of!(ClipId); -define_empty_heap_size_of!(ImageKey); -define_empty_heap_size_of!(LocalClip); -define_empty_heap_size_of!(MixBlendMode); -define_empty_heap_size_of!(RepeatMode); -define_empty_heap_size_of!(ScrollSensitivity); -define_empty_heap_size_of!(StickySideConstraint); -define_empty_heap_size_of!(TransformStyle); diff --git a/gfx/webrender_api/src/display_list.rs b/gfx/webrender_api/src/display_list.rs index 0886e1f9da35..8afa4acb042b 100644 --- a/gfx/webrender_api/src/display_list.rs +++ b/gfx/webrender_api/src/display_list.rs @@ -12,7 +12,7 @@ use {LineDisplayItem, LineOrientation, LineStyle, LocalClip, MixBlendMode, Pipel use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem}; use {RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity}; use {SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, StickyFrameInfo}; -use {TextDisplayItem, Shadow, TransformStyle, YuvColorSpace, YuvData}; +use {BorderRadius, TextDisplayItem, Shadow, TransformStyle, YuvColorSpace, YuvData}; use YuvImageDisplayItem; use bincode; use serde::{Deserialize, Serialize, Serializer}; @@ -153,23 +153,25 @@ fn skip_slice Deserialize<'de>>( data: &mut &[u8], ) -> (ItemRange, usize) { let base = list.data.as_ptr() as usize; - let start = data.as_ptr() as usize; - // Read through the values (this is a bit of a hack to reuse logic) - let mut iter = AuxIter::::new(*data); - let count = iter.len(); - for _ in &mut iter {} - let end = iter.data.as_ptr() as usize; + let byte_size: usize = bincode::deserialize_from(data, bincode::Infinite) + .expect("MEH: malicious input?"); + let start = data.as_ptr() as usize; + let item_count: usize = bincode::deserialize_from(data, bincode::Infinite) + .expect("MEH: malicious input?"); + + // Remember how many bytes item_count occupied + let item_count_size = data.as_ptr() as usize - start; let range = ItemRange { - start: start - base, - length: end - start, + start: start - base, // byte offset to item_count + length: byte_size + item_count_size, // number of bytes for item_count + payload _boo: PhantomData, }; // Adjust data pointer to skip read values - *data = &data[range.length ..]; - (range, count) + *data = &data[byte_size ..]; + (range, item_count) } @@ -737,12 +739,29 @@ impl DisplayListBuilder { let len = iter.len(); let mut count = 0; + // Format: + // payload_byte_size: usize, item_count: usize, [I; item_count] + + // We write a dummy value so there's room for later + let byte_size_offset = self.data.len(); + serialize_fast(&mut self.data, &0usize); serialize_fast(&mut self.data, &len); + let payload_offset = self.data.len(); + for elem in iter { count += 1; serialize_fast(&mut self.data, &elem); } + // Now write the actual byte_size + let final_offset = self.data.len(); + let byte_size = final_offset - payload_offset; + + // Note we don't use serialize_fast because we don't want to change the Vec's len + bincode::serialize_into(&mut &mut self.data[byte_size_offset..], + &byte_size, + bincode::Infinite).unwrap(); + debug_assert_eq!(len, count); } @@ -1024,7 +1043,7 @@ impl DisplayListBuilder { color: ColorF, blur_radius: f32, spread_radius: f32, - border_radius: f32, + border_radius: BorderRadius, clip_mode: BoxShadowClipMode, ) { let item = SpecificDisplayItem::BoxShadow(BoxShadowDisplayItem { diff --git a/gfx/webrender_api/src/image.rs b/gfx/webrender_api/src/image.rs index db78c8dc1dbf..d067d282ca93 100644 --- a/gfx/webrender_api/src/image.rs +++ b/gfx/webrender_api/src/image.rs @@ -151,7 +151,7 @@ pub trait BlobImageResources { pub trait BlobImageRenderer: Send { fn add(&mut self, key: ImageKey, data: BlobImageData, tiling: Option); - fn update(&mut self, key: ImageKey, data: BlobImageData); + fn update(&mut self, key: ImageKey, data: BlobImageData, dirty_rect: Option); fn delete(&mut self, key: ImageKey); diff --git a/gfx/webrender_api/src/lib.rs b/gfx/webrender_api/src/lib.rs index c9d3d11d937a..ec701dc7209d 100644 --- a/gfx/webrender_api/src/lib.rs +++ b/gfx/webrender_api/src/lib.rs @@ -13,8 +13,6 @@ extern crate byteorder; #[cfg(feature = "nightly")] extern crate core; extern crate euclid; -#[macro_use] -extern crate heapsize; #[cfg(feature = "ipc")] extern crate ipc_channel; #[macro_use] diff --git a/gfx/webrender_bindings/Cargo.toml b/gfx/webrender_bindings/Cargo.toml index 2617609fafad..f17b3caa4e50 100644 --- a/gfx/webrender_bindings/Cargo.toml +++ b/gfx/webrender_bindings/Cargo.toml @@ -5,7 +5,7 @@ authors = ["The Mozilla Project Developers"] license = "MPL-2.0" [dependencies] -webrender_api = {path = "../webrender_api", version = "0.52.1"} +webrender_api = {path = "../webrender_api", version = "0.53.0"} bincode = "0.8" rayon = "0.8" thread_profiler = "0.1.1" @@ -15,5 +15,5 @@ gleam = "0.4" [dependencies.webrender] path = "../webrender" -version = "0.52.1" +version = "0.53.0" default-features = false