README.md
1Gradients on the GPU
2====================
3
4Gradients can be thought of, at a very high level, as three pieces:
5
61. A color interpolator ("colorizer") that is one dimensional, returning a color
7 for an interpolant value "t" within the range [0.0, 1.0]. This encapsulates
8 the definition of specific color stops and how to wrap, tile, or clamp out
9 of bound inputs. A color interpolator will be named `GrXxxxxGradientColorizer`.
102. A layout that converts from 2D geometry/position to the one dimensional
11 domain of the color interpolator. This is how a linear or radial gradient
12 distinguishes itself. When designing a new gradient shape, this is the
13 component that will need to be implemented. A layout will generally be
14 named `GrYyyyyGradientLayout`.
153. A top-level effect that composes the layout and color interpolator together.
16 This processor is also responsible for implementing the clamping behavior,
17 which is abstracted away from both the layout and colorization.
18
19`GrClampedGradientEffect` handles clamped and decal tile modes, while
20`GrTiledGradientEffect` implements repeat and mirror tile modes. The
21`GrClampedGradientEffect` requires border colors to be specified outside of its
22colorizer child, but these border colors may be defined by the gradient color
23stops. Both of these top-level effects delegate calculating the t interpolant to
24the layout child processor, then perform their respective tile mode operations,
25and finally convert the tiled t value (guaranteed to be within 0 and 1) into an
26output color using the colorizer child processor.
27
28Fragment processors only support returning colors; conceptually, however,
29layout processors need to generate an interpolant, not a color. So the
30layout processor encodes its result into a color as follows:
31
32- `sk_OutColor.r`: computed t interpolant [0.0, 1.0], untiled
33- `sk_OutColor.g`: Positive value = render, negative value = discard pixel.
34- `sk_OutColor.b`: unused
35- `sk_OutColor.a`: unused
36
37Layouts can report "invalid gradient location" by outputting a negative value
38into the `sk_OutColor.g` component. (Currently, the two-point conical gradient
39does this.) When this happens, the top-level effect immediately returns transparent
40black and does not invoke the colorizer at all. When the gradient location is valid,
41the top-level effect samples from the colorizer at the explicit coordinate (t, 0). The
42y coordinate will always be zero and can be ignored by the colorizer.
43
44There are several hand-written colorizers for analytic color cases; these are
45evaluated directly in the shader. Generated texture maps can also be used to
46colorize a gradient; in this case, a `GrTextureEffect` will be used as the colorizer.
47
48`GrGradientShader` provides static factory functions to create
49`GrFragmentProcessor` graphs that reproduce a particular `SkGradientShader`.
50
51Optimization Flags
52==================
53
54At an abstract level, gradient shaders are compatible with coverage as alpha
55and, under certain conditions, preserve opacity when the inputs are opaque. To
56reduce the amount of duplicate code and boilerplate, these optimization
57decisions are implemented in the top-level effects and not in the colorizers. It
58is assumed that all colorizer FPs will be compatible with coverage as alpha and
59will preserve opacity if input colors are opaque. Since this is assumed by the
60top-level effects, they do not need to report these optimizations or check input
61opacity (this does mean if the colorizers are used independently from the
62top-level effect shader that the reported flags might not be optimal, but since
63that is unlikely, this convention really simplifies the colorizer
64implementations).
65
66Unlike colorizers, which do not need to report any optimization flags, layout
67FPs should report opacity preserving optimizations because they can impact the
68opacity of a pixel outside of how the gradient would otherwise color it.
69Layouts that potentially reject pixels (i.e. could output a negative y value)
70must not report kPreservesOpaqueInput_OptimizationFlag. Layouts that never
71reject a pixel should report kPreservesOpaqueInput_OptimizationFlag since the
72top-level effects can optimize away checking if the layout rejects a pixel.
73