1cb93a386Sopenharmony_ci---
2cb93a386Sopenharmony_cititle: 'SkSL & Runtime Effects'
3cb93a386Sopenharmony_cilinkTitle: 'SkSL'
4cb93a386Sopenharmony_ci---
5cb93a386Sopenharmony_ci
6cb93a386Sopenharmony_ci## Overview
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci**SkSL** is Skia's
9cb93a386Sopenharmony_ci[shading language](https://en.wikipedia.org/wiki/Shading_language).
10cb93a386Sopenharmony_ci**`SkRuntimeEffect`** is a Skia C++ object that can be used to create
11cb93a386Sopenharmony_ci`SkShader`, `SkColorFilter`, and `SkBlender` objects with behavior controlled by
12cb93a386Sopenharmony_ciSkSL code.
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_ciYou can experiment with SkSL at https://shaders.skia.org/. The syntax is very
15cb93a386Sopenharmony_cisimilar to GLSL. When using SkSL effects in your Skia application, there are
16cb93a386Sopenharmony_ciimportant differences (from GLSL) to remember. Most of these differences are
17cb93a386Sopenharmony_cibecause of one basic fact: **With GPU shading languages, you are programming a
18cb93a386Sopenharmony_cistage of the
19cb93a386Sopenharmony_ci[GPU pipeline](https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview).
20cb93a386Sopenharmony_ciWith SkSL, you are programming a stage of the Skia pipeline.**
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ciIn particular, a GLSL fragment shader controls the entire behavior of the GPU
23cb93a386Sopenharmony_cibetween the rasterizer and the blending hardware. That shader does all of the
24cb93a386Sopenharmony_ciwork to compute a color, and the color it generates is exactly what is fed to
25cb93a386Sopenharmony_cithe fixed-function blending stage of the pipeline.
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ciSkSL effects exist as part of the larger Skia pipeline. When you issue a canvas
28cb93a386Sopenharmony_cidrawing operation, Skia (generally) assembles a single GPU fragment shader to do
29cb93a386Sopenharmony_ciall of the required work. This shader typically includes several pieces. For
30cb93a386Sopenharmony_ciexample, it might include:
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci- Evaluating whether a pixel falls inside or outside of the shape being drawn
33cb93a386Sopenharmony_ci  (or on the border, where it might apply antialiasing).
34cb93a386Sopenharmony_ci- Evaluating whether a pixel falls inside or outside of the clipping region
35cb93a386Sopenharmony_ci  (again, with possible antialiasing logic for border pixels).
36cb93a386Sopenharmony_ci- Logic for the `SkShader` on the `SkPaint`. The `SkShader` can actually be a
37cb93a386Sopenharmony_ci  tree of objects (due to `SkShaders::Blend` and other features described
38cb93a386Sopenharmony_ci  below).
39cb93a386Sopenharmony_ci- Similar logic for the `SkColorFilter` (which can also be a tree, due to
40cb93a386Sopenharmony_ci  `SkColorFilters::Compose`, `SkColorFilters::Blend`, and features described
41cb93a386Sopenharmony_ci  below).
42cb93a386Sopenharmony_ci- Blending code (for certain `SkBlendMode`s, or for custom blending specified
43cb93a386Sopenharmony_ci  with `SkPaint::setBlender`).
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ciEven if the `SkPaint` has a complex tree of objects in the `SkShader`,
46cb93a386Sopenharmony_ci`SkColorFilter`, or `SkBlender` fields, there is still only a _single_ GPU
47cb93a386Sopenharmony_cifragment shader. Each node in that tree creates a single function. The clipping
48cb93a386Sopenharmony_cicode and geometry code each create a function. The blending code might create a
49cb93a386Sopenharmony_cifunction. The overall fragment shader then calls all of these functions (which
50cb93a386Sopenharmony_cimay call other functions, e.g. in the case of an `SkShader` tree).
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci**Your SkSL effect contributes a function to the GPU's fragment shader.**
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci---
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci## Evaluating (sampling) other SkShaders
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ciIn GLSL, a fragment shader can sample a texture. With runtime effects, the
59cb93a386Sopenharmony_ciobject that you bind (in C++) is an `SkShader`, represented by a `shader` in
60cb93a386Sopenharmony_ciSkSL. To make it clear that you are operating on an object that will emit its
61cb93a386Sopenharmony_ciown shader code, you don't use `sample`. Instead, the `shader` object has a
62cb93a386Sopenharmony_ci`.eval()` method. Regardless, Skia has simple methods for creating an `SkShader`
63cb93a386Sopenharmony_cifrom an `SkImage`, so it's easy to use images in your runtime effects:
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ci<fiddle-embed name='3654053c76b5c23f18eb9a1c82abbde4'></fiddle-embed>
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ciBecause the object you bind and evaluate is an `SkShader`, you can directly use
68cb93a386Sopenharmony_ciany Skia shader, without necessarily turning it into an image (texture) first.
69cb93a386Sopenharmony_ciFor example, you can evaluate a linear gradient. In this example, there is no
70cb93a386Sopenharmony_citexture created to hold the gradient. Skia generates a single fragment shader
71cb93a386Sopenharmony_cithat computes the gradient color, samples from the image's texture, and then
72cb93a386Sopenharmony_cimultiplies the two together:
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci<fiddle-embed name='f282a4411782ed92057350e339586502'></fiddle-embed>
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ciOf course, you can even invoke another runtime effect, allowing you to combine
77cb93a386Sopenharmony_cishader snippets dynamically:
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_ci<fiddle-embed name='2151b061428f47844a2500b57c887ddf'></fiddle-embed>
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ci---
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci## Premultiplied Alpha
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ciWhen dealing with transparent colors, there are two (common)
86cb93a386Sopenharmony_ci[possible representations](https://en.wikipedia.org/wiki/Alpha_compositing#Straight_versus_premultiplied).
87cb93a386Sopenharmony_ciSkia calls these _unpremultiplied_ (what Wikipedia calls _straight_), and
88cb93a386Sopenharmony_ci_premultiplied_. In the Skia pipeline, every `SkShader` returns premultiplied
89cb93a386Sopenharmony_cicolors.
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ciIf you're familiar with OpenGL blending, you can think of it in terms of the
92cb93a386Sopenharmony_ciblend equation. For common alpha blending (called
93cb93a386Sopenharmony_ci[source-over](https://developer.android.com/reference/android/graphics/PorterDuff.Mode#SRC_OVER)),
94cb93a386Sopenharmony_ciyou would normally configure your blend function as
95cb93a386Sopenharmony_ci`(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)`. Skia defines source-over blending as
96cb93a386Sopenharmony_ciif the blend function were `(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)`.
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ciSkia's use of premultiplied alpha implies:
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_ci- If you start with an unpremultiplied `SkImage` (like a PNG), turn that into an
101cb93a386Sopenharmony_ci  `SkImageShader`, and evaluate that shader... the resulting colors will be
102cb93a386Sopenharmony_ci  `[R*A, G*A, B*A, A]`, **not** `[R, G, B, A]`.
103cb93a386Sopenharmony_ci- If your SkSL will return transparent colors, it must be sure to multiply the
104cb93a386Sopenharmony_ci  `RGB` by `A`.
105cb93a386Sopenharmony_ci- For more complex shaders, you must understand which of your colors are
106cb93a386Sopenharmony_ci  premultiplied vs. unpremultiplied. Many operations don't make sense if you mix
107cb93a386Sopenharmony_ci  both kinds of color together.
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ciThe image below demonstrates this: properly premultiplied colors produce a smooth
110cb93a386Sopenharmony_cigradient as alpha decreases. Unpremultipled colors cause the gradient to display
111cb93a386Sopenharmony_ciincorrectly, becoming too bright and shifting hue as the alpha changes.
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci<fiddle-embed name='4aa28e27a9682fec18d8c0ca265151ad'></fiddle-embed>
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci---
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci## Coordinate Spaces
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ciTo understand how coordinates work in SkSL, you first need to understand
120cb93a386Sopenharmony_ci[how they work in Skia](/docs/user/coordinates). If you're comfortable with
121cb93a386Sopenharmony_ciSkia's coordinate spaces, then just remember that the coordinates supplied to
122cb93a386Sopenharmony_ciyour `main()` are **local** coordinates. They will be relative to the coordinate
123cb93a386Sopenharmony_cispace of the `SkShader`. This will match the local space of the canvas and any
124cb93a386Sopenharmony_ci`localMatrix` transformations. Additionally, if the shader is invoked by
125cb93a386Sopenharmony_cianother, that parent shader may modify them arbitrarily.
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ciIn addition, the `SkShader` produced from an `SkImage` does not use normalized
128cb93a386Sopenharmony_cicoordinates (like a texture in GLSL). It uses `(0, 0)` in the upper-left corner,
129cb93a386Sopenharmony_ciand `(w, h)` in the bottom-right corner. Normally, this is exactly what you
130cb93a386Sopenharmony_ciwant. If you're evaluating an `SkImageShader` with coordinates based on the ones
131cb93a386Sopenharmony_cipassed to you, the scale is correct. However, if you want to adjust those
132cb93a386Sopenharmony_cicoordinates (to do some kind of re-mapping of the image), remember that the
133cb93a386Sopenharmony_cicoordinates are scaled up to the dimensions of the image:
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci<fiddle-embed name='ddbd4142c1c88232ae131d27266e72b3'></fiddle-embed>
136