Documentation
¶
Overview ¶
Package compose is a Pure Go multi-process composition library for the gogpu ecosystem. It lets independent OS processes render UI content into offscreen buffers and ship pixels to a single compositor process that blits them onto the screen.
The compositor model provides process isolation (a crash in one module does not take down the display), hot-pluggable third-party modules, and the possibility of cross-language modules — anything that can write RGBA to a Unix socket or shared memory segment can participate.
Quick Start ¶
Compositor (server) side:
srv, err := compose.Listen("/tmp/compose.sock",
compose.WithMaxModules(8),
)
if err != nil {
log.Fatal(err)
}
defer srv.Close()
srv.OnFrame(func(f compose.Frame) {
// Blit f.Pixels onto the compositor window.
})
Module (client) side:
client, err := compose.Dial("/tmp/compose.sock",
compose.WithName("clock"),
compose.WithFrameSize(400, 120),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
client.OnFrameRequest(func() {
// Render and publish a frame.
_ = client.PublishFrame(compose.Frame{
Pixels: renderClock(),
Width: 400,
Height: 120,
})
})
Architecture ¶
Multi-window in gogpu (ADR-010) and the compose model are different concepts. Multi-window shares one GPU Device across N native windows inside a single process. The compose model is the opposite: N independent processes, each with its own GPU Device, cooperating over IPC to produce a single composed display.
The public API consists of five types (Frame, Server, Client, ServerOption, ClientOption) and three constructor functions (Listen, Dial, and With* options). All implementation details live behind internal/ boundaries.
Part of the GoGPU ecosystem: https://github.com/gogpu
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrClosed is returned when an operation is attempted on a closed // Server or Client. ErrClosed = errors.New("compose: server/client closed") // ErrNotAccepted is returned by Dial when the compositor rejects the // connection (e.g., due to capacity limits or policy). ErrNotAccepted = errors.New("compose: connection not accepted by compositor") // ErrModuleNotFound is returned by RequestFrame when the specified // module ID does not exist in the server's module table. ErrModuleNotFound = errors.New("compose: module not found") // ErrMaxModules is returned when the server cannot accept a new module // because the maximum module count has been reached. ErrMaxModules = conn.ErrMaxModules // ErrNameTaken is returned when a module with the same name is already // connected to the server. ErrNameTaken = conn.ErrNameTaken )
Sentinel errors returned by Server and Client.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the module-side endpoint that connects to a compositor and publishes frames. All methods are safe for concurrent use.
func Dial ¶
func Dial(addr string, opts ...ClientOption) (*Client, error)
Dial creates a Client that connects to a compositor at the given Unix domain socket address. Dial performs the handshake immediately: it sends a HelloMsg and reads the WelcomeMsg. If the compositor rejects the connection, ErrNotAccepted is returned.
Use ClientOption functions to configure the module:
client, err := compose.Dial("/tmp/compose.sock",
compose.WithName("clock"),
compose.WithFrameSize(400, 120),
compose.WithFPS(1),
)
func (*Client) Close ¶
Close disconnects from the compositor and releases resources. After Close returns, no more callbacks will be invoked.
func (*Client) ModuleID ¶
ModuleID returns the compositor-assigned module identifier. This is valid after Dial returns successfully.
func (*Client) OnFrameRequest ¶
func (c *Client) OnFrameRequest(fn func())
OnFrameRequest registers a callback invoked when the compositor requests a frame. This enables pull-based rendering: the module renders only when asked. The callback is called on an internal goroutine; it must not block for extended periods. Only one callback can be active; subsequent calls replace the previous one. Pass nil to remove.
func (*Client) PublishFrame ¶
PublishFrame sends a frame to the compositor. The frame's ModuleID is automatically set to this client's assigned ID.
Returns ErrClosed if the client has been shut down.
func (*Client) SetCompression ¶
SetCompression sets the codec used for frame payload compression. This allows the compositor to negotiate compression during or after handshake. Supported values: "lz4". Any other value uses raw.
type ClientOption ¶
type ClientOption func(*clientConfig)
ClientOption configures a Client. Use With* functions to create options.
func WithFPS ¶
func WithFPS(fps uint16) ClientOption
WithFPS sets the module's preferred frame rate. A value of 0 defaults to 1 FPS (suitable for static content). Default: 1.
func WithFrameSize ¶
func WithFrameSize(width, height uint32) ClientOption
WithFrameSize sets the initial frame dimensions in pixels. The compositor may acknowledge different dimensions during handshake. Default: 400x300.
func WithName ¶
func WithName(name string) ClientOption
WithName sets the human-readable module name sent during the handshake. The name is used for logging, slot assignment, and module identification. Names longer than 63 bytes are silently truncated. Default: "module".
type Frame ¶
type Frame struct {
// ModuleID is the compositor-assigned identifier.
// Ignored on publish (server assigns).
ModuleID uint64
// Name is a human-readable module name (e.g., "clock", "weather").
// Set during handshake, included in received frames for convenience.
Name string
// Pixels is the RGBA premultiplied pixel buffer.
// Stride is always Width * 4.
Pixels []byte
// Width and Height of the frame in pixels.
Width uint32
Height uint32
// DirtyRect is the sub-region that changed since the last frame.
// Zero value means the entire frame is dirty (keyframe).
DirtyRect image.Rectangle
// Timestamp is a monotonic nanosecond timestamp from the module's clock.
Timestamp int64
// Sequence is the monotonically increasing frame counter assigned by
// the publishing client. It is carried from the wire protocol header
// and can be used for change detection (e.g., comparing against a
// previously seen sequence number in Snapshot).
Sequence uint64
}
Frame is the fundamental data unit: a rectangular pixel buffer from a module. Users construct it to publish (module side) or receive it in callbacks (compositor side).
On the module side, ModuleID is ignored in PublishFrame — the server assigns the module's ID automatically. On the compositor side, OnFrame delivers a Frame with ModuleID populated.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the compositor-side endpoint that accepts module connections and delivers frames. All methods are safe for concurrent use.
func Listen ¶
func Listen(addr string, opts ...ServerOption) (*Server, error)
Listen creates a Server that accepts module connections on the given Unix domain socket address. The server immediately begins accepting connections in a background goroutine.
Use ServerOption functions to configure behavior:
srv, err := compose.Listen("/tmp/compose.sock",
compose.WithMaxModules(8),
compose.WithCompression("lz4"),
)
func (*Server) Close ¶
Close shuts down the server, disconnects all modules, and releases resources. After Close returns, no more callbacks will be invoked.
func (*Server) OnConnect ¶
OnConnect registers a callback invoked when a module completes the handshake and becomes active. Only one callback can be active; subsequent calls replace the previous one. Pass nil to remove.
func (*Server) OnDisconnect ¶
OnDisconnect registers a callback invoked when a module disconnects or crashes. Only one callback can be active; subsequent calls replace the previous one. Pass nil to remove.
func (*Server) OnFrame ¶
OnFrame registers a callback invoked when a module delivers a frame. The callback is called on an internal goroutine; it must not block for extended periods. Only one callback can be active; subsequent calls replace the previous one. Pass nil to remove.
func (*Server) RequestFrame ¶
RequestFrame sends a frame-request signal to the specified module (pull model). The module should respond with its next frame via PublishFrame.
Returns ErrModuleNotFound if the module ID is not connected. Returns ErrClosed if the server has been shut down.
func (*Server) Snapshot ¶ added in v0.2.0
Snapshot returns the latest frame from each connected module. Returns nil entries for modules that haven't sent any frames yet. The returned map is keyed by module ID.
Snapshot does NOT clear the mailbox — the frame stays until overwritten by a newer one from the same module. Compositors may call Snapshot multiple times per render tick; each call returns the same frame until the module publishes a new one. Use Frame.Sequence for change detection.
Thread-safe. Designed to be called once per compositor render tick.
type ServerOption ¶
type ServerOption func(*serverConfig)
ServerOption configures a Server. Use With* functions to create options.
func WithCompression ¶
func WithCompression(algo string) ServerOption
WithCompression enables frame payload compression on the Server. Supported values: "lz4". Any other value (including "") uses raw pass-through (no compression). Default: no compression.
func WithMaxModules ¶
func WithMaxModules(n int) ServerOption
WithMaxModules sets the maximum number of concurrent module connections the Server will accept. Values less than 1 are clamped to 1. Default: 16.
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
codec
Package codec provides frame payload compression and decompression for the compose protocol.
|
Package codec provides frame payload compression and decompression for the compose protocol. |
|
conn
Package conn provides connection lifecycle management for the compose library.
|
Package conn provides connection lifecycle management for the compose library. |
|
flow
Package flow provides pull-based frame pacing for the compose library.
|
Package flow provides pull-based frame pacing for the compose library. |
|
protocol
Package protocol defines the wire format for gogpu/compose inter-process communication.
|
Package protocol defines the wire format for gogpu/compose inter-process communication. |
|
transport/socket
Package socket provides a Unix domain socket transport for the compose protocol.
|
Package socket provides a Unix domain socket transport for the compose protocol. |