luv

Workshop wiki

slug-cache.lisp

hal/shader/slug-cache.lisp

system luv · 23 definitions · on GitHub

Device-owned Slug shaping, outline, and atlas resources.

slug-glyph-cache is the semantic device boundary. It retains durable HarfBuzz results and normalized outlines, then packs the exact glyph set a run needs into shared RG16U/RGBA16F atlases. Screen and world renderers supply their own placement geometry around these reusable records.

in-package#:luv.slug
defstructslug-device-glyphkeyglyph-idserialized
defstructslug-glyph-placementglyph-idresourceorigin-xorigin-youtline-min-xoutline-min-youtline-max-xoutline-max-y
defstructslug-glyph-atlaskeylocationsband-texel-countcurve-texel-countband-textureband-viewcurve-texturecurve-view
defclassslug-glyph-cache
device:initarg:device:readerslug-glyph-cache-device
entries:initform
make-hash-table:test#'equal
:readerslug-glyph-cache-entries
atlases:initform
make-hash-table:test#'equal
:readerslug-glyph-cache-atlases
:documentation

Reusable HarfBuzz results and exact Slug GPU outlines owned by one device.

defunmake-slug-glyph-cache
device
make-instance'slug-glyph-cache:devicedevice
defvar*slug-font-keys*
make-hash-table:test#'equal:synchronizedt

Resolved font keys by the namestring asked for: TRUENAME is a few system calls and some consing, and is asked for once per glyph.

defunslug-font-key
font-pathname
let
name
namestringfont-pathname
or
gethashname*slug-font-keys*
setf
gethashname*slug-font-keys*
namestring
truenamefont-pathname

One parsed font per file for the whole process. Opening a TTF with ZPB-TTF reads and parses its tables, which is far too much to do per string per frame; the loader keeps its stream and is never closed.

defvar*slug-font-loaders*
make-hash-table:test#'equal
"Open ZPB-TTF font loaders, keyed by the font file's true name."
defvar*slug-font-loaders-lock*
sb-thread:make-mutex:name"slug font loaders"
defunslug-font-loader
font-pathname

The process-wide open ZPB-TTF loader for font-pathname.

let
key
slug-font-keyfont-pathname
sb-thread:with-mutex
or
setf
zpb-ttf:open-font-loaderkey
defvar*slug-shaped-texts*
make-hash-table:test#'equal:synchronizedt

HarfBuzz results for the whole process, by font key, string, and direction. Shaping does not depend on the device, and measuring text (text-size) happens with no device cache at hand, so one table serves all.

defunslug-shaped-text-for
font-pathnamestring&keydirection

Return one durable HarfBuzz result for an exact font, string, and direction.

let
key
list
slug-font-keyfont-pathname
stringdirection
or
setf
shape-slug-textstringfont-pathname:directiondirection
defuncached-slug-shaped-text
cachefont-pathnamestring&keydirection

Return one durable HarfBuzz result for an exact font, string, and direction.

declare
ignorecache
slug-shaped-text-forfont-pathnamestring:directiondirection
defuncreate-slug-device-glyph
keyglyph-idfont-loader
let*
glyph
load-slug-glyph-indexglyph-idfont-loader
when
slug-outline-contoursoutline
make-slug-device-glyph:keykey:glyph-idglyph-id:serialized
defunslug-device-glyph-for
cachefont-pathnameglyph-idfont-loader
let*
key
list
slug-font-keyfont-pathname
glyph-id
entries
slug-glyph-cache-entriescache
multiple-value-bind
valuepresent-p
gethashkeyentries
ifpresent-p
unless
eqvalue:empty
value
let
resource
create-slug-device-glyphkeyglyph-idfont-loader
setf
gethashkeyentries
orresource:empty
resource
defunslug-glyph-cache-resource-count
cache
loopforresourcebeingthehash-valuesof
slug-glyph-cache-entriescache
count
not
eqresource:empty
defunslug-atlas-upload-data
resourcescount-readerdata-readerelement-type
let*
width4096
texel-count
loopforresourceinresourcessum
funcallcount-reader
slug-device-glyph-serializedresource
height
max1
ceilingtexel-countwidth
data
make-array:element-typeelement-type:initial-element0
offset0
dolist
resourceresources
let*
serialized
slug-device-glyph-serializedresource
count
funcallcount-readerserialized
source
funcalldata-readerserialized
dotimes
indexcount
setf
row-major-arefdata
+offsetindex
row-major-arefsourceindex
incfoffsetcount
valuesdatatexel-count
defuncreate-slug-glyph-atlas
cachekeyresources

Pack resources into one RG16U band and one RGBA16F curve texture.

let
locations
make-hash-table:test#'eq
band-offset0
curve-offset0
dolist
resourceresources
setf
gethashresourcelocations
listband-offsetcurve-offset
incfband-offset
slug-serialized-outline-band-texel-count
slug-device-glyph-serializedresource
incfcurve-offset
slug-serialized-outline-curve-texel-count
slug-device-glyph-serializedresource
multiple-value-bind
band-databand-count
slug-atlas-upload-dataresources#'slug-serialized-outline-band-texel-count#'slug-serialized-outline-band-upload-data'
unsigned-byte32
multiple-value-bind
curve-datacurve-count
slug-atlas-upload-dataresources#'slug-serialized-outline-curve-texel-count#'slug-serialized-outline-curve-upload-data'
unsigned-byte64
let*
device
slug-glyph-cache-devicecache
band-size
list4096
array-dimensionband-data0
curve-size
list4096
array-dimensioncurve-data0
band-texturenil
curve-texturenil
band-viewnil
curve-viewnil
completed-pnil
unwind-protect
progn
setfband-texture
luv:createdevice
luv:make-texture-descriptor:label"Slug RG16U band atlas":sizeband-size:dimensions:2d:format:rg16-uint:usage'
:texture-binding:copy-dst
curve-texture
luv:createdevice
luv:make-texture-descriptor:label"Slug RGBA16F curve atlas":sizecurve-size:dimensions:2d:format:rgba16-float:usage'
:texture-binding:copy-dst
band-view
luv:createdevice
luv:make-texture-view-descriptor:textureband-texture
curve-view
luv:createdevice
luv:make-texture-view-descriptor:texturecurve-texture
luv:write-texture
luv:make-texture-copy:textureband-texture
band-data
luv:make-texture-data-layout:bytes-per-row
*44096
:rows-per-image
secondband-size
band-size
luv:write-texture
luv:make-texture-copy:texturecurve-texture
curve-data
luv:make-texture-data-layout:bytes-per-row
*84096
:rows-per-image
secondcurve-size
curve-size
prog1
make-slug-glyph-atlas:keykey:locationslocations:band-texel-countband-count:curve-texel-countcurve-count:band-textureband-texture:band-viewband-view:curve-texturecurve-texture:curve-viewcurve-view
setfcompleted-pt
unlesscompleted-p
dolist
resource
removenil
listcurve-viewband-viewcurve-textureband-texture
luv:destroyresource
defunslug-glyph-atlas-for
cacheglyphs
let*
resources
remove-duplicates
mapcar#'slug-glyph-placement-resourceglyphs
:test#'eq
key
mapcar#'slug-device-glyph-keyresources
atlases
slug-glyph-cache-atlasescache
or
gethashkeyatlases
setf
gethashkeyatlases
create-slug-glyph-atlascachekeyresources
defunrelease-slug-glyph-atlas
atlas
luv:destroy
slug-glyph-atlas-curve-viewatlas
luv:destroy
slug-glyph-atlas-band-viewatlas
luv:destroy
slug-glyph-atlas-curve-textureatlas
luv:destroy
slug-glyph-atlas-band-textureatlas
defunrelease-slug-glyph-cache
cache
maphash
lambda
keyatlas
declare
ignorekey
slug-glyph-cache-atlasescache
clrhash
slug-glyph-cache-atlasescache
clrhash
slug-glyph-cache-entriescache
values
defunmake-slug-glyph-placements
shapedfont-loadercachefont-pathname

Join HarfBuzz placements to normalized Slug outlines by selected glyph ID.

let*
unit
/1
slug-shaped-text-units-per-emshaped
pen-x0
pen-y0
glyphs
loopforplacementacross
slug-shaped-text-glyphsshaped
forglyph-id=
slug-shaped-glyph-glyph-idplacement
forresource=
slug-device-glyph-forcachefont-pathnameglyph-idfont-loader
do
whenresource
let*
serialized
slug-device-glyph-serializedresource
packed
slug-serialized-outline-packed-outlineserialized
push
make-slug-glyph-placement:glyph-idglyph-id:resourceresource:origin-x
*
+pen-x
slug-shaped-glyph-x-offsetplacement
unit
:origin-y
*
+pen-y
slug-shaped-glyph-y-offsetplacement
unit
:outline-min-x
slug-packed-outline-min-xpacked
:outline-min-y
slug-packed-outline-min-ypacked
:outline-max-x
slug-packed-outline-max-xpacked
:outline-max-y
slug-packed-outline-max-ypacked
glyphs
incfpen-x
slug-shaped-glyph-x-advanceplacement
incfpen-y
slug-shaped-glyph-y-advanceplacement
nreverseglyphs
defunslug-text-extents
glyphsshapedfont-loader

Return normalized left, bottom, right, and top extents for glyphs.

let*
unit
/1
slug-shaped-text-units-per-emshaped
advance-x
*unit
slug-shaped-text-x-advanceshaped
advance-y
*unit
slug-shaped-text-y-advanceshaped
values
min0.0
loopforglyphinglyphsminimize
+
slug-glyph-placement-origin-xglyph
slug-glyph-placement-outline-min-xglyph
min0.0
*unit
zpb-ttf:descenderfont-loader
loopforglyphinglyphsminimize
+
slug-glyph-placement-origin-yglyph
slug-glyph-placement-outline-min-yglyph
maxadvance-x
loopforglyphinglyphsmaximize
+
slug-glyph-placement-origin-xglyph
slug-glyph-placement-outline-max-xglyph
maxadvance-y
*unit
zpb-ttf:ascenderfont-loader
loopforglyphinglyphsmaximize
+
slug-glyph-placement-origin-yglyph
slug-glyph-placement-outline-max-yglyph