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 brushes with transforms plus edge AA. #2102

Merged
merged 1 commit into from Nov 27, 2017
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Add support for brushes with transforms plus edge AA.

This means that brush items such as box-shadows get correct edge
AA when they are transformed, which was not previously supported.

Also fix up the segment / rect AA support for transformed primitives.
Previously, we were using the clip rect or the local rect. This
works in most cases, but is not correct. Instead, explicitly pass
in the prim rect and the segment rect, and apply the local clip
rect to each of those. In most cases, these are the same, but for
some primitives they differ.

Add a basic test suite to ensure AA is working correctly on border,
box-shadow, rect and image primitives.
  • Loading branch information
gw3583 committed Nov 27, 2017
commit 86348b29b49b316fb816c49a7b816544a1099609
@@ -67,22 +67,41 @@ void main(void) {
// Write the final position transformed by the orthographic device-pixel projection.
gl_Position = uTransform * vec4(device_pos, 0.0, 1.0);
} else {
VertexInfo vi;
Layer layer = fetch_layer(brush.clip_node_id, brush.scroll_node_id);
ClipArea clip_area = fetch_clip_area(brush.clip_address);

// Write the normal vertex information out.
// TODO(gw): Support transform types in brushes. For now,
// the old cache image shader didn't support
// them yet anyway, so we're not losing any
// existing functionality.
VertexInfo vi = write_vertex(
geom.local_rect,
geom.local_clip_rect,
float(brush.z),
layer,
pic_task,
geom.local_rect
);
if (layer.is_axis_aligned) {
vi = write_vertex(
geom.local_rect,
geom.local_clip_rect,
float(brush.z),
layer,
pic_task,
geom.local_rect
);

// TODO(gw): vLocalBounds may be referenced by
// the fragment shader when running in
// the alpha pass, even on non-transformed
// items. For now, just ensure it has no
// effect. We can tidy this up as we move
// more items to be brush shaders.
vLocalBounds = vec4(
geom.local_clip_rect.p0,
geom.local_clip_rect.p0 + geom.local_clip_rect.size
);
} else {
vi = write_transform_vertex(geom.local_rect,
geom.local_rect,
geom.local_clip_rect,
vec4(1.0),
float(brush.z),
layer,
pic_task
);
}

local_pos = vi.local_pos;

@@ -4,6 +4,10 @@

#include shared,prim_shared,brush

#ifdef WR_FEATURE_ALPHA_PASS
varying vec2 vLocalPos;
#endif

varying vec3 vUv;
flat varying int vImageKind;
flat varying vec4 vUvBounds;
@@ -76,6 +80,10 @@ void brush_vs(

vUvBounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) / texture_size.xyxy;
vUvBounds_NoClamp = vec4(uv0, uv1) / texture_size.xyxy;

#ifdef WR_FEATURE_ALPHA_PASS
vLocalPos = local_pos;
#endif
}
#endif

@@ -116,6 +124,10 @@ vec4 brush_fs() {
vec4 color = vColor * texture(sColor1, vec3(uv, vUv.z)).r;
#endif

#ifdef WR_FEATURE_ALPHA_PASS
color *= init_transform_fs(vLocalPos);
#endif

return color;
}
#endif
@@ -36,9 +36,7 @@ float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
// TODO: convert back to RectWithEndPoint if driver issues are resolved, if ever.
flat varying vec4 vClipMaskUvBounds;
varying vec3 vClipMaskUv;
#ifdef WR_FEATURE_TRANSFORM
flat varying vec4 vLocalBounds;
#endif
flat varying vec4 vLocalBounds;

// TODO(gw): This is here temporarily while we have
// both GPU store and cache. When the GPU
@@ -71,7 +69,7 @@ vec4[2] fetch_from_resource_cache_2(int address) {

#ifdef WR_VERTEX_SHADER

#define VECS_PER_LAYER 10
#define VECS_PER_LAYER 11
#define VECS_PER_RENDER_TASK 3
#define VECS_PER_PRIM_HEADER 2
#define VECS_PER_TEXT_RUN 3
@@ -149,6 +147,7 @@ struct ClipScrollNode {
vec4 local_clip_rect;
vec2 reference_frame_relative_scroll_offset;
vec2 scroll_offset;
bool is_axis_aligned;
};

ClipScrollNode fetch_clip_scroll_node(int index) {
@@ -179,13 +178,17 @@ ClipScrollNode fetch_clip_scroll_node(int index) {
node.reference_frame_relative_scroll_offset = offsets.xy;
node.scroll_offset = offsets.zw;

vec4 misc = TEXEL_FETCH(sClipScrollNodes, uv1, 0, ivec2(2, 0));
node.is_axis_aligned = misc.x == 0.0;

return node;
}

struct Layer {
mat4 transform;
mat4 inv_transform;
RectWithSize local_clip_rect;
bool is_axis_aligned;
};

Layer fetch_layer(int clip_node_id, int scroll_node_id) {
@@ -202,6 +205,7 @@ Layer fetch_layer(int clip_node_id, int scroll_node_id) {
local_clip_rect.xy -= scroll_node.scroll_offset;

layer.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw);
layer.is_axis_aligned = scroll_node.is_axis_aligned;

return layer;
}
@@ -615,8 +619,6 @@ VertexInfo write_vertex(RectWithSize instance_rect,
return vi;
}

#ifdef WR_FEATURE_TRANSFORM

float cross2(vec2 v0, vec2 v1) {
return v0.x * v1.y - v0.y * v1.x;
}
@@ -636,7 +638,8 @@ vec2 intersect_lines(vec2 p0, vec2 p1, vec2 p2, vec2 p3) {
return vec2(nx / d, ny / d);
}

VertexInfo write_transform_vertex(RectWithSize instance_rect,
VertexInfo write_transform_vertex(RectWithSize local_segment_rect,
RectWithSize local_prim_rect,
RectWithSize local_clip_rect,
vec4 clip_edge_mask,
float z,
@@ -648,9 +651,14 @@ VertexInfo write_transform_vertex(RectWithSize instance_rect,
clip_rect.p1 = clamp_rect(clip_rect.p1, layer.local_clip_rect);

// Calculate a clip rect from local_rect + local clip + layer clip.
RectWithEndpoint local_rect = to_rect_with_endpoint(instance_rect);
local_rect.p0 = clamp(local_rect.p0, clip_rect.p0, clip_rect.p1);
local_rect.p1 = clamp(local_rect.p1, clip_rect.p0, clip_rect.p1);
RectWithEndpoint segment_rect = to_rect_with_endpoint(local_segment_rect);
segment_rect.p0 = clamp(segment_rect.p0, clip_rect.p0, clip_rect.p1);
segment_rect.p1 = clamp(segment_rect.p1, clip_rect.p0, clip_rect.p1);

// Calculate a clip rect from local_rect + local clip + layer clip.
RectWithEndpoint prim_rect = to_rect_with_endpoint(local_prim_rect);
prim_rect.p0 = clamp(prim_rect.p0, clip_rect.p0, clip_rect.p1);
prim_rect.p1 = clamp(prim_rect.p1, clip_rect.p0, clip_rect.p1);

// As this is a transform shader, extrude by 2 (local space) pixels
// in each direction. This gives enough space around the edge to
@@ -661,11 +669,11 @@ VertexInfo write_transform_vertex(RectWithSize instance_rect,
// can do some math on the projection matrix to work out a variable
// amount to extrude.
float extrude_distance = 2.0;
instance_rect.p0 -= vec2(extrude_distance);
instance_rect.size += vec2(2.0 * extrude_distance);
local_segment_rect.p0 -= vec2(extrude_distance);
local_segment_rect.size += vec2(2.0 * extrude_distance);

// Select the corner of the local rect that we are processing.
vec2 local_pos = instance_rect.p0 + instance_rect.size * aPosition.xy;
vec2 local_pos = local_segment_rect.p0 + local_segment_rect.size * aPosition.xy;

// Transform the current vertex to the world cpace.
vec4 world_pos = layer.transform * vec4(local_pos, 0.0, 1.0);
@@ -683,8 +691,8 @@ VertexInfo write_transform_vertex(RectWithSize instance_rect,
gl_Position = uTransform * final_pos;

vLocalBounds = mix(
vec4(clip_rect.p0, clip_rect.p1),
vec4(local_rect.p0, local_rect.p1),
vec4(prim_rect.p0, prim_rect.p1),
vec4(segment_rect.p0, segment_rect.p1),
clip_edge_mask
);

@@ -694,17 +702,16 @@ VertexInfo write_transform_vertex(RectWithSize instance_rect,

VertexInfo write_transform_vertex_primitive(Primitive prim) {
return write_transform_vertex(
prim.local_rect,
prim.local_rect,
prim.local_clip_rect,
vec4(1.0),
vec4(0.0),
prim.z,
prim.layer,
prim.task
);
}

#endif //WR_FEATURE_TRANSFORM

struct GlyphResource {
vec4 uv_rect;
float layer;
@@ -809,7 +816,6 @@ float distance_aa(float aa_range, float signed_distance) {
return 1.0 - smoothstep(-aa_range, aa_range, signed_distance);
}

#ifdef WR_FEATURE_TRANSFORM
float signed_distance_rect(vec2 pos, vec2 p0, vec2 p1) {
vec2 d = max(p0 - pos, pos - p1);
return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y));
@@ -829,7 +835,6 @@ float init_transform_fs(vec2 local_pos) {
// Only apply AA to fragments outside the signed distance field.
return distance_aa(aa_range, d);
}
#endif //WR_FEATURE_TRANSFORM

float do_clip() {
// anything outside of the mask is considered transparent
@@ -299,6 +299,7 @@ void main(void) {

#ifdef WR_FEATURE_TRANSFORM
VertexInfo vi = write_transform_vertex(segment_rect,
prim.local_rect,
prim.local_clip_rect,
vec4(1.0),
prim.z,
@@ -217,6 +217,7 @@ void main(void) {

#ifdef WR_FEATURE_TRANSFORM
VertexInfo vi = write_transform_vertex(segment_rect,
prim.local_rect,
prim.local_clip_rect,
vec4(1.0),
prim.z,
@@ -68,6 +68,7 @@ void main(void) {

#ifdef WR_FEATURE_TRANSFORM
VertexInfo vi = write_transform_vertex(segment_rect,
prim.local_rect,
prim.local_clip_rect,
vec4(1.0),
prim.z,
@@ -17,6 +17,7 @@ void main(void) {
vColor = rect.color;
#ifdef WR_FEATURE_TRANSFORM
VertexInfo vi = write_transform_vertex(prim.local_rect,
prim.local_rect,
prim.local_clip_rect,
rect.edge_aa_segment_mask,
prim.z,
@@ -17,7 +17,7 @@ use resource_cache::ResourceCache;
use scene::SceneProperties;
use spring::{DAMPING, STIFFNESS, Spring};
use std::rc::Rc;
use util::{MatrixHelpers, MaxRect};
use util::{MatrixHelpers, MaxRect, TransformedRectKind};

#[cfg(target_os = "macos")]
const CAN_OVERSCROLL: bool = true;
@@ -304,13 +304,21 @@ impl ClipScrollNode {

let data = match self.world_content_transform.inverse() {
Some(inverse) => {
let transform_kind = if self.world_content_transform.preserves_2d_axis_alignment() {
TransformedRectKind::AxisAligned
} else {
TransformedRectKind::Complex
};

ClipScrollNodeData {
transform: self.world_content_transform,
inv_transform: inverse,
local_clip_rect,
reference_frame_relative_scroll_offset:
self.reference_frame_relative_scroll_offset,
scroll_offset: self.scroll_offset(),
transform_kind: transform_kind as u32 as f32,
padding: [0.0; 3],
}
}
None => {
@@ -198,6 +198,8 @@ pub struct ClipScrollNodeData {
pub local_clip_rect: LayerRect,
pub reference_frame_relative_scroll_offset: LayerVector2D,
pub scroll_offset: LayerVector2D,
pub transform_kind: f32,
pub padding: [f32; 3],
}

impl ClipScrollNodeData {
@@ -208,6 +210,8 @@ impl ClipScrollNodeData {
local_clip_rect: LayerRect::zero(),
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
scroll_offset: LayerVector2D::zero(),
transform_kind: 0.0,
padding: [0.0; 3],
}
}
}
@@ -210,7 +210,7 @@ pub fn get_normal(x: f32) -> Option<f32> {
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[repr(u8)]
#[repr(u32)]
pub enum TransformedRectKind {
AxisAligned = 0,
Complex = 1,
Binary file not shown.
@@ -0,0 +1,39 @@
---
root:
items:
- type: stacking-context
bounds: [50, 50, 100, 100]
transform: rotate(30)
items:
- type: rect
bounds: [ 10, 10, 80, 80 ]
color: [0, 255, 0]
- type: box-shadow
bounds: [ 10, 10, 80, 80 ]
blur-radius: 25
clip-mode: inset

- type: rect
bounds: [ 140, 10, 80, 80 ]
color: [0, 255, 0]
- type: box-shadow
bounds: [ 140, 10, 80, 80 ]
blur-radius: 25
clip-mode: outset

- type: border
bounds: [ 250, 10, 100, 100 ]
width: [ 10, 10, 10, 10 ]
border-type: normal
style: solid
color: [ red, green, blue, black ]
radius: {
top-left: [20, 20],
top-right: [10, 10],
bottom-left: [25, 25],
bottom-right: [0, 0],
}

- bounds: [150, 150, 128, 128]
image: checkerboard(4, 15, 8)
stretch-size: 128 128
@@ -6,3 +6,5 @@
fuzzy(1,2) == rotated-image.yaml rotated-image.png
== singular.yaml singular-ref.yaml
fuzzy(1,41) == perspective.yaml perspective.png
== prim-suite.yaml prim-suite.png

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