diff --git a/gfx/webrender/Cargo.toml b/gfx/webrender/Cargo.toml index b0ee83d52599..6da5e986cc4f 100644 --- a/gfx/webrender/Cargo.toml +++ b/gfx/webrender/Cargo.toml @@ -18,20 +18,20 @@ pathfinder = ["pathfinder_font_renderer", "pathfinder_gfx_utils", "pathfinder_pa serialize_program = ["serde"] [dependencies] -app_units = "0.6" +app_units = "0.7" base64 = { optional = true, version = "0.6" } bincode = "1.0" bitflags = "1.0" byteorder = "1.0" cfg-if = "0.1.2" -euclid = "0.18" +euclid = "0.19" fxhash = "0.2.1" gleam = "0.6" image = { optional = true, version = "0.19" } lazy_static = "1" log = "0.4" -num-traits = "0.1.43" -plane-split = "0.10" +num-traits = "0.2" +plane-split = "0.12" png = { optional = true, version = "0.12" } rayon = "1" ron = { optional = true, version = "0.1.7" } diff --git a/gfx/webrender/res/brush.glsl b/gfx/webrender/res/brush.glsl index c59992c5f6ec..0d04a1a4d5de 100644 --- a/gfx/webrender/res/brush.glsl +++ b/gfx/webrender/res/brush.glsl @@ -70,7 +70,6 @@ void main(void) { #endif } else { bvec4 edge_mask = notEqual(edge_flags & ivec4(1, 2, 4, 8), ivec4(0)); - bool do_perspective_interpolation = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0; vi = write_transform_vertex( local_segment_rect, @@ -79,8 +78,7 @@ void main(void) { mix(vec4(0.0), vec4(1.0), edge_mask), ph.z, transform, - pic_task, - do_perspective_interpolation + pic_task ); } @@ -92,7 +90,7 @@ void main(void) { // implies the other, for now. #ifdef WR_FEATURE_ALPHA_PASS write_clip( - vi.screen_pos, + vi.world_pos, clip_area ); #endif diff --git a/gfx/webrender/res/brush_blend.glsl b/gfx/webrender/res/brush_blend.glsl index 5f2e4a8fd835..5445e7d70d3a 100644 --- a/gfx/webrender/res/brush_blend.glsl +++ b/gfx/webrender/res/brush_blend.glsl @@ -29,9 +29,9 @@ void brush_vs( ) { PictureTask src_task = fetch_picture_task(user_data.x); vec2 texture_size = vec2(textureSize(sColor0, 0).xy); - vec2 uv = vi.snapped_device_pos + - src_task.common_data.task_rect.p0 - - src_task.content_origin; + vec2 uv = snap_device_pos(vi) + + src_task.common_data.task_rect.p0 - + src_task.content_origin; vUv = vec3(uv / texture_size, src_task.common_data.texture_layer_index); vec2 uv0 = src_task.common_data.task_rect.p0; diff --git a/gfx/webrender/res/brush_image.glsl b/gfx/webrender/res/brush_image.glsl index 6fb7685b9963..5356036cb4b4 100644 --- a/gfx/webrender/res/brush_image.glsl +++ b/gfx/webrender/res/brush_image.glsl @@ -11,7 +11,8 @@ varying vec2 vLocalPos; #endif // Interpolated uv coordinates in xy, and layer in z. -varying vec3 vUv; +// W is 1 when perspective interpolation is enabled. +varying vec4 vUv; // Normalized bounds of the source image in the texture. flat varying vec4 vUvBounds; // Normalized bounds of the source image in the texture, adjusted to avoid @@ -106,6 +107,7 @@ void brush_vs( } vUv.z = res.layer; + vUv.w = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0; // Handle case where the UV coords are inverted (e.g. from an // external image). @@ -151,6 +153,10 @@ void brush_vs( vUv.xy = mix(uv0, uv1, f) - min_uv; vUv.xy /= texture_size; vUv.xy *= repeat.xy; + if ((brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) == 0) { + // Multiply by W to compensate for perspective interpolation. + vUv.xy *= gl_Position.w; + } #ifdef WR_FEATURE_TEXTURE_RECT vUvBounds = vec4(0.0, 0.0, vec2(textureSize(sColor0))); @@ -196,12 +202,14 @@ void brush_vs( Fragment brush_fs() { vec2 uv_size = vUvBounds.zw - vUvBounds.xy; + // Unapply the W scaler when no perspective interpolation is enabled. + vec2 base_uv = vUv.xy * mix(gl_FragCoord.w, 1.0, vUv.w); #ifdef WR_FEATURE_ALPHA_PASS // This prevents the uv on the top and left parts of the primitive that was inflated // for anti-aliasing purposes from going beyound the range covered by the regular // (non-inflated) primitive. - vec2 local_uv = max(vUv.xy, vec2(0.0)); + vec2 local_uv = max(base_uv, vec2(0.0)); // Handle horizontal and vertical repetitions. vec2 repeated_uv = mod(local_uv, uv_size) + vUvBounds.xy; @@ -217,7 +225,7 @@ Fragment brush_fs() { } #else // Handle horizontal and vertical repetitions. - vec2 repeated_uv = mod(vUv.xy, uv_size) + vUvBounds.xy; + vec2 repeated_uv = mod(base_uv, uv_size) + vUvBounds.xy; #endif // Clamp the uvs to avoid sampling artifacts. diff --git a/gfx/webrender/res/brush_mix_blend.glsl b/gfx/webrender/res/brush_mix_blend.glsl index 0494974443c5..aec357a54b74 100644 --- a/gfx/webrender/res/brush_mix_blend.glsl +++ b/gfx/webrender/res/brush_mix_blend.glsl @@ -23,17 +23,18 @@ void brush_vs( int brush_flags, vec4 unused ) { + vec2 snapped_device_pos = snap_device_pos(vi); vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0)); vOp = user_data.x; PictureTask src_task = fetch_picture_task(user_data.z); - vec2 src_uv = vi.snapped_device_pos + + vec2 src_uv = snapped_device_pos + src_task.common_data.task_rect.p0 - src_task.content_origin; vSrcUv = vec3(src_uv / texture_size, src_task.common_data.texture_layer_index); RenderTaskCommonData backdrop_task = fetch_render_task_common_data(user_data.y); - vec2 backdrop_uv = vi.snapped_device_pos + + vec2 backdrop_uv = snapped_device_pos + backdrop_task.task_rect.p0 - src_task.content_origin; vBackdropUv = vec3(backdrop_uv / texture_size, backdrop_task.texture_layer_index); diff --git a/gfx/webrender/res/prim_shared.glsl b/gfx/webrender/res/prim_shared.glsl index 5bad278de160..0b09753b7a3f 100644 --- a/gfx/webrender/res/prim_shared.glsl +++ b/gfx/webrender/res/prim_shared.glsl @@ -27,7 +27,8 @@ vec2 clamp_rect(vec2 pt, RectWithSize rect) { // TODO: convert back to RectWithEndPoint if driver issues are resolved, if ever. flat varying vec4 vClipMaskUvBounds; -varying vec3 vClipMaskUv; +// XY and W are homogeneous coordinates, Z is the layer index +varying vec4 vClipMaskUv; #ifdef WR_VERTEX_SHADER @@ -86,11 +87,15 @@ PrimitiveHeader fetch_prim_header(int index) { struct VertexInfo { vec2 local_pos; - vec2 screen_pos; - float w; - vec2 snapped_device_pos; + vec2 snap_offset; + vec4 world_pos; }; +//Note: this function is unsafe for `vi.world_pos.w <= 0.0` +vec2 snap_device_pos(VertexInfo vi) { + return vi.world_pos.xy * uDevicePixelRatio / max(0.0, vi.world_pos.w) + vi.snap_offset; +} + VertexInfo write_vertex(RectWithSize instance_rect, RectWithSize local_clip_rect, float z, @@ -119,8 +124,7 @@ VertexInfo write_vertex(RectWithSize instance_rect, vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio; // Apply offsets for the render task to get correct screen location. - vec2 snapped_device_pos = device_pos + snap_offset; - vec2 final_pos = snapped_device_pos - + vec2 final_pos = device_pos + snap_offset - task.content_origin + task.common_data.task_rect.p0; @@ -128,9 +132,8 @@ VertexInfo write_vertex(RectWithSize instance_rect, VertexInfo vi = VertexInfo( clamped_local_pos, - device_pos, - world_pos.w, - snapped_device_pos + snap_offset, + world_pos ); return vi; @@ -161,8 +164,7 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect, vec4 clip_edge_mask, float z, Transform transform, - PictureTask task, - bool do_perspective_interpolation) { + PictureTask task) { // Calculate a clip rect from local_rect + local clip RectWithEndpoint clip_rect = to_rect_with_endpoint(local_clip_rect); RectWithEndpoint segment_rect = to_rect_with_endpoint(local_segment_rect); @@ -192,23 +194,17 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect, // Select the corner of the local rect that we are processing. vec2 local_pos = local_segment_rect.p0 + local_segment_rect.size * aPosition.xy; - // Transform the current vertex to the world cpace. - vec4 world_pos = transform.m * vec4(local_pos, 0.0, 1.0); - // Convert the world positions to device pixel space. - vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio; vec2 task_offset = task.common_data.task_rect.p0 - task.content_origin; - // Force w = 1, if we don't want perspective interpolation (for - // example, drawing a screen-space quad on an element with a - // perspective transform). - world_pos.w = mix(1.0, world_pos.w, do_perspective_interpolation); + // Transform the current vertex to the world cpace. + vec4 world_pos = transform.m * vec4(local_pos, 0.0, 1.0); + vec4 final_pos = vec4( + world_pos.xy * uDevicePixelRatio + task_offset * world_pos.w, + z * world_pos.w, + world_pos.w + ); - // We want the world space coords to be perspective divided by W. - // We also want that to apply to any interpolators. However, we - // want a constant Z across the primitive, since we're using it - // for draw ordering - so scale by the W coord to ensure this. - vec4 final_pos = vec4(device_pos + task_offset, z, 1.0) * world_pos.w; gl_Position = uTransform * final_pos; init_transform_vs(mix( @@ -219,36 +215,44 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect, VertexInfo vi = VertexInfo( local_pos, - device_pos, - world_pos.w, - device_pos + vec2(0.0), + world_pos ); return vi; } -void write_clip(vec2 global_pos, ClipArea area) { - vec2 uv = global_pos + - area.common_data.task_rect.p0 - - area.screen_origin; +void write_clip(vec4 world_pos, ClipArea area) { + vec2 uv = world_pos.xy * uDevicePixelRatio + + world_pos.w * (area.common_data.task_rect.p0 - area.screen_origin); vClipMaskUvBounds = vec4( area.common_data.task_rect.p0, area.common_data.task_rect.p0 + area.common_data.task_rect.size ); - vClipMaskUv = vec3(uv, area.common_data.texture_layer_index); + vClipMaskUv = vec4(uv, area.common_data.texture_layer_index, world_pos.w); } #endif //WR_VERTEX_SHADER #ifdef WR_FRAGMENT_SHADER float do_clip() { - // anything outside of the mask is considered transparent - bvec4 inside = lessThanEqual( - vec4(vClipMaskUvBounds.xy, vClipMaskUv.xy), - vec4(vClipMaskUv.xy, vClipMaskUvBounds.zw)); // check for the dummy bounds, which are given to the opaque objects - return vClipMaskUvBounds.xy == vClipMaskUvBounds.zw ? 1.0: - all(inside) ? texelFetch(sCacheA8, ivec3(vClipMaskUv), 0).r : 0.0; + if (vClipMaskUvBounds.xy == vClipMaskUvBounds.zw) { + return 1.0; + } + // anything outside of the mask is considered transparent + //Note: we assume gl_FragCoord.w == interpolated(1 / vClipMaskUv.w) + vec2 mask_uv = vClipMaskUv.xy * gl_FragCoord.w; + bvec4 inside = lessThanEqual( + vec4(vClipMaskUvBounds.xy, mask_uv), + vec4(mask_uv, vClipMaskUvBounds.zw)); + // bail out if the pixel is outside the valid bounds + if (!all(inside)) { + return 0.0; + } + // finally, the slow path - fetch the mask value from an image + ivec3 tc = ivec3(mask_uv, vClipMaskUv.z); + return texelFetch(sCacheA8, tc, 0).r; } #ifdef WR_FEATURE_DITHERING diff --git a/gfx/webrender/res/ps_text_run.glsl b/gfx/webrender/res/ps_text_run.glsl index 81770befb96b..49730e84a9f6 100644 --- a/gfx/webrender/res/ps_text_run.glsl +++ b/gfx/webrender/res/ps_text_run.glsl @@ -73,37 +73,33 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos, // Convert the world positions to device pixel space. float device_scale = uDevicePixelRatio / world_pos.w; vec2 device_pos = world_pos.xy * device_scale; - - // Apply offsets for the render task to get correct screen location. - vec2 final_pos = device_pos - - task.content_origin + - task.common_data.task_rect.p0; + vec2 snap_offset = vec2(0.0); #if defined(WR_FEATURE_GLYPH_TRANSFORM) bool remove_subpx_offset = true; #else - // Compute the snapping offset only if the scroll node transform is axis-aligned. bool remove_subpx_offset = transform.is_axis_aligned; #endif + // Compute the snapping offset only if the scroll node transform is axis-aligned. if (remove_subpx_offset) { // Ensure the transformed text offset does not contain a subpixel translation // such that glyph snapping is stable for equivalent glyph subpixel positions. vec2 world_text_offset = mat2(transform.m) * text_offset; vec2 device_text_pos = (transform.m[3].xy + world_text_offset) * device_scale; - final_pos += floor(device_text_pos + 0.5) - device_text_pos; + snap_offset += floor(device_text_pos + 0.5) - device_text_pos; #ifdef WR_FEATURE_GLYPH_TRANSFORM // For transformed subpixels, we just need to align the glyph origin to a device pixel. // The transformed text offset has already been snapped, so remove it from the glyph // origin when snapping the glyph. - vec2 snap_offset = snap_rect.p0 - world_text_offset * device_scale; - final_pos += floor(snap_offset + snap_bias) - snap_offset; + vec2 rough_offset = snap_rect.p0 - world_text_offset * device_scale; + snap_offset += floor(rough_offset + snap_bias) - rough_offset; #else // The transformed text offset has already been snapped, so remove it from the transform // when snapping the glyph. mat4 snap_transform = transform.m; snap_transform[3].xy = -world_text_offset; - final_pos += compute_snap_offset( + snap_offset += compute_snap_offset( clamped_local_pos, snap_transform, snap_rect, @@ -112,13 +108,17 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos, #endif } + // Apply offsets for the render task to get correct screen location. + vec2 final_pos = device_pos + snap_offset - + task.content_origin + + task.common_data.task_rect.p0; + gl_Position = uTransform * vec4(final_pos, z, 1.0); VertexInfo vi = VertexInfo( clamped_local_pos, - device_pos, - world_pos.w, - final_pos + snap_offset, + world_pos ); return vi; @@ -223,7 +223,7 @@ void main(void) { vec2 f = (vi.local_pos - glyph_rect.p0) / glyph_rect.size; #endif - write_clip(vi.screen_pos, clip_area); + write_clip(vi.world_pos, clip_area); switch (color_mode) { case COLOR_MODE_ALPHA: diff --git a/gfx/webrender/src/batch.rs b/gfx/webrender/src/batch.rs index 426c22889916..ebd690e65d27 100644 --- a/gfx/webrender/src/batch.rs +++ b/gfx/webrender/src/batch.rs @@ -1788,7 +1788,7 @@ impl ClipBatcher { ) { let mut coordinate_system_id = coordinate_system_id; for work_item in clips.iter() { - let info = clip_store.get(work_item.clip_sources_index); + let info = &clip_store[work_item.clip_sources_index]; let instance = ClipMaskInstance { render_task_address: task_address, transform_id: transforms.get_id(info.spatial_node_index), diff --git a/gfx/webrender/src/border.rs b/gfx/webrender/src/border.rs index 8a035d241479..1152d551c875 100644 --- a/gfx/webrender/src/border.rs +++ b/gfx/webrender/src/border.rs @@ -9,10 +9,20 @@ use app_units::Au; use ellipse::Ellipse; use display_list_flattener::DisplayListFlattener; use gpu_types::{BorderInstance, BorderSegment, BrushFlags}; -use prim_store::{BrushKind, BrushPrimitive, BrushSegment}; +use prim_store::{BrushKind, BrushPrimitive, BrushSegment, VECS_PER_SEGMENT}; use prim_store::{BorderSource, EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain}; +use renderer::{MAX_VERTEX_TEXTURE_WIDTH}; use util::{lerp, RectHelpers}; +// Using 2048 as the maximum radius in device space before which we +// start stretching is up for debate. +// the value must be chosen so that the corners will not use an +// unreasonable amount of memory but should allow crisp corners in the +// common cases. + +/// Maximum resolution in device pixels at which borders are rasterized. +pub const MAX_BORDER_RESOLUTION: u32 = 2048; + trait AuSizeConverter { fn to_au(&self) -> LayoutSizeAu; } @@ -345,18 +355,24 @@ impl BorderCornerClipSource { 1.0 - 2.0 * outer_scale.y, ); + // No point in pushing more clips as it will blow up the maximum amount of + // segments per primitive later down the road. + // See #2915 for a better fix. + let clip_limit = MAX_VERTEX_TEXTURE_WIDTH / VECS_PER_SEGMENT; + let max_clip_count = self.max_clip_count.min(clip_limit); + match self.kind { BorderCornerClipKind::Dash => { // Get the correct dash arc length. let dash_arc_length = - 0.5 * self.ellipse.total_arc_length / self.max_clip_count as f32; + 0.5 * self.ellipse.total_arc_length / max_clip_count as f32; // Start the first dash at one quarter the length of a single dash // along the arc line. This is arbitrary but looks reasonable in // most cases. We need to spend some time working on a more // sophisticated dash placement algorithm that takes into account // the offset of the dashes along edge segments. let mut current_arc_length = 0.25 * dash_arc_length; - for _ in 0 .. self.max_clip_count { + for _ in 0 .. max_clip_count { let arc_length0 = current_arc_length; current_arc_length += dash_arc_length; @@ -401,7 +417,7 @@ impl BorderCornerClipSource { ]); } } - BorderCornerClipKind::Dot if self.max_clip_count == 1 => { + BorderCornerClipKind::Dot if max_clip_count == 1 => { let dot_diameter = lerp(self.widths.width, self.widths.height, 0.5); dot_dash_data.push([ self.widths.width / 2.0, self.widths.height / 2.0, 0.5 * dot_diameter, 0., @@ -422,7 +438,7 @@ impl BorderCornerClipSource { self.widths.height, )); - for dot_index in 0 .. self.max_clip_count { + for dot_index in 0 .. max_clip_count { let prev_forward_pos = *forward_dots.last().unwrap(); let prev_back_pos = *back_dots.last().unwrap(); @@ -927,6 +943,23 @@ impl BorderRenderTaskInfo { instances } + + /// Computes the maximum scale that we allow for this set of border radii. + /// capping the scale will result in rendering very large corners at a lower + /// resolution and stretching them, so they will have the right shape, but + /// blurrier. + pub fn get_max_scale(radii: &BorderRadius) -> LayoutToDeviceScale { + let r = radii.top_left.width + .max(radii.top_left.height) + .max(radii.top_right.width) + .max(radii.top_right.height) + .max(radii.bottom_left.width) + .max(radii.bottom_left.height) + .max(radii.bottom_right.width) + .max(radii.bottom_right.height); + + LayoutToDeviceScale::new(MAX_BORDER_RESOLUTION as f32 / r) + } } fn add_brush_segment( diff --git a/gfx/webrender/src/clip.rs b/gfx/webrender/src/clip.rs index 4fd9ecd758af..68826739086a 100644 --- a/gfx/webrender/src/clip.rs +++ b/gfx/webrender/src/clip.rs @@ -14,8 +14,9 @@ use gpu_types::BoxShadowStretchMode; use prim_store::{ClipData, ImageMaskData}; use render_task::to_cache_size; use resource_cache::{ImageRequest, ResourceCache}; -use util::{LayoutToWorldFastTransform, MaxRect, calculate_screen_bounding_rect}; -use util::{extract_inner_rect_safe, pack_as_float, recycle_vec}; +use util::{LayoutToWorldFastTransform, MaxRect, TransformedRectKind}; +use util::{calculate_screen_bounding_rect, extract_inner_rect_safe, pack_as_float, recycle_vec}; +use std::{iter, ops}; use std::sync::Arc; #[derive(Debug, Copy, Clone)] @@ -28,13 +29,13 @@ pub struct ClipStore { } impl ClipStore { - pub fn new() -> ClipStore { + pub fn new() -> Self { ClipStore { clip_sources: Vec::new(), } } - pub fn recycle(self) -> ClipStore { + pub fn recycle(self) -> Self { ClipStore { clip_sources: recycle_vec(self.clip_sources), } @@ -45,12 +46,17 @@ impl ClipStore { self.clip_sources.push(clip_sources); index } +} - pub fn get(&self, index: ClipSourcesIndex) -> &ClipSources { +impl ops::Index for ClipStore { + type Output = ClipSources; + fn index(&self, index: ClipSourcesIndex) -> &Self::Output { &self.clip_sources[index.0] } +} - pub fn get_mut(&mut self, index: ClipSourcesIndex) -> &mut ClipSources { +impl ops::IndexMut for ClipStore { + fn index_mut(&mut self, index: ClipSourcesIndex) -> &mut Self::Output { &mut self.clip_sources[index.0] } } @@ -63,51 +69,77 @@ pub struct LineDecorationClipSource { wavy_line_thickness: f32, } -#[derive(Clone, Debug)] -pub struct ClipRegion { - pub main: LayoutRect, - pub image_mask: Option, - pub complex_clips: Vec, + +pub struct ComplexTranslateIter { + source: I, + offset: LayoutVector2D, } -impl ClipRegion { +impl> Iterator for ComplexTranslateIter { + type Item = ComplexClipRegion; + fn next(&mut self) -> Option { + self.source + .next() + .map(|mut complex| { + complex.rect = complex.rect.translate(&self.offset); + complex + }) + } +} + +#[derive(Clone, Debug)] +pub struct ClipRegion { + pub main: LayoutRect, + pub image_mask: Option, + pub complex_clips: I, +} + +impl ClipRegion> { pub fn create_for_clip_node( rect: LayoutRect, - mut complex_clips: Vec, + complex_clips: J, mut image_mask: Option, reference_frame_relative_offset: &LayoutVector2D, - ) -> ClipRegion { - let rect = rect.translate(reference_frame_relative_offset); - + ) -> Self + where + J: Iterator + { if let Some(ref mut image_mask) = image_mask { image_mask.rect = image_mask.rect.translate(reference_frame_relative_offset); } - for complex_clip in complex_clips.iter_mut() { - complex_clip.rect = complex_clip.rect.translate(reference_frame_relative_offset); - } - ClipRegion { - main: rect, + main: rect.translate(reference_frame_relative_offset), image_mask, - complex_clips, + complex_clips: ComplexTranslateIter { + source: complex_clips, + offset: *reference_frame_relative_offset, + }, } } +} +impl ClipRegion> { pub fn create_for_clip_node_with_local_clip( local_clip: &LocalClip, reference_frame_relative_offset: &LayoutVector2D - ) -> ClipRegion { - let complex_clips = match *local_clip { - LocalClip::Rect(_) => Vec::new(), - LocalClip::RoundedRect(_, ref region) => vec![region.clone()], - }; - ClipRegion::create_for_clip_node( - *local_clip.clip_rect(), - complex_clips, - None, - reference_frame_relative_offset - ) + ) -> Self { + ClipRegion { + main: local_clip + .clip_rect() + .translate(reference_frame_relative_offset), + image_mask: None, + complex_clips: match *local_clip { + LocalClip::Rect(_) => None, + LocalClip::RoundedRect(_, ref region) => { + Some(ComplexClipRegion { + rect: region.rect.translate(reference_frame_relative_offset), + radii: region.radii, + mode: region.mode, + }) + }, + } + } } } @@ -280,6 +312,92 @@ impl ClipSource { } } + +struct BoundsAccumulator { + local_outer: Option, + local_inner: Option, + can_calculate_inner_rect: bool, + can_calculate_outer_rect: bool, +} + +impl BoundsAccumulator { + fn new() -> Self { + BoundsAccumulator { + local_outer: Some(LayoutRect::max_rect()), + local_inner: Some(LayoutRect::max_rect()), + can_calculate_inner_rect: true, + can_calculate_outer_rect: false, + } + } + + fn add(&mut self, source: &ClipSource) { + // Depending on the complexity of the clip, we may either know the outer and/or inner + // rect, or neither or these. In the case of a clip-out, we currently set the mask bounds + // to be unknown. This is conservative, but ensures correctness. In the future we can make + // this a lot more clever with some proper region handling. + if !self.can_calculate_inner_rect { + return + } + + match *source { + ClipSource::Image(ref mask) => { + if !mask.repeat { + self.can_calculate_outer_rect = true; + self.local_outer = self.local_outer.and_then(|r| r.intersection(&mask.rect)); + } + self.local_inner = None; + } + ClipSource::Rectangle(rect, mode) => { + // Once we encounter a clip-out, we just assume the worst + // case clip mask size, for now. + if mode == ClipMode::ClipOut { + self.can_calculate_inner_rect = false; + return + } + + self.can_calculate_outer_rect = true; + self.local_outer = self.local_outer.and_then(|r| r.intersection(&rect)); + self.local_inner = self.local_inner.and_then(|r| r.intersection(&rect)); + } + ClipSource::RoundedRectangle(ref rect, ref radius, mode) => { + // Once we encounter a clip-out, we just assume the worst + // case clip mask size, for now. + if mode == ClipMode::ClipOut { + self.can_calculate_inner_rect = false; + return + } + + self.can_calculate_outer_rect = true; + self.local_outer = self.local_outer.and_then(|r| r.intersection(rect)); + + let inner_rect = extract_inner_rect_safe(rect, radius); + self.local_inner = self.local_inner + .and_then(|r| inner_rect.and_then(|ref inner| r.intersection(inner))); + } + ClipSource::BoxShadow(..) | + ClipSource::LineDecoration(..) => { + self.can_calculate_inner_rect = false; + } + } + } + + fn finish(self) -> (LayoutRect, Option) { + ( + if self.can_calculate_inner_rect { + self.local_inner.unwrap_or_else(LayoutRect::zero) + } else { + LayoutRect::zero() + }, + if self.can_calculate_outer_rect { + Some(self.local_outer.unwrap_or_else(LayoutRect::zero)) + } else { + None + }, + ) + } +} + + #[derive(Debug)] pub struct ClipSources { pub clips: Vec<(ClipSource, GpuCacheHandle)>, @@ -291,20 +409,24 @@ pub struct ClipSources { } impl ClipSources { - pub fn new( - clips: Vec, - spatial_node_index: SpatialNodeIndex, - ) -> Self { - let (local_inner_rect, local_outer_rect) = Self::calculate_inner_and_outer_rects(&clips); + pub fn new(clip_iter: I, spatial_node_index: SpatialNodeIndex) -> Self + where + I: IntoIterator, + { + let mut clips = Vec::new(); + let mut bounds_accum = BoundsAccumulator::new(); + let mut has_image_or_line_decoration_clip = false; + let mut only_rectangular_clips = true; - let has_image_or_line_decoration_clip = - clips.iter().any(|clip| clip.is_image_or_line_decoration_clip()); - let only_rectangular_clips = - !has_image_or_line_decoration_clip && clips.iter().all(|clip| clip.is_rect()); - let clips = clips - .into_iter() - .map(|clip| (clip, GpuCacheHandle::new())) - .collect(); + for clip in clip_iter { + bounds_accum.add(&clip); + has_image_or_line_decoration_clip |= clip.is_image_or_line_decoration_clip(); + only_rectangular_clips &= clip.is_rect(); + clips.push((clip, GpuCacheHandle::new())); + } + + only_rectangular_clips &= !has_image_or_line_decoration_clip; + let (local_inner_rect, local_outer_rect) = bounds_accum.finish(); ClipSources { clips, @@ -316,105 +438,31 @@ impl ClipSources { } } - pub fn from_region( - region: ClipRegion, + pub fn from_region( + region: ClipRegion, spatial_node_index: SpatialNodeIndex, - ) -> ClipSources { - let mut clips = Vec::new(); - - if let Some(info) = region.image_mask { - clips.push(ClipSource::Image(info)); - } - - clips.push(ClipSource::Rectangle(region.main, ClipMode::Clip)); - - for complex in region.complex_clips { - clips.push(ClipSource::new_rounded_rect( + ) -> ClipSources + where + I: IntoIterator + { + let clip_rect = iter::once(ClipSource::Rectangle(region.main, ClipMode::Clip)); + let clip_image = region.image_mask.map(ClipSource::Image); + let clips_complex = region.complex_clips + .into_iter() + .map(|complex| ClipSource::new_rounded_rect( complex.rect, complex.radii, complex.mode, )); - } - ClipSources::new(clips, spatial_node_index) + let clips_all = clip_rect.chain(clip_image).chain(clips_complex); + ClipSources::new(clips_all, spatial_node_index) } pub fn clips(&self) -> &[(ClipSource, GpuCacheHandle)] { &self.clips } - fn calculate_inner_and_outer_rects(clips: &Vec) -> (LayoutRect, Option) { - if clips.is_empty() { - return (LayoutRect::zero(), None); - } - - // Depending on the complexity of the clip, we may either know the outer and/or inner - // rect, or neither or these. In the case of a clip-out, we currently set the mask bounds - // to be unknown. This is conservative, but ensures correctness. In the future we can make - // this a lot more clever with some proper region handling. - let mut local_outer = Some(LayoutRect::max_rect()); - let mut local_inner = local_outer; - let mut can_calculate_inner_rect = true; - let mut can_calculate_outer_rect = false; - for source in clips { - match *source { - ClipSource::Image(ref mask) => { - if !mask.repeat { - can_calculate_outer_rect = true; - local_outer = local_outer.and_then(|r| r.intersection(&mask.rect)); - } - local_inner = None; - } - ClipSource::Rectangle(rect, mode) => { - // Once we encounter a clip-out, we just assume the worst - // case clip mask size, for now. - if mode == ClipMode::ClipOut { - can_calculate_inner_rect = false; - break; - } - - can_calculate_outer_rect = true; - local_outer = local_outer.and_then(|r| r.intersection(&rect)); - local_inner = local_inner.and_then(|r| r.intersection(&rect)); - } - ClipSource::RoundedRectangle(ref rect, ref radius, mode) => { - // Once we encounter a clip-out, we just assume the worst - // case clip mask size, for now. - if mode == ClipMode::ClipOut { - can_calculate_inner_rect = false; - break; - } - - can_calculate_outer_rect = true; - local_outer = local_outer.and_then(|r| r.intersection(rect)); - - let inner_rect = extract_inner_rect_safe(rect, radius); - local_inner = local_inner - .and_then(|r| inner_rect.and_then(|ref inner| r.intersection(inner))); - } - ClipSource::BoxShadow(..) | - ClipSource::LineDecoration(..) => { - can_calculate_inner_rect = false; - break; - } - } - } - - let outer = if can_calculate_outer_rect { - Some(local_outer.unwrap_or_else(LayoutRect::zero)) - } else { - None - }; - - let inner = if can_calculate_inner_rect { - local_inner.unwrap_or_else(LayoutRect::zero) - } else { - LayoutRect::zero() - }; - - (inner, outer) - } - pub fn update( &mut self, gpu_cache: &mut GpuCache, @@ -523,7 +571,8 @@ impl ClipSources { // rectangle so that we can do screen inner rectangle optimizations for these kind of // cilps. let can_calculate_inner_rect = - transform.preserves_2d_axis_alignment() && !transform.has_perspective_component(); + transform.kind() == TransformedRectKind::AxisAligned && + !transform.has_perspective_component(); let screen_inner_rect = if can_calculate_inner_rect { calculate_screen_bounding_rect(transform, &self.local_inner_rect, device_pixel_scale, screen_rect) .unwrap_or(DeviceIntRect::zero()) diff --git a/gfx/webrender/src/clip_node.rs b/gfx/webrender/src/clip_node.rs index 78363d6c7c89..bcb8b2ce5ff8 100644 --- a/gfx/webrender/src/clip_node.rs +++ b/gfx/webrender/src/clip_node.rs @@ -37,7 +37,7 @@ impl ClipNode { clip_chains: &mut [ClipChain], spatial_nodes: &[SpatialNode], ) { - let clip_sources = clip_store.get_mut(self.clip_sources_index); + let clip_sources = &mut clip_store[self.clip_sources_index]; clip_sources.update(gpu_cache, resource_cache, device_pixel_scale); let spatial_node = &spatial_nodes[clip_sources.spatial_node_index.0]; @@ -60,10 +60,8 @@ impl ClipNode { clip_sources_index: self.clip_sources_index, coordinate_system_id: spatial_node.coordinate_system_id, }, - local_clip_rect: spatial_node - .coordinate_system_relative_transform - .transform_rect(&local_outer_rect) - .expect("clip node transform is not valid"), + local_clip_rect: local_outer_rect + .translate(&spatial_node.coordinate_system_relative_offset), screen_outer_rect, screen_inner_rect, prev: None, diff --git a/gfx/webrender/src/clip_scroll_tree.rs b/gfx/webrender/src/clip_scroll_tree.rs index 53a7d8906877..763cd62c3c7c 100644 --- a/gfx/webrender/src/clip_scroll_tree.rs +++ b/gfx/webrender/src/clip_scroll_tree.rs @@ -14,7 +14,7 @@ use print_tree::{PrintTree, PrintTreePrinter}; use resource_cache::ResourceCache; use scene::SceneProperties; use spatial_node::{ScrollFrameInfo, SpatialNode, SpatialNodeType, StickyFrameInfo}; -use util::{LayoutFastTransform, LayoutToWorldFastTransform}; +use util::LayoutToWorldFastTransform; pub type ScrollStates = FastHashMap; @@ -103,8 +103,8 @@ pub struct TransformUpdateState { /// coordinate systems which are relatively axis aligned. pub current_coordinate_system_id: CoordinateSystemId, - /// Transform from the coordinate system that started this compatible coordinate system. - pub coordinate_system_relative_transform: LayoutFastTransform, + /// Offset from the coordinate system that started this compatible coordinate system. + pub coordinate_system_relative_offset: LayoutVector2D, /// True if this node is transformed by an invertible transform. If not, display items /// transformed by this node will not be displayed and display items not transformed by this @@ -242,7 +242,7 @@ impl ClipScrollTree { nearest_scrolling_ancestor_offset: LayoutVector2D::zero(), nearest_scrolling_ancestor_viewport: LayoutRect::zero(), current_coordinate_system_id: CoordinateSystemId::root(), - coordinate_system_relative_transform: LayoutFastTransform::identity(), + coordinate_system_relative_offset: LayoutVector2D::zero(), invertible: true, }; diff --git a/gfx/webrender/src/device/query_gl.rs b/gfx/webrender/src/device/query_gl.rs index 97068146edf8..4064363ad637 100644 --- a/gfx/webrender/src/device/query_gl.rs +++ b/gfx/webrender/src/device/query_gl.rs @@ -71,16 +71,18 @@ pub struct GpuFrameProfile { samplers: QuerySet>, frame_id: FrameId, inside_frame: bool, + ext_debug_marker: bool } impl GpuFrameProfile { - fn new(gl: Rc) -> Self { + fn new(gl: Rc, ext_debug_marker: bool) -> Self { GpuFrameProfile { gl, timers: QuerySet::new(), samplers: QuerySet::new(), frame_id: FrameId::new(0), inside_frame: false, + ext_debug_marker } } @@ -140,7 +142,7 @@ impl GpuFrameProfile { fn start_timer(&mut self, tag: T) -> GpuTimeQuery { self.finish_timer(); - let marker = GpuMarker::new(&self.gl, tag.get_label()); + let marker = GpuMarker::new(&self.gl, tag.get_label(), self.ext_debug_marker); if let Some(query) = self.timers.add(GpuTimer { tag, time_ns: 0 }) { self.gl.begin_query(gl::TIME_ELAPSED, query); @@ -187,19 +189,21 @@ pub struct GpuProfiler { gl: Rc, frames: Vec>, next_frame: usize, + ext_debug_marker: bool } impl GpuProfiler { - pub fn new(gl: Rc) -> Self { + pub fn new(gl: Rc, ext_debug_marker: bool) -> Self { const MAX_PROFILE_FRAMES: usize = 4; let frames = (0 .. MAX_PROFILE_FRAMES) - .map(|_| GpuFrameProfile::new(Rc::clone(&gl))) + .map(|_| GpuFrameProfile::new(Rc::clone(&gl), ext_debug_marker)) .collect(); GpuProfiler { gl, next_frame: 0, frames, + ext_debug_marker } } @@ -263,33 +267,42 @@ impl GpuProfiler { } pub fn start_marker(&mut self, label: &str) -> GpuMarker { - GpuMarker::new(&self.gl, label) + GpuMarker::new(&self.gl, label, self.ext_debug_marker) } pub fn place_marker(&mut self, label: &str) { - GpuMarker::fire(&self.gl, label) + GpuMarker::fire(&self.gl, label, self.ext_debug_marker) } } #[must_use] pub struct GpuMarker { - gl: Rc, + gl: Option> } impl GpuMarker { - fn new(gl: &Rc, message: &str) -> Self { - gl.push_group_marker_ext(message); - GpuMarker { gl: Rc::clone(gl) } + fn new(gl: &Rc, message: &str, ext_debug_marker: bool) -> Self { + let gl = if ext_debug_marker { + gl.push_group_marker_ext(message); + Some(Rc::clone(gl)) + } else { + None + }; + GpuMarker { gl } } - fn fire(gl: &Rc, message: &str) { - gl.insert_event_marker_ext(message); + fn fire(gl: &Rc, message: &str, ext_debug_marker: bool) { + if ext_debug_marker { + gl.insert_event_marker_ext(message); + } } } impl Drop for GpuMarker { fn drop(&mut self) { - self.gl.pop_group_marker_ext(); + if let Some(ref gl) = self.gl { + gl.pop_group_marker_ext(); + } } } diff --git a/gfx/webrender/src/display_list_flattener.rs b/gfx/webrender/src/display_list_flattener.rs index a3227e007d1a..0ab767a6fdf1 100644 --- a/gfx/webrender/src/display_list_flattener.rs +++ b/gfx/webrender/src/display_list_flattener.rs @@ -224,22 +224,22 @@ impl<'a> DisplayListFlattener<'a> { &self, pipeline_id: PipelineId, complex_clips: ItemRange, - ) -> Vec { - if complex_clips.is_empty() { - return vec![]; - } - self.scene.get_display_list_for_pipeline(pipeline_id).get(complex_clips).collect() + ) -> impl 'a + Iterator { + //Note: we could make this a bit more complex to early out + // on `complex_clips.is_empty()` if it's worth it + self.scene + .get_display_list_for_pipeline(pipeline_id) + .get(complex_clips) } fn get_clip_chain_items( &self, pipeline_id: PipelineId, items: ItemRange, - ) -> Vec { - if items.is_empty() { - return vec![]; - } - self.scene.get_display_list_for_pipeline(pipeline_id).get(items).collect() + ) -> impl 'a + Iterator { + self.scene + .get_display_list_for_pipeline(pipeline_id) + .get(items) } fn flatten_root(&mut self, pipeline: &'a ScenePipeline, frame_size: &LayoutSize) { @@ -685,8 +685,7 @@ impl<'a> DisplayListFlattener<'a> { } SpecificDisplayItem::ClipChain(ref info) => { let items = self.get_clip_chain_items(pipeline_id, item.clip_chain_items()) - .iter() - .map(|id| self.id_to_index_mapper.get_clip_node_index(*id)) + .map(|id| self.id_to_index_mapper.get_clip_node_index(id)) .collect(); let parent = match info.parent { Some(id) => Some( @@ -1241,12 +1240,15 @@ impl<'a> DisplayListFlattener<'a> { ); } - pub fn add_clip_node( + pub fn add_clip_node( &mut self, new_node_id: ClipId, parent_id: ClipId, - clip_region: ClipRegion, - ) -> ClipChainIndex { + clip_region: ClipRegion, + ) -> ClipChainIndex + where + I: IntoIterator + { let parent_clip_chain_index = self.id_to_index_mapper.get_clip_chain_index(&parent_id); let spatial_node = self.id_to_index_mapper.get_spatial_node_index(parent_id); diff --git a/gfx/webrender/src/frame_builder.rs b/gfx/webrender/src/frame_builder.rs index 593b9dfafbf8..8319c793a565 100644 --- a/gfx/webrender/src/frame_builder.rs +++ b/gfx/webrender/src/frame_builder.rs @@ -104,7 +104,7 @@ pub struct PictureState { } impl PictureState { - pub fn new() -> PictureState { + pub fn new() -> Self { PictureState { tasks: Vec::new(), has_non_root_coord_system: false, @@ -117,7 +117,7 @@ pub struct PrimitiveRunContext<'a> { pub clip_chain: &'a ClipChain, pub scroll_node: &'a SpatialNode, pub spatial_node_index: SpatialNodeIndex, - pub transform: Transform, + pub transform: Transform<'a>, pub local_clip_rect: LayoutRect, } @@ -127,7 +127,7 @@ impl<'a> PrimitiveRunContext<'a> { scroll_node: &'a SpatialNode, spatial_node_index: SpatialNodeIndex, local_clip_rect: LayoutRect, - transform: Transform, + transform: Transform<'a>, ) -> Self { PrimitiveRunContext { clip_chain, diff --git a/gfx/webrender/src/gpu_types.rs b/gfx/webrender/src/gpu_types.rs index c3a813b2b8de..af93dbf2b991 100644 --- a/gfx/webrender/src/gpu_types.rs +++ b/gfx/webrender/src/gpu_types.rs @@ -8,7 +8,7 @@ use clip_scroll_tree::SpatialNodeIndex; use gpu_cache::{GpuCacheAddress, GpuDataRequest}; use prim_store::{EdgeAaSegmentMask, Transform}; use render_task::RenderTaskAddress; -use util::{MatrixHelpers, TransformedRectKind}; +use util::{LayoutToWorldFastTransform, TransformedRectKind}; // Contains type that must exactly match the same structures declared in GLSL. @@ -374,12 +374,12 @@ impl TransformPaletteId { #[cfg_attr(feature = "replay", derive(Deserialize))] #[repr(C)] pub struct TransformData { - pub transform: LayoutToWorldTransform, - pub inv_transform: WorldToLayoutTransform, + transform: LayoutToWorldTransform, + inv_transform: WorldToLayoutTransform, } impl TransformData { - pub fn invalid() -> Self { + fn invalid() -> Self { TransformData { transform: LayoutToWorldTransform::identity(), inv_transform: WorldToLayoutTransform::identity(), @@ -389,7 +389,7 @@ impl TransformData { // Extra data stored about each transform palette entry. pub struct TransformMetadata { - pub transform_kind: TransformedRectKind, + transform_kind: TransformedRectKind, } // Stores a contiguous list of TransformData structs, that @@ -405,38 +405,60 @@ pub struct TransformPalette { } impl TransformPalette { - pub fn new(spatial_node_count: usize) -> TransformPalette { + pub fn new(spatial_node_count: usize) -> Self { TransformPalette { transforms: Vec::with_capacity(spatial_node_count), metadata: Vec::with_capacity(spatial_node_count), } } - // Set the local -> world transform for a given spatial - // node in the transform palette. - pub fn set( - &mut self, - index: SpatialNodeIndex, - data: TransformData, - ) { - let index = index.0 as usize; - + #[inline] + fn grow(&mut self, index: SpatialNodeIndex) { // Pad the vectors out if they are not long enough to // account for this index. This can occur, for instance, // when we stop recursing down the CST due to encountering // a node with an invalid transform. - while index >= self.transforms.len() { + while self.transforms.len() <= index.0 as usize { self.transforms.push(TransformData::invalid()); self.metadata.push(TransformMetadata { transform_kind: TransformedRectKind::AxisAligned, }); } + } - // Store the transform itself, along with metadata about it. - self.metadata[index] = TransformMetadata { - transform_kind: data.transform.transform_kind(), + pub fn invalidate(&mut self, index: SpatialNodeIndex) { + self.grow(index); + self.metadata[index.0 as usize] = TransformMetadata { + transform_kind: TransformedRectKind::AxisAligned, }; - self.transforms[index] = data; + self.transforms[index.0 as usize] = TransformData::invalid(); + } + + // Set the local -> world transform for a given spatial + // node in the transform palette. + pub fn set( + &mut self, index: SpatialNodeIndex, fast_transform: &LayoutToWorldFastTransform, + ) -> bool { + self.grow(index); + + match fast_transform.inverse() { + Some(inverted) => { + // Store the transform itself, along with metadata about it. + self.metadata[index.0 as usize] = TransformMetadata { + transform_kind: fast_transform.kind() + }; + // Write the data that will be made available to the GPU for this node. + self.transforms[index.0 as usize] = TransformData { + transform: fast_transform.to_transform().into_owned(), + inv_transform: inverted.to_transform().into_owned(), + }; + true + } + None => { + self.invalidate(index); + false + } + } } // Get the relevant information about a given transform that is @@ -448,14 +470,13 @@ impl TransformPalette { &self, index: SpatialNodeIndex, ) -> Transform { - let index = index.0; - let transform = &self.transforms[index]; - let metadata = &self.metadata[index]; + let data = &self.transforms[index.0 as usize]; + let metadata = &self.metadata[index.0 as usize]; Transform { - m: transform.transform, + m: &data.transform, transform_kind: metadata.transform_kind, - backface_is_visible: transform.transform.is_backface_visible(), + backface_is_visible: data.transform.is_backface_visible(), } } diff --git a/gfx/webrender/src/hit_test.rs b/gfx/webrender/src/hit_test.rs index 57b02534daee..7b47f75a3c97 100644 --- a/gfx/webrender/src/hit_test.rs +++ b/gfx/webrender/src/hit_test.rs @@ -36,7 +36,7 @@ pub struct HitTestClipNode { impl HitTestClipNode { fn new(node: &ClipNode, clip_store: &ClipStore) -> Self { - let clips = clip_store.get(node.clip_sources_index); + let clips = &clip_store[node.clip_sources_index]; let regions = clips.clips().iter().map(|source| { match source.0 { ClipSource::Rectangle(ref rect, mode) => HitTestRegion::Rectangle(*rect, mode), diff --git a/gfx/webrender/src/prim_store.rs b/gfx/webrender/src/prim_store.rs index d9a169e6acae..a28ed42a228b 100644 --- a/gfx/webrender/src/prim_store.rs +++ b/gfx/webrender/src/prim_store.rs @@ -63,8 +63,8 @@ impl ScrollNodeAndClipChain { // the information in the clip-scroll tree. However, if we decide // to rasterize a picture in local space, then this will be the // transform relative to that picture's coordinate system. -pub struct Transform { - pub m: LayoutToWorldTransform, +pub struct Transform<'a> { + pub m: &'a LayoutToWorldTransform, pub backface_is_visible: bool, pub transform_kind: TransformedRectKind, } @@ -1495,7 +1495,9 @@ impl PrimitiveStore { // scale factor from the world transform to get an appropriately // sized border task. let world_scale = LayoutToWorldScale::new(1.0); - let scale = world_scale * frame_context.device_pixel_scale; + let mut scale = world_scale * frame_context.device_pixel_scale; + let max_scale = BorderRenderTaskInfo::get_max_scale(&border.radius); + scale.0 = scale.0.min(max_scale.0); let scale_au = Au::from_f32_px(scale.0); let needs_update = scale_au != cache_key.scale; let mut new_segments = Vec::new(); @@ -1572,7 +1574,7 @@ impl PrimitiveStore { PrimitiveKind::TextRun => { let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0]; // The transform only makes sense for screen space rasterization - let transform = prim_run_context.scroll_node.world_content_transform.into(); + let transform = prim_run_context.scroll_node.world_content_transform.to_transform(); text.prepare_for_render( frame_context.device_pixel_scale, &transform, @@ -2062,7 +2064,7 @@ impl PrimitiveStore { continue; } - let local_clips = frame_state.clip_store.get(clip_item.clip_sources_index); + let local_clips = &frame_state.clip_store[clip_item.clip_sources_index]; rect_clips_only = rect_clips_only && local_clips.only_rectangular_clips; // TODO(gw): We can easily extend the segment builder to support these clip sources in @@ -2289,7 +2291,7 @@ impl PrimitiveStore { let extra_clip = { let metadata = &self.cpu_metadata[prim_index.0]; metadata.clip_sources_index.map(|clip_sources_index| { - let prim_clips = frame_state.clip_store.get_mut(clip_sources_index); + let prim_clips = &mut frame_state.clip_store[clip_sources_index]; prim_clips.update( frame_state.gpu_cache, frame_state.resource_cache, @@ -2964,8 +2966,8 @@ fn get_local_clip_rect_for_nodes( }) } ) - .and_then(|local_rect| { - scroll_node.coordinate_system_relative_transform.unapply(&local_rect) + .map(|local_rect| { + local_rect.translate(&-scroll_node.coordinate_system_relative_offset) }) } diff --git a/gfx/webrender/src/render_task.rs b/gfx/webrender/src/render_task.rs index 631baed66bfd..37ad045416a3 100644 --- a/gfx/webrender/src/render_task.rs +++ b/gfx/webrender/src/render_task.rs @@ -403,7 +403,7 @@ impl RenderTask { // whether a ClipSources contains any box-shadows and skip // this iteration for the majority of cases. for clip_item in &clips { - let clip_sources = clip_store.get_mut(clip_item.clip_sources_index); + let clip_sources = &mut clip_store[clip_item.clip_sources_index]; for &mut (ref mut clip, _) in &mut clip_sources.clips { match *clip { ClipSource::BoxShadow(ref mut info) => { diff --git a/gfx/webrender/src/renderer.rs b/gfx/webrender/src/renderer.rs index f5969f6cf96b..72e16648f44a 100644 --- a/gfx/webrender/src/renderer.rs +++ b/gfx/webrender/src/renderer.rs @@ -1767,7 +1767,8 @@ impl Renderer { } })?; - let gpu_profile = GpuProfiler::new(Rc::clone(device.rc_gl())); + let ext_debug_marker = device.supports_extension("GL_EXT_debug_marker"); + let gpu_profile = GpuProfiler::new(Rc::clone(device.rc_gl()), ext_debug_marker); #[cfg(feature = "capture")] let read_fbo = device.create_fbo_for_external_texture(0); diff --git a/gfx/webrender/src/spatial_node.rs b/gfx/webrender/src/spatial_node.rs index b544f36609f2..31da4e481f82 100644 --- a/gfx/webrender/src/spatial_node.rs +++ b/gfx/webrender/src/spatial_node.rs @@ -8,9 +8,9 @@ use api::{LayoutVector2D, PipelineId, PropertyBinding, ScrollClamping, ScrollLoc use api::{ScrollSensitivity, StickyOffsetBounds}; use clip_scroll_tree::{CoordinateSystemId, SpatialNodeIndex, TransformUpdateState}; use euclid::SideOffsets2D; -use gpu_types::{TransformData, TransformPalette}; +use gpu_types::TransformPalette; use scene::SceneProperties; -use util::{LayoutFastTransform, LayoutToWorldFastTransform, TransformedRectKind}; +use util::{LayoutFastTransform, LayoutToWorldFastTransform, MatrixHelpers, TransformedRectKind}; #[derive(Clone, Debug)] pub enum SpatialNodeType { @@ -66,7 +66,7 @@ pub struct SpatialNode { /// The transformation from the coordinate system which established our compatible coordinate /// system (same coordinate system id) and us. This can change via scroll offsets and via new /// reference frame transforms. - pub coordinate_system_relative_transform: LayoutFastTransform, + pub coordinate_system_relative_offset: LayoutVector2D, } impl SpatialNode { @@ -85,7 +85,7 @@ impl SpatialNode { node_type, invertible: true, coordinate_system_id: CoordinateSystemId(0), - coordinate_system_relative_transform: LayoutFastTransform::identity(), + coordinate_system_relative_offset: LayoutVector2D::zero(), } } @@ -204,25 +204,11 @@ impl SpatialNode { node_index: SpatialNodeIndex, ) { if !self.invertible { - transform_palette.set(node_index, TransformData::invalid()); + transform_palette.invalidate(node_index); return; } - let inv_transform = match self.world_content_transform.inverse() { - Some(inverted) => inverted.to_transform(), - None => { - transform_palette.set(node_index, TransformData::invalid()); - return; - } - }; - - let data = TransformData { - transform: self.world_content_transform.into(), - inv_transform, - }; - - // Write the data that will be made available to the GPU for this node. - transform_palette.set(node_index, data); + transform_palette.set(node_index, &self.world_content_transform); } pub fn update( @@ -239,12 +225,7 @@ impl SpatialNode { } self.update_transform(state, next_coordinate_system_id, scene_properties); - - self.transform_kind = if self.world_content_transform.preserves_2d_axis_alignment() { - TransformedRectKind::AxisAligned - } else { - TransformedRectKind::Complex - }; + self.transform_kind = self.world_content_transform.kind(); // If this node is a reference frame, we check if it has a non-invertible matrix. // For non-reference-frames we assume that they will produce only additional @@ -292,13 +273,16 @@ impl SpatialNode { // Try to update our compatible coordinate system transform. If we cannot, start a new // incompatible coordinate system. - match state.coordinate_system_relative_transform.update(relative_transform) { - Some(offset) => self.coordinate_system_relative_transform = offset, - None => { - self.coordinate_system_relative_transform = LayoutFastTransform::identity(); - state.current_coordinate_system_id = *next_coordinate_system_id; - next_coordinate_system_id.advance(); - } + if relative_transform.is_simple_2d_translation() { + self.coordinate_system_relative_offset = + state.coordinate_system_relative_offset + + LayoutVector2D::new(relative_transform.m41, relative_transform.m42); + } else { + // If we break 2D axis alignment or have a perspective component, we need to start a + // new incompatible coordinate system with which we cannot share clips without masking. + self.coordinate_system_relative_offset = LayoutVector2D::zero(); + state.current_coordinate_system_id = *next_coordinate_system_id; + next_coordinate_system_id.advance(); } self.coordinate_system_id = state.current_coordinate_system_id; @@ -330,8 +314,8 @@ impl SpatialNode { }; let added_offset = state.parent_accumulated_scroll_offset + sticky_offset + scroll_offset; - self.coordinate_system_relative_transform = - state.coordinate_system_relative_transform.offset(added_offset); + self.coordinate_system_relative_offset = + state.coordinate_system_relative_offset + added_offset; if let SpatialNodeType::StickyFrame(ref mut info) = self.node_type { info.current_offset = sticky_offset; @@ -478,8 +462,7 @@ impl SpatialNode { SpatialNodeType::ReferenceFrame(ref info) => { state.parent_reference_frame_transform = self.world_viewport_transform; state.parent_accumulated_scroll_offset = LayoutVector2D::zero(); - state.coordinate_system_relative_transform = - self.coordinate_system_relative_transform.clone(); + state.coordinate_system_relative_offset = self.coordinate_system_relative_offset; let translation = -info.origin_in_parent_reference_frame; state.nearest_scrolling_ancestor_viewport = state.nearest_scrolling_ancestor_viewport diff --git a/gfx/webrender/src/util.rs b/gfx/webrender/src/util.rs index a59bb3e486d6..1e308bc3de8b 100644 --- a/gfx/webrender/src/util.rs +++ b/gfx/webrender/src/util.rs @@ -11,6 +11,8 @@ use euclid::{HomogeneousVector}; use num_traits::Zero; use plane_split::{Clipper, Plane, Polygon}; use std::{i32, f32}; +use std::borrow::Cow; + // Matches the definition of SK_ScalarNearlyZero in Skia. const NEARLY_ZERO: f32 = 1.0 / 4096.0; @@ -486,11 +488,20 @@ impl FastTransform { FastTransform::Transform { transform, inverse, is_2d} } - pub fn to_transform(&self) -> TypedTransform3D { + pub fn kind(&self) -> TransformedRectKind { match *self { - FastTransform::Offset(offset) => - TypedTransform3D::create_translation(offset.x, offset.y, 0.0), - FastTransform::Transform { transform, .. } => transform + FastTransform::Offset(_) => TransformedRectKind::AxisAligned, + FastTransform::Transform { ref transform, .. } if transform.preserves_2d_axis_alignment() => TransformedRectKind::AxisAligned, + FastTransform::Transform { .. } => TransformedRectKind::Complex, + } + } + + pub fn to_transform(&self) -> Cow> { + match *self { + FastTransform::Offset(offset) => Cow::Owned( + TypedTransform3D::create_translation(offset.x, offset.y, 0.0) + ), + FastTransform::Transform { ref transform, .. } => Cow::Borrowed(transform), } } @@ -528,15 +539,6 @@ impl FastTransform { } } - #[inline(always)] - pub fn preserves_2d_axis_alignment(&self) -> bool { - match *self { - FastTransform::Offset(..) => true, - FastTransform::Transform { ref transform, .. } => - transform.preserves_2d_axis_alignment(), - } - } - #[inline(always)] pub fn has_perspective_component(&self) -> bool { match *self { @@ -596,17 +598,6 @@ impl FastTransform { } } - #[inline(always)] - pub fn offset(&self, new_offset: TypedVector2D) -> Self { - match *self { - FastTransform::Offset(offset) => FastTransform::Offset(offset + new_offset), - FastTransform::Transform { ref transform, .. } => { - let transform = transform.pre_translate(new_offset.to_3d()); - FastTransform::with_transform(transform) - } - } - } - pub fn post_translate(&self, new_offset: TypedVector2D) -> Self { match *self { FastTransform::Offset(offset) => { @@ -635,16 +626,6 @@ impl FastTransform { } } - - pub fn update(&self, transform: TypedTransform3D) -> Option { - if transform.is_simple_2d_translation() { - Some(self.offset(TypedVector2D::new(transform.m41, transform.m42))) - } else { - // If we break 2D axis alignment or have a perspective component, we need to start a - // new incompatible coordinate system with which we cannot share clips without masking. - None - } - } } impl From> for FastTransform { @@ -653,12 +634,6 @@ impl From> for FastTransform } } -impl Into> for FastTransform { - fn into(self) -> TypedTransform3D { - self.to_transform() - } -} - impl From> for FastTransform { fn from(vector: TypedVector2D) -> Self { FastTransform::with_vector(vector) diff --git a/gfx/webrender_api/Cargo.toml b/gfx/webrender_api/Cargo.toml index baebc3a48c43..ca8911ec78e2 100644 --- a/gfx/webrender_api/Cargo.toml +++ b/gfx/webrender_api/Cargo.toml @@ -12,12 +12,12 @@ serialize = [] deserialize = [] [dependencies] -app_units = "0.6" +app_units = "0.7" bincode = "1.0" bitflags = "1.0" byteorder = "1.2.1" ipc-channel = {version = "0.10.0", optional = true} -euclid = { version = "0.18", features = ["serde"] } +euclid = { version = "0.19", features = ["serde"] } serde = { version = "=1.0.66", features = ["rc"] } serde_derive = { version = "=1.0.66", features = ["deserialize_in_place"] } serde_bytes = "0.10" diff --git a/gfx/webrender_api/src/display_list.rs b/gfx/webrender_api/src/display_list.rs index 806286beed9d..27f6469fca4c 100644 --- a/gfx/webrender_api/src/display_list.rs +++ b/gfx/webrender_api/src/display_list.rs @@ -123,7 +123,7 @@ pub struct AuxIter<'a, T> { impl BuiltDisplayListDescriptor {} impl BuiltDisplayList { - pub fn from_data(data: Vec, descriptor: BuiltDisplayListDescriptor) -> BuiltDisplayList { + pub fn from_data(data: Vec, descriptor: BuiltDisplayListDescriptor) -> Self { BuiltDisplayList { data, descriptor } } diff --git a/gfx/webrender_bindings/Cargo.toml b/gfx/webrender_bindings/Cargo.toml index 3894fe8d2e2f..61d9f9d9f293 100644 --- a/gfx/webrender_bindings/Cargo.toml +++ b/gfx/webrender_bindings/Cargo.toml @@ -7,8 +7,8 @@ license = "MPL-2.0" [dependencies] rayon = "1" thread_profiler = "0.1.1" -euclid = { version = "0.18", features = ["serde"] } -app_units = "0.6" +euclid = { version = "0.19", features = ["serde"] } +app_units = "0.7" gleam = "0.6" log = "0.4" nsstring = { path = "../../servo/support/gecko/nsstring" } diff --git a/gfx/webrender_bindings/revision.txt b/gfx/webrender_bindings/revision.txt index 4e8cc14cd219..d589586878d8 100644 --- a/gfx/webrender_bindings/revision.txt +++ b/gfx/webrender_bindings/revision.txt @@ -1 +1 @@ -8a4fe66528aa362721e4048aac3cd5abf7faaf2c +7a1b919e37d6cd0155077aa90f98cfcdf9fa5bae diff --git a/gfx/wrench/Cargo.toml b/gfx/wrench/Cargo.toml index a908ed50d5d3..789884222d1a 100644 --- a/gfx/wrench/Cargo.toml +++ b/gfx/wrench/Cargo.toml @@ -10,10 +10,10 @@ base64 = "0.6" bincode = "1.0" byteorder = "1.0" env_logger = { version = "0.5", optional = true } -euclid = "0.18" +euclid = "0.19" gleam = "0.6" glutin = "0.17" -app_units = "0.6" +app_units = "0.7" image = "0.19" clap = { version = "2", features = ["yaml"] } lazy_static = "1"