Skip to content

Commit f13e95b

Browse files
author
bors-servo
authored
Auto merge of #445 - kvark:image_mask, r=glennw
Image mask support Closes #405 I'm not completely sure if this is the right approach, hoping to get some review/feedback to proceed. The API and logic works for me with `wr_sample`, although the implementation lacks a lot of features to support, like image repeating and layout transformations. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/445) <!-- Reviewable:end -->
2 parents 9de780b + 1e33028 commit f13e95b

19 files changed

+464
-184
lines changed

webrender/res/clip_shared.glsl

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@
55

66
flat varying vec4 vClipRect;
77
flat varying vec4 vClipRadius;
8+
flat varying vec4 vClipMaskUvRect;
9+
flat varying vec4 vClipMaskLocalRect;
810

911
#ifdef WR_VERTEX_SHADER
10-
void write_clip(Clip clip) {
12+
void write_clip(ClipInfo clip) {
1113
vClipRect = vec4(clip.rect.rect.xy, clip.rect.rect.xy + clip.rect.rect.zw);
1214
vClipRadius = vec4(clip.top_left.outer_inner_radius.x,
1315
clip.top_right.outer_inner_radius.x,
1416
clip.bottom_right.outer_inner_radius.x,
1517
clip.bottom_left.outer_inner_radius.x);
18+
//TODO: interpolate the final mask UV
19+
vClipMaskUvRect = clip.mask_info.uv_rect;
20+
vClipMaskLocalRect = clip.mask_info.local_rect; //TODO: transform
1621
}
1722
#endif
1823

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

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

35-
bool out0 = pos.x < ref_tl.x && pos.y < ref_tl.y && d_tl > vClipRadius.x - nudge;
36-
bool out1 = pos.x > ref_tr.x && pos.y < ref_tr.y && d_tr > vClipRadius.y - nudge;
37-
bool out2 = pos.x > ref_br.x && pos.y > ref_br.y && d_br > vClipRadius.z - nudge;
38-
bool out3 = pos.x < ref_bl.x && pos.y > ref_bl.y && d_bl > vClipRadius.w - nudge;
40+
bvec4 is_out = bvec4(pos.x < ref_tl.x && pos.y < ref_tl.y,
41+
pos.x > ref_tr.x && pos.y < ref_tr.y,
42+
pos.x > ref_br.x && pos.y > ref_br.y,
43+
pos.x < ref_bl.x && pos.y > ref_bl.y);
3944

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

4348
// Move the distance back into pixels.
4449
distance_from_border /= pixels_per_fragment;
45-
4650
// Apply a more gradual fade out to transparent.
4751
//distance_from_border -= 0.5;
4852

49-
return 1.0 - smoothstep(0.0, 1.0, distance_from_border);
53+
float border_alpha = 1.0 - smoothstep(0.0, 1.0, distance_from_border);
54+
55+
bool repeat_mask = false; //TODO
56+
vec2 vMaskUv = (pos - vClipMaskLocalRect.xy) / vClipMaskLocalRect.zw;
57+
vec2 clamped_mask_uv = repeat_mask ? fract(vMaskUv) :
58+
clamp(vMaskUv, vec2(0.0, 0.0), vec2(1.0, 1.0));
59+
vec2 source_uv = clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy;
60+
float mask_alpha = texture(sMask, source_uv).r; //careful: texture has type A8
61+
62+
return border_alpha * mask_alpha;
5063
}
5164
#endif

webrender/res/prim_shared.glsl

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,6 @@ PrimitiveInstance fetch_instance(int index) {
257257

258258
return pi;
259259
}
260-
261260
struct Primitive {
262261
Layer layer;
263262
Tile tile;
@@ -298,11 +297,28 @@ ClipRect fetch_clip_rect(int index) {
298297
ivec2 uv = get_fetch_uv_2(index);
299298

300299
rect.rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
301-
rect.dummy = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
300+
//rect.dummy = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
301+
rect.dummy = vec4(0.0, 0.0, 0.0, 0.0);
302302

303303
return rect;
304304
}
305305

306+
struct ImageMaskInfo {
307+
vec4 uv_rect;
308+
vec4 local_rect;
309+
};
310+
311+
ImageMaskInfo fetch_mask_info(int index) {
312+
ImageMaskInfo info;
313+
314+
ivec2 uv = get_fetch_uv_2(index);
315+
316+
info.uv_rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
317+
info.local_rect = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
318+
319+
return info;
320+
}
321+
306322
struct ClipCorner {
307323
vec4 rect;
308324
vec4 outer_inner_radius;
@@ -319,22 +335,24 @@ ClipCorner fetch_clip_corner(int index) {
319335
return corner;
320336
}
321337

322-
struct Clip {
338+
struct ClipInfo {
323339
ClipRect rect;
324340
ClipCorner top_left;
325341
ClipCorner top_right;
326342
ClipCorner bottom_left;
327343
ClipCorner bottom_right;
344+
ImageMaskInfo mask_info;
328345
};
329346

330-
Clip fetch_clip(int index) {
331-
Clip clip;
347+
ClipInfo fetch_clip(int index) {
348+
ClipInfo clip;
332349

333350
clip.rect = fetch_clip_rect(index + 0);
334351
clip.top_left = fetch_clip_corner(index + 1);
335352
clip.top_right = fetch_clip_corner(index + 2);
336353
clip.bottom_left = fetch_clip_corner(index + 3);
337354
clip.bottom_right = fetch_clip_corner(index + 4);
355+
clip.mask_info = fetch_mask_info(index+5);
338356

339357
return clip;
340358
}

webrender/res/ps_gradient.fs.glsl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
void main(void) {
6+
#ifdef WR_FEATURE_TRANSFORM
7+
float alpha = 0.0;
8+
vec2 local_pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
9+
#else
10+
float alpha = 1.0;
11+
vec2 local_pos = vPos;
12+
#endif
13+
14+
oFragColor = vColor * vec4(1, 1, 1, alpha);
15+
}

webrender/res/ps_gradient.glsl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
varying vec4 vColor;
6+
7+
#ifdef WR_FEATURE_TRANSFORM
8+
varying vec3 vLocalPos;
9+
flat varying vec4 vLocalRect;
10+
#else
11+
varying vec2 vPos;
12+
#endif

webrender/res/ps_gradient.vs.glsl

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#line 1
2+
/* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5+
6+
void main(void) {
7+
Primitive prim = load_primitive(gl_InstanceID);
8+
Gradient gradient = fetch_gradient(prim.prim_index);
9+
10+
int stop_index = prim.user_data.x + prim.user_data.y;
11+
GradientStop g0 = fetch_gradient_stop(stop_index + 0);
12+
GradientStop g1 = fetch_gradient_stop(stop_index + 1);
13+
14+
vec4 segment_rect;
15+
switch (int(gradient.kind.x)) {
16+
case GRADIENT_HORIZONTAL:
17+
float x0 = mix(gradient.start_end_point.x,
18+
gradient.start_end_point.z,
19+
g0.offset.x);
20+
float x1 = mix(gradient.start_end_point.x,
21+
gradient.start_end_point.z,
22+
g1.offset.x);
23+
segment_rect.yw = prim.local_rect.yw;
24+
segment_rect.x = x0;
25+
segment_rect.z = x1 - x0;
26+
break;
27+
case GRADIENT_VERTICAL:
28+
float y0 = mix(gradient.start_end_point.y,
29+
gradient.start_end_point.w,
30+
g0.offset.x);
31+
float y1 = mix(gradient.start_end_point.y,
32+
gradient.start_end_point.w,
33+
g1.offset.x);
34+
segment_rect.xz = prim.local_rect.xz;
35+
segment_rect.y = y0;
36+
segment_rect.w = y1 - y0;
37+
break;
38+
}
39+
40+
#ifdef WR_FEATURE_TRANSFORM
41+
TransformVertexInfo vi = write_transform_vertex(segment_rect,
42+
prim.local_clip_rect,
43+
prim.layer,
44+
prim.tile);
45+
vLocalRect = vi.clipped_local_rect;
46+
vLocalPos = vi.local_pos;
47+
vec2 f = (vi.local_pos.xy - prim.local_rect.xy) / prim.local_rect.zw;
48+
#else
49+
VertexInfo vi = write_vertex(segment_rect,
50+
prim.local_clip_rect,
51+
prim.layer,
52+
prim.tile);
53+
54+
vec2 f = (vi.local_clamped_pos - segment_rect.xy) / segment_rect.zw;
55+
vPos = vi.local_clamped_pos;
56+
#endif
57+
58+
switch (int(gradient.kind.x)) {
59+
case GRADIENT_HORIZONTAL:
60+
vColor = mix(g0.color, g1.color, f.x);
61+
break;
62+
case GRADIENT_VERTICAL:
63+
vColor = mix(g0.color, g1.color, f.y);
64+
break;
65+
case GRADIENT_ROTATED:
66+
vColor = vec4(1.0, 0.0, 1.0, 1.0);
67+
break;
68+
}
69+
}

webrender/res/ps_gradient_clip.fs.glsl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,4 @@ void main(void) {
1313

1414
alpha = min(alpha, do_clip(local_pos));
1515
oFragColor = vColor * vec4(1, 1, 1, alpha);
16-
17-
#ifdef WR_FEATURE_TRANSFORM
18-
oFragColor.a *= alpha;
19-
#endif
2016
}

webrender/res/ps_gradient_clip.vs.glsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,6 @@ void main(void) {
6767
break;
6868
}
6969

70-
Clip clip = fetch_clip(prim.clip_index);
70+
ClipInfo clip = fetch_clip(prim.clip_index);
7171
write_clip(clip);
7272
}

webrender/res/ps_image_clip.vs.glsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ void main(void) {
2323
vLocalPos = vi.local_clamped_pos;
2424
#endif
2525

26-
Clip clip = fetch_clip(prim.clip_index);
26+
ClipInfo clip = fetch_clip(prim.clip_index);
2727
write_clip(clip);
2828

2929
// vUv will contain how many times this image has wrapped around the image size.

webrender/res/ps_rectangle_clip.vs.glsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ void main(void) {
2222
vPos = vi.local_clamped_pos;
2323
#endif
2424

25-
Clip clip = fetch_clip(prim.clip_index);
25+
ClipInfo clip = fetch_clip(prim.clip_index);
2626
write_clip(clip);
2727
}

webrender/src/frame.rs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ use internal_types::{CompositionOp};
1111
use internal_types::{LowLevelFilterOp};
1212
use internal_types::{RendererFrame};
1313
use layer::{Layer, ScrollingState};
14-
use prim_store::Clip;
15-
use resource_cache::ResourceCache;
14+
use prim_store::ClipInfo;
15+
use resource_cache::{DummyResources, ResourceCache};
1616
use scene::{SceneStackingContext, ScenePipeline, Scene, SceneItem, SpecificSceneItem};
1717
use std::collections::{HashMap, HashSet};
1818
use std::hash::BuildHasherDefault;
19-
use tiling::{FrameBuilder, FrameBuilderConfig, InsideTest, PrimitiveFlags};
19+
use tiling::{FrameBuilder, FrameBuilderConfig, InsideTest, Clip, MaskImageSource};
20+
use tiling::PrimitiveFlags;
2021
use util::MatrixHelpers;
2122
use webrender_traits::{AuxiliaryLists, PipelineId, Epoch, ScrollPolicy, ScrollLayerId};
2223
use webrender_traits::{ColorF, StackingContext, FilterOp, MixBlendMode};
@@ -35,6 +36,7 @@ static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.6
3536

3637
struct FlattenContext<'a> {
3738
resource_cache: &'a mut ResourceCache,
39+
dummy_resources: &'a DummyResources,
3840
scene: &'a Scene,
3941
pipeline_sizes: &'a mut HashMap<PipelineId, Size2D<f32>>,
4042
builder: &'a mut FrameBuilder,
@@ -368,6 +370,7 @@ impl Frame {
368370
pub fn create(&mut self,
369371
scene: &Scene,
370372
resource_cache: &mut ResourceCache,
373+
dummy_resources: &DummyResources,
371374
pipeline_sizes: &mut HashMap<PipelineId, Size2D<f32>>,
372375
device_pixel_ratio: f32) {
373376
if let Some(root_pipeline_id) = scene.root_pipeline_id {
@@ -415,6 +418,7 @@ impl Frame {
415418
{
416419
let mut context = FlattenContext {
417420
resource_cache: resource_cache,
421+
dummy_resources: dummy_resources,
418422
scene: scene,
419423
pipeline_sizes: pipeline_sizes,
420424
builder: &mut frame_builder,
@@ -530,33 +534,50 @@ impl Frame {
530534
PrimitiveFlags::None);
531535
}
532536

537+
let dummy_mask_source = {
538+
let cache_id = context.dummy_resources.opaque_mask_image_id;
539+
let cache_item = context.resource_cache.get_image_by_cache_id(cache_id);
540+
MaskImageSource::Renderer(cache_item.texture_id)
541+
};
542+
533543
for item in scene_items {
534544
match item.specific {
535545
SpecificSceneItem::DrawList(draw_list_id) => {
536546
let draw_list = context.resource_cache.get_draw_list(draw_list_id);
537547
let builder = &mut context.builder;
538-
539-
let auxiliary_lists = {
540-
self.pipeline_auxiliary_lists
548+
let auxiliary_lists = self.pipeline_auxiliary_lists
541549
.get(&parent_info.pipeline_id)
542-
.expect("No auxiliary lists?!")
543-
};
550+
.expect("No auxiliary lists?!");
544551

545552
for item in &draw_list.items {
546553
let clips = auxiliary_lists.complex_clip_regions(&item.clip.complex);
547-
let clip = match clips.len() {
548-
0 => None,
549-
1 => Some(Box::new(Clip::from_clip_region(&clips[0]))),
554+
let mut clip = match clips.len() {
555+
0 if item.clip.image_mask.is_none() => None,
556+
0 => Some(Clip::new(ClipInfo::uniform(item.clip.main, 0.0), dummy_mask_source)),
557+
1 => Some(Clip::new(ClipInfo::from_clip_region(&clips[0]), dummy_mask_source)),
550558
_ => {
551559
let internal_clip = clips.last().unwrap();
552-
if clips.iter().all(|current_clip| current_clip.might_contain(internal_clip)) {
553-
Some(Box::new(Clip::from_clip_region(internal_clip)))
560+
let region = if clips.iter().all(|current_clip| current_clip.might_contain(internal_clip)) {
561+
internal_clip
554562
} else {
555-
Some(Box::new(Clip::from_clip_region(&clips[0])))
556-
}
563+
&clips[0]
564+
};
565+
Some(Clip::new(ClipInfo::from_clip_region(region), dummy_mask_source))
557566
},
558567
};
559568

569+
if let Some(ref mask) = item.clip.image_mask {
570+
let old = match clip {
571+
Some(masked) => *masked.clip,
572+
None => ClipInfo::uniform(item.clip.main, 0.0),
573+
};
574+
//Note: can't call `tex_cache.aligned_uv_rect()` here since the image
575+
// is not yet marked as needed this frame.
576+
clip = Some(Clip::new(old.with_mask(Rect::zero(), mask.rect),
577+
MaskImageSource::User(mask.image)));
578+
}
579+
580+
560581
match item.item {
561582
SpecificDisplayItem::WebGL(ref info) => {
562583
builder.add_webgl_rectangle(item.rect,

0 commit comments

Comments
 (0)