diff --git a/webrender/res/cs_clip_border.glsl b/webrender/res/cs_clip_border.glsl index 8358871f26..33ec855d9e 100644 --- a/webrender/res/cs_clip_border.glsl +++ b/webrender/res/cs_clip_border.glsl @@ -4,6 +4,9 @@ #include shared,clip_shared +in vec4 aDashOrDot0; +in vec4 aDashOrDot1; + varying vec3 vPos; flat varying vec2 vClipCenter; @@ -46,9 +49,8 @@ struct BorderClipDash { vec4 point_tangent_1; }; -BorderClipDash fetch_border_clip_dash(ivec2 address, int segment) { - vec4 data[2] = fetch_from_resource_cache_2_direct(address + ivec2(2 + 2 * (segment - 1), 0)); - return BorderClipDash(data[0], data[1]); +BorderClipDash fetch_border_clip_dash(ivec2 address) { + return BorderClipDash(aDashOrDot0, aDashOrDot1); } // Per-dot clip information. @@ -56,9 +58,8 @@ struct BorderClipDot { vec3 center_radius; }; -BorderClipDot fetch_border_clip_dot(ivec2 address, int segment) { - vec4 data = fetch_from_resource_cache_1_direct(address + ivec2(2 + (segment - 1), 0)); - return BorderClipDot(data.xyz); +BorderClipDot fetch_border_clip_dot(ivec2 address) { + return BorderClipDot(aDashOrDot0.xyz); } void main(void) { @@ -98,7 +99,7 @@ void main(void) { switch (corner.clip_mode) { case CLIP_MODE_DASH: { // Fetch the information about this particular dash. - BorderClipDash dash = fetch_border_clip_dash(cmi.clip_data_address, cmi.segment); + BorderClipDash dash = fetch_border_clip_dash(cmi.clip_data_address); vPoint_Tangent0 = dash.point_tangent_0 * sign_modifier.xyxy; vPoint_Tangent1 = dash.point_tangent_1 * sign_modifier.xyxy; vDotParams = vec3(0.0); @@ -106,7 +107,7 @@ void main(void) { break; } case CLIP_MODE_DOT: { - BorderClipDot cdot = fetch_border_clip_dot(cmi.clip_data_address, cmi.segment); + BorderClipDot cdot = fetch_border_clip_dot(cmi.clip_data_address); vPoint_Tangent0 = vec4(1.0); vPoint_Tangent1 = vec4(1.0); vDotParams = vec3(cdot.center_radius.xy * sign_modifier, cdot.center_radius.z); diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index b32811baf7..5b53a6f712 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -12,9 +12,10 @@ use clip_scroll_tree::{CoordinateSystemId}; use euclid::{TypedTransform3D, vec3}; use glyph_rasterizer::GlyphFormat; use gpu_cache::{GpuCache, GpuCacheAddress}; -use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex, ZBufferId, ZBufferIdGenerator}; -use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, RasterizationSpace}; -use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance}; +use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex, ClipMaskBorderCornerDotDash}; +use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, CompositePrimitiveInstance}; +use gpu_types::{PrimitiveInstance, RasterizationSpace, SimplePrimitiveInstance, ZBufferId}; +use gpu_types::ZBufferIdGenerator; use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface}; use picture::{IMAGE_BRUSH_BLOCKS, IMAGE_BRUSH_EXTRA_BLOCKS}; @@ -1645,8 +1646,8 @@ pub struct ClipBatcher { pub rectangles: Vec, /// Image draws apply the image masking. pub images: FastHashMap>, - pub border_clears: Vec, - pub borders: Vec, + pub border_clears: Vec, + pub borders: Vec, pub box_shadows: FastHashMap>, pub line_decorations: Vec, } @@ -1770,16 +1771,26 @@ impl ClipBatcher { }); } ClipSource::BorderCorner(ref source) => { - self.border_clears.push(ClipMaskInstance { - clip_data_address: gpu_address, - segment: 0, - ..instance - }); - for clip_index in 0 .. source.actual_clip_count { - self.borders.push(ClipMaskInstance { + let instance = ClipMaskBorderCornerDotDash { + clip_mask_instance: ClipMaskInstance { clip_data_address: gpu_address, - segment: 1 + clip_index as i32, + segment: 0, ..instance + }, + dot_dash_data: [0.; 8], + }; + + self.border_clears.push(instance); + + for data in source.dot_dash_data.iter() { + self.borders.push(ClipMaskBorderCornerDotDash { + clip_mask_instance: ClipMaskInstance { + // The shader understands segment=0 as the clear, so the + // segment here just needs to be non-zero. + segment: 1, + ..instance.clip_mask_instance + }, + dot_dash_data: *data, }) } } diff --git a/webrender/src/border.rs b/webrender/src/border.rs index 789c150925..e5de20b941 100644 --- a/webrender/src/border.rs +++ b/webrender/src/border.rs @@ -677,10 +677,10 @@ pub enum BorderCornerClipKind { pub struct BorderCornerClipSource { pub corner_data: BorderCornerClipData, pub max_clip_count: usize, - pub actual_clip_count: usize, kind: BorderCornerClipKind, widths: LayoutSize, ellipse: Ellipse, + pub dot_dash_data: Vec<[f32; 8]>, } impl BorderCornerClipSource { @@ -753,45 +753,49 @@ impl BorderCornerClipSource { kind, corner_data, max_clip_count, - actual_clip_count: 0, ellipse, widths, + dot_dash_data: Vec::new(), } } pub fn write(&mut self, mut request: GpuDataRequest) { self.corner_data.write(&mut request); + assert_eq!(request.close(), 2); match self.kind { BorderCornerClipKind::Dash => { // Get the correct dash arc length. - self.actual_clip_count = self.max_clip_count; let dash_arc_length = - 0.5 * self.ellipse.total_arc_length / (self.actual_clip_count - 1) as f32; + 0.5 * self.ellipse.total_arc_length / (self.max_clip_count - 1) as f32; + self.dot_dash_data.clear(); let mut current_arc_length = -0.5 * dash_arc_length; - for _ in 0 .. self.actual_clip_count { + for _ in 0 .. self.max_clip_count { let arc_length0 = current_arc_length; current_arc_length += dash_arc_length; let arc_length1 = current_arc_length; current_arc_length += dash_arc_length; - let dash_data = - BorderCornerDashClipData::new(arc_length0, arc_length1, &self.ellipse); - dash_data.write(&mut request); - } + let alpha = self.ellipse.find_angle_for_arc_length(arc_length0); + let beta = self.ellipse.find_angle_for_arc_length(arc_length1); + + let (point0, tangent0) = self.ellipse.get_point_and_tangent(alpha); + let (point1, tangent1) = self.ellipse.get_point_and_tangent(beta); - assert_eq!(request.close(), 2 + 2 * self.actual_clip_count); + self.dot_dash_data.push([ + point0.x, point0.y, tangent0.x, tangent0.y, + point1.x, point1.y, tangent1.x, tangent1.y + ]); + } } BorderCornerClipKind::Dot if self.max_clip_count == 1 => { let dot_diameter = lerp(self.widths.width, self.widths.height, 0.5); - let dot = BorderCornerDotClipData { - center: LayoutPoint::new(self.widths.width / 2.0, self.widths.height / 2.0), - radius: 0.5 * dot_diameter, - }; - self.actual_clip_count = 1; - dot.write(&mut request); - assert_eq!(request.close(), 3); + self.dot_dash_data.clear(); + self.dot_dash_data.push([ + self.widths.width / 2.0, self.widths.height / 2.0, 0.5 * dot_diameter, 0., + 0., 0., 0., 0., + ]); } BorderCornerClipKind::Dot => { let mut forward_dots = Vec::new(); @@ -852,30 +856,31 @@ impl BorderCornerClipSource { // leftover space on the arc between them evenly. Once // the final arc position is determined, generate the correct // arc positions and angles that get passed to the clip shader. - self.actual_clip_count = forward_dots.len() + back_dots.len(); - let extra_space_per_dot = leftover_arc_length / (self.actual_clip_count - 1) as f32; + let number_of_dots = forward_dots.len() + back_dots.len(); + let extra_space_per_dot = leftover_arc_length / (number_of_dots - 1) as f32; + + self.dot_dash_data.clear(); + + let create_dot_data = |ellipse: &Ellipse, arc_length: f32, radius: f32| -> [f32; 8] { + // Represents the GPU data for drawing a single dot to a clip mask. The order + // these are specified must stay in sync with the way this data is read in the + // dot clip shader. + let theta = ellipse.find_angle_for_arc_length(arc_length); + let (center, _) = ellipse.get_point_and_tangent(theta); + [center.x, center.y, radius, 0., 0., 0., 0., 0.,] + }; for (i, dot) in forward_dots.iter().enumerate() { let extra_dist = i as f32 * extra_space_per_dot; - let dot = BorderCornerDotClipData::new( - dot.arc_pos + extra_dist, - 0.5 * dot.diameter, - &self.ellipse, - ); - dot.write(&mut request); + let dot_data = create_dot_data(&self.ellipse, dot.arc_pos + extra_dist, 0.5 * dot.diameter); + self.dot_dash_data.push(dot_data); } for (i, dot) in back_dots.iter().enumerate() { let extra_dist = i as f32 * extra_space_per_dot; - let dot = BorderCornerDotClipData::new( - dot.arc_pos - extra_dist, - 0.5 * dot.diameter, - &self.ellipse, - ); - dot.write(&mut request); + let dot_data = create_dot_data(&self.ellipse, dot.arc_pos - extra_dist, 0.5 * dot.diameter); + self.dot_dash_data.push(dot_data); } - - assert_eq!(request.close(), 2 + self.actual_clip_count); } } } @@ -910,74 +915,6 @@ impl BorderCornerClipData { } } -/// Represents the GPU data for drawing a single dash -/// to a clip mask. A dash clip is defined by two lines. -/// We store a point on the ellipse curve, and a tangent -/// to that point, which allows for efficient line-distance -/// calculations in the fragment shader. -#[derive(Debug, Clone)] -#[repr(C)] -pub struct BorderCornerDashClipData { - pub point0: LayoutPoint, - pub tangent0: LayoutPoint, - pub point1: LayoutPoint, - pub tangent1: LayoutPoint, -} - -impl BorderCornerDashClipData { - pub fn new(arc_length0: f32, arc_length1: f32, ellipse: &Ellipse) -> BorderCornerDashClipData { - let alpha = ellipse.find_angle_for_arc_length(arc_length0); - let beta = ellipse.find_angle_for_arc_length(arc_length1); - - let (p0, t0) = ellipse.get_point_and_tangent(alpha); - let (p1, t1) = ellipse.get_point_and_tangent(beta); - - BorderCornerDashClipData { - point0: p0, - tangent0: t0, - point1: p1, - tangent1: t1, - } - } - - fn write(&self, request: &mut GpuDataRequest) { - request.push([ - self.point0.x, - self.point0.y, - self.tangent0.x, - self.tangent0.y, - ]); - request.push([ - self.point1.x, - self.point1.y, - self.tangent1.x, - self.tangent1.y, - ]); - } -} - -/// Represents the GPU data for drawing a single dot -/// to a clip mask. -#[derive(Debug, Clone)] -#[repr(C)] -pub struct BorderCornerDotClipData { - pub center: LayoutPoint, - pub radius: f32, -} - -impl BorderCornerDotClipData { - pub fn new(arc_length: f32, radius: f32, ellipse: &Ellipse) -> BorderCornerDotClipData { - let theta = ellipse.find_angle_for_arc_length(arc_length); - let (center, _) = ellipse.get_point_and_tangent(theta); - - BorderCornerDotClipData { center, radius } - } - - fn write(&self, request: &mut GpuDataRequest) { - request.push([self.center.x, self.center.y, self.radius, 0.0]); - } -} - #[derive(Copy, Clone, Debug)] struct DotInfo { arc_pos: f32, diff --git a/webrender/src/gpu_types.rs b/webrender/src/gpu_types.rs index b9a4ea9cdc..5eb15a0956 100644 --- a/webrender/src/gpu_types.rs +++ b/webrender/src/gpu_types.rs @@ -83,6 +83,16 @@ pub struct ClipMaskInstance { pub resource_address: GpuCacheAddress, } +/// A border corner dot or dash drawn into the clipping mask. +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[repr(C)] +pub struct ClipMaskBorderCornerDotDash { + pub clip_mask_instance: ClipMaskInstance, + pub dot_dash_data: [f32; 8], +} + // 32 bytes per instance should be enough for anyone! #[derive(Debug, Clone)] #[cfg_attr(feature = "capture", derive(Serialize))] diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index f8b0a51eb1..7f0efb6154 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -433,6 +433,48 @@ pub(crate) mod desc { ], }; + pub const BORDER_CORNER_DASH_AND_DOT: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[ + VertexAttribute { + name: "aClipRenderTaskAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aScrollNodeId", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aClipSegment", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aClipDataResourceAddress", + count: 4, + kind: VertexAttributeKind::U16, + }, + VertexAttribute { + name: "aDashOrDot0", + count: 4, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aDashOrDot1", + count: 4, + kind: VertexAttributeKind::F32, + }, + ], + }; + pub const GPU_CACHE_UPDATE: VertexDescriptor = VertexDescriptor { vertex_attributes: &[ VertexAttribute { @@ -539,6 +581,7 @@ pub(crate) enum VertexArrayKind { Primitive, Blur, Clip, + DashAndDot, VectorStencil, VectorCover, } @@ -1260,6 +1303,7 @@ pub struct RendererVAOs { prim_vao: VAO, blur_vao: VAO, clip_vao: VAO, + dash_and_dot_vao: VAO, } /// The renderer is responsible for submitting to the GPU the work prepared by the @@ -1546,6 +1590,8 @@ impl Renderer { let blur_vao = device.create_vao_with_new_instances(&desc::BLUR, &prim_vao); let clip_vao = device.create_vao_with_new_instances(&desc::CLIP, &prim_vao); + let dash_and_dot_vao = + device.create_vao_with_new_instances(&desc::BORDER_CORNER_DASH_AND_DOT, &prim_vao); let texture_cache_upload_pbo = device.create_pbo(); let texture_resolver = SourceTextureResolver::new(&mut device); @@ -1698,6 +1744,7 @@ impl Renderer { prim_vao, blur_vao, clip_vao, + dash_and_dot_vao, }, node_data_texture, local_clip_rects_texture, @@ -3065,7 +3112,7 @@ impl Renderer { .bind(&mut self.device, projection, &mut self.renderer_errors); self.draw_instanced_batch( &target.clip_batcher.border_clears, - VertexArrayKind::Clip, + VertexArrayKind::DashAndDot, &BatchTextures::no_texture(), stats, ); @@ -3084,7 +3131,7 @@ impl Renderer { .bind(&mut self.device, projection, &mut self.renderer_errors); self.draw_instanced_batch( &target.clip_batcher.borders, - VertexArrayKind::Clip, + VertexArrayKind::DashAndDot, &BatchTextures::no_texture(), stats, ); @@ -3817,6 +3864,7 @@ impl Renderer { self.device.delete_vao(self.vaos.prim_vao); self.device.delete_vao(self.vaos.clip_vao); self.device.delete_vao(self.vaos.blur_vao); + self.device.delete_vao(self.vaos.dash_and_dot_vao); #[cfg(feature = "debug_renderer")] { @@ -4409,6 +4457,7 @@ fn get_vao<'a>(vertex_array_kind: VertexArrayKind, VertexArrayKind::Primitive => &vaos.prim_vao, VertexArrayKind::Clip => &vaos.clip_vao, VertexArrayKind::Blur => &vaos.blur_vao, + VertexArrayKind::DashAndDot => &vaos.dash_and_dot_vao, VertexArrayKind::VectorStencil => &gpu_glyph_renderer.vector_stencil_vao, VertexArrayKind::VectorCover => &gpu_glyph_renderer.vector_cover_vao, } @@ -4423,6 +4472,7 @@ fn get_vao<'a>(vertex_array_kind: VertexArrayKind, VertexArrayKind::Primitive => &vaos.prim_vao, VertexArrayKind::Clip => &vaos.clip_vao, VertexArrayKind::Blur => &vaos.blur_vao, + VertexArrayKind::DashAndDot => &vaos.dash_and_dot_vao, VertexArrayKind::VectorStencil | VertexArrayKind::VectorCover => unreachable!(), } } diff --git a/webrender/src/shade.rs b/webrender/src/shade.rs index f83d870dfe..1b9eae7ea9 100644 --- a/webrender/src/shade.rs +++ b/webrender/src/shade.rs @@ -400,6 +400,7 @@ fn create_prim_shader( VertexArrayKind::Primitive => desc::PRIM_INSTANCES, VertexArrayKind::Blur => desc::BLUR, VertexArrayKind::Clip => desc::CLIP, + VertexArrayKind::DashAndDot => desc::BORDER_CORNER_DASH_AND_DOT, VertexArrayKind::VectorStencil => desc::VECTOR_STENCIL, VertexArrayKind::VectorCover => desc::VECTOR_COVER, };