gecko-dev/gfx/webrender/res/brush_image.glsl

233 строки
6.7 KiB
GLSL

/* 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 VECS_PER_SPECIFIC_BRUSH 3
#include shared,prim_shared,brush
#ifdef WR_FEATURE_ALPHA_PASS
varying vec2 vLocalPos;
#endif
// Interpolated uv coordinates in xy, and layer in z.
varying vec3 vUv;
// Normalized bounds of the source image in the texture.
flat varying vec4 vUvBounds;
// Normalized bounds of the source image in the texture, adjusted to avoid
// sampling artifacts.
flat varying vec4 vUvSampleBounds;
#ifdef WR_FEATURE_ALPHA_PASS
flat varying vec4 vColor;
flat varying vec2 vMaskSwizzle;
flat varying vec2 vTileRepeat;
#endif
#ifdef WR_VERTEX_SHADER
struct ImageBrushData {
vec4 color;
vec4 background_color;
vec2 stretch_size;
};
ImageBrushData fetch_image_data(int address) {
vec4[3] raw_data = fetch_from_gpu_cache_3(address);
ImageBrushData data = ImageBrushData(
raw_data[0],
raw_data[1],
raw_data[2].xy
);
return data;
}
void brush_vs(
VertexInfo vi,
int prim_address,
RectWithSize prim_rect,
RectWithSize segment_rect,
ivec4 user_data,
mat4 transform,
PictureTask pic_task,
int brush_flags,
vec4 segment_data
) {
ImageBrushData image_data = fetch_image_data(prim_address);
// If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use
// non-normalized texture coordinates.
#ifdef WR_FEATURE_TEXTURE_RECT
vec2 texture_size = vec2(1, 1);
#else
vec2 texture_size = vec2(textureSize(sColor0, 0));
#endif
ImageResource res = fetch_image_resource(user_data.w);
vec2 uv0 = res.uv_rect.p0;
vec2 uv1 = res.uv_rect.p1;
RectWithSize local_rect = prim_rect;
vec2 stretch_size = image_data.stretch_size;
// If this segment should interpolate relative to the
// segment, modify the parameters for that.
if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
local_rect = segment_rect;
stretch_size = local_rect.size;
if ((brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_X) != 0) {
stretch_size.x = (segment_data.z - segment_data.x);
}
if ((brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_Y) != 0) {
stretch_size.y = (segment_data.w - segment_data.y);
}
// If the extra data is a texel rect, modify the UVs.
if ((brush_flags & BRUSH_FLAG_TEXEL_RECT) != 0) {
uv0 = res.uv_rect.p0 + segment_data.xy;
uv1 = res.uv_rect.p0 + segment_data.zw;
}
}
vUv.z = res.layer;
// Handle case where the UV coords are inverted (e.g. from an
// external image).
vec2 min_uv = min(uv0, uv1);
vec2 max_uv = max(uv0, uv1);
vUvSampleBounds = vec4(
min_uv + vec2(0.5),
max_uv - vec2(0.5)
) / texture_size.xyxy;
vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
#ifdef WR_FEATURE_ALPHA_PASS
int color_mode = user_data.x;
int raster_space = user_data.y;
if (color_mode == COLOR_MODE_FROM_PASS) {
color_mode = uMode;
}
// Derive the texture coordinates for this image, based on
// whether the source image is a local-space or screen-space
// image.
switch (raster_space) {
case RASTER_SCREEN: {
// Since the screen space UVs specify an arbitrary quad, do
// a bilinear interpolation to get the correct UV for this
// local position.
ImageResourceExtra extra_data = fetch_image_resource_extra(user_data.w);
vec2 x = mix(extra_data.st_tl, extra_data.st_tr, f.x);
vec2 y = mix(extra_data.st_bl, extra_data.st_br, f.x);
f = mix(x, y, f.y);
break;
}
default:
break;
}
#endif
// Offset and scale vUv here to avoid doing it in the fragment shader.
vec2 repeat = local_rect.size / stretch_size;
vUv.xy = mix(uv0, uv1, f) - min_uv;
vUv.xy /= texture_size;
vUv.xy *= repeat.xy;
#ifdef WR_FEATURE_TEXTURE_RECT
vUvBounds = vec4(0.0, 0.0, vec2(textureSize(sColor0)));
#else
vUvBounds = vec4(min_uv, max_uv) / texture_size.xyxy;
#endif
#ifdef WR_FEATURE_ALPHA_PASS
vTileRepeat = repeat.xy;
switch (color_mode) {
case COLOR_MODE_ALPHA:
case COLOR_MODE_BITMAP:
vMaskSwizzle = vec2(0.0, 1.0);
vColor = image_data.color;
break;
case COLOR_MODE_SUBPX_BG_PASS2:
case COLOR_MODE_SUBPX_DUAL_SOURCE:
case COLOR_MODE_IMAGE:
vMaskSwizzle = vec2(1.0, 0.0);
vColor = image_data.color;
break;
case COLOR_MODE_SUBPX_CONST_COLOR:
case COLOR_MODE_SUBPX_BG_PASS0:
case COLOR_MODE_COLOR_BITMAP:
vMaskSwizzle = vec2(1.0, 0.0);
vColor = vec4(image_data.color.a);
break;
case COLOR_MODE_SUBPX_BG_PASS1:
vMaskSwizzle = vec2(-1.0, 1.0);
vColor = vec4(image_data.color.a) * image_data.background_color;
break;
default:
vMaskSwizzle = vec2(0.0);
vColor = vec4(1.0);
}
vLocalPos = vi.local_pos;
#endif
}
#endif
#ifdef WR_FRAGMENT_SHADER
Fragment brush_fs() {
vec2 uv_size = vUvBounds.zw - vUvBounds.xy;
#ifdef WR_FEATURE_ALPHA_PASS
// This prevents the uv on the top and left parts of the primitive that was inflated
// for anti-aliasing purposes from going beyound the range covered by the regular
// (non-inflated) primitive.
vec2 local_uv = max(vUv.xy, vec2(0.0));
// Handle horizontal and vertical repetitions.
vec2 repeated_uv = mod(local_uv, uv_size) + vUvBounds.xy;
// This takes care of the bottom and right inflated parts.
// We do it after the modulo because the latter wraps around the values exactly on
// the right and bottom edges, which we do not want.
if (local_uv.x >= vTileRepeat.x * uv_size.x) {
repeated_uv.x = vUvBounds.z;
}
if (local_uv.y >= vTileRepeat.y * uv_size.y) {
repeated_uv.y = vUvBounds.w;
}
#else
// Handle horizontal and vertical repetitions.
vec2 repeated_uv = mod(vUv.xy, uv_size) + vUvBounds.xy;
#endif
// Clamp the uvs to avoid sampling artifacts.
vec2 uv = clamp(repeated_uv, vUvSampleBounds.xy, vUvSampleBounds.zw);
vec4 texel = TEX_SAMPLE(sColor0, vec3(uv, vUv.z));
Fragment frag;
#ifdef WR_FEATURE_ALPHA_PASS
float alpha = init_transform_fs(vLocalPos);
texel.rgb = texel.rgb * vMaskSwizzle.x + texel.aaa * vMaskSwizzle.y;
vec4 alpha_mask = texel * alpha;
frag.color = vColor * alpha_mask;
#ifdef WR_FEATURE_DUAL_SOURCE_BLENDING
frag.blend = alpha_mask * vColor.a;
#endif
#else
frag.color = texel;
#endif
return frag;
}
#endif