Errors
Every error clsl signals is a clsl-error, whose message,
clsl-error-message, says what went wrong and what to do about it, in the
terms of the shader code. A mistake in shader code is found when its
definition is evaluated, not by a driver: the error names the definition and
the form at fault, and the definition before it stays.
The conditions
| Condition | Is a | Signalled for | Readers |
|---|---|---|---|
clsl-error |
error |
every error clsl signals | clsl-error-message |
shader-error |
clsl-error |
shader code clsl refuses, or stages that do not fit together | shader-error-definition, shader-error-form |
undefined-shader-function |
shader-error |
a call of a function neither built into the language nor defined, when a program is compiled | undefined-shader-function-name |
no-target-error |
clsl-error |
a target no system loaded has defined; the message names the system to load | no-target-error-target |
unsupported-error |
clsl-error |
what a target cannot express | unsupported-error-feature, unsupported-error-form |
internal-error |
clsl-error |
invalid IR or SPIR-V made of shaders clsl had accepted: a bug in clsl | internal-error-ir |
clsl/ir:ir-error |
clsl-error |
IR that breaks the IR's rules: by the verifier, the reader of the external form, or the builder | clsl-error-message |
clsl/spirv:spirv-error |
clsl-error |
SPIR-V that SPIR-V's grammar does not allow | clsl-error-message |
clsl/generator:grammar-error |
error |
a grammar file that is not well-formed JSON, or not of the grammar's format | grammar-error-source, grammar-error-context, grammar-error-message |
And the warnings:
| Condition | Is a | Signalled for | Readers |
|---|---|---|---|
forward-reference-warning |
style-warning |
a definition that calls a shader function not defined yet; the definition is made | forward-reference-warning-definition, forward-reference-warning-name |
program-warning |
warning |
a redefinition after which a program define-program defined no longer compiles; the redefinition is made |
program-warning-program, program-warning-error |
uniformity-warning |
warning |
a derivative or texture read, declared a warning, that may run where control flow is not uniform; compile-program signals it |
uniformity-warning-definition, uniformity-warning-form, uniformity-warning-message |
Shader errors
A shader-error's report names the definition, gives the message, and quotes
the form at fault; clsl-error-message is the message alone:
(handler-case (define-function half ((n :int))
(/ n 2))
(shader-error (error)
(list (princ-to-string error)
(clsl-error-message error)
(shader-error-definition error)
(shader-error-form 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)"
;; "/ 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."
;; HALF
;; (/ N 2))
Some of what the language refuses, with each message, or the part of it that matters:
| Code | Message |
|---|---|
(/ n 2) of an :int |
/ of integers is a ratio in Lisp, and clsl has no ratios: divide with TRUNCATE, FLOOR, CEILING or ROUND, ... |
(+ x i) of a :float and an :int |
+ takes numbers of one type, :INT, :UINT, :FLOAT, :DOUBLE or :DFLOAT, ... not :FLOAT, :INT. |
(* x 1d0) of a :float |
... 1.0d0 is a double-float, so in Lisp the result would be a double: write 1.0 for a :FLOAT, or make the floats :DOUBLEs with (float x 1d0). |
1/3 |
1/3 is a ratio, and clsl has no ratios, ... write 0.33333334, or (/ 1.0 3.0), ... |
(+ 1 4294967296) |
4294967297 does not fit in 32 bits, as clsl's integers do. |
(vec3 i 0 0) of an :int |
VEC3 takes :FLOATs and vectors of them with 3 components in all, one :FLOAT, or a vector of more of them, not :INT, 0, 0. |
(int x) of a :float |
INT takes integers. A float becomes an integer through a function that names its rounding: (truncate x), (floor x), (ceiling x) or (round x). |
(sin d) of a :double |
SIN takes a :FLOAT, or a vector of them, or a :COMPLEX, not :DOUBLE. GPUs compute it of :FLOATs only: ... |
(aref v 3) of a :vec3 |
:VEC3 has 3 components, from 0 to 2, and none at 3. |
(floor a 0) |
FLOOR divides an integer by zero, whose quotient Lisp does not define: ... |
(multiple-value-bind (a b c) (floor x) ...) |
MULTIPLE-VALUE-BIND takes 3 values, but (FLOOR X) gives 2 values: in Lisp the others would be NIL, which no type of a shader holds. |
(return 1) outside a loop |
RETURN leaves the innermost DOTIMES or LOOP around it, and there is none here. A shader function gives the value of its last form. |
(setf i 2) of a dotimes variable |
I counts the iterations of its DOTIMES, and Common Lisp leaves it to each implementation what assigning it does: bind a variable of your own with LET, and assign that. |
| a function that calls itself | NO-RECURSION calls itself, through other functions or not, and shader code cannot recurse. |
(x :vec5) in a parameter list |
:VEC5 is not a type of clsl's language. Types are keywords such as :FLOAT, :IVEC2, :VEC3, :MAT4 and :SAMPLER2D; ... |
&uniform of a package that does not use clsl |
&UNIFORM is not CLSL:&UNIFORM, which starts the uniforms: write clsl:&uniform, or use the package CLSL. |
| a built-in of another stage | FRAGMENT-COORD belongs to fragment shaders, and PIXEL-X, which uses it, is called by the vertex shader WRONG-STAGE. |
| stages that do not fit | The vertex shader COLORED-VERTEX passes :VEC3 to the fragment shader MISFIT-FRAGMENT, which takes :VEC4: ... |
| a derivative in a branch | (FWIDTH UV) computes a derivative, which the fragments of a quad compute together, so it needs uniform control flow; ... |
| an atomic of a float | ATOMIC-INCF changes an :INT or a :UINT, and (AREF SUMS 0) is :FLOAT. |
a write to :storage :read |
SUMS is a storage buffer of :STORAGE :READ, which shader code reads but never writes: give it :STORAGE :READ-WRITE to write it. |
(compile-program 'no-such-program ...) |
There is no program called NO-SUCH-PROGRAM: define it with DEFINE-PROGRAM, or give COMPILE-PROGRAM its stages, ... |
Most are shown in full, with their code, on the page of their topic.
Undefined functions and forward references
A call of a shader function not defined yet is no error when the definition is
evaluated: the definition is made, and signals a forward-reference-warning,
whose forward-reference-warning-definition calls its
forward-reference-warning-name. Compiling a program that still calls it
signals an undefined-shader-function:
(define-shader toned :fragment ((color :vec3))
(vec4 (gamma-correct color) 1))
(handler-case (compile-program '(:fragment toned) :target :vulkan)
(undefined-shader-function (error)
(list (undefined-shader-function-name error) (shader-error-definition error)
(shader-error-form error))))
;; => (GAMMA-CORRECT TONED (GAMMA-CORRECT COLOR))
Program and uniformity warnings
A program-warning says that a program no longer compiles after a
redefinition, which is made, so that a change to several stages can be made a
stage at a time. program-warning-program is the program's name, and
program-warning-error the shader-error compiling it would signal. See
Programs.
A uniformity-warning comes from compile-program, for a derivative or
texture read in a body declared (derivative-uniformity :warning). The
program is compiled, and its results are undefined where control flow is not
uniform after all. See Uniform Control Flow.
Both are warnings: muffle-warning silences them in a handler-bind.
Targets
A no-target-error names the system that defines the target, or lists
clsl's targets:
The target :VULKAN is not loaded: load the system clsl/vulkan, which defines it.
An unsupported-error says what a target cannot express:
unsupported-error-feature names what the target lacks, such as "the
capability Float64", and unsupported-error-form is the form that needs it,
or nil where no one form does, as for a type. :vulkan allows the
capabilities Vulkan 1.4 allows; Targets shows the
error of a target that allows fewer.
An internal-error is a bug in clsl: clsl made invalid IR or SPIR-V of
shaders it had accepted. internal-error-ir is the external form of the IR it
was compiling, for the report: please report it with the shaders'
definitions.
Packing and the program's readers
The functions that write uniform blocks and read programs signal a
clsl-error for what does not fit. With
(define-shader tinted :fragment ((color :vec3) &uniform (tint :vec4))
(* (vec4 color 1) tint))
(define-struct lamp
(power :float))
and program the program (compile-program '(:fragment tinted) :target :vulkan):
| Call | Message |
|---|---|
(pack-uniforms program :material :values '()) |
PACK-UNIFORMS has no value for the uniform TINT of the group :MATERIAL: give it in :VALUES, as (:TINT value). |
(pack-uniforms program :material :values '(:tintt #(1.0 1.0 1.0 1.0))) |
PACK-UNIFORMS has a value for :TINTT, which is no uniform of the blocks of #<PROGRAM :fragment TINTED for :vulkan {120206BC33}>: their uniforms are :TINT. |
(pack-uniforms program :material :values '(:tint 1.0)) |
1.0 is not a value of :VEC4, which is a sequence of 4 components. |
(pack-uniforms program :material :values '(:tint #(1.0 1.0 1.0 1.0)) :buffer (make-array 4 :element-type '(unsigned-byte 8))) |
The :MATERIAL block of #<PROGRAM :fragment TINTED for :vulkan {1201B736C3}> is 16 bytes, and the buffer has 4. |
(program-spirv program :vertex) |
#<PROGRAM :fragment TINTED for :vulkan {1202391953}> has no vertex shader: its stages are :fragment. |
(pack-value :vec3 #(1.0 2.0) (make-array 16 :element-type '(unsigned-byte 8))) |
#(1.0 2.0) is not a value of :VEC3, which is a sequence of 3 components. |
(dfloat-parts 1d300) |
1.0d300 is beyond the range of float pairs, whose high part is a :FLOAT, at most 3.4028235e38 in magnitude. |
(remove-definition 'make-lamp) |
MAKE-LAMP is a function of the struct LAMP, which goes with it: remove the struct, LAMP. |
Type errors
Every exported function declares the types of its arguments, which SBCL checks
as the function is entered. An argument of the wrong type, or a keyword
outside its documented choices, signals a standard type-error that names
the argument and the type it takes. SBCL may list a type's choices in another
order:
(pack-uniforms program group) ; GROUP being :MATERAL
The value
:MATERAL
is not of type
(MEMBER :DRAW :MATERIAL :FRAME)
when binding CLSL/LANGUAGE::GROUP
Written as a constant, such an argument is caught sooner: SBCL warns as it compiles the call.
(pack-uniforms program :materal)
; caught WARNING:
; Constant
; :MATERAL conflicts with its asserted type
; (MEMBER :DRAW :MATERIAL :FRAME).
The lower layers
The IR's verifier, its reader and its builder signal an ir-error, which
names the function and the statement at fault, as the external form writes
them, and what would fit:
In the function MAIN, (%1 (:ADD (:UINT 1) (:INT 2))): :add takes two operands
of one type, integers or floats, scalars or vectors; they are :uint and :int.
The SPIR-V layer signals a spirv-error for a name its grammar lacks, an
operand its instruction does not take, or an instruction where SPIR-V's
layout does not allow it:
SPIR-V has no instruction :FADD. Did you mean :F-ADD?
OpTypeInt's operand 3, Signedness, should be an unsigned 32-bit integer, not
:SIGNED.
The generator signals a grammar-error, its own, which is no clsl-error.
Its report is the file, where in the grammar, and what is wrong:
grammar-error-source is the file read, or nil for a string,
grammar-error-context where in the grammar the problem is, outermost first,
and grammar-error-message what is wrong:
The JSON is not well-formed: End of input when reading object. Expecting comma
or object close, at line 1, column 26.
The IR, SPIR-V and Grammar and Generator say more.