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