Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions webrender/res/cs_clip_border.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

#include shared,clip_shared

in vec4 aDashOrDot0;
in vec4 aDashOrDot1;

varying vec3 vPos;

flat varying vec2 vClipCenter;
Expand Down Expand Up @@ -46,19 +49,17 @@ 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.
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) {
Expand Down Expand Up @@ -98,15 +99,15 @@ 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);
vAlphaMask = vec2(0.0, 1.0);
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);
Expand Down
37 changes: 24 additions & 13 deletions webrender/src/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -1645,8 +1646,8 @@ pub struct ClipBatcher {
pub rectangles: Vec<ClipMaskInstance>,
/// Image draws apply the image masking.
pub images: FastHashMap<SourceTexture, Vec<ClipMaskInstance>>,
pub border_clears: Vec<ClipMaskInstance>,
pub borders: Vec<ClipMaskInstance>,
pub border_clears: Vec<ClipMaskBorderCornerDotDash>,
pub borders: Vec<ClipMaskBorderCornerDotDash>,
pub box_shadows: FastHashMap<SourceTexture, Vec<ClipMaskInstance>>,
pub line_decorations: Vec<ClipMaskInstance>,
}
Expand Down Expand Up @@ -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,
})
}
}
Expand Down
139 changes: 38 additions & 101 deletions webrender/src/border.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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,
Expand Down
10 changes: 10 additions & 0 deletions webrender/src/gpu_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand Down
Loading