diff --git a/site/docs/user/sksl.md b/site/docs/user/sksl.md
index 5a6f9f031d..64007e5fb8 100644
--- a/site/docs/user/sksl.md
+++ b/site/docs/user/sksl.md
@@ -7,8 +7,9 @@ linkTitle: 'SkSL'
**SkSL** is Skia's
[shading language](https://en.wikipedia.org/wiki/Shading_language).
-**`SkRuntimeEffect`** is a Skia C++ object that can be used to create `SkShader`
-and `SkColorFilter` objects with behavior controlled by SkSL code.
+**`SkRuntimeEffect`** is a Skia C++ object that can be used to create
+`SkShader`, `SkColorFilter`, and `SkBlender` objects with behavior controlled by
+SkSL code.
You can experiment with SkSL at https://shaders.skia.org/. The syntax is very
similar to GLSL. When using SkSL effects in your Skia application, there are
@@ -18,26 +19,65 @@ stage of the
[GPU pipeline](https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview).
With SkSL, you are programming a stage of the Skia pipeline.**
+In particular, a GLSL fragment shader controls the entire behavior of the GPU
+between the rasterizer and the blending hardware. That shader does all of the
+work to compute a color, and the color it generates is exactly what is fed to
+the fixed-function blending stage of the pipeline.
+
+SkSL effects exist as part of the larger Skia pipeline. When you issue a canvas
+drawing operation, Skia (generally) assembles a single GPU fragment shader to do
+all of the required work. This shader typically includes several pieces. For
+example, it might include:
+
+- Evaluating whether a pixel falls inside or outside of the shape being drawn
+ (or on the border, where it might apply antialiasing).
+- Evaluating whether a pixel falls inside or outside of the clipping region
+ (again, with possible antialiasing logic for border pixels).
+- Logic for the `SkShader` on the `SkPaint`. The `SkShader` can actually be a
+ tree of objects (due to `SkShaders::Blend` and other features described
+ below).
+- Similar logic for the `SkColorFilter` (which can also be a tree, due to
+ `SkColorFilters::Compose`, `SkColorFilters::Blend`, and features described
+ below).
+- Blending code (for certain `SkBlendMode`s, or for custom blending specified
+ with `SkPaint::setBlender`).
+
+Even if the `SkPaint` has a complex tree of objects in the `SkShader`,
+`SkColorFilter`, or `SkBlender` fields, there is still only a *single* GPU
+fragment shader. Each node in that tree creates a single function. The clipping
+code and geometry code each create a function. The blending code might create a
+function. The overall fragment shader then calls all of these functions (which
+may call other functions, e.g. in the case of an `SkShader` tree).
+
+**Your SkSL effect contributes a function to the GPU's fragment shader.**
+
---
-## Sampling other SkShaders
+## Evaluating (sampling) other SkShaders
In GLSL, a fragment shader can sample a texture. With runtime effects, the
-object that you bind (in C++) and sample (in SkSL) is an `SkShader`. Skia has
-simple methods for creating an `SkShader` from an `SkImage`, so it's easy to use
-images in your runtime effects:
+object that you bind (in C++) is an `SkShader`, represented by a `shader` in
+SkSL. To make it clear that you are operating on an object that will emit its
+own shader code, you don't use `sample`. Instead, the `shader` object has a
+`.eval()` method. Regardless, Skia has simple methods for creating an
+`SkShader` from an `SkImage`, so it's easy to use images in your runtime
+effects:
-
+
-Because the object you bind and sample is an `SkShader`, you can directly use
-any Skia shader, without necessarily turning it into an image (texture) first.
-For example, you can sample a linear gradient:
+Because the object you bind and evaluate is an `SkShader`, you can directly
+use any Skia shader, without necessarily turning it into an image (texture)
+first. For example, you can evaluate a linear gradient. In this example,
+there is no texture created to hold the gradient. Skia generates a single
+fragment shader that computes the gradient color, samples from the image's
+texture, and then multiplies the two together:
-
+
-You can even sample another runtime effect:
+Of course, you can even invoke another runtime effect, allowing you to combine
+shader snippets dynamically:
-
+
---
@@ -59,7 +99,7 @@ if the blend function were `(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)`.
Skia's use of premultiplied alpha implies:
- If you start with an unpremultiplied `SkImage` (like a PNG), turn that into an
- `SkImageShader`, and sample that shader... the resulting colors will be
+ `SkImageShader`, and evaluate that shader... the resulting colors will be
`[R*A, G*A, B*A, A]`, **not** `[R, G, B, A]`.
- If your SkSL will return transparent colors, it must be sure to multiply the
`RGB` by `A`.
@@ -68,7 +108,7 @@ Skia's use of premultiplied alpha implies:
both kinds of color together.
Skia _enforces_ that the color produced by your SkSL is a valid premultiplied
-color. In other words, `RGB <= A`. If your SkSL returns colors where that is not
+color. In other words, `RGB ≤ A`. If your SkSL returns colors where that is not
true, they will be clamped, leading to incorrect colors. The image below
demonstrates this: properly premultiplied colors produce a smooth gradient as
alpha decreases. Unpremultipled colors cause the gradient to display
@@ -90,9 +130,9 @@ invoked by another, that parent shader may modify them arbitrarily.
In addition, the `SkShader` produced from an `SkImage` does not use normalized coordinates (like a
texture in GLSL). It uses `(0, 0)` in the upper-left corner, and `(w, h)` in the bottom-right
-corner. Normally, this is exactly what you want. If you're sampling an `SkImageShader` with
+corner. Normally, this is exactly what you want. If you're evaluating an `SkImageShader` with
coordinates based on the ones passed to you, the scale is correct. However, if you want to adjust
those coordinates (to do some kind of re-mapping of the image), remember that the coordinates are
scaled up to the dimensions of the image:
-
+