interface Images
Control plane
interface Images
Image registration that does not stop the desktop.
RegisterImage on Compositor decodes on the compositor's event loop,
because every call on that object is dispatched there — and a decode is the
one call in the interface that is not microseconds. A 24-megapixel JPEG is a
quarter of a second of stbi_load, during which no window on the desktop
draws a frame; a folder of thumbnails asks for thirty at once.
This object lives on a POA of its own with no loop executor, so a call runs on an RPC worker thread. It visits the loop twice, briefly — once to find an image already registered or still resident, once to upload the pixels and record the lease — and decodes in between, on the worker. Several decode at once; the loop never waits for any of them.
Same arguments, same answers and the same identity as the Compositor
methods: an image registered through either is one texture, released with
Compositor.ReleaseImage, and counted against the same connection.
idl/lava.npidl:2604
Methods
u32 AttachPixelArena(name: string) raises(PixelArenaNotFound)
Opens a shared-memory object the client created, and returns the handle later calls name it by.
The client creates it and the renderer attaches, the same direction as
a draw arena and for the same reason: the client knows how much it
needs. name is the shm_open name and must begin /lava-pixels-, so
this cannot be used to open some other mapping by name. The client may
shm_unlink it as soon as this returns: what the renderer holds is
the open file, not the name, so a client that is later killed leaves
nothing behind in /dev/shm.
Read, never mapped. The renderer reads each region with pread, so
a client that truncates the object under it gets a short read and
PixelRegionInvalid, where a mapping would have taken the compositor
down with SIGBUS.
Leased to the connection like a registration, and closed with everything else when the session's last input subscription ends. A few per connection at most, since each is an open file in the compositor; a client that outgrows its arena attaches a bigger one and detaches the old one.
idl/lava.npidl:2645
u32 AttachVideoBuffer(dmabuf: fd, layout: VideoBufferLayout) raises(VideoBufferInvalid)
Imports one dma-buf and returns the handle ShowVideoBuffer names it
by. The compositor keeps its own reference to the memory, so the client
may close dmabuf once this returns; the import lives until
DetachVideoBuffer, or until the session's last input subscription
ends, like a pixel arena.
A handful per connection — a player needs three — since each is an imported allocation on the compositor's device.
idl/lava.npidl:2695
void DetachPixelArena(arena: u32)
Closes it. Images already uploaded from it stay valid: they are
textures now, and nothing about them refers back to the arena. A handle
already detached, or never attached, is ignored, as ReleaseImage does.
idl/lava.npidl:2650
void DetachVideoBuffer(handle: u32)
Drops the import and its texture. Unknown handles are ignored.
idl/lava.npidl:2717
VideoTarget GetVideoTarget()
The device and layouts a video buffer must have. See VideoTarget.
idl/lava.npidl:2685
ImageInfo RegisterImage(path: string, maxPixelSize: u32, turn: ImageTurn) raises(ImageNotFound)
Compositor.RegisterImage, decoded off the loop.
idl/lava.npidl:2606
ImageInfo RegisterImageData(bytes: vector<u8>, maxPixelSize: u32) raises(ImageNotFound)
Compositor.RegisterImageData, decoded off the loop.
idl/lava.npidl:2611
ImageInfo ShowVideoBuffer(handle: u32) raises(VideoBufferInvalid)
"The buffer holds a finished frame": the compositor copies it into the
texture it keeps for that buffer and returns the texture's id, for an
Image command like any other.
Finished means finished on the GPU — the client has waited for its
own rendering (a glFinish, or a fence) before calling. There is no
acquire fence on the wire because the drivers this runs on do not agree
about implicit ones, and the client's wait is off everybody's loop.
The reply is the release. The copy is complete before it is sent, so
the client may render into the buffer again as soon as it arrives —
the same contract as UploadPixels.
The id is usually the same from one call to the next for the same buffer, but not always: a texture a frame in flight is still sampling is replaced rather than overwritten. Use the id this returns, every time.
idl/lava.npidl:2714
ImageInfo UploadPixels(region: PixelRegion) raises(PixelArenaNotFound, PixelRegionInvalid)
Uploads one region of an attached arena as a new texture, and returns its id and size.
The region is lent for the length of the call and no longer. By the time the reply arrives the pixels have been read, and the client may write over them straight away. That is the whole synchronisation protocol: there is no fence or "done reading" message, because the reply already serves as one.
Not content-addressed, and not idempotent. Hashing four megabytes to
find a tile nobody else will ever ask for is pure cost, so every call is
a new texture. Compositor.ReleaseImage discards it rather than
letting it go dormant, since no later call could name it again (see
TextureManager::discardTexture). Counted against LAVA_IMAGE_BUDGET_MB
like any other standalone texture.
There is no in-place update here. A tile pool would want one, so that a
tile is a copy rather than an allocation. Video has its own path, which
does overwrite in place — AttachVideoBuffer below — because a frame
there is a dma-buf on the GPU already and never needed to be pixels.
idl/lava.npidl:2672