1package ports
2
3import (
4 "errors"
5 "fmt"
6 "image"
7 "os"
8 "time"
9)
10
11// MaxCaptureInflight bounds the capture requests admitted but not yet
12// answered, across outputs. The reply channel of the production app has
13// at least this capacity, so an output never blocks on a reply.
14const MaxCaptureInflight = 32
15
16// ErrCaptureTransient marks a capture failure that may clear on its own (the
17// renderer busy, the indicator or an exclusion not shown yet): a protocol
18// frame tries again shortly instead of failing. Test with errors.Is.
19var ErrCaptureTransient = errors.New("capture: transient")
20
21// ErrCaptureBusy: every capture slot of the renderer is leased.
22var ErrCaptureBusy = fmt.Errorf("%w: no free slot", ErrCaptureTransient)
23
24// CaptureFrame is a lease on one renderer readback slot holding a GPU
25// copy of a rendered frame. Done and Read make no Vulkan call: a worker
26// goroutine waits on Done, then reads. EndCapture returns the lease.
27type CaptureFrame interface {
28 // Done is the sync file signalled when the copy finished; nil means it
29 // had finished when BeginCapture returned. The frame owns it.
30 Done() *os.File
31 // Read copies region (output pixels) as opaque sRGB8 BGRA rows into
32 // dst, stride bytes per row. Valid after Done signalled and before
33 // EndCapture.
34 Read(region image.Rectangle, dst []byte, stride int) error
35}
36
37// Renderer draws scenes for an output. One goroutine owns it. Frames go
38// to its own image until ExportTargets gives it scanout images; then each
39// Render draws into the target chosen by UseTarget (ADR 014: no CPU pass).
40type Renderer interface {
41 // SetHDR selects the HDR10 output transform (0 disables it).
42 // The DRM output calls this before ExportTargets.
43 SetHDR(sdrNits float64)
44 // Render draws the scene. done is a sync file signalled when the GPU
45 // finished the frame (nil: already finished); the caller closes it.
46 Render(Scene, map[WindowID]SurfaceContent) (done *os.File, err error)
47 // ExportTargets allocates n images of the renderer's size that the
48 // display can scan out, with one of the given XRGB8888 (SDR) or
49 // XRGB2101010 (HDR) modifiers (none: any the device exports),
50 // and returns them as dmabufs; a modifier may have several memory
51 // planes (DCC metadata), each plane owning its file. singlePlane
52 // restricts the choice to one-plane modifiers.
53 // n = 0 drops the targets.
54 ExportTargets(n int, modifiers []uint64, singlePlane bool) ([]DMABuf, error)
55 // UseTarget selects the exported image the next Render draws into.
56 UseTarget(i int)
57 // CursorBuffers allocates two linear ARGB8888 images of size×size the
58 // display can show on its cursor plane, and returns them as dmabufs.
59 CursorBuffers(size int) ([2]DMABuf, error)
60 // WriteCursor fills cursor image i with premultiplied ARGB8888 pixels
61 // (w×h, w*4 per row), cropped to the image and cleared around it.
62 WriteCursor(i int, pixels []byte, w, h int) error
63 // Pixels reads the last frame back (headless screenshots, tests). It
64 // waits for the GPU: debug only. Nil when it cannot (every capture
65 // slot leased, or the copy failed).
66 Pixels() *image.RGBA
67 // HDRPixels reads the last HDR frame's XRGB2101010 target back, each
68 // 10-bit code scaled to 16 bits (c<<6 | c>>4), A = 0xffff. It waits for
69 // the GPU: debug only. Nil when the output is SDR, the target is not
70 // readable, a slot is busy or the copy failed.
71 HDRPixels() *image.RGBA64
72 // BeginCapture submits a GPU copy of the last rendered frame into a
73 // free slot and returns without waiting. ErrCaptureBusy when every
74 // slot is leased; another error when the copy cannot be tracked (no
75 // sync file): the caller fails the request.
76 BeginCapture() (CaptureFrame, error)
77 // EndCapture returns a lease. It never waits: a slot whose copy may
78 // still run is reused only once the renderer sees it finished.
79 EndCapture(CaptureFrame)
80 // Trim frees client buffer caches left undrawn for a while and what
81 // finished frames held, without rendering. Outputs call it
82 // periodically: an idle output renders no frame to free them.
83 Trim(now time.Time) error
84 // TakeRedrawn returns the target pixels drawn since the last call
85 // (damage-limited frames count their damage only) and starts over.
86 TakeRedrawn() int
87 Close()
88}
89
90// Seat is the device broker (libseat) input devices are opened through.
91type Seat interface {
92 OpenDevice(path string) (int, error)
93 CloseDevice(fd int)
94 SwitchVT(vt int)
95}