protocol GPUResourceHost
Swift
protocol GPUResourceHost : AnyObject, Sendable
Who names the things that live on a GPU.
A GlyphInstance carries a font id and an image command carries a texture
id, and both are only meaningful to the process that owns the atlas they
index. In a normal app that process is this one, so the ids come from the
Editor and nobody has to think about it. Under a shared renderer they
come from the compositor, and a locally-invented number would draw the
wrong face or the wrong picture — silently, because a stale id is still a
valid index.
So this is the seam between the two modes, and it is deliberately the whole seam: a client differs from a windowed app in who answers these five questions and in nothing else. Shaping, measurement, layout and emit are unchanged, because none of them ever needed a device — only naming does.
Note what is not here: pixels. A remote host is asked to register a file it can open itself, never handed a decoded bitmap, which is the same rule the control plane follows for draw lists. Whoever owns the GPU does the decode, because they are about to own the result.
Sources/LavaUI/ResourceHost.swift:23
Methods
func registerFont(path: String, pixelSize26_6: UInt32, faceIndex: UInt32, rasterFlags: UInt32) -> UInt32?
Registers a face and returns the id to stamp into GlyphInstance.
Idempotent per face, which is a stronger claim than per path: the host opens the file and keys on what it contained, so two names for one file are one id, and a file whose bytes changed is correctly a new one. Nil if the file will not load.
The size is 26.6 fixed point — pixels times 64 — because a Float is
not something two processes can compare for equality and agree on, and
FreeType wants it quantised anyway. rasterFlags is a
FontRasterFlags.raw; unknown bits are refused, not ignored.
Sources/LavaUI/ResourceHost.swift:35
func registerFont(path: String, pixelSize: Float) -> UInt32?
Face 0 of path at pixelSize, hinted the renderer's default way —
what a caller that just wants a font file at a size should use.
Rounds the size to 26.6 here rather than making every caller do it, which is the point: there is exactly one conversion from "pixels a human typed" to "the number the renderer keys on", and it lives here.
Sources/LavaUI/ResourceHost.swift:110
func registerImage(path: String, maxPixelSize: UInt32, turn: ImageTurn) -> UIImage?
Registers an image, decoded from path, capped to maxPixelSize
(0 = native) and quarter-turned by turn, returning a handle with the
id and the decoded size.
Blocks. For anything an app needs before its first frame — an icon, a brand mark — where a placeholder would be worse than a stall.
The turn is asked of the host rather than done by the caller because
one of the two hosts is a compositor the caller cannot decode for — see
ImageTurn. Most callers want none and should use the two-argument
convenience below.
Sources/LavaUI/ResourceHost.swift:51
func registerImage(data: [UInt8], maxPixelSize: UInt32) -> UIImage?
Registers an image from encoded bytes (PNG, JPEG, …) rather than a path, for one that was downloaded, generated, or unpacked and never touched the filesystem.
Identity is the content, so registering the same bytes twice is one
texture without the caller keeping a key. Prefer registerImage(path:)
whenever there is a path: under a compositor this one sends the file
through shared memory, where a path sends a path.
Blocks, like its sibling.
Sources/LavaUI/ResourceHost.swift:76
func registerImage(path: String, maxPixelSize: UInt32) -> UIImage?
The overwhelmingly common case: no turn.
A convenience rather than a defaulted argument because a protocol requirement cannot carry one, and every caller but a viewer's rotate button wants a picture the way it is stored.
Sources/LavaUI/ResourceHost.swift:90
func registerImageAsync(path: String, maxPixelSize: UInt32, turn: ImageTurn, completion: @escaping @Sendable (UIImage?) -> Void)
The same registration off the calling thread, with completion run on
the main queue.
A protocol requirement rather than a helper because the two hosts split the work differently and only they know where. Locally, the decode belongs on a worker and the upload must be back on the main thread — it touches the device. Remotely the whole thing is one call, and there is no main-thread half at all.
Sources/LavaUI/ResourceHost.swift:61
func registerImageAsync(path: String, maxPixelSize: UInt32, completion: @escaping @Sendable (UIImage?) -> Void)
Not documented.
Sources/LavaUI/ResourceHost.swift:94
func registerImageAsync(path: String, maxPixelSize: UInt32, turn: ImageTurn, completion: @escaping @Sendable (UIImage?) -> Void)
Off-thread registration for a host that has no main-thread half — a
remote one, where the call is already a round trip and touches nothing
local. Editor overrides this, because it does.
Sources/LavaUI/ResourceHost.swift:122
func releaseImage(key: String)
Drops one reference to a registered image. key is the cacheKey
from the handle, not the bare path — the same file at two decode sizes
is two textures.
Sources/LavaUI/ResourceHost.swift:81