Skip to content

Image mask support #445

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

Merged
merged 2 commits into from
Oct 26, 2016
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
33 changes: 23 additions & 10 deletions webrender/res/clip_shared.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@

flat varying vec4 vClipRect;
flat varying vec4 vClipRadius;
flat varying vec4 vClipMaskUvRect;
flat varying vec4 vClipMaskLocalRect;

#ifdef WR_VERTEX_SHADER
void write_clip(Clip clip) {
void write_clip(ClipInfo clip) {
vClipRect = vec4(clip.rect.rect.xy, clip.rect.rect.xy + clip.rect.rect.zw);
vClipRadius = vec4(clip.top_left.outer_inner_radius.x,
clip.top_right.outer_inner_radius.x,
clip.bottom_right.outer_inner_radius.x,
clip.bottom_left.outer_inner_radius.x);
//TODO: interpolate the final mask UV
vClipMaskUvRect = clip.mask_info.uv_rect;
vClipMaskLocalRect = clip.mask_info.local_rect; //TODO: transform
}
#endif

Expand All @@ -29,23 +34,31 @@ float do_clip(vec2 pos) {
float d_bl = distance(pos, ref_bl);

float pixels_per_fragment = length(fwidth(pos.xy));
// TODO: compute the `nudge` separately for X and Y
float nudge = 0.5 * pixels_per_fragment;
vec4 distances = vec4(d_tl, d_tr, d_br, d_bl) - vClipRadius + nudge;

bool out0 = pos.x < ref_tl.x && pos.y < ref_tl.y && d_tl > vClipRadius.x - nudge;
bool out1 = pos.x > ref_tr.x && pos.y < ref_tr.y && d_tr > vClipRadius.y - nudge;
bool out2 = pos.x > ref_br.x && pos.y > ref_br.y && d_br > vClipRadius.z - nudge;
bool out3 = pos.x < ref_bl.x && pos.y > ref_bl.y && d_bl > vClipRadius.w - nudge;
bvec4 is_out = bvec4(pos.x < ref_tl.x && pos.y < ref_tl.y,
pos.x > ref_tr.x && pos.y < ref_tr.y,
pos.x > ref_br.x && pos.y > ref_br.y,
pos.x < ref_bl.x && pos.y > ref_bl.y);

vec4 distances = vec4(d_tl, d_tr, d_br, d_bl) - vClipRadius + nudge;
float distance_from_border = dot(vec4(out0, out1, out2, out3), distances);
float distance_from_border = dot(vec4(is_out),
max(vec4(0.0, 0.0, 0.0, 0.0), distances));

// Move the distance back into pixels.
distance_from_border /= pixels_per_fragment;

// Apply a more gradual fade out to transparent.
//distance_from_border -= 0.5;

return 1.0 - smoothstep(0.0, 1.0, distance_from_border);
float border_alpha = 1.0 - smoothstep(0.0, 1.0, distance_from_border);

bool repeat_mask = false; //TODO
vec2 vMaskUv = (pos - vClipMaskLocalRect.xy) / vClipMaskLocalRect.zw;
vec2 clamped_mask_uv = repeat_mask ? fract(vMaskUv) :
clamp(vMaskUv, vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 source_uv = clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy;
float mask_alpha = texture(sMask, source_uv).r; //careful: texture has type A8

return border_alpha * mask_alpha;
}
#endif
28 changes: 23 additions & 5 deletions webrender/res/prim_shared.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ PrimitiveInstance fetch_instance(int index) {

return pi;
}

struct Primitive {
Layer layer;
Tile tile;
Expand Down Expand Up @@ -298,11 +297,28 @@ 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));
//rect.dummy = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
rect.dummy = vec4(0.0, 0.0, 0.0, 0.0);

return rect;
}

struct ImageMaskInfo {
vec4 uv_rect;
vec4 local_rect;
};

ImageMaskInfo fetch_mask_info(int index) {
ImageMaskInfo info;

ivec2 uv = get_fetch_uv_2(index);

info.uv_rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
info.local_rect = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));

return info;
}

struct ClipCorner {
vec4 rect;
vec4 outer_inner_radius;
Expand All @@ -319,22 +335,24 @@ ClipCorner fetch_clip_corner(int index) {
return corner;
}

struct Clip {
struct ClipInfo {
ClipRect rect;
ClipCorner top_left;
ClipCorner top_right;
ClipCorner bottom_left;
ClipCorner bottom_right;
ImageMaskInfo mask_info;
};

Clip fetch_clip(int index) {
Clip clip;
ClipInfo fetch_clip(int index) {
ClipInfo clip;

clip.rect = fetch_clip_rect(index + 0);
clip.top_left = fetch_clip_corner(index + 1);
clip.top_right = fetch_clip_corner(index + 2);
clip.bottom_left = fetch_clip_corner(index + 3);
clip.bottom_right = fetch_clip_corner(index + 4);
clip.mask_info = fetch_mask_info(index+5);

return clip;
}
Expand Down
15 changes: 15 additions & 0 deletions webrender/res/ps_gradient.fs.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

void main(void) {
#ifdef WR_FEATURE_TRANSFORM
float alpha = 0.0;
vec2 local_pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
#else
float alpha = 1.0;
vec2 local_pos = vPos;
#endif

oFragColor = vColor * vec4(1, 1, 1, alpha);
}
12 changes: 12 additions & 0 deletions webrender/res/ps_gradient.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

varying vec4 vColor;

#ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos;
flat varying vec4 vLocalRect;
#else
varying vec2 vPos;
#endif
69 changes: 69 additions & 0 deletions webrender/res/ps_gradient.vs.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#line 1
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

void main(void) {
Primitive prim = load_primitive(gl_InstanceID);
Gradient gradient = fetch_gradient(prim.prim_index);

int stop_index = prim.user_data.x + prim.user_data.y;
GradientStop g0 = fetch_gradient_stop(stop_index + 0);
GradientStop g1 = fetch_gradient_stop(stop_index + 1);

vec4 segment_rect;
switch (int(gradient.kind.x)) {
case GRADIENT_HORIZONTAL:
float x0 = mix(gradient.start_end_point.x,
gradient.start_end_point.z,
g0.offset.x);
float x1 = mix(gradient.start_end_point.x,
gradient.start_end_point.z,
g1.offset.x);
segment_rect.yw = prim.local_rect.yw;
segment_rect.x = x0;
segment_rect.z = x1 - x0;
break;
case GRADIENT_VERTICAL:
float y0 = mix(gradient.start_end_point.y,
gradient.start_end_point.w,
g0.offset.x);
float y1 = mix(gradient.start_end_point.y,
gradient.start_end_point.w,
g1.offset.x);
segment_rect.xz = prim.local_rect.xz;
segment_rect.y = y0;
segment_rect.w = y1 - y0;
break;
}

#ifdef WR_FEATURE_TRANSFORM
TransformVertexInfo vi = write_transform_vertex(segment_rect,
prim.local_clip_rect,
prim.layer,
prim.tile);
vLocalRect = vi.clipped_local_rect;
vLocalPos = vi.local_pos;
vec2 f = (vi.local_pos.xy - prim.local_rect.xy) / prim.local_rect.zw;
#else
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,
prim.layer,
prim.tile);

vec2 f = (vi.local_clamped_pos - segment_rect.xy) / segment_rect.zw;
vPos = vi.local_clamped_pos;
#endif

switch (int(gradient.kind.x)) {
case GRADIENT_HORIZONTAL:
vColor = mix(g0.color, g1.color, f.x);
break;
case GRADIENT_VERTICAL:
vColor = mix(g0.color, g1.color, f.y);
break;
case GRADIENT_ROTATED:
vColor = vec4(1.0, 0.0, 1.0, 1.0);
break;
}
}
4 changes: 0 additions & 4 deletions webrender/res/ps_gradient_clip.fs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,4 @@ void main(void) {

alpha = min(alpha, do_clip(local_pos));
oFragColor = vColor * vec4(1, 1, 1, alpha);

#ifdef WR_FEATURE_TRANSFORM
oFragColor.a *= alpha;
#endif
}
2 changes: 1 addition & 1 deletion webrender/res/ps_gradient_clip.vs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,6 @@ void main(void) {
break;
}

Clip clip = fetch_clip(prim.clip_index);
ClipInfo clip = fetch_clip(prim.clip_index);
write_clip(clip);
}
2 changes: 1 addition & 1 deletion webrender/res/ps_image_clip.vs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void main(void) {
vLocalPos = vi.local_clamped_pos;
#endif

Clip clip = fetch_clip(prim.clip_index);
ClipInfo clip = fetch_clip(prim.clip_index);
write_clip(clip);

// vUv will contain how many times this image has wrapped around the image size.
Expand Down
2 changes: 1 addition & 1 deletion webrender/res/ps_rectangle_clip.vs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ void main(void) {
vPos = vi.local_clamped_pos;
#endif

Clip clip = fetch_clip(prim.clip_index);
ClipInfo clip = fetch_clip(prim.clip_index);
write_clip(clip);
}
51 changes: 36 additions & 15 deletions webrender/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ use internal_types::{CompositionOp};
use internal_types::{LowLevelFilterOp};
use internal_types::{RendererFrame};
use layer::{Layer, ScrollingState};
use prim_store::Clip;
use resource_cache::ResourceCache;
use prim_store::ClipInfo;
use resource_cache::{DummyResources, ResourceCache};
use scene::{SceneStackingContext, ScenePipeline, Scene, SceneItem, SpecificSceneItem};
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
use tiling::{FrameBuilder, FrameBuilderConfig, InsideTest, PrimitiveFlags};
use tiling::{FrameBuilder, FrameBuilderConfig, InsideTest, Clip, MaskImageSource};
use tiling::PrimitiveFlags;
use util::MatrixHelpers;
use webrender_traits::{AuxiliaryLists, PipelineId, Epoch, ScrollPolicy, ScrollLayerId};
use webrender_traits::{ColorF, StackingContext, FilterOp, MixBlendMode};
Expand All @@ -35,6 +36,7 @@ static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.6

struct FlattenContext<'a> {
resource_cache: &'a mut ResourceCache,
dummy_resources: &'a DummyResources,
scene: &'a Scene,
pipeline_sizes: &'a mut HashMap<PipelineId, Size2D<f32>>,
builder: &'a mut FrameBuilder,
Expand Down Expand Up @@ -368,6 +370,7 @@ impl Frame {
pub fn create(&mut self,
scene: &Scene,
resource_cache: &mut ResourceCache,
dummy_resources: &DummyResources,
pipeline_sizes: &mut HashMap<PipelineId, Size2D<f32>>,
device_pixel_ratio: f32) {
if let Some(root_pipeline_id) = scene.root_pipeline_id {
Expand Down Expand Up @@ -415,6 +418,7 @@ impl Frame {
{
let mut context = FlattenContext {
resource_cache: resource_cache,
dummy_resources: dummy_resources,
scene: scene,
pipeline_sizes: pipeline_sizes,
builder: &mut frame_builder,
Expand Down Expand Up @@ -530,33 +534,50 @@ impl Frame {
PrimitiveFlags::None);
}

let dummy_mask_source = {
let cache_id = context.dummy_resources.opaque_mask_image_id;
let cache_item = context.resource_cache.get_image_by_cache_id(cache_id);
MaskImageSource::Renderer(cache_item.texture_id)
};

for item in scene_items {
match item.specific {
SpecificSceneItem::DrawList(draw_list_id) => {
let draw_list = context.resource_cache.get_draw_list(draw_list_id);
let builder = &mut context.builder;

let auxiliary_lists = {
self.pipeline_auxiliary_lists
let auxiliary_lists = self.pipeline_auxiliary_lists
.get(&parent_info.pipeline_id)
.expect("No auxiliary lists?!")
};
.expect("No auxiliary lists?!");

for item in &draw_list.items {
let clips = auxiliary_lists.complex_clip_regions(&item.clip.complex);
let clip = match clips.len() {
0 => None,
1 => Some(Box::new(Clip::from_clip_region(&clips[0]))),
let mut clip = match clips.len() {
0 if item.clip.image_mask.is_none() => None,
0 => Some(Clip::new(ClipInfo::uniform(item.clip.main, 0.0), dummy_mask_source)),
1 => Some(Clip::new(ClipInfo::from_clip_region(&clips[0]), dummy_mask_source)),
_ => {
let internal_clip = clips.last().unwrap();
if clips.iter().all(|current_clip| current_clip.might_contain(internal_clip)) {
Some(Box::new(Clip::from_clip_region(internal_clip)))
let region = if clips.iter().all(|current_clip| current_clip.might_contain(internal_clip)) {
internal_clip
} else {
Some(Box::new(Clip::from_clip_region(&clips[0])))
}
&clips[0]
};
Some(Clip::new(ClipInfo::from_clip_region(region), dummy_mask_source))
},
};

if let Some(ref mask) = item.clip.image_mask {
let old = match clip {
Some(masked) => *masked.clip,
None => ClipInfo::uniform(item.clip.main, 0.0),
};
//Note: can't call `tex_cache.aligned_uv_rect()` here since the image
// is not yet marked as needed this frame.
clip = Some(Clip::new(old.with_mask(Rect::zero(), mask.rect),
MaskImageSource::User(mask.image)));
}


match item.item {
SpecificDisplayItem::WebGL(ref info) => {
builder.add_webgl_rectangle(item.rect,
Expand Down
Loading