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