summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/sksl/sksl_gpu.sksl
blob: 80ac013a55f3661c98cae60d7ef33d2d65a40890 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
// Not exposed in shared module

$pure $genIType mix($genIType x, $genIType y, $genBType a);
$pure $genBType mix($genBType x, $genBType y, $genBType a);
$pure $genType fma($genType a, $genType b, $genType c);
$pure $genHType fma($genHType a, $genHType b, $genHType c);
      $genType frexp($genType x, out $genIType exp);
      $genHType frexp($genHType x, out $genIType exp);
$pure $genType ldexp($genType x, in $genIType exp);
$pure $genHType ldexp($genHType x, in $genIType exp);

$pure uint packSnorm2x16(float2 v);
$pure uint packUnorm4x8(float4 v);
$pure uint packSnorm4x8(float4 v);
$pure float2 unpackSnorm2x16(uint p);
$pure float4 unpackUnorm4x8(uint p);
$pure float4 unpackSnorm4x8(uint p);
$pure uint packHalf2x16(float2 v);
$pure float2 unpackHalf2x16(uint v);

$pure $genIType bitCount($genIType value);
$pure $genIType bitCount($genUType value);
$pure $genIType findLSB($genIType value);
$pure $genIType findLSB($genUType value);
$pure $genIType findMSB($genIType value);
$pure $genIType findMSB($genUType value);

$pure sampler2D makeSampler2D(texture2D texture, sampler s);

$pure half4 sample(sampler2D s, float2 P);
$pure half4 sample(sampler2D s, float3 P);
$pure half4 sample(sampler2D s, float3 P, float bias);

$pure half4 sample(samplerExternalOES s, float2 P);
$pure half4 sample(samplerExternalOES s, float2 P, float bias);

$pure half4 sample(sampler2DRect s, float2 P);
$pure half4 sample(sampler2DRect s, float3 P);

$pure half4 sampleLod(sampler2D s, float2 P, float lod);
$pure half4 sampleLod(sampler2D s, float3 P, float lod);

$pure half4 sampleGrad(sampler2D s, float2, float2 dPdx, float2 dPdy);

// Currently we do not support the generic types of loading subpassInput so we have some explicit
// versions that we currently use
$pure half4 subpassLoad(subpassInput subpass);
$pure half4 subpassLoad(subpassInputMS subpass, int sample);

/** Atomically loads the value from `a` and returns it. */
$pure uint atomicLoad(atomicUint a);

/** Atomically stores the value of `value` to `a` */
void atomicStore(atomicUint a, uint value);

/**
 * Performs an atomic addition of `value` to the contents of `a` and returns the original contents
 * of `a` from before the addition occurred.
 */
uint atomicAdd(atomicUint a, uint value);

// Definitions of functions implementing all of the SkBlendMode blends.

$pure half4 blend_clear(half4 src, half4 dst) { return half4(0); }

$pure half4 blend_src(half4 src, half4 dst) { return src; }

$pure half4 blend_dst(half4 src, half4 dst) { return dst; }

$pure half4 blend_src_over(half4 src, half4 dst) { return src + (1 - src.a)*dst; }

$pure half4 blend_dst_over(half4 src, half4 dst) { return (1 - dst.a)*src + dst; }

$pure half4 blend_src_in(half4 src, half4 dst) { return src*dst.a; }

$pure half4 blend_dst_in(half4 src, half4 dst) { return dst*src.a; }

$pure half4 blend_src_out(half4 src, half4 dst) { return (1 - dst.a)*src; }

$pure half4 blend_dst_out(half4 src, half4 dst) { return (1 - src.a)*dst; }

$pure half4 blend_src_atop(half4 src, half4 dst) { return dst.a*src + (1 - src.a)*dst; }

$pure half4 blend_dst_atop(half4 src, half4 dst)  { return  (1 - dst.a) * src + src.a*dst; }

$pure half4 blend_xor(half4 src, half4 dst) { return (1 - dst.a)*src + (1 - src.a)*dst; }

$pure half4 blend_plus(half4 src, half4 dst) { return min(src + dst, 1); }

// This multi-purpose Porter-Duff blend function can perform any of the thirteen blends above,
// when passed one of the following values for BlendOp:
// - Clear:   half4(0, 0,  0,  0)
// - Src:     half4(1, 0,  0,  0)
// - Dst:     half4(0, 1,  0,  0)
// - SrcOver: half4(1, 0,  0, -1)
// - DstOver: half4(0, 1, -1,  0)
// - SrcIn:   half4(0, 0,  1,  0)
// - DstIn:   half4(0, 0,  0,  1)
// - SrcOut:  half4(0, 0, -1,  0)
// - DstOut:  half4(0, 0,  0, -1)
// - SrcATop: half4(0, 0,  1, -1)
// - DstATop: half4(0, 0, -1,  1)
// - Xor:     half4(0, 0, -1, -1)
// - Plus:    half4(1, 1,  0,  0)
$pure half4 blend_porter_duff(half4 blendOp, half4 src, half4 dst) {
    half2 coeff = blendOp.xy + (blendOp.zw * (half2(dst.a, src.a) + min(blendOp.zw, 0)));
    return min(half4(1), src * coeff.x + dst * coeff.y);
}

$pure half4 blend_modulate(half4 src, half4 dst) { return src*dst; }

$pure half4 blend_screen(half4 src, half4 dst) { return src + (1 - src)*dst; }

$pure half $blend_overlay_component(half2 s, half2 d) {
    return (2*d.x <= d.y) ? 2*s.x*d.x
                          : s.y*d.y - 2*(d.y - d.x)*(s.y - s.x);
}

$pure half4 blend_overlay(half4 src, half4 dst) {
    half4 result = half4($blend_overlay_component(src.ra, dst.ra),
                         $blend_overlay_component(src.ga, dst.ga),
                         $blend_overlay_component(src.ba, dst.ba),
                         src.a + (1 - src.a)*dst.a);
    result.rgb += dst.rgb*(1 - src.a) + src.rgb*(1 - dst.a);
    return result;
}

$pure half4 blend_overlay(half flip, half4 a, half4 b) {
    return blend_overlay(bool(flip) ? b : a, bool(flip) ? a : b);
}

$pure half4 blend_lighten(half4 src, half4 dst) {
    half4 result = blend_src_over(src, dst);
    result.rgb = max(result.rgb, (1 - dst.a)*src.rgb + dst.rgb);
    return result;
}

$pure half4 blend_darken(half mode /* darken: 1, lighten: -1 */, half4 src, half4 dst) {
    half4 a = blend_src_over(src, dst);
    half3 b = (1 - dst.a) * src.rgb + dst.rgb;  // DstOver.rgb
    a.rgb = mode * min(a.rgb * mode, b.rgb * mode);
    return a;
}

$pure half4 blend_darken(half4 src, half4 dst) {
   return blend_darken(1, src, dst);
}

const half $kGuardedDivideEpsilon = sk_Caps.mustGuardDivisionEvenAfterExplicitZeroCheck
                                        ? 0.00000001
                                        : 0.0;

$pure inline half $guarded_divide(half n, half d) {
    return n / (d + $kGuardedDivideEpsilon);
}

$pure inline half3 $guarded_divide(half3 n, half d) {
    return n / (d + $kGuardedDivideEpsilon);
}

$pure half $color_dodge_component(half2 s, half2 d) {
    if (d.x == 0) {
        return s.x*(1 - d.y);
    } else {
        half delta = s.y - s.x;
        if (delta == 0) {
             return s.y*d.y + s.x*(1 - d.y) + d.x*(1 - s.y);
        } else {
            delta = min(d.y, $guarded_divide(d.x*s.y, delta));
            return delta*s.y + s.x*(1 - d.y) + d.x*(1 - s.y);
        }
    }
}

$pure half4 blend_color_dodge(half4 src, half4 dst) {
    return half4($color_dodge_component(src.ra, dst.ra),
                 $color_dodge_component(src.ga, dst.ga),
                 $color_dodge_component(src.ba, dst.ba),
                 src.a + (1 - src.a)*dst.a);
}

$pure half $color_burn_component(half2 s, half2 d) {
    if (d.y == d.x) {
        return s.y*d.y + s.x*(1 - d.y) + d.x*(1 - s.y);
    } else if (s.x == 0) {
        return d.x*(1 - s.y);
    } else {
        half delta = max(0, d.y - $guarded_divide((d.y - d.x)*s.y, s.x));
        return delta*s.y + s.x*(1 - d.y) + d.x*(1 - s.y);
    }
}

$pure half4 blend_color_burn(half4 src, half4 dst) {
    return half4($color_burn_component(src.ra, dst.ra),
                 $color_burn_component(src.ga, dst.ga),
                 $color_burn_component(src.ba, dst.ba),
                 src.a + (1 - src.a)*dst.a);
}

$pure half4 blend_hard_light(half4 src, half4 dst) {
    return blend_overlay(dst, src);
}

$pure half $soft_light_component(half2 s, half2 d) {
    if (2*s.x <= s.y) {
        return $guarded_divide(d.x*d.x*(s.y - 2*s.x), d.y) + (1 - d.y)*s.x + d.x*(-s.y + 2*s.x + 1);
    } else if (4.0 * d.x <= d.y) {
        half DSqd = d.x*d.x;
        half DCub = DSqd*d.x;
        half DaSqd = d.y*d.y;
        half DaCub = DaSqd*d.y;
        return $guarded_divide(DaSqd*(s.x - d.x*(3*s.y - 6*s.x - 1)) + 12*d.y*DSqd*(s.y - 2*s.x)
                               - 16*DCub * (s.y - 2*s.x) - DaCub*s.x, DaSqd);
    } else {
        return d.x*(s.y - 2*s.x + 1) + s.x - sqrt(d.y*d.x)*(s.y - 2*s.x) - d.y*s.x;
    }
}

$pure half4 blend_soft_light(half4 src, half4 dst) {
    return (dst.a == 0) ? src : half4($soft_light_component(src.ra, dst.ra),
                                      $soft_light_component(src.ga, dst.ga),
                                      $soft_light_component(src.ba, dst.ba),
                                      src.a + (1 - src.a)*dst.a);
}

$pure half4 blend_difference(half4 src, half4 dst) {
    return half4(src.rgb + dst.rgb - 2*min(src.rgb*dst.a, dst.rgb*src.a),
                 src.a + (1 - src.a)*dst.a);
}

$pure half4 blend_exclusion(half4 src, half4 dst) {
    return half4(dst.rgb + src.rgb - 2*dst.rgb*src.rgb, src.a + (1 - src.a)*dst.a);
}

$pure half4 blend_multiply(half4 src, half4 dst) {
    return half4((1 - src.a)*dst.rgb + (1 - dst.a)*src.rgb + src.rgb*dst.rgb,
                 src.a + (1 - src.a)*dst.a);
}

$pure half $blend_color_luminance(half3 color) { return dot(half3(0.3, 0.59, 0.11), color); }

$pure half3 $blend_set_color_luminance(half3 hueSatColor, half alpha, half3 lumColor) {
    half lum = $blend_color_luminance(lumColor);
    half3 result = lum - $blend_color_luminance(hueSatColor) + hueSatColor;
    half minComp = min(min(result.r, result.g), result.b);
    half maxComp = max(max(result.r, result.g), result.b);
    if (minComp < 0 && lum != minComp) {
        result = lum + (result - lum) * $guarded_divide(lum, (lum - minComp));
    }
    if (maxComp > alpha && maxComp != lum) {
        result = lum + $guarded_divide((result - lum) * (alpha - lum), (maxComp - lum));
    }
    return result;
}

$pure half $blend_color_saturation(half3 color) {
    return max(max(color.r, color.g), color.b) - min(min(color.r, color.g), color.b);
}

$pure half3 $blend_set_color_saturation(half3 color, half3 satColor) {
    half mn = min(min(color.r, color.g), color.b);
    half mx = max(max(color.r, color.g), color.b);

    return (mx > mn) ? ((color - mn) * $blend_color_saturation(satColor)) / (mx - mn)
                     : half3(0);
}

$pure half4 blend_hslc(half2 flipSat, half4 src, half4 dst) {
    half alpha = dst.a * src.a;
    half3 sda = src.rgb * dst.a;
    half3 dsa = dst.rgb * src.a;
    half3 l = bool(flipSat.x) ? dsa : sda;
    half3 r = bool(flipSat.x) ? sda : dsa;
    if (bool(flipSat.y)) {
        l = $blend_set_color_saturation(l, r);
        r = dsa;
    }
    return half4($blend_set_color_luminance(l, alpha, r) + dst.rgb - dsa + src.rgb - sda,
                 src.a + dst.a - alpha);
}

$pure half4 blend_hue(half4 src, half4 dst) {
    return blend_hslc(half2(0, 1), src, dst);
}

$pure half4 blend_saturation(half4 src, half4 dst) {
    return blend_hslc(half2(1), src, dst);
}

$pure half4 blend_color(half4 src, half4 dst)  {
    return blend_hslc(half2(0), src, dst);
}

$pure half4 blend_luminosity(half4 src, half4 dst) {
    return blend_hslc(half2(1, 0), src, dst);
}

$pure float2 proj(float3 p) { return p.xy / p.z; }

// Implement cross() as a determinant to communicate our intent more clearly to the compiler.
// NOTE: Due to precision issues, it might be the case that cross(a, a) != 0.
$pure float cross_length_2d(float2 a, float2 b) {
    return determinant(float2x2(a, b));
}

$pure half cross_length_2d(half2 a, half2 b) {
    return determinant(half2x2(a, b));
}

$pure float2 perp(float2 v) {
    return float2(-v.y, v.x);
}

$pure half2 perp(half2 v) {
    return half2(-v.y, v.x);
}

// Returns a bias given a scale factor, such that 'scale * (dist + bias)' converts the distance to
// a per-pixel coverage value, automatically widening the visible coverage ramp for subpixel
// dimensions. The 'scale' must already be equal to the narrowest dimension of the shape and clamped
// to [0, 1.0].
$pure float coverage_bias(float scale) {
    return 1.0 - 0.5 * scale;
}