Style Guide/GLSL

= Coding Style (GLSL) =

While Blender uses auto-formatting (clang-format), this page covers aspects of code style which aren't automated. Please make sure that your IDE is running auto-formatting on .glsl files or that you manually run it.

''Note: There is a lot of existing code that does not follow the rules below yet. Don't do global replacements without talking to a maintainer beforehand.''

There are only two important rules:
 * When making changes, always follow the style of this documentation. The code style of the existing code-base is so fragmented that it is better to always follow the new conventions.
 * Strive for clarity, even if that means occasionally breaking the guidelines. Use your head and ask for advice if your common sense seems to disagree with the conventions.

As a starting point, you should follow the C and C++ Style Guide even in GLSL files. This present documentation will only list what is different from the C and C++ guide.

Files

 * Vertex, fragment, geometry and compute shaders file should have respectively `_vert`, `_frag`,  `_geom` and `_comp` suffix (ex: `eevee_film_frag.glsl`).
 * Shader files name must be unique and must be prefixed by the module they are part of (ex: `workbench_material_lib.glsl`, `eevee_film_lib.glsl`).
 * A shader file must contain one and only one `main` function.
 * If a shader file does not contain a `main` function it is considered as a shader library and must have `_lib` suffix in its filename.
 * Put code shared between multiple shaders inside library files.

Naming

 * Use descriptive names for global variables and functions.
 * Naming should follow the `snake_case` convention. The only exception is type names (ex: `ViewMatrices`).
 * Given that GLSL has only a global namespace, prefix all function inside a `_lib.glsl` with the library name (ex: `curvature_soft_clamp` in `workbench_curvature_lib.glsl`).
 * Use variable names with common words at the beginning, and specifics as suffixes. Sort them alphabetically.

Shading Variables
Some common variables used in shading code are shortened by a single uppercase letter. All of them, with the exception of P, are expected to be unit vectors.
 * `P` for Position.
 * `N` for surface shading Normal.
 * `Ng` for surface geometric Normal.
 * `T` for surface Tangent.
 * `B` for surface BiTangent or curve BiNormal.
 * `L` for Light direction from the shading point.
 * `V` for View vector (also named `I`) from the shading point towards the camera.

Space Prefix
These can have a prefix telling the space they are supposed to be in: Note that local position is most often read from a vertex input and name `pos` instead of `lP`.
 * no prefix is assumed to be World space.
 * `v` for View space (ex: `vV` for view space view vector).
 * `l` for Local object space (ex: `lP` for local position).

For other variable, we use a two character prefix (ex: `wp_ray_dir` for world space ray direction):
 * `ws_` for World Space.
 * `vs_` for View Space.
 * `ls_` for Local object Space.

Normalized Device Coordinate space is a special case and use the `ndc_` prefix.

Value Literals

 * float (no f suffix): use: 0.3, 1.0 not: .3, 1.f
 * uint (always have u suffix): use: 0xFFu, 0u not: 0xFF, uint(0)

Vector Constructors

 * Vectors use same type of argument in multi-scalar constructors: use: vec2(2.0, 0.0) not: vec2(2, 0.0)
 * Matrices use either all scalar constructor or multi-column constructor: use: mat2(vec2(0.0), vec2(0.0)) or mat2(0.0, 0.0, 0.0, 0.0); not:  mat2(vec2(0.0), 0.0, 0.0)</tt>

Vector Components

 * Do not use vector array subscript `[]` unless it is for runtime random access. Use swizzle syntax instead `.x`, `.y`,  `.z` and `.w`.
 * Prefer using `.xyzw` set of swizzle. `.rgba` can be used when it make sense.
 * ```Do not``` use the `.stpq` set of swizzle. They are not available on Metal.

Comparison

 * Do not use direct vector comparison (ex: `my_vec == vec2(1.0)`) use `is_equal(a, b)` or `is_zero(a)`.

Types

 * Use GLSL vector and matrix types even if HLSL/MSL ones are defined (ex: `vec2` instead of `float2`).

Interface

 * Resource name and input / output variable should follow the `snake_case` convention.
 * Sampler resource names should have `_tx` suffix.
 * Image resource names should have `_img` suffix.
 * Storage and Uniform Buffers resource names should have `_buf` suffix.
 * Output fragment variable or written resources should have `out_`.
 * Read & Write resources can have `inout_` or `in_` prefix if it make sense.

Defines
Use `#define` and `#ifdef` only if needed. Optimizing out branches of code can be made using constant boolean and `if` clauses.

A good use case of defines is to remove code sections that need resources that may not be available in some shader configuration.

Driver Differences
Not all drivers are created equal. These rules are written in order to minimise the most common errors when dealing with different GLSL compilers.
 * Avoid putting too much data in global space. Prefer moving large arrays to local function constant variable.
 * Do not rely on implicit cast for `int` to `float` or `uint` to `int` promotion. Use explicit cast.
 * Avoid multi-line preprocessor directive like `#if`. Prefer breaking into multiple statements. Multi-line `#define` seems to cause no issues.
 * The `const` keyword is only allowed on compile time constant expression. Some driver do not consider function calls as constant expression even if all their parameters are.
 * The `discard` keyword needs to be manually followed by a `return` to avoid undefined behavior on Metal.
 * If fragment shader is writing to `gl_FragDepth`, usage must be correctly defined in the shader's create info using `.depth_write(DepthWrite)`.
 * Image type opaque variables (ex: image2D) are not allowed to be function parameters (because of differences in the decorators required). Transform the function into a macro, or access the image as a global variable.

Shader File Structure
The structure of a shader file should follow this order:

Shared Shader Files
These files contains data structures and small functions shared between GPU and CPU code. They have `.h` or `.hh` extensions.
 * Use the supported C or C++ syntax subset depending on file extensions. (TODO link to documentation)
 * Use blender's `floatX`, `intX`, `uintX`, `boolX` vectors and `float4x4` matrix types instead of `vecX`, `ivecX`, `uvecX`, `bvecX` and `mat4`.

Packing Rules
Shared structures should follow `std140` and `std430` packing rules depending if the struct is used in a Uniform Buffer or a Storage Buffer. Member alignment is currently not error checked so be sure to follow the rules. Here is a list of the rules:
 * Do not use `float3x3`.
 * Do not use arrays of scalars (ex: `float array[16]`) inside struct used by Uniform Buffers.
 * Use `float3_packed` instead of `float3`, and always follow it by a single scalar.
 * Use `bool1` instead of `bool`.
 * Align `float2`, `int2`, `uint2` and `bool2` to 8 bytes.
 * Align `float3`, `int3`, `uint3` and `bool3` to 16 bytes.
 * Align `float4`, `int4`, `uint4` and `bool4` to 16 bytes.
 * Align all structures to 16 bytes.
 * Remember that `float`, `int`, `uint` and `bool1` are 4 bytes long.

Metal Shading Language Compatiblity
Our Metal Backend takes adds some modifications to the GLSL sources to make them MSL compatible. This mean 2 things:
 * Not all of the GLSL syntaxes are supported. It isn't a goal of our backend to have 100% GLSL syntax compatible.
 * It might make some MSL syntax valid inside the GLSL if the Metal backend enabled. Always check if the shaders compile with other backends using compile-time shader compilation.