4 Types
dxtr edited this page 2026-10-14 03:35:08 +02:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Types

Shader types are written as keywords for the built-in types, symbols for structs, and lists for arrays. They appear in parameter lists, the, struct slots and uniforms. (shader-documentation 'shader-type) lists them all.

Value types

Kind Types Notes
Scalars :bool :int :uint :float :double :int and :uint are 32 bits and wrap around.
Float vectors :vec2 :vec3 :vec4
Integer vectors :ivec2–:ivec4, :uvec2–:uvec4
Boolean vectors :bvec2–:bvec4 What per-component comparisons give.
Double vectors :dvec2 :dvec3 :dvec4
Float matrices :mat2 :mat3 :mat4, :matCxR :matCxR has C columns and R rows, such as :mat2x3.
Double matrices :dmat2 :dmat3 :dmat4, :dmatCxR
Complex numbers :complex, :dcomplex Of floats, of doubles.
Ratios :ratio Exact fractions of 32-bit integers.
Structs a symbol defined with define-struct See Structs.
Arrays (:array type length) (:array type), without a length, only in storage buffers.

Vectors and matrices

Constructors are named after their types and take components as scalars and vectors in order, or one scalar for every component:

(vec3 1)                 ; (1.0 1.0 1.0)
(vec4 position 1)        ; a :vec3 and a scalar
(ivec2 (fragment-coord)) ; the first two components, converted to :int

A matrix constructor takes its components in column-major order, as cl-gmath keeps them; or one scalar for the diagonal; or another matrix to resize:

(mat4 1)          ; the identity
(mat3 model)      ; the upper left 3x3 of a :mat4
(mat2 a b c d)    ; columns (a b) and (c d)

(aref m i) is column i of a matrix. * of matrices and vectors is the linear algebra product; matrix-component-product multiplies per component.

Components are read and assigned with x, y, z, w, (aref v i) and (swizzle v :zyx).

Doubles

:double, :dvecN and :dmat... work like their float counterparts, with these differences, all of which come from GLSL:

  • Doubles and floats do not mix in arithmetic. (+ d f) is an error; convert with (double f) or (float d). Integer and float literals fit a double, so (* d 2) and (+ d 1.5) work.
  • The trigonometric, exponential and logarithmic functions take floats only. (sin d) is an error.
  • A vertex input of doubles takes two locations if it is a :dvec3 or :dvec4: inputs (position :dvec3) (scale :double) are at locations 0 and 2.
  • Doubles are never interpolated. A fragment shader's double inputs are :flat, and asking for :smooth is an error.
  • A fragment shader cannot return doubles.
  • pack-double-2x32 and unpack-double-2x32 convert between a :double and its bits as a :uvec2, low word first.
  • (float x 1d0) converts to a double, as cl:float does with a prototype. (float d) keeps a double a double.
  • The device needs the shaderFloat64 feature.

Complex numbers

:complex is a complex number of floats, and :dcomplex one of doubles. GLSL has neither: in GLSL they are a vec2 and a dvec2 of the real and imaginary parts.

(define-function rotate-by ((p :vec2) (angle :float))
  (let ((z (* (complex (x p) (y p)) (cis angle))))
    (vec2 (realpart z) (imagpart z))))
  • Make them with (complex re [im]), (cis angle) or literals such as #c(1.0 2.0).
  • + - * /, =, /= and zerop take them, mixed with real numbers. A double anywhere makes the result a :dcomplex.
  • abs, phase, conjugate, realpart and imagpart take them.
  • exp, log, sqrt, expt, sin, cos and tan take a :complex. They do not take a :dcomplex, because GLSL has no transcendental functions of doubles.
  • < and the other orderings do not take complex numbers, as in Lisp.

Ratios

:ratio is an exact fraction, as Lisp's ratios are, of 32-bit integers. In GLSL it is an ivec2 of the numerator and denominator, always in lowest terms with a positive denominator, so = compares two ratios as they are.

(define-function thirds ((n :int))
  (let ((r (* n 1/3)))
    (if (< r 1/2) (float r) (float (numerator r)))))
  • Make them with literals such as 2/3, or with (rational i) from an integer.
  • + - * / of ratios and integers stay exact. A float anywhere makes the result a float.
  • They compare with < > <= >= = /=, and take abs, signum, floor, ceiling, truncate and round (which give an integer quotient and a ratio remainder), numerator and denominator.
  • (float r) and (float r 1d0) convert them to floats.
  • The numerator and denominator are 32-bit and can overflow, as :ints can.

Opaque types

Opaque types name resources that shader code reads and writes but cannot store: they can be passed to a shader function, but not bound to a variable, computed with, or returned. They appear only as uniforms and as parameters of shader functions.

Textures

A texture type is a texture together with its sampler.

Shape Float Int Uint Shadow
1D :sampler1d :isampler1d :usampler1d :sampler1d-shadow
1D array :sampler1d-array :isampler1d-array :usampler1d-array :sampler1d-array-shadow
2D :sampler2d :isampler2d :usampler2d :sampler2d-shadow
2D array :sampler2d-array :isampler2d-array :usampler2d-array :sampler2d-array-shadow
2D multisampled :sampler2d-ms :isampler2d-ms :usampler2d-ms
2D multisampled array :sampler2d-ms-array :isampler2d-ms-array :usampler2d-ms-array
3D :sampler3d :isampler3d :usampler3d
Cube :sampler-cube :isampler-cube :usampler-cube :sampler-cube-shadow
Cube array :sampler-cube-array :isampler-cube-array :usampler-cube-array :sampler-cube-array-shadow
Buffer :sampler-buffer :isampler-buffer :usampler-buffer

A texel of a :sampler... is a :vec4, of an :isampler... an :ivec4, and of a :usampler... a :uvec4. A shadow texture compares depths and gives a :float. See Textures and Images.

Storage images

Storage image types are named as the textures are, with image for sampler and no shadow kinds: :image1d, :iimage2d, :uimage3d, :image-cube-array, :image2d-ms, :uimage-buffer and so on. Each needs a :format when declared as a uniform. See Uniforms and Resources.

Asking about an opaque type

(texture-type-p :usampler2d)               ; => T
(image-type-p :image2d)                    ; => T
(texture-type-shape :usampler2d-array)     ; => :2D-ARRAY, NIL, NIL
(texture-type-shape :sampler2d-ms)         ; => :2D, T, NIL
(texture-type-shape :sampler-cube-shadow)  ; => :CUBE, NIL, T

texture-type-shape takes a texture or image type and returns the shape, one of :1d :1d-array :2d :2d-array :3d :cube :cube-array :buffer, then whether it is multisampled, then whether it is a shadow texture. A GPU layer uses it to decide what kind of view to bind.

Memory layout

Values in uniform blocks follow the std140 rules; values in storage buffers follow std430, which pads arrays and structs less. The layout-rules type names them, :std140 and :std430.

(layout-size :vec3)                               ; => 12
(layout-alignment :vec3)                          ; => 16
(layout-size '(:array :float 4))                  ; => 64, std140 pads each element to 16 bytes
(layout-size '(:array :float 4) :rules :std430)   ; => 16
(array-stride '(:array :vec3 4))                  ; => 16
(struct-layout 'light)                            ; => ((POSITION :VEC3 0) (COLOR :VEC3 16)), 32
Function Returns
(layout-size type &key rules) Size in bytes. An array without a length counts as 0.
(layout-alignment type &key rules) Alignment in bytes.
(array-stride array-type &key rules) Bytes from one element to the next. std140 rounds it up to 16.
(struct-layout name &key rules) The slots as ((slot type offset) ...), then the struct's size.

rules defaults to :std140. Some sizes worth knowing:

Type std140 size Notes
:double 8
:dvec3 24 Aligned to 32.
:dmat4 128
:complex 8 A vec2.
:dcomplex 16 A dvec2.
:ratio 8 An ivec2.
:mat2x3 32 Each column is padded to 16 bytes.

pack-value writes a Lisp value into a byte vector by these rules. See Uniforms and Resources.

Naming types after a library's

(define-type-alias colour :vec3) makes colour another name for :vec3 in parameter lists and the. cl-gsl/gmath uses this to make gm:vec3 and gm:quat shader types. See Extending Shader Code.