gecko-dev/gfx/wr/webrender/res/shared.glsl
Jamie Nicol ce7a78895a Bug 1556763 - Add layout qualifier to fragment shader output for advanced blend. r=kvark
When using an advanced blend equation, fragment shader output must be
marked with a matching layout qualifier. Not doing so was causing
subsequent glDraw* operations to fail.

This patch adds a new shader feature, WR_FEATURE_ADVANCED_BLEND, which
requires the necessary extension and adds the qualifier. Variants of
the brush_image shaders are created with this feature, and are used
whenever a brush_image shader is requested for BlendMode::Advanced.

Differential Revision: https://phabricator.services.mozilla.com/D34617

--HG--
extra : moz-landing-system : lando
2019-06-15 11:56:14 +00:00

242 lines
10 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/. */
#ifdef WR_FEATURE_PIXEL_LOCAL_STORAGE
// For now, we need both extensions here, in order to initialize
// the PLS to the current framebuffer color. In future, we can
// possibly remove that requirement, or at least support the
// other framebuffer fetch extensions that provide the same
// functionality.
#extension GL_EXT_shader_pixel_local_storage : require
#extension GL_ARM_shader_framebuffer_fetch : require
#endif
#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_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) || defined(WR_FEATURE_TEXTURE_RECT) || defined(WR_FEATURE_TEXTURE_2D)
#define TEX_SAMPLE(sampler, tex_coord) texture(sampler, tex_coord.xy)
#else
#define TEX_SAMPLE(sampler, tex_coord) texture(sampler, tex_coord)
#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
in vec3 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
#ifdef WR_FEATURE_PIXEL_LOCAL_STORAGE
// Define the storage class of the pixel local storage.
// If defined as writable, it's a compile time error to
// have a normal fragment output variable declared.
#if defined(PLS_READONLY)
#define PLS_BLOCK __pixel_local_inEXT
#elif defined(PLS_WRITEONLY)
#define PLS_BLOCK __pixel_local_outEXT
#else
#define PLS_BLOCK __pixel_localEXT
#endif
// The structure of pixel local storage. Right now, it's
// just the current framebuffer color. In future, we have
// (at least) 12 bytes of space we can store extra info
// here (such as clip mask values).
PLS_BLOCK FrameBuffer {
layout(rgba8) highp vec4 color;
} PLS;
#ifndef PLS_READONLY
// Write the output of a fragment shader to PLS. Applies
// premultipled alpha blending by default, since the blender
// is disabled when PLS is active.
// TODO(gw): Properly support alpha blend mode for webgl / canvas.
void write_output(vec4 color) {
PLS.color = color + PLS.color * (1.0 - color.a);
}
// Write a raw value straight to PLS, if the fragment shader has
// already applied blending.
void write_output_raw(vec4 color) {
PLS.color = color;
}
#endif
#ifndef PLS_WRITEONLY
// Retrieve the current framebuffer color. Useful in conjunction with
// the write_output_raw function.
vec4 get_current_framebuffer_color() {
return PLS.color;
}
#endif
#else
// Fragment shader outputs
#ifdef WR_FEATURE_ADVANCED_BLEND
layout(blend_support_all_equations) out;
#endif
#ifdef 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 (non-PLS) shaders.
void write_output(vec4 color) {
oFragColor = color;
}
#endif
#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);
}
/// 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.
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. 0.5/sqrt(2) = 0.35355.
//
// 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).
return 0.35355 * length(fwidth(position));
}
/// Return the blending coefficient for distance antialiasing.
///
/// 0.0 means inside the shape, 1.0 means outside.
///
/// This cubic polynomial approximates the area of a 1x1 pixel square under a
/// line, given the signed Euclidean distance from the center of the square to
/// that line. Calculating the *exact* area would require taking into account
/// not only this distance but also the angle of the line. However, in
/// practice, this complexity is not required, as the area is roughly the same
/// regardless of the angle.
///
/// The coefficients of this polynomial were determined through least-squares
/// regression and are accurate to within 2.16% of the total area of the pixel
/// square 95% of the time, with a maximum error of 3.53%.
///
/// See the comments in `compute_aa_range()` for more information on the
/// cutoff values of -0.5 and 0.5.
float distance_aa(float aa_range, float signed_distance) {
float dist = 0.5 * signed_distance / aa_range;
if (dist <= -0.5 + EPSILON)
return 1.0;
if (dist >= 0.5 - EPSILON)
return 0.0;
return 0.5 + dist * (0.8431027 * dist * dist - 1.14453603);
}
/// 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
uniform samplerExternalOES sColor0;
uniform samplerExternalOES sColor1;
uniform samplerExternalOES sColor2;
#else
uniform sampler2DArray sColor0;
uniform sampler2DArray sColor1;
uniform sampler2DArray sColor2;
#endif
#ifdef WR_FEATURE_DITHERING
uniform sampler2D sDither;
#endif
//======================================================================================
// Interpolator definitions
//======================================================================================
//======================================================================================
// VS only types and UBOs
//======================================================================================
//======================================================================================
// VS only functions
//======================================================================================