luv

Workshop wiki

lowering.lisp

hal/webgpu/wgsl/lowering.lisp

system luv/wgsl · 103 definitions · on GitHub

Direct WebGPU Shading Language lowering for luv's mathematical shaders.

The shared graph remains the semantic source. This sibling target owns WGSL spelling, entry-point/resource ABI, pipeline overrides, structured statements, and source occurrences. The first target surface is deliberately conventional WebGPU: vertex and fragment stages, without pretending that task or mesh stages exist in standard WGSL.

in-package#:luv.wgsl
defclasswgsl-target
overrides:initarg:overrides:initformnil:readerwgsl-target-overrides
:documentation

The WebGPU target policy for one lowering.

OVERRIDES is an ordered list of shader source-value symbols which should stay pipeline-overridable instead of becoming their already checked literal defaults. Other source values retain the native folded-literal semantics.

defclasswgsl-source-occurrence
expression:initarg:expression:readerwgsl-source-occurrence-expression
text:initarg:text:readerwgsl-source-occurrence-text
defclasswgsl-override
name:initarg:name:readerwgsl-override-name
identifier:initarg:identifier:readerwgsl-override-identifier
type:initarg:type:readerwgsl-override-type
default:initarg:default:readerwgsl-override-default
:documentation

One scalar WGSL override retained with its Lisp source identity.

defclasswgsl-variable-statement
type:initarg:type:readerwgsl-variable-statement-type
name:initarg:name:readerwgsl-variable-statement-name
value:initarg:value:readerwgsl-variable-statement-value
defclasswgsl-output-statement
declaration:initarg:declaration:readerwgsl-output-statement-declaration
field:initarg:field:readerwgsl-output-statement-field
value:initarg:value:readerwgsl-output-statement-value
defclasswgsl-if-statement
condition:initarg:condition:readerwgsl-if-statement-condition
statements:initarg:statements:readerwgsl-if-statement-statements
defclasswgsl-counted-fold-statement
type:initarg:type:readerwgsl-counted-fold-statement-type
state-name:initarg:state-name:readerwgsl-counted-fold-statement-state-name
initial:initarg:initial:readerwgsl-counted-fold-statement-initial
index-name:initarg:index-name:readerwgsl-counted-fold-statement-index-name
index-type:initarg:index-type:readerwgsl-counted-fold-statement-index-type
count:initarg:count:readerwgsl-counted-fold-statement-count
bindings:initarg:bindings:initformnil:readerwgsl-counted-fold-statement-bindings
update:initarg:update:readerwgsl-counted-fold-statement-update
until-bindings:initarg:until-bindings:initformnil:readerwgsl-counted-fold-statement-until-bindings
until:initarg:until:initformnil:readerwgsl-counted-fold-statement-until
defclasswgsl-document
target:initarg:target:readerwgsl-document-target
specification:initarg:specification:readerwgsl-document-specification
source:initarg:source:readerwgsl-document-source
overrides:initarg:overrides:readerwgsl-document-overrides
expression-occurrences:initarg:expression-occurrences:readerwgsl-document-expression-occurrences
occurrence-expression:initarg:occurrence-expression:readerwgsl-document-occurrence-expression
defclasswgsl-lowering-context
target:initarg:target:readerwgsl-context-target
specification:initarg:specification:readerwgsl-context-specification
references:initform
make-hash-table:test#'eq
:readerwgsl-context-references
expression-occurrences:initform
make-hash-table:test#'eq
:readerwgsl-context-expression-occurrences
occurrence-expression:initform
make-hash-table:test#'eq
:readerwgsl-context-occurrence-expression
function-call-results:initform
make-hash-table:test#'eq
:readerwgsl-context-function-call-results
pending-statements:initformnil:accessorwgsl-context-pending-statements
fold-counter:initform0:accessorwgsl-context-fold-counter
encountered-overrides:initform
make-hash-table:test#'eq
:readerwgsl-context-encountered-overrides
defunwgsl-identifier
name

Spell name as a deterministic non-reserved WGSL identifier.

let
text
string-downcase
stringname
with-output-to-string
stream
when
or
zerop
lengthtext
digit-char-p
chartext0
write-char#\_stream
loopforcharacteracrosstextdo
write-char
if
or
alphanumericpcharacter
char=character#\_
character#\_
stream
defunwgsl-structure-name
namesuffix
let
capitalize-next-pt
with-output-to-string
stream
loopforcharacteracross
string-downcase
stringname
if
alphanumericpcharacter
do
write-char
ifcapitalize-next-p
char-upcasecharacter
character
stream
setfcapitalize-next-pnil
elsedo
setfcapitalize-next-pt
write-stringsuffixstream
defunwgsl-type-name
type&optionalsource-form
case
shader:shader-type-name
:bool"bool"
:float"f32"
:uint"u32"
:vec2"vec2<f32>"
:vec3"vec3<f32>"
:vec4"vec4<f32>"
:uvec2"vec2<u32>"
:uvec3"vec3<u32>"
:uvec4"vec4<u32>"
otherwise
error'shader:shader-language-error:formsource-form:reason:unsupported-wgsl-type:details
shader:shader-type-nametype
defunwgsl-float-literal
value
let*
raw
string-downcase
write-to-string
coercevalue'single-float
normalized
map'string
lambda
character
if
findcharacter"sfdl":test#'char=
#\echaracter
raw
formatnil"~A~Af"normalized
if
or
find#\.normalized
find#\enormalized
""".0"
defunnote-wgsl-occurrence
contextexpressiontext
let
occurrence
make-instance'wgsl-source-occurrence:expressionexpression:texttext
pushoccurrence
gethashexpression
wgsl-context-expression-occurrencescontext
setf
gethashoccurrence
wgsl-context-occurrence-expressioncontext
expression
occurrence
defunwgsl-occurrence-text
occurrence
wgsl-source-occurrence-textoccurrence
defundrain-wgsl-pending-statements
prog1
wgsl-context-pending-statementscontext
setf
wgsl-context-pending-statementscontext
nil
defunwgsl-override-name-p
membername
wgsl-target-overrides
wgsl-context-targetcontext
:test#'eq
defunensure-wgsl-override
contextexpression
let
or
gethashname
wgsl-context-encountered-overridescontext
let
type
shader:shader-expression-typeexpression
unless
=1
shader:shader-type-component-counttype
error'shader:shader-language-error:formname:reason:non-scalar-wgsl-override:details
shader:shader-type-nametype
setf
gethashname
wgsl-context-encountered-overridescontext
make-instance'wgsl-override:namename:identifier
formatnil"knob_~A"
:type:default
defgenericlower-wgsl-expression
contextexpression
defmethodlower-wgsl-expression
multiple-value-bind
cached-resultcached-p
gethashexpression
wgsl-context-function-call-resultscontext
ifcached-p
note-wgsl-occurrencecontextexpressioncached-result
let
local-statementsnil
saved-referencesnil
unwind-protect
progn
dolist
unless
or
nth-value1
gethashbinding
wgsl-context-referencescontext
multiple-value-bind
old-referenceold-reference-p
gethashbinding
wgsl-context-referencescontext
push
listbindingold-referenceold-reference-p
saved-references
let*
setflocal-statements
gethashbinding
wgsl-context-referencescontext
name
setflocal-statements
nconclocal-statements
list
make-instance'wgsl-variable-statement:type
wgsl-type-name
shader:shader-expression-typebinding-expression
:namename:valuevalue
let*
setflocal-statements
wgsl-context-pending-statementscontext
nconcouter-statementslocal-statements
gethashexpression
wgsl-context-function-call-resultscontext
result-text
note-wgsl-occurrencecontextexpressionresult-text
dolist
savedsaved-references
destructuring-bind
bindingold-referenceold-reference-p
saved
ifold-reference-p
setf
gethashbinding
wgsl-context-referencescontext
old-reference
remhashbinding
wgsl-context-referencescontext
defmethodlower-wgsl-expression
let
condition
lower-wgsl-expressioncontext
lang:arithmetic-conditional-conditionexpression
consequent
lower-wgsl-expressioncontext
lang:arithmetic-conditional-consequentexpression
alternative
lower-wgsl-expressioncontext
lang:arithmetic-conditional-alternativeexpression

WGSL has no conditional expression. select is valid here because shader expressions are pure; ordered effects live in shader statements.

note-wgsl-occurrencecontextexpression
formatnil"select(~A, ~A, ~A)"
defmethodlower-wgsl-expression
let*
ordinal
incf
wgsl-context-fold-countercontext
state-name
formatnil"fold_state_~D"ordinal
index-name
formatnil"fold_index_~D"ordinal
count
lower-wgsl-expressioncontext
lang:arithmetic-counted-fold-countexpression
initial
lower-wgsl-expressioncontext
lang:arithmetic-counted-fold-initialexpression
index-binding
lang:arithmetic-counted-fold-index-bindingexpression
state-binding
lang:arithmetic-counted-fold-state-bindingexpression
multiple-value-bind
old-indexold-index-p
gethashindex-binding
wgsl-context-referencescontext
multiple-value-bind
old-stateold-state-p
gethashstate-binding
wgsl-context-referencescontext
setf
gethashindex-binding
wgsl-context-referencescontext
index-name
gethashstate-binding
wgsl-context-referencescontext
state-name
let*
until-expression
lang:arithmetic-counted-fold-untilexpression
until
anduntil-expression
local-statementsnil
dolist
binding
lang:arithmetic-counted-fold-bindingsexpression
let*
setflocal-statements
gethashbinding
wgsl-context-referencescontext
name
setflocal-statements
nconclocal-statements
list
make-instance'wgsl-variable-statement:type
wgsl-type-name
shader:shader-expression-typebinding-expression
:namename:valuevalue
let
update
lower-wgsl-expressioncontext
lang:arithmetic-counted-fold-updateexpression
setflocal-statements
wgsl-context-pending-statementscontext
nconcpreheader-statements
list
make-instance'wgsl-counted-fold-statement:type
wgsl-type-name
shader:shader-expression-typeexpression
:state-namestate-name:initialinitial:index-nameindex-name:index-type
wgsl-type-name
shader:shader-expression-type
lang:arithmetic-counted-fold-countexpression
:countcount:bindingslocal-statements:updateupdate:until-bindingsuntil-statements:untiluntil
dolist
binding
lang:arithmetic-counted-fold-bindingsexpression
remhashbinding
wgsl-context-referencescontext
ifold-index-p
setf
gethashindex-binding
wgsl-context-referencescontext
old-index
remhashindex-binding
wgsl-context-referencescontext
ifold-state-p
setf
gethashstate-binding
wgsl-context-referencescontext
old-state
remhashstate-binding
wgsl-context-referencescontext
note-wgsl-occurrencecontextexpressionstate-name
defmethodlower-wgsl-expression
declare
ignorecontext
error'shader:shader-language-error:form:reason:unsupported-wgsl-expression:details
class-name
class-ofexpression
defunlower-wgsl-infix-call
contextexpressionoperator
let
note-wgsl-occurrencecontextexpression
cond
and
string=operator"-"
=
lengthoperands
1
formatnil"(-~A)"
firstoperands
=
lengthoperands
1
formatnil"(~A)"
firstoperands
t
reduce
lambda
leftright
formatnil"(~A ~A ~A)"leftoperatorright
restoperands
:initial-value
firstoperands
defunlower-wgsl-function-call
contextexpressionname
let
note-wgsl-occurrencecontextexpression
formatnil"~A(~{~A~^, ~})"nameoperands
defunlower-wgsl-chained-function-call
contextexpressionname
let
note-wgsl-occurrencecontextexpression
reduce
lambda
leftright
formatnil"~A(~A, ~A)"nameleftright
restoperands
:initial-value
firstoperands
defmethodshader:lower-shader-call
error'shader:shader-language-error:form:reason:unsupported-wgsl-operator:detailsoperator
defmacrodefine-wgsl-infix-operator
operatortext
`
defmethodshader:lower-shader-call
operator
eql',operator
declare
ignoreoperator
defmacrodefine-wgsl-function-operator
operatorname
`
defmethodshader:lower-shader-call
operator
eql',operator
declare
ignoreoperator
defunlower-wgsl-vector-constructor
contextexpression
let
note-wgsl-occurrencecontextexpression
formatnil"~A(~{~A~^, ~})"
wgsl-type-name
shader:shader-expression-typeexpression
operands
defmethodshader:lower-shader-call
declare
ignoreoperator
let*
components
string-downcase
string
note-wgsl-occurrencecontextexpression
formatnil"~A.~A"components
defunwgsl-interface-attribute
let
location
shader:shader-interface-locationdeclaration
built-in
shader:shader-interface-built-indeclaration
interpolation
shader:shader-interface-interpolationdeclaration
cond
built-in
formatnil"@builtin(~A)"
casebuilt-in
:position"position"
:vertex-index"vertex_index"
:instance-index"instance_index"
otherwise
error'shader:shader-language-error:formsource-form:reason:unsupported-wgsl-built-in:detailsbuilt-in
location
formatnil"@location(~D)~@[ @interpolate(~A)~]"location
caseinterpolation
:flat"flat"
t
error'shader:shader-language-error:formsource-form:reason:undecorated-wgsl-interface
defunwrite-wgsl-uniform-block
streamresource
let
formatstream"struct ~A {~%"structure-name
dolist
member
shader:shader-uniform-block-membersresource
formatstream" ~A: ~A,~%"
wgsl-type-name
shader:shader-declaration-typemember
formatstream"}~%"
formatstream"@group(~D) @binding(~D) var<uniform> ~A: ~A;~%~%"
shader:shader-resource-descriptor-setresource
shader:shader-resource-bindingresource
resource-namestructure-name
defunregister-wgsl-references
contextspecification
dolist
input
shader:shader-specification-inputsspecification
setf
gethashinput
wgsl-context-referencescontext
formatnil"stage_in.~A"
dolist
resource
shader:shader-specification-resourcesspecification
unless
error'shader:shader-language-error:form:reason:unsupported-wgsl-resource:details
shader:shader-type-opaque-kind
shader:shader-declaration-typeresource
let
setf
gethashresource
wgsl-context-referencescontext
resource-name
dolist
member
shader:shader-uniform-block-membersresource
setf
gethashmember
wgsl-context-referencescontext
formatnil"~A.~A"resource-name
context
defgenericlower-wgsl-statement
contextstatement
defmethodlower-wgsl-statement
let
value
lower-wgsl-expressioncontext
shader:shader-assignment-valuestatement
append
list
make-instance'wgsl-output-statement:declaration
shader:shader-assignment-outputstatement
:field
wgsl-identifier
shader:shader-object-name
shader:shader-assignment-outputstatement
:valuevalue
defmethodlower-wgsl-statement
let
condition
lower-wgsl-expressioncontext
shader:shader-conditional-statement-conditionstatement
append
list
make-instance'wgsl-if-statement:conditioncondition:statements
mapcan
shader:shader-conditional-statement-statementsstatement
defmethodlower-wgsl-statement
declare
ignorecontext
error'shader:shader-language-error:form
shader:shader-statement-source-formstatement
:reason:unsupported-wgsl-statement:details
class-name
class-ofstatement
defunwgsl-index-zero
if
string=type"u32"
"0u""0.0f"
defunwgsl-index-one
if
string=type"u32"
"1u""1.0f"
defunwrite-wgsl-indent
stream&optional
extra0
looprepeatdo
write-string" "stream
defgenericwrite-wgsl-statement-form
statementstream
defmethodwrite-wgsl-statement-form
formatstream"let ~A: ~A = ~A;~%"
wgsl-variable-statement-namestatement
wgsl-variable-statement-typestatement
wgsl-occurrence-text
wgsl-variable-statement-valuestatement
defmethodwrite-wgsl-statement-form
stream
let*
declaration
wgsl-output-statement-declarationstatement
value
wgsl-occurrence-text
wgsl-output-statement-valuestatement
text
if
eq:position
shader:shader-interface-built-indeclaration

The shared camera graph intentionally retains Vulkan's framebuffer-oriented clip Y. WebGPU owns this conversion.

formatnil"vec4<f32>((~A).x, -(~A).y, (~A).z, (~A).w)"valuevaluevaluevalue
value
formatstream"result.~A = ~A;~%"
wgsl-output-statement-fieldstatement
text
defmethodwrite-wgsl-statement-form
stream
formatstream"if (~A) {~%"
wgsl-occurrence-text
wgsl-if-statement-conditionstatement
let
dolist
child
wgsl-if-statement-statementsstatement
formatstream"}~%"
defmethodwrite-wgsl-statement-form
formatstream"var ~A: ~A = ~A;~%"
wgsl-counted-fold-statement-state-namestatement
wgsl-counted-fold-statement-typestatement
wgsl-occurrence-text
wgsl-counted-fold-statement-initialstatement
formatstream"for (var ~A: ~A = ~A; ~A < ~A; ~A = ~A + ~A) {~%"
wgsl-counted-fold-statement-index-namestatement
wgsl-counted-fold-statement-index-typestatement
wgsl-index-zero
wgsl-counted-fold-statement-index-typestatement
wgsl-counted-fold-statement-index-namestatement
wgsl-occurrence-text
wgsl-counted-fold-statement-countstatement
wgsl-counted-fold-statement-index-namestatement
wgsl-counted-fold-statement-index-namestatement
wgsl-index-one
wgsl-counted-fold-statement-index-typestatement
let
dolist
binding
wgsl-counted-fold-statement-until-bindingsstatement
when
wgsl-counted-fold-statement-untilstatement
formatstream"if (~A) { break; }~%"
wgsl-occurrence-text
wgsl-counted-fold-statement-untilstatement
dolist
binding
wgsl-counted-fold-statement-bindingsstatement
formatstream"~A = ~A;~%"
wgsl-counted-fold-statement-state-namestatement
wgsl-occurrence-text
wgsl-counted-fold-statement-updatestatement
formatstream"}~%"
defunencountered-wgsl-overrides
loopfornamein
wgsl-target-overrides
wgsl-context-targetcontext
foroverride=
gethashname
wgsl-context-encountered-overridescontext
whenoverridecollectoverride
defunrender-wgsl-document
contextstatements
let*
specification
wgsl-context-specificationcontext
stage
shader:shader-specification-stagespecification
inputs
shader:shader-specification-inputsspecification
outputs
shader:shader-specification-outputsspecification
unless
memberstage'
:vertex:fragment
error'shader:shader-language-error:form:reason:unsupported-wgsl-stage:detailsstage
with-output-to-string
stream
dolist
formatstream"override ~A: ~A = ~A;~%"
wgsl-override-identifieroverride
wgsl-override-typeoverride
wgsl-float-literal
wgsl-override-defaultoverride
dolist
resource
shader:shader-specification-resourcesspecification
let
input-name
write-wgsl-interface-structurestreamspecification"Input"inputs
output-name
write-wgsl-interface-structurestreamspecification"Output"outputs
formatstream"@~(~A~)~%fn ~A(stage_in: ~A) -> ~A {~%"stageinput-nameoutput-name
formatstream" var result: ~A;~%"output-name
let
dolist
statementstatements
formatstream" return result;~%}~%"
defmethodshader:lower-shader-specification

Lower the shared shader graph directly to deterministic WGSL.

let
context
make-instance'wgsl-lowering-context:targettarget:specificationspecification
unless
member
shader:shader-specification-stagespecification
'
:vertex:fragment
error'shader:shader-language-error:form:reason:unsupported-wgsl-stage:details
shader:shader-specification-stagespecification
let
statementsnil
dolist
binding
shader:shader-specification-bindingsspecification
let*
setfstatements
gethashbinding
wgsl-context-referencescontext
name
setfstatements
nconcstatements
list
make-instance'wgsl-variable-statement:type
wgsl-type-name
shader:shader-expression-typeexpression
:namename:valuevalue
dolist
statement
shader:shader-specification-statementsspecification
setfstatements
nconcstatements
maphash
lambda
expressionoccurrences
setf
gethashexpression
wgsl-context-expression-occurrencescontext
nreverseoccurrences
wgsl-context-expression-occurrencescontext
make-instance'wgsl-document:targettarget:specificationspecification:source:overrides:expression-occurrences
wgsl-context-expression-occurrencescontext
:occurrence-expression
wgsl-context-occurrence-expressioncontext
defuncompile-wgsl
specification&keyoverrides
shader:lower-shader-specification
make-instance'wgsl-target:overridesoverrides
specification
defunwrite-wgsl
documentpathname
with-open-file
streampathname:direction:output:if-exists:supersede:if-does-not-exist:create
write-string
wgsl-document-sourcedocument
stream
pathname