Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for clip in/out. #1015

Merged
merged 2 commits into from Mar 29, 2017
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

Add support for clip in/out.

This is not a super-efficient implementation, but it adds the
functionality required for box shadows that have border radii.

Once this is in place, we can do some follow up optimization passes.

Fixes #189.
  • Loading branch information
gw3583 committed Mar 28, 2017
commit 85c87777e7010790d4365790be5e7c1b5197ac79
@@ -40,5 +40,10 @@ void main(void) {

float clip_alpha = rounded_rect(local_pos);

oFragColor = vec4(min(alpha, clip_alpha), 0.0, 0.0, 1.0);
float combined_alpha = min(alpha, clip_alpha);

// Select alpha or inverse alpha depending on clip in/out.
float final_alpha = mix(combined_alpha, 1.0 - combined_alpha, vClipMode);

oFragColor = vec4(final_alpha, 0.0, 0.0, 1.0);
}
@@ -8,3 +8,4 @@ varying vec3 vPos;
flat varying vec4 vLocalRect;
flat varying vec4 vClipRect;
flat varying vec4 vClipRadius;
flat varying float vClipMode;
@@ -5,7 +5,7 @@

struct ClipRect {
vec4 rect;
vec4 dummy;
vec4 mode;
};

ClipRect fetch_clip_rect(int index) {
@@ -14,8 +14,7 @@ ClipRect fetch_clip_rect(int index) {
ivec2 uv = get_fetch_uv_2(index);

rect.rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
//rect.dummy = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));

This comment has been minimized.

@Hywan

Hywan Apr 6, 2017

Why keeping this comment?

rect.dummy = vec4(0.0, 0.0, 0.0, 0.0);
rect.mode = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));

return rect;
}
@@ -70,6 +69,7 @@ void main(void) {
vLocalRect = vi.clipped_local_rect;
vPos = vi.local_pos;

vClipMode = clip.rect.mode.x;
vClipRect = vec4(local_rect.xy, local_rect.xy + local_rect.zw);
vClipRadius = vec4(clip.top_left.outer_inner_radius.x,
clip.top_right.outer_inner_radius.x,
@@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

void main(void) {
vec4 clip_scale = vec4(1.0, 1.0, 1.0, do_clip());

// Mirror and stretch the box shadow corner over the entire
// primitives.
vec2 uv = vMirrorPoint - abs(vUv.xy - vMirrorPoint);
@@ -16,5 +18,5 @@ void main(void) {
uv = mix(vCacheUvRectCoords.xy, vCacheUvRectCoords.zw, uv);

// Modulate the box shadow by the color.
oFragColor = dither(vColor * texture(sCacheRGBA8, vec3(uv, vUv.z)));
oFragColor = clip_scale * dither(vColor * texture(sCacheRGBA8, vec3(uv, vUv.z)));
}
@@ -29,4 +29,6 @@ void main(void) {
vCacheUvRectCoords = vec4(patch_origin, patch_origin + patch_size_device_pixels) / texture_size.xyxy;

vColor = bs.color;

write_clip(vi.screen_pos, prim.clip_area);
}
@@ -24,7 +24,7 @@ const CAN_OVERSCROLL: bool = false;
#[derive(Clone, Debug)]
pub struct ClipInfo {
/// The ClipSource for this node, which is used to generate mask_cache_info.
pub clip_source: ClipSource,
pub clip_sources: Vec<ClipSource>,

/// The MaskCacheInfo for this node, which is produced by processing the
/// provided ClipSource.
@@ -47,10 +47,10 @@ impl ClipInfo {
-> ClipInfo {
// We pass true here for the MaskCacheInfo because this type of
// mask needs an extra clip for the clip rectangle.
let clip_source = ClipSource::Region(clip_region.clone());
let clip_sources = vec![ClipSource::Region(clip_region.clone(), true)];
ClipInfo {
mask_cache_info: MaskCacheInfo::new(&clip_source, true, clip_store),
clip_source: clip_source,
mask_cache_info: MaskCacheInfo::new(&clip_sources, clip_store),
clip_sources: clip_sources,
packed_layer_index: packed_layer_index,
xf_rect: None,
}
@@ -7,7 +7,7 @@ use batch_builder::BorderSideHelpers;
use frame::FrameId;
use gpu_store::GpuStoreAddress;
use internal_types::{HardwareCompositeOp, SourceTexture};
use mask_cache::{ClipSource, MaskCacheInfo};
use mask_cache::{ClipMode, ClipSource, MaskCacheInfo};
use prim_store::{BorderPrimitiveCpu, BorderPrimitiveGpu, BoxShadowPrimitiveGpu};
use prim_store::{GradientPrimitiveCpu, GradientPrimitiveGpu, ImagePrimitiveCpu, ImagePrimitiveGpu};
use prim_store::{ImagePrimitiveKind, PrimitiveContainer, PrimitiveGeometry, PrimitiveIndex};
@@ -148,6 +148,7 @@ impl FrameBuilder {
scroll_layer_id: ScrollLayerId,
rect: &LayerRect,
clip_region: &ClipRegion,
extra_clip: Option<ClipSource>,
container: PrimitiveContainer)
-> PrimitiveIndex {
let stacking_context_index = *self.stacking_context_stack.last().unwrap();
@@ -163,17 +164,21 @@ impl FrameBuilder {
local_rect: *rect,
local_clip_rect: clip_region.main,
};
let clip_source = if clip_region.is_complex() {
ClipSource::Region(clip_region.clone())
} else {
ClipSource::NoClip
};
let clip_info = MaskCacheInfo::new(&clip_source,
false,
let mut clip_sources = Vec::new();
if clip_region.is_complex() {
clip_sources.push(ClipSource::Region(clip_region.clone(), false));
}
// TODO(gw): Perhaps in the future it's worth passing in an array
// so that callers can provide an arbitrary number
// of clips?
if let Some(extra_clip) = extra_clip {
clip_sources.push(extra_clip);
}
let clip_info = MaskCacheInfo::new(&clip_sources,
&mut self.prim_store.gpu_data32);

let prim_index = self.prim_store.add_primitive(geometry,
Box::new(clip_source),
clip_sources,
clip_info,
container);

@@ -353,6 +358,7 @@ impl FrameBuilder {
let prim_index = self.add_primitive(scroll_layer_id,
rect,
clip_region,
None,
PrimitiveContainer::Rectangle(prim));

match flags {
@@ -651,6 +657,7 @@ impl FrameBuilder {
self.add_primitive(scroll_layer_id,
&rect,
clip_region,
None,
PrimitiveContainer::Border(prim_cpu, prim_gpu));
}
BorderDetails::Gradient(ref border) => {
@@ -732,7 +739,11 @@ impl FrameBuilder {
PrimitiveContainer::AngleGradient(gradient_cpu, gradient_gpu)
};

self.add_primitive(scroll_layer_id, &rect, clip_region, prim);
self.add_primitive(scroll_layer_id,
&rect,
clip_region,
None,
prim);
}

pub fn add_radial_gradient(&mut self,
@@ -763,6 +774,7 @@ impl FrameBuilder {
self.add_primitive(scroll_layer_id,
&rect,
clip_region,
None,
PrimitiveContainer::RadialGradient(radial_gradient_cpu, radial_gradient_gpu));
}

@@ -832,6 +844,7 @@ impl FrameBuilder {
self.add_primitive(scroll_layer_id,
&rect,
clip_region,
None,
PrimitiveContainer::TextRun(prim_cpu, prim_gpu));
}
}
@@ -888,12 +901,18 @@ impl FrameBuilder {

let shadow_kind = match clip_mode {
BoxShadowClipMode::Outset | BoxShadowClipMode::None => {
// If a border radius is set, we need to draw inside
// the original box in order to draw where the border
// corners are. A clip-out mask applied below will
// ensure that we don't draw on the box itself.
let inner_box_bounds = box_bounds.inflate(-border_radius,
-border_radius);
// For outset shadows, subtracting the element rectangle
// from the outer rectangle gives the rectangles we need
// to draw. In the simple case (no blur radius), we can
// just draw these as solid colors.
let mut rects = Vec::new();
subtract_rect(&outer_rect, box_bounds, &mut rects);
subtract_rect(&outer_rect, &inner_box_bounds, &mut rects);
if edge_size == 0.0 {
BoxShadowKind::Simple(rects)
} else {
@@ -942,6 +961,15 @@ impl FrameBuilder {
BoxShadowClipMode::Inset => 1.0,
};

// If we have a border radius, we'll need to apply
// a clip-out mask.
let extra_clip = if border_radius > 0.0 {
Some(ClipSource::Complex(*box_bounds,
border_radius,
ClipMode::ClipOut))
} else {
None
};

let prim_gpu = BoxShadowPrimitiveGpu {
src_rect: *box_bounds,
@@ -956,6 +984,7 @@ impl FrameBuilder {
self.add_primitive(scroll_layer_id,
&outer_rect,
clip_region,
extra_clip,
PrimitiveContainer::BoxShadow(prim_gpu, rects));
}
}
@@ -981,6 +1010,7 @@ impl FrameBuilder {
self.add_primitive(scroll_layer_id,
&rect,
clip_region,
None,
PrimitiveContainer::Image(prim_cpu, prim_gpu));
}

@@ -1012,6 +1042,7 @@ impl FrameBuilder {
self.add_primitive(scroll_layer_id,
&rect,
clip_region,
None,
PrimitiveContainer::Image(prim_cpu, prim_gpu));
}

@@ -1035,6 +1066,7 @@ impl FrameBuilder {
self.add_primitive(scroll_layer_id,
&rect,
clip_region,
None,
PrimitiveContainer::YuvImage(prim_cpu, prim_gpu));
}

@@ -1092,10 +1124,10 @@ impl FrameBuilder {
geom.local_rect.origin.y = util::lerp(min_y, max_y, f);
geom.local_clip_rect = geom.local_rect;

let clip_source = if scrollbar_prim.border_radius == 0.0 {
ClipSource::NoClip
let clip_source = if scrollbar_prim.border_radius > 0.0 {
Some(ClipSource::Complex(geom.local_rect, scrollbar_prim.border_radius, ClipMode::Clip))
} else {
ClipSource::Complex(geom.local_rect, scrollbar_prim.border_radius)
None
};
self.prim_store.set_clip_source(scrollbar_prim.prim_index, clip_source);
*self.prim_store.gpu_geometry.get_mut(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32)) = geom;
@@ -1457,16 +1489,18 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> {
let auxiliary_lists = self.auxiliary_lists_map.get(&node.pipeline_id)
.expect("No auxiliary lists?");

mask_info.update(&node_clip_info.clip_source,
mask_info.update(&node_clip_info.clip_sources,
&packed_layer.transform,
&mut self.frame_builder.prim_store.gpu_data32,
self.device_pixel_ratio,
auxiliary_lists);

if let Some(mask) = node_clip_info.clip_source.image_mask() {
// We don't add the image mask for resolution, because
// layer masks are resolved later.
self.resource_cache.request_image(mask.image, ImageRendering::Auto, None);
for clip_source in &node_clip_info.clip_sources {
if let Some(mask) = clip_source.image_mask() {
// We don't add the image mask for resolution, because
// layer masks are resolved later.
self.resource_cache.request_image(mask.image, ImageRendering::Auto, None);
}
}
}
}
@@ -20,6 +20,14 @@ impl Add<i32> for GpuStoreAddress {
}
}

impl Add<usize> for GpuStoreAddress {
type Output = GpuStoreAddress;

fn add(self, other: usize) -> GpuStoreAddress {
GpuStoreAddress(self.0 + other as i32)
}
}

pub trait GpuStoreLayout {
fn image_format() -> ImageFormat;

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.