xref: /aosp_15_r20/external/skia/src/sksl/README.md (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker# Overview
2*c8dee2aaSAndroid Build Coastguard Worker
3*c8dee2aaSAndroid Build Coastguard WorkerSkSL ("Skia Shading Language") is a variant of GLSL which is used as Skia's
4*c8dee2aaSAndroid Build Coastguard Workerinternal shading language. SkSL is, at its heart, a single standardized version
5*c8dee2aaSAndroid Build Coastguard Workerof GLSL which avoids all of the various version and dialect differences found
6*c8dee2aaSAndroid Build Coastguard Workerin GLSL "in the wild", but it does bring a few of its own changes to the table.
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard WorkerSkia uses the SkSL compiler to convert SkSL code to GLSL, GLSL ES, SPIR-V, or
9*c8dee2aaSAndroid Build Coastguard WorkerMSL before handing it over to the graphics driver.
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker
12*c8dee2aaSAndroid Build Coastguard Worker# Differences from GLSL
13*c8dee2aaSAndroid Build Coastguard Worker
14*c8dee2aaSAndroid Build Coastguard Worker* Precision modifiers are not used. 'float', 'int', and 'uint' are always high
15*c8dee2aaSAndroid Build Coastguard Worker  precision. New types 'half', 'short', and 'ushort' are medium precision (we
16*c8dee2aaSAndroid Build Coastguard Worker  do not use low precision).
17*c8dee2aaSAndroid Build Coastguard Worker* Vector types are named <base type><columns>, so float2 instead of vec2 and
18*c8dee2aaSAndroid Build Coastguard Worker  bool4 instead of bvec4
19*c8dee2aaSAndroid Build Coastguard Worker* Matrix types are named <base type><columns>x<rows>, so float2x3 instead of
20*c8dee2aaSAndroid Build Coastguard Worker  mat2x3 and double4x4 instead of dmat4
21*c8dee2aaSAndroid Build Coastguard Worker* GLSL caps can be referenced via the syntax 'sk_Caps.<name>', e.g.
22*c8dee2aaSAndroid Build Coastguard Worker  sk_Caps.integerSupport. The value will be a constant boolean or int,
23*c8dee2aaSAndroid Build Coastguard Worker  as appropriate. As SkSL supports constant folding and branch elimination, this
24*c8dee2aaSAndroid Build Coastguard Worker  means that an 'if' statement which statically queries a cap will collapse down
25*c8dee2aaSAndroid Build Coastguard Worker  to the chosen branch, meaning that:
26*c8dee2aaSAndroid Build Coastguard Worker
27*c8dee2aaSAndroid Build Coastguard Worker    if (sk_Caps.integerSupport)
28*c8dee2aaSAndroid Build Coastguard Worker        do_something();
29*c8dee2aaSAndroid Build Coastguard Worker    else
30*c8dee2aaSAndroid Build Coastguard Worker        do_something_else();
31*c8dee2aaSAndroid Build Coastguard Worker
32*c8dee2aaSAndroid Build Coastguard Worker  will compile as if you had written either 'do_something();' or
33*c8dee2aaSAndroid Build Coastguard Worker  'do_something_else();', depending on whether that cap is enabled or not.
34*c8dee2aaSAndroid Build Coastguard Worker* no #version statement is required, and it will be ignored if present
35*c8dee2aaSAndroid Build Coastguard Worker* the output color is sk_FragColor (do not declare it)
36*c8dee2aaSAndroid Build Coastguard Worker* use sk_Position instead of gl_Position. sk_Position is in device coordinates
37*c8dee2aaSAndroid Build Coastguard Worker  rather than normalized coordinates.
38*c8dee2aaSAndroid Build Coastguard Worker* use sk_PointSize instead of gl_PointSize
39*c8dee2aaSAndroid Build Coastguard Worker* use sk_VertexID instead of gl_VertexID
40*c8dee2aaSAndroid Build Coastguard Worker* use sk_InstanceID instead of gl_InstanceID
41*c8dee2aaSAndroid Build Coastguard Worker* the fragment coordinate is sk_FragCoord, and is always relative to the upper
42*c8dee2aaSAndroid Build Coastguard Worker  left.
43*c8dee2aaSAndroid Build Coastguard Worker* use sk_Clockwise instead of gl_FrontFacing. This is always relative to an
44*c8dee2aaSAndroid Build Coastguard Worker  upper left origin.
45*c8dee2aaSAndroid Build Coastguard Worker* you do not need to include ".0" to make a number a float (meaning that
46*c8dee2aaSAndroid Build Coastguard Worker  "float2(x, y) * 4" is perfectly legal in SkSL, unlike GLSL where it would
47*c8dee2aaSAndroid Build Coastguard Worker  often have to be expressed "float2(x, y) * 4.0". There is no performance
48*c8dee2aaSAndroid Build Coastguard Worker  penalty for this, as the number is converted to a float at compile time)
49*c8dee2aaSAndroid Build Coastguard Worker* type suffixes on numbers (1.0f, 0xFFu) are both unnecessary and unsupported
50*c8dee2aaSAndroid Build Coastguard Worker* creating a smaller vector from a larger vector (e.g. float2(float3(1))) is
51*c8dee2aaSAndroid Build Coastguard Worker  intentionally disallowed, as it is just a wordier way of performing a swizzle.
52*c8dee2aaSAndroid Build Coastguard Worker  Use swizzles instead.
53*c8dee2aaSAndroid Build Coastguard Worker* Swizzle components, in addition to the normal rgba / xyzw components, can also
54*c8dee2aaSAndroid Build Coastguard Worker  be LTRB (meaning "left/top/right/bottom", for when we store rectangles in
55*c8dee2aaSAndroid Build Coastguard Worker  vectors), and may also be the constants '0' or '1' to produce a constant 0 or
56*c8dee2aaSAndroid Build Coastguard Worker  1 in that channel instead of selecting anything from the source vector.
57*c8dee2aaSAndroid Build Coastguard Worker  foo.rgb1 is equivalent to float4(foo.rgb, 1).
58*c8dee2aaSAndroid Build Coastguard Worker* All texture functions are named "sample", e.g. sample(sampler2D, float3) is
59*c8dee2aaSAndroid Build Coastguard Worker  equivalent to GLSL's textureProj(sampler2D, float3).
60*c8dee2aaSAndroid Build Coastguard Worker* Functions support the 'inline' modifier, which causes the compiler to ignore
61*c8dee2aaSAndroid Build Coastguard Worker  its normal inlining heuristics and inline the function if at all possible
62*c8dee2aaSAndroid Build Coastguard Worker* some built-in functions and one or two rarely-used language features are not
63*c8dee2aaSAndroid Build Coastguard Worker  yet supported (sorry!)
64*c8dee2aaSAndroid Build Coastguard Worker
65*c8dee2aaSAndroid Build Coastguard Worker
66*c8dee2aaSAndroid Build Coastguard Worker# Synchronization Primitives
67*c8dee2aaSAndroid Build Coastguard Worker
68*c8dee2aaSAndroid Build Coastguard WorkerSkSL offers atomic operations and synchronization primitives geared towards GPU compute
69*c8dee2aaSAndroid Build Coastguard Workerprograms. These primitives are designed to abstract over the capabilities provided by
70*c8dee2aaSAndroid Build Coastguard WorkerMSL, SPIR-V, and WGSL, and differ from the corresponding primitives in GLSL.
71*c8dee2aaSAndroid Build Coastguard Worker
72*c8dee2aaSAndroid Build Coastguard Worker## Atomics
73*c8dee2aaSAndroid Build Coastguard Worker
74*c8dee2aaSAndroid Build Coastguard WorkerSkSL provides the `atomicUint` type. This is an opaque type that requires the use of an
75*c8dee2aaSAndroid Build Coastguard Workeratomic intrinsic (such as `atomicLoad`, `atomicStore`, and `atomicAdd`) to act on its value (which
76*c8dee2aaSAndroid Build Coastguard Workeris of type `uint`).
77*c8dee2aaSAndroid Build Coastguard Worker
78*c8dee2aaSAndroid Build Coastguard WorkerA variable with the `atomicUint` type must be declared inside a writable storage buffer block or as
79*c8dee2aaSAndroid Build Coastguard Workera workgroup-shared variable. When declared inside a buffer block, it is guaranteed to conform to the
80*c8dee2aaSAndroid Build Coastguard Workersame size and stride as a `uint`.
81*c8dee2aaSAndroid Build Coastguard Worker
82*c8dee2aaSAndroid Build Coastguard Worker```
83*c8dee2aaSAndroid Build Coastguard Workerworkgroup atomicUint myLocalAtomicUint;
84*c8dee2aaSAndroid Build Coastguard Worker
85*c8dee2aaSAndroid Build Coastguard Workerlayout(set = 0, binding = 0) buffer mySSBO {
86*c8dee2aaSAndroid Build Coastguard Worker    atomicUint myGlobalAtomicUint;
87*c8dee2aaSAndroid Build Coastguard Worker};
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker```
90*c8dee2aaSAndroid Build Coastguard Worker
91*c8dee2aaSAndroid Build Coastguard WorkerAn `atomicUint` can be declared as a struct member or the element type of an array, provided that
92*c8dee2aaSAndroid Build Coastguard Workerthe struct/array type is only instantiated in a workgroup-shared or storage buffer block variable.
93*c8dee2aaSAndroid Build Coastguard Worker
94*c8dee2aaSAndroid Build Coastguard Worker### Backend considerations and differences from GLSL
95*c8dee2aaSAndroid Build Coastguard Worker
96*c8dee2aaSAndroid Build Coastguard Worker`atomicUint` should not be confused with the GLSL [`atomic_uint` (aka Atomic
97*c8dee2aaSAndroid Build Coastguard WorkerCounter)](https://www.khronos.org/opengl/wiki/Atomic_Counter) type. The semantics provided by
98*c8dee2aaSAndroid Build Coastguard Worker`atomicUint` are more similar to GLSL ["Atomic Memory
99*c8dee2aaSAndroid Build Coastguard WorkerFunctions"](https://www.khronos.org/opengl/wiki/Atomic_Variable_Operations)
100*c8dee2aaSAndroid Build Coastguard Worker(see GLSL Spec v4.3, 8.11 "Atomic Memory Functions"). The key difference is that SkSL atomic
101*c8dee2aaSAndroid Build Coastguard Workeroperations only operate on a variable of type `atomicUint` while GLSL Atomic Memory Functions can
102*c8dee2aaSAndroid Build Coastguard Workeroperate over arbitrary memory locations (such as a component of a vector).
103*c8dee2aaSAndroid Build Coastguard Worker
104*c8dee2aaSAndroid Build Coastguard Worker* The semantics of `atomicUint` are similar to Metal's `atomic<uint>` and WGSL's `atomic<u32>`.
105*c8dee2aaSAndroid Build Coastguard Worker  These are the types that an `atomicUint` is translated to when targeting Metal and WGSL.
106*c8dee2aaSAndroid Build Coastguard Worker* When translated to Metal, the atomic intrinsics use relaxed memory order semantics.
107*c8dee2aaSAndroid Build Coastguard Worker* When translated to SPIR-V, the atomic intrinsics use relaxed [memory
108*c8dee2aaSAndroid Build Coastguard Worker  semantics](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Memory_Semantics_-id-)
109*c8dee2aaSAndroid Build Coastguard Worker  (i.e. `0x0 None`). The [memory
110*c8dee2aaSAndroid Build Coastguard Worker  scope](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Scope_-id-) is either `1
111*c8dee2aaSAndroid Build Coastguard Worker  Device` or `2 Workgroup` depending on whether the `atomicUint` is declared in a buffer block or
112*c8dee2aaSAndroid Build Coastguard Worker  workgroup variable.
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker## Barriers
115*c8dee2aaSAndroid Build Coastguard Worker
116*c8dee2aaSAndroid Build Coastguard WorkerSkSL provides two barrier intrinsics: `workgroupBarrier()` and `storageBarrier()`. These functions
117*c8dee2aaSAndroid Build Coastguard Workerare only available in compute programs and synchronize access to workgroup-shared and storage buffer
118*c8dee2aaSAndroid Build Coastguard Workermemory between invocations in the same workgroup. They provide the same semantics as the equivalent
119*c8dee2aaSAndroid Build Coastguard Worker[WGSL Synchronization Built-in Functions](https://www.w3.org/TR/WGSL/#sync-builtin-functions). More
120*c8dee2aaSAndroid Build Coastguard Workerspecifically:
121*c8dee2aaSAndroid Build Coastguard Worker
122*c8dee2aaSAndroid Build Coastguard Worker* Both functions execute a control barrier with Acquire/Release memory ordering.
123*c8dee2aaSAndroid Build Coastguard Worker* Both functions use a `Workgroup` execution and memory scope. This means that a coherent memory
124*c8dee2aaSAndroid Build Coastguard Worker  view is only guaranteed between invocations in the same workgroup and NOT across workgroups in a
125*c8dee2aaSAndroid Build Coastguard Worker  given compute pipeline dispatch. If multiple workgroups require a _synchronized_ coherent view
126*c8dee2aaSAndroid Build Coastguard Worker  over the same shared mutable state, their access must be synchronized via other means (such as a
127*c8dee2aaSAndroid Build Coastguard Worker  pipeline barrier between multiple dispatches).
128*c8dee2aaSAndroid Build Coastguard Worker
129*c8dee2aaSAndroid Build Coastguard Worker### Backend considerations
130*c8dee2aaSAndroid Build Coastguard Worker
131*c8dee2aaSAndroid Build Coastguard Worker* The closest GLSL equivalent for `workgroupBarrier()` is the
132*c8dee2aaSAndroid Build Coastguard Worker[`barrier()`](https://registry.khronos.org/OpenGL-Refpages/gl4/html/barrier.xhtml) intrinsic. Both
133*c8dee2aaSAndroid Build Coastguard Worker`workgroupBarrier()` and `storageBarrier()` can be defined as the following invocations of the
134*c8dee2aaSAndroid Build Coastguard Worker`controlBarrier` intrinsic defined in
135*c8dee2aaSAndroid Build Coastguard Worker[GL_KHR_memory_scope_semantics](https://github.com/KhronosGroup/GLSL/blob/master/extensions/khr/GL_KHR_memory_scope_semantics.txt):
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker```
138*c8dee2aaSAndroid Build Coastguard Worker// workgroupBarrier():
139*c8dee2aaSAndroid Build Coastguard WorkercontrolBarrier(gl_ScopeWorkgroup,
140*c8dee2aaSAndroid Build Coastguard Worker               gl_ScopeWorkgroup,
141*c8dee2aaSAndroid Build Coastguard Worker               gl_StorageSemanticsShared,
142*c8dee2aaSAndroid Build Coastguard Worker               gl_SemanticsAcquireRelease);
143*c8dee2aaSAndroid Build Coastguard Worker
144*c8dee2aaSAndroid Build Coastguard Worker// storageBarrier():
145*c8dee2aaSAndroid Build Coastguard WorkercontrolBarrier(gl_ScopeWorkgroup,
146*c8dee2aaSAndroid Build Coastguard Worker               gl_ScopeWorkgroup,
147*c8dee2aaSAndroid Build Coastguard Worker               gl_StorageSemanticsBuffer,
148*c8dee2aaSAndroid Build Coastguard Worker               gl_SemanticsAcquireRelease);
149*c8dee2aaSAndroid Build Coastguard Worker```
150*c8dee2aaSAndroid Build Coastguard Worker
151*c8dee2aaSAndroid Build Coastguard Worker* In Metal, `workgroupBarrier()` is equivalent to `threadgroup_barrier(mem_flags::mem_threadgroup)`.
152*c8dee2aaSAndroid Build Coastguard Worker  `storageBarrier()` is equivalent to `threadgroup_barrier(mem_flags::mem_device)`.
153*c8dee2aaSAndroid Build Coastguard Worker
154*c8dee2aaSAndroid Build Coastguard Worker* In Vulkan SPIR-V, `workgroupBarrier()` is equivalent to `OpControlBarrier` with `Workgroup`
155*c8dee2aaSAndroid Build Coastguard Worker  execution and memory scope, and `AcquireRelease | WorkgroupMemory` memory semantics.
156*c8dee2aaSAndroid Build Coastguard Worker
157*c8dee2aaSAndroid Build Coastguard Worker  `storageBarrier()` is equivalent to `OpControlBarrier` with `Workgroup` execution and memory
158*c8dee2aaSAndroid Build Coastguard Worker  scope, and `AcquireRelease | UniformMemory` memory semantics.
159