servo/resources/shaders/prim_shared.glsl
2016-08-13 05:50:31 +10:00

238 lines
7.4 KiB
GLSL

#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/. */
#define PST_INVALID uint(0)
#define PST_TOP_LEFT uint(1)
#define PST_TOP_RIGHT uint(2)
#define PST_BOTTOM_LEFT uint(3)
#define PST_BOTTOM_RIGHT uint(4)
#define PST_TOP uint(5)
#define PST_LEFT uint(6)
#define PST_BOTTOM uint(7)
#define PST_RIGHT uint(8)
// Border styles as defined in webrender_traits/types.rs
#define BORDER_STYLE_NONE uint(0)
#define BORDER_STYLE_SOLID uint(1)
#define BORDER_STYLE_DOUBLE uint(2)
#define BORDER_STYLE_DOTTED uint(3)
#define BORDER_STYLE_DASHED uint(4)
#define BORDER_STYLE_HIDDEN uint(5)
#define BORDER_STYLE_GROOVE uint(6)
#define BORDER_STYLE_RIDGE uint(7)
#define BORDER_STYLE_INSET uint(8)
#define BORDER_STYLE_OUTSET uint(9)
#ifdef WR_VERTEX_SHADER
struct Layer {
mat4 transform;
mat4 inv_transform;
ivec4 world_clip_rect;
vec4 screen_vertices[4];
};
layout(std140) uniform Layers {
Layer layers[WR_MAX_PRIM_LAYERS];
};
struct Tile {
uvec4 actual_rect;
uvec4 target_rect;
};
layout(std140) uniform Tiles {
Tile tiles[WR_MAX_PRIM_TILES];
};
struct PrimitiveInfo {
uvec4 layer_tile_part;
vec4 local_clip_rect;
vec4 local_rect;
};
struct ClipCorner {
vec4 rect;
vec4 outer_inner_radius;
};
struct Clip {
vec4 rect;
ClipCorner top_left;
ClipCorner top_right;
ClipCorner bottom_left;
ClipCorner bottom_right;
};
bool ray_plane(vec3 normal, vec3 point, vec3 ray_origin, vec3 ray_dir, out float t)
{
float denom = dot(normal, ray_dir);
if (denom > 1e-6) {
vec3 d = point - ray_origin;
t = dot(d, normal) / denom;
return t >= 0.0;
}
return false;
}
vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) {
vec3 p = vec3(ref, -10000.0);
vec3 d = vec3(0, 0, 1.0);
float t;
ray_plane(n, a, p, d, t);
vec3 c = p + d * t;
vec4 r = inv_transform * vec4(c, 1.0);
return r;
}
vec3 get_layer_pos(vec2 pos, uint layer_index) {
Layer layer = layers[layer_index];
vec3 a = layer.screen_vertices[0].xyz / layer.screen_vertices[0].w;
vec3 b = layer.screen_vertices[3].xyz / layer.screen_vertices[3].w;
vec3 c = layer.screen_vertices[2].xyz / layer.screen_vertices[2].w;
vec3 n = normalize(cross(b-a, c-a));
vec4 local_pos = untransform(pos, n, a, layer.inv_transform);
return local_pos.xyw;
}
struct Rect {
vec2 p0;
vec2 p1;
};
struct VertexInfo {
Rect local_rect;
vec2 local_clamped_pos;
vec2 global_clamped_pos;
};
VertexInfo write_vertex(PrimitiveInfo info) {
Layer layer = layers[info.layer_tile_part.x];
Tile tile = tiles[info.layer_tile_part.y];
vec2 p0 = floor(0.5 + info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio;
vec2 p1 = floor(0.5 + (info.local_rect.xy + info.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio;
vec2 local_pos = mix(p0, p1, aPosition.xy);
vec2 cp0 = floor(0.5 + info.local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio;
vec2 cp1 = floor(0.5 + (info.local_clip_rect.xy + info.local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio;
local_pos = clamp(local_pos, cp0, cp1);
vec4 world_pos = layer.transform * vec4(local_pos, 0, 1);
world_pos.xyz /= world_pos.w;
vec2 device_pos = world_pos.xy * uDevicePixelRatio;
vec2 clamped_pos = clamp(device_pos,
vec2(tile.actual_rect.xy),
vec2(tile.actual_rect.xy + tile.actual_rect.zw));
clamped_pos = clamp(clamped_pos,
vec2(layer.world_clip_rect.xy),
vec2(layer.world_clip_rect.xy + layer.world_clip_rect.zw));
vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, world_pos.z, 1);
local_clamped_pos.xyz /= local_clamped_pos.w;
vec2 final_pos = clamped_pos + vec2(tile.target_rect.xy) - vec2(tile.actual_rect.xy);
gl_Position = uTransform * vec4(final_pos, 0, 1);
VertexInfo vi = VertexInfo(Rect(p0, p1), local_clamped_pos.xy, clamped_pos.xy);
return vi;
}
struct TransformVertexInfo {
vec3 local_pos;
};
TransformVertexInfo write_transform_vertex(PrimitiveInfo info) {
Layer layer = layers[info.layer_tile_part.x];
Tile tile = tiles[info.layer_tile_part.y];
vec2 p0 = info.local_rect.xy;
vec2 p1 = info.local_rect.xy + vec2(info.local_rect.z, 0.0);
vec2 p2 = info.local_rect.xy + vec2(0.0, info.local_rect.w);
vec2 p3 = info.local_rect.xy + info.local_rect.zw;
vec4 t0 = layer.transform * vec4(p0, 0, 1);
vec4 t1 = layer.transform * vec4(p1, 0, 1);
vec4 t2 = layer.transform * vec4(p2, 0, 1);
vec4 t3 = layer.transform * vec4(p3, 0, 1);
vec2 tp0 = t0.xy / t0.w;
vec2 tp1 = t1.xy / t1.w;
vec2 tp2 = t2.xy / t2.w;
vec2 tp3 = t3.xy / t3.w;
vec2 min_pos = min(tp0.xy, min(tp1.xy, min(tp2.xy, tp3.xy)));
vec2 max_pos = max(tp0.xy, max(tp1.xy, max(tp2.xy, tp3.xy)));
vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio,
vec2(tile.actual_rect.xy),
vec2(tile.actual_rect.xy + tile.actual_rect.zw));
vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio,
vec2(tile.actual_rect.xy),
vec2(tile.actual_rect.xy + tile.actual_rect.zw));
vec2 clamped_pos = mix(min_pos_clamped,
max_pos_clamped,
aPosition.xy);
vec3 layer_pos = get_layer_pos(clamped_pos / uDevicePixelRatio, info.layer_tile_part.x);
vec2 final_pos = clamped_pos + vec2(tile.target_rect.xy) - vec2(tile.actual_rect.xy);
gl_Position = uTransform * vec4(final_pos, 0, 1);
return TransformVertexInfo(layer_pos);
}
#endif
#ifdef WR_FRAGMENT_SHADER
void do_clip(vec2 pos, vec4 clip_rect, vec4 radius) {
vec2 ref_tl = clip_rect.xy + vec2( radius.x, radius.x);
vec2 ref_tr = clip_rect.zy + vec2(-radius.y, radius.y);
vec2 ref_br = clip_rect.zw + vec2(-radius.z, -radius.z);
vec2 ref_bl = clip_rect.xw + vec2( radius.w, -radius.w);
float d_tl = distance(pos, ref_tl);
float d_tr = distance(pos, ref_tr);
float d_br = distance(pos, ref_br);
float d_bl = distance(pos, ref_bl);
bool out0 = pos.x < ref_tl.x && pos.y < ref_tl.y && d_tl > radius.x;
bool out1 = pos.x > ref_tr.x && pos.y < ref_tr.y && d_tr > radius.y;
bool out2 = pos.x > ref_br.x && pos.y > ref_br.y && d_br > radius.z;
bool out3 = pos.x < ref_bl.x && pos.y > ref_bl.y && d_bl > radius.w;
// TODO(gw): Alpha anti-aliasing based on edge distance!
if (out0 || out1 || out2 || out3) {
discard;
}
}
float squared_distance_from_rect(vec2 p, vec2 origin, vec2 size) {
vec2 clamped = clamp(p, origin, origin + size);
return distance(clamped, p);
}
vec2 init_transform_fs(vec3 local_pos, vec4 local_rect, out float fragment_alpha) {
fragment_alpha = 1.0;
vec2 pos = local_pos.xy / local_pos.z;
float squared_distance = squared_distance_from_rect(pos, local_rect.xy, local_rect.zw);
if (squared_distance != 0) {
float delta = length(fwidth(local_pos.xy));
fragment_alpha = smoothstep(1.0, 0.0, squared_distance / delta * 2);
}
return pos;
}
#endif