summaryrefslogtreecommitdiffstats
path: root/gfx/wr/webrender/res/shared.glsl
blob: 4f21bd205d46b13ec59a184f2c99e4c82554df65 (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
/* 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/. */

#ifdef WR_FEATURE_TEXTURE_EXTERNAL
// Please check https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external_essl3.txt
// for this extension.
#extension GL_OES_EGL_image_external_essl3 : require
#endif

#ifdef WR_FEATURE_TEXTURE_EXTERNAL_ESSL1
// Some GLES 3 devices do not support GL_OES_EGL_image_external_essl3, so we
// must use GL_OES_EGL_image_external instead and make the shader ESSL1
// compatible.
#extension GL_OES_EGL_image_external : require
#endif

#ifdef WR_FEATURE_ADVANCED_BLEND
#extension GL_KHR_blend_equation_advanced : require
#endif

#ifdef WR_FEATURE_DUAL_SOURCE_BLENDING
#ifdef GL_ES
#extension GL_EXT_blend_func_extended : require
#else
#extension GL_ARB_explicit_attrib_location : require
#endif
#endif

#include base

#if defined(WR_FEATURE_TEXTURE_EXTERNAL_ESSL1)
#define TEX_SAMPLE(sampler, tex_coord) texture2D(sampler, tex_coord.xy)
#else
#define TEX_SAMPLE(sampler, tex_coord) texture(sampler, tex_coord.xy)
#endif

#if defined(WR_FEATURE_TEXTURE_EXTERNAL) && defined(PLATFORM_ANDROID)
// On some Mali GPUs we have encountered crashes in glDrawElements when using
// textureSize(samplerExternalOES) in a vertex shader without potentially
// sampling from the texture. This tricks the driver in to thinking the texture
// may be sampled from, avoiding the crash. See bug 1692848.
uniform bool u_mali_workaround_dummy;
#define TEX_SIZE(sampler) (u_mali_workaround_dummy ? ivec2(texture(sampler, vec2(0.0, 0.0)).rr) : textureSize(sampler, 0))
#else
#define TEX_SIZE(sampler) textureSize(sampler, 0)
#endif

//======================================================================================
// Vertex shader attributes and uniforms
//======================================================================================
#ifdef WR_VERTEX_SHADER
    // A generic uniform that shaders can optionally use to configure
    // an operation mode for this batch.
    uniform int uMode;

    // Uniform inputs
    uniform mat4 uTransform;       // Orthographic projection

    // Attribute inputs
    attribute vec2 aPosition;

    // get_fetch_uv is a macro to work around a macOS Intel driver parsing bug.
    // TODO: convert back to a function once the driver issues are resolved, if ever.
    // https://github.com/servo/webrender/pull/623
    // https://github.com/servo/servo/issues/13953
    // Do the division with unsigned ints because that's more efficient with D3D
    #define get_fetch_uv(i, vpi)  ivec2(int(vpi * (uint(i) % (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi))), int(uint(i) / (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi)))
#endif

//======================================================================================
// Fragment shader attributes and uniforms
//======================================================================================
#ifdef WR_FRAGMENT_SHADER
    // Uniform inputs

    // Fragment shader outputs
    #ifdef WR_FEATURE_ADVANCED_BLEND
        layout(blend_support_all_equations) out;
    #endif

    #if __VERSION__ == 100
        #define oFragColor gl_FragColor
    #elif defined(WR_FEATURE_DUAL_SOURCE_BLENDING)
        layout(location = 0, index = 0) out vec4 oFragColor;
        layout(location = 0, index = 1) out vec4 oFragBlend;
    #else
        out vec4 oFragColor;
    #endif

    // Write an output color in normal shaders.
    void write_output(vec4 color) {
        oFragColor = color;
    }

    #define EPSILON                     0.0001

    // "Show Overdraw" color. Premultiplied.
    #define WR_DEBUG_OVERDRAW_COLOR     vec4(0.110, 0.077, 0.027, 0.125)

    float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
        vec2 dir_to_p0 = p0 - p;
        return dot(normalize(perp_dir), dir_to_p0);
    }

// fwidth is not defined in ESSL 1, but that's okay because we don't need
// it for any ESSL 1 shader variants.
#if __VERSION__ != 100
    /// Find the appropriate half range to apply the AA approximation over.
    /// This range represents a coefficient to go from one CSS pixel to half a device pixel.
    vec2 compute_aa_range_xy(vec2 position) {
        return fwidth(position);
    }

    float compute_aa_range(vec2 position) {
        // The constant factor is chosen to compensate for the fact that length(fw) is equal
        // to sqrt(2) times the device pixel ratio in the typical case.
        //
        // This coefficient is chosen to ensure that any sample 0.5 pixels or more inside of
        // the shape has no anti-aliasing applied to it (since pixels are sampled at their center,
        // such a pixel (axis aligned) is fully inside the border). We need this so that antialiased
        // curves properly connect with non-antialiased vertical or horizontal lines, among other things.
        //
        // Lines over a half-pixel away from the pixel center *can* intersect with the pixel square;
        // indeed, unless they are horizontal or vertical, they are guaranteed to. However, choosing
        // a nonzero area for such pixels causes noticeable artifacts at the junction between an anti-
        // aliased corner and a straight edge.
        //
        // We may want to adjust this constant in specific scenarios (for example keep the principled
        // value for straight edges where we want pixel-perfect equivalence with non antialiased lines
        // when axis aligned, while selecting a larger and smoother aa range on curves).
        //
        // As a further optimization, we compute the reciprocal of this range, such that we
        // can then use the cheaper inversesqrt() instead of length(). This also elides a
        // division that would otherwise be necessary inside distance_aa.
        #ifdef SWGL
            // SWGL uses an approximation for fwidth() such that it returns equal x and y.
            // Thus, sqrt(2)/length(w) = sqrt(2)/sqrt(x*x + x*x) = recip(x).
            return recip(fwidth(position).x);
        #else
            // sqrt(2)/length(w) = inversesqrt(0.5 * dot(w, w))
            vec2 w = fwidth(position);
            return inversesqrt(0.5 * dot(w, w));
        #endif
    }
#endif

    /// Return the blending coefficient for distance antialiasing.
    ///
    /// 0.0 means inside the shape, 1.0 means outside.
    ///
    /// This makes the simplifying assumption that the area of a 1x1 pixel square
    /// under a line is reasonably similar to just the signed Euclidian distance
    /// from the center of the square to that line. This diverges slightly from
    /// better approximations of the exact area, but the difference between the
    /// methods is not perceptibly noticeable, while this approximation is much
    /// faster to compute.
    ///
    /// See the comments in `compute_aa_range()` for more information on the
    /// cutoff values of -0.5 and 0.5.
    float distance_aa_xy(vec2 aa_range, vec2 signed_distance) {
        // The aa_range is the raw per-axis filter width, so we need to divide
        // the local signed distance by the filter width to get an approximation
        // of screen distance.
        #ifdef SWGL
            // The SWGL fwidth() approximation returns uniform X and Y ranges.
            vec2 dist = signed_distance * recip(aa_range.x);
        #else
            vec2 dist = signed_distance / aa_range;
        #endif
        // Choose whichever axis is further outside the rectangle for AA.
        return clamp(0.5 - max(dist.x, dist.y), 0.0, 1.0);
    }

    float distance_aa(float aa_range, float signed_distance) {
        // The aa_range is already stored as a reciprocal with uniform scale,
        // so just multiply it, then use that for AA.
        float dist = signed_distance * aa_range;
        return clamp(0.5 - dist, 0.0, 1.0);
    }

    /// Component-wise selection.
    ///
    /// The idea of using this is to ensure both potential branches are executed before
    /// selecting the result, to avoid observable timing differences based on the condition.
    ///
    /// Example usage: color = if_then_else(LessThanEqual(color, vec3(0.5)), vec3(0.0), vec3(1.0));
    ///
    /// The above example sets each component to 0.0 or 1.0 independently depending on whether
    /// their values are below or above 0.5.
    ///
    /// This is written as a macro in order to work with vectors of any dimension.
    ///
    /// Note: Some older android devices don't support mix with bvec. If we ever run into them
    /// the only option we have is to polyfill it with a branch per component.
    #define if_then_else(cond, then_branch, else_branch) mix(else_branch, then_branch, cond)
#endif

//======================================================================================
// Shared shader uniforms
//======================================================================================
#ifdef WR_FEATURE_TEXTURE_2D
uniform sampler2D sColor0;
uniform sampler2D sColor1;
uniform sampler2D sColor2;
#elif defined WR_FEATURE_TEXTURE_RECT
uniform sampler2DRect sColor0;
uniform sampler2DRect sColor1;
uniform sampler2DRect sColor2;
#elif defined(WR_FEATURE_TEXTURE_EXTERNAL) || defined(WR_FEATURE_TEXTURE_EXTERNAL_ESSL1)
uniform samplerExternalOES sColor0;
uniform samplerExternalOES sColor1;
uniform samplerExternalOES sColor2;
#endif

#ifdef WR_FEATURE_DITHERING
uniform sampler2D sDither;
#endif

//======================================================================================
// Interpolator definitions
//======================================================================================

//======================================================================================
// VS only types and UBOs
//======================================================================================

//======================================================================================
// VS only functions
//======================================================================================