protocol FrameSink
Swift
protocol FrameSink : AnyObject
Where a DrawList writes its frame, and who it hands the frame to.
Those are one question rather than two, and that is the whole point: the property worth keeping is that a draw command is written once, into the memory its consumer will read it from. A sink that only received a finished list would have to copy it, and a 1 MB copy is 0.3 ms — 2% of a frame, for something that should cost nothing. So a sink hands out the buffers first and is told what was filled in afterwards.
Two of them, and the shapes match closely enough that DrawList needed no
new concepts to support the second:
- In-process. The buffers are the engine's own per-window vectors, and
commitis a submission the renderer picks up on its next repaint. - Shared memory. The buffers are a slot in a
DrawArenaanother process reads, andcommitpublishes it. SeeArenaFrameSink.
The mid-frame growth is not an optimization either, in either case: how
many commands a frame needs is not known when it starts, because DrawList
grows during emit as the tree turns out to be bigger than last time.
Sources/LavaUI/FrameSink.swift:74
Properties
var framesInFlight: Int { get }
Frames handed over that the consumer has not taken yet.
Back-pressure, and the producer's half of a frame-callback contract: a non-zero answer means the last frame has not been picked up, so building another one is work nobody asked for. Zero for a sink whose consumer is in this process and takes every frame synchronously.
Advisory, never a lock. The signal that clears it can be lost, so a
caller that waits on this has to give up after a deadline — see
DrawArena::framesInFlight.
Sources/LavaUI/FrameSink.swift:106
var framesInFlight: Int { get }
Nothing is in flight for a sink that has no other process in the loop.
Sources/LavaUI/FrameSink.swift:111
Methods
func beginFrame(minimum: FrameCapacity) -> FrameBuffers?
Claims buffers for a new frame with at least minimum room.
Returns nil if none could be claimed, which DrawList treats as a
frame that draws nothing rather than as an error — the next one will
try again, and refusing to emit is better than emitting into memory
somebody else is reading.
Sources/LavaUI/FrameSink.swift:81
func commit(_ written: FrameCapacity)
Publishes what was written.
Sources/LavaUI/FrameSink.swift:94
func grow(to wanted: FrameCapacity, written: FrameCapacity) -> FrameBuffers?
Enlarges mid-frame, preserving the written prefix and returning
where it now lives.
Takes written rather than reading it from anywhere because a growth
may move the storage, and the part already filled in has to come with
it. Returns nil if the sink could not grow, leaving the caller with
the buffers it already had — a frame that has to finish smaller than
it wanted, not a frame that is abandoned halfway.
Sources/LavaUI/FrameSink.swift:91