1 Home
dxtr edited this page 2026-10-18 19:16:33 +02:00

clsl

clsl is a shading language in Common Lisp, compiled to SPIR-V by clsl itself: no glslang, no C or C++ toolchain and no foreign library, on Linux and Windows alike. Shader code is Common Lisp. On numbers every operator means what it means in Lisp, and what a GPU cannot do as Lisp does is refused when the definition is evaluated, with a message that says what to write instead. A program compiles for a target, such as :vulkan, into each stage's SPIR-V and what a GPU layer needs to draw with it, in cl-gfx's terms: the vertex buffer layout, the bind group layouts, the bytes of the uniform blocks and the device features.

clsl is one of the libraries of the Pyssel game engine, whose shaders it compiles, and it replaced cl-gsl there. It does not depend on the engine, and is usable on its own.

A first look

(asdf:load-system :clsl/vulkan)

(defpackage #:example
  (:use #:cl #:clsl))
(in-package #:example)

(define-shader triangle-vertex :vertex ((position :vec2) (color :vec3))
  "Place each vertex at its POSITION, and pass its COLOR on."
  (values (vec4 position 0 1) color))

(define-shader triangle-fragment :fragment ((color :vec3) &uniform (tint :vec4))
  "Draw the COLOR the vertices pass, times TINT."
  (* (vec4 color 1) tint))

(define-program triangle
  "A triangle in its vertices' colours."
  :vertex triangle-vertex :fragment triangle-fragment)

(let ((program (compile-program 'triangle :target :vulkan)))
  (values
   ;; Each stage's SPIR-V, which cl-gfx's CREATE-SHADER-MODULE takes.
   (program-spirv program :vertex)
   ;; What the pipeline needs to know: the vertex inputs and the bindings.
   (program-vertex-inputs program)
   (program-bindings program)
   ;; The bytes of the :MATERIAL group's uniform block, for its buffer.
   (pack-uniforms program :material :values (list :tint #(1.0 0.5 0.5 1.0)))))
;; => #(119734787 67072 0 22 0 131089 1 196622 0 1 589839 0 1 1852399981 ...)
;;    (#S(VERTEX-INPUT :NAME POSITION :LOCATION 0 :TYPE :VEC2 :FORMATS (:FLOAT32X2))
;;     #S(VERTEX-INPUT :NAME COLOR :LOCATION 1 :TYPE :VEC3 :FORMATS (:FLOAT32X3)))
;;    (#S(PROGRAM-BINDING :GROUP :MATERIAL :NUMBER 0 :KIND :UNIFORM-BLOCK :STAGES (:FRAGMENT)))
;;    #(0 0 128 63 0 0 0 63 0 0 0 63 0 0 128 63)

The first value is the vertex shader's SPIR-V, 156 words, which begins with SPIR-V's magic number and version 1.6. The tint goes to binding 0 of the :material group, bind group 1, as four floats. Running on the GPU draws this triangle with cl-gfx, and Getting Started runs a first compute shader.

A form a GPU cannot compute as Lisp does is refused when its definition is evaluated:

(define-function half ((n :int))
  (/ n 2))

signals a shader-error:

In HALF: / of integers is a ratio in Lisp, and clsl has no ratios: divide with
TRUNCATE, FLOOR, CEILING or ROUND, which give integer quotients, or make the
integers floats with FLOAT.
  in: (/ N 2)

and (floor n 2) is accepted: two values, the quotient and the remainder, as in Lisp.

Pages

Using clsl

  • Getting Started: requirements, the systems, installing, loading, a first program on the GPU, running the tests.
  • Shader Code: the language: its types, numbers written in the code, forms, places, loops, several values, structs, local functions, macros, and where it differs from Common Lisp.
  • Language Functions: every function of the language, from + and floor to dot, mix and ldb.
  • Numbers and Precision: integers that wrap, floats, doubles, complex numbers, float pairs, and the defined results of every operation.
  • Definitions and Stages: define-function, define-shader and its six stages, the built-in inputs, stage interfaces, structs, macros and type aliases.
  • Uniforms and Resources: uniform blocks, define-uniform, textures, storage images and storage buffers, bind groups, and std140 and std430.
  • Shared Memory and Atomics: compute shaders' shared variables, barriers and atomics, with a histogram on the GPU.
  • Uniform Control Flow: what derivatives, texture reads, barriers and tessellation levels need, and how clsl checks it.
  • Programs: define-program, compile-program, what a program tells a GPU layer, and redefinition.
  • Running on the GPU: compute, drawing, uniforms every frame and textures, with cl-gfx.

Reference

  • API Reference: every exported symbol of clsl, clsl/vulkan and clsl/gmath.
  • Errors: the conditions, what each says, and Lisp's own type errors.
  • Threads: what may be shared between threads.
  • Systems: the ASDF systems, the packages, the dependencies, and cl-gmath in shader code.

Inside clsl

  • Targets: targets, :vulkan, the SPIR-V back end, and defining a target.
  • The IR: the intermediate representation between the language and SPIR-V: modules, types, operations, control flow, the external form, the builder and the verifier.
  • SPIR-V: clsl/spirv, which writes, reads and disassembles SPIR-V, and the grammar's tables.
  • Grammar and Generator: the vendored SPIR-V grammar, and the generator that writes clsl's tables from it.
  • Development and Testing: the test suite, what it holds clsl to, and working on clsl.
  • IR and SPIR-V Reference: every exported symbol of clsl/ir, clsl/spirv, clsl/spirv-back-end and clsl/generator.

At a glance

  • Lisp: SBCL. clsl is plain Common Lisp: loading it needs no foreign library, and nothing in it needs setting up again when a saved image starts.
  • Dependencies: cl-threads, for the lock definitions are made under. clsl/gmath needs cl-gmath, the generator jzon, and the tests cl-gfx, cl-vk, Parachute, SPIRV-Tools and a Vulkan 1.4 driver.
  • Targets: :vulkan, SPIR-V 1.6 under Vulkan 1.4's rules. GLSL output and an OpenGL target come next.
  • Threads: definitions may be made in any thread, programs compiled in several at once, and a compiled program never changes. See Threads.
  • Status: the language's core is done: every stage, scalars, vectors, matrices, structs and arrays, control flow, local functions and macros, every kind of texture and storage image, storage buffers, shared memory and atomics, derivatives with WGSL's uniformity analysis, doubles, complex numbers and float pairs.
  • Licence: MIT. The SPIR-V grammar files in grammar/ are Khronos's, under the MIT licence in grammar/LICENSE.
  • Source: https://fakehacker.cc/dxtr/clsl