pathfinder/shaders/gles2/common.inc.glsl

184 lines
5.9 KiB
GLSL

// pathfinder/shaders/gles2/common.inc.glsl
//
// Copyright (c) 2017 Mozilla Foundation
#version 100
#extension GL_EXT_draw_buffers : require
#extension GL_EXT_frag_depth : require
#define LCD_FILTER_FACTOR_0 (86.0 / 255.0)
#define LCD_FILTER_FACTOR_1 (77.0 / 255.0)
#define LCD_FILTER_FACTOR_2 (8.0 / 255.0)
#define MAX_PATHS 65536
#define EPSILON 0.001
precision highp float;
// https://stackoverflow.com/a/36078859
int imod(int ia, int ib) {
float a = float(ia), b = float(ib);
float m = a - floor((a + 0.5) / b) * b;
return int(floor(m + 0.5));
}
bool xor(bool a, bool b) {
return (a && !b) || (!a && b);
}
float det2(vec2 a, vec2 b) {
return a.x * b.y - b.x * a.y;
}
vec2 transformVertexPosition(vec2 position, mat4 transform) {
return (transform * vec4(position, 0.0, 1.0)).xy;
}
vec2 transformVertexPositionST(vec2 position, vec4 stTransform) {
return position * stTransform.xy + stTransform.zw;
}
vec2 convertScreenToClipSpace(vec2 position, ivec2 framebufferSize) {
return position / vec2(framebufferSize) * 2.0 - 1.0;
}
float convertPathIndexToViewportDepthValue(int pathIndex) {
return mix(-1.0, 1.0, float(pathIndex) / float(MAX_PATHS));
}
float convertPathIndexToWindowDepthValue(int pathIndex) {
return float(pathIndex) / float(MAX_PATHS);
}
bool computeQuadPosition(out vec2 outPosition,
inout vec2 leftPosition,
inout vec2 rightPosition,
vec2 quadPosition,
ivec2 framebufferSize,
vec4 transform) {
leftPosition = transformVertexPositionST(leftPosition, transform);
rightPosition = transformVertexPositionST(rightPosition, transform);
if (abs(leftPosition.x - rightPosition.x) <= EPSILON) {
outPosition = vec2(0.0);
return false;
}
vec2 verticalExtents = vec2(min(leftPosition.y, rightPosition.y),
max(leftPosition.y, rightPosition.y));
vec4 roundedExtents = vec4(floor(vec2(leftPosition.x, verticalExtents.x)),
ceil(vec2(rightPosition.x, verticalExtents.y)));
vec2 position = mix(roundedExtents.xy, roundedExtents.zw, quadPosition);
outPosition = convertScreenToClipSpace(position, framebufferSize);
return true;
}
// Computes the area of the polygon covering the pixel with the given boundaries.
//
// * `p0` and `p1` are the endpoints of the line.
// * `spanP0` and `spanP1` are the endpoints of the line, clipped to the left and right edges of
// the pixel.
// * `t` is the times of `spanP0` and `spanP1` relative to `p0` and `p1` respectively.
// * `pixelExtents` are the boundaries of the pixel (left/right/bottom/top respectively).
// * `p` and `q` are the Liang-Barsky clipping distances.
// * `lowerPart` is true if this is the lower half of the B-quad.
//
// FIXME(pcwalton): This API is ludicrous. Clean it up!
float computeCoverage(vec2 p0,
vec2 p1,
vec2 spanP0,
vec2 spanP1,
vec2 t,
vec4 pixelExtents,
vec4 p,
vec4 q,
bool lowerPart) {
bool slopeNegative = p0.y > p1.y;
// Clip to the bottom and top.
if (p.z != 0.0) {
vec2 tVertical = q.zw / p.zw;
if (slopeNegative)
tVertical.xy = tVertical.yx; // FIXME(pcwalton): Can this be removed?
t = vec2(max(t.x, tVertical.x), min(t.y, tVertical.y));
}
// If the line doesn't pass through this pixel, detect that and bail.
if (t.x >= t.y) {
bool fill = lowerPart ? spanP0.y < pixelExtents.z : spanP0.y > pixelExtents.w;
return fill ? spanP1.x - spanP0.x : 0.0;
}
// Calculate A2.x.
float a2x;
if (xor(lowerPart, slopeNegative)) {
a2x = spanP0.x;
t.xy = t.yx;
} else {
a2x = spanP1.x;
}
// Calculate A3.y.
float a3y = lowerPart ? pixelExtents.w : pixelExtents.z;
// Calculate A0-A5.
vec2 a0 = p0 + p.yw * t.x;
vec2 a1 = p0 + p.yw * t.y;
vec2 a2 = vec2(a2x, a1.y);
vec2 a3 = vec2(a2x, a3y);
vec2 a4 = vec2(a0.x, a3y);
// Calculate area with the shoelace formula.
float area = det2(a0, a1) + det2(a1, a2) + det2(a2, a3) + det2(a3, a4) + det2(a4, a0);
return area * (slopeNegative ? 0.5 : -0.5);
}
// https://www.freetype.org/freetype2/docs/reference/ft2-lcd_filtering.html
float lcdFilter(float shadeL2, float shadeL1, float shade0, float shadeR1, float shadeR2) {
return LCD_FILTER_FACTOR_2 * shadeL2 +
LCD_FILTER_FACTOR_1 * shadeL1 +
LCD_FILTER_FACTOR_0 * shade0 +
LCD_FILTER_FACTOR_1 * shadeR1 +
LCD_FILTER_FACTOR_2 * shadeR2;
}
int unpackUInt16(vec2 packedValue) {
ivec2 valueBytes = ivec2(floor(packedValue * 255.0));
return valueBytes.y * 256 + valueBytes.x;
}
int unpackUInt32Attribute(vec2 packedValue) {
ivec2 valueWords = ivec2(packedValue);
return valueWords.y * 65536 + valueWords.x;
}
vec4 fetchFloat4Data(sampler2D dataTexture, int index, ivec2 dimensions) {
ivec2 pixelCoord = ivec2(imod(index, dimensions.x), index / dimensions.x);
return texture2D(dataTexture, (vec2(pixelCoord) + 0.5) / vec2(dimensions));
}
vec4 fetchFloat4NormIndexedData(sampler2D dataTexture, float normIndex, ivec2 dimensions) {
return fetchFloat4Data(dataTexture, int(normIndex * float(dimensions.x)), dimensions);
}
vec2 fetchFloat2Data(sampler2D dataTexture, int index, ivec2 dimensions) {
vec4 float4Data = fetchFloat4Data(dataTexture, index / 2, dimensions);
return index / 2 * 2 == index ? float4Data.xy : float4Data.zw;
}
int fetchUInt16Data(sampler2D dataTexture, int index, ivec2 dimensions) {
return unpackUInt16(fetchFloat2Data(dataTexture, index, dimensions));
}
vec2 packPathID(int pathID) {
return vec2(imod(pathID, 256), pathID / 256) / 255.0;
}
int unpackPathID(vec2 packedPathID) {
return unpackUInt16(packedPathID);
}