main f2d166b

surface_content.go RawHistoryFolder

1package ports
2
3import (
4	"image"
5	"math"
6	"os"
7)
8
9// SurfaceColor is the committed encoding of a surface. Zero means sRGB.
10// PQ+BT.2020 and extended-linear sRGB are color-managed; zero is legacy
11// sRGB. MaxCLL/MaxFALL are in nits. YUV metadata is per surface commit.
12type SurfaceColor struct {
13	TF, Primaries   uint8
14	MaxCLL, MaxFALL uint16
15	// Coefficients/range follow wp_color_representation_v1 (zero =
16	// unspecified, for YUV interpreted as BT.709 limited). Chroma is a
17	// H.273 Chroma420SampleLocType + 1 (zero defaults to type 0).
18	Coefficients, Range, Chroma uint8
19}
20
21const (
22	ColorTFPQ             uint8 = 11 // wp_color_manager_v1 ST2084 PQ
23	ColorTFExtendedLinear uint8 = 5  // wp_color_manager_v1 ext_linear
24	ColorPrimariesBT2020  uint8 = 6  // wp_color_manager_v1 BT.2020
25	ColorPrimariesSRGB    uint8 = 1
26	ColorTFSRGB           uint8 = 9 // wp_color_manager_v1 sRGB
27)
28
29func (c SurfaceColor) IsPQ2020() bool {
30	return c.TF == ColorTFPQ && c.Primaries == ColorPrimariesBT2020
31}
32
33func (c SurfaceColor) IsExtendedLinear() bool {
34	return c.TF == ColorTFExtendedLinear && c.Primaries == ColorPrimariesSRGB
35}
36
37// ContentType is the committed wp_content_type_v1 hint.
38type ContentType uint8
39
40const (
41	ContentNone ContentType = iota
42	ContentPhoto
43	ContentVideo
44	ContentGame
45)
46
47// SurfaceContent carries wayland → output the latest committed content of a
48// window: SHM, a client shared-memory buffer, DMABuf, a GPU buffer, or
49// Solid, a single-pixel buffer. Renderers read them in place and never modify
50// them. Empty means the window
51// has no content. LogicalW and LogicalH are the surface size in logical
52// pixels (buffer scale and viewport applied). Subsurfaces come in Children;
53// Geometry is the part of the surface that is the window (xdg window
54// geometry), the rest being client shadows.
55type SurfaceContent struct {
56	ID          WindowID
57	ContentType ContentType
58	// Surface is a never-reused wl_surface identity; Version identifies its
59	// applied buffer content independently of the window publication Seq.
60	Surface, Version uint64
61	// Seq counts the window's contents (wayland sets it), for release.
62	Seq                uint64
63	Width, Height      int
64	LogicalW, LogicalH int
65	// Source is the committed crop in buffer pixels: x, y, width, height.
66	// Zero width means the entire buffer is used.
67	Source [4]float32
68	// Transform is the wl_output.transform the client applied to the
69	// buffer: readers apply its inverse. Width and Height stay the buffer's.
70	Transform BufferTransform
71	// Opaque ignores the alpha byte: an x format, or an opaque region that
72	// covers the whole surface. It is false while Fade is set.
73	Opaque bool
74	// OpaqueRect is the largest rect of the opaque region inside a surface
75	// that is not wholly Opaque, in logical pixels from the surface origin:
76	// the pixels there ignore alpha too, so the surfaces below it are hidden
77	// by it. Empty when there is none or while Fade is set.
78	OpaqueRect Rect
79	// Fade is how much wp_alpha_modifier_v1 fades the surface: 0 none,
80	// 1 invisible. Its opacity is multiplied by 1-Fade.
81	Fade   float32
82	Color  SurfaceColor
83	SHM    *SHMBuffer
84	DMABuf *DMABuf
85	// Solid is a single-pixel buffer (Width and Height are 1): the surface is
86	// one flat color.
87	Solid *SolidColor
88	// Children are the subsurfaces, bottom to top, flattened.
89	Children []Subsurface
90	// Geometry is in logical pixels from the surface origin; empty means
91	// the whole surface.
92	Geometry Rect
93	// Async asks for tearing presentation (wp_tearing_control_v1); outputs
94	// honour it only in direct scanout.
95	Async bool
96	// Acquire is the explicit-sync fence of this content's root buffer
97	// (wp_linux_drm_syncobj_v1): readers wait on it before reading the
98	// buffer, instead of the buffer's implicit fences. Wayland owns it and
99	// closes it when the buffer is released; a reader that keeps it past
100	// the call duplicates it under Acquire.SyscallConn. nil: implicit sync.
101	// Wayland closes it only after every output reported a later content of
102	// the window as seen, so a reader never gets it already closed.
103	Acquire *os.File
104	// DamageHistory is what changed in the root surface's buffer over the
105	// window's last contents, oldest first, ending with this one (Seq).
106	// A renderer holding an older content redraws the union of the
107	// entries after it, or everything when the history does not reach it.
108	DamageHistory []SeqDamage
109}
110
111// ContentBatch is the window contents wayland hands to one output: at most
112// one per window, the latest published. A content superseded before the
113// output took the batch is overwritten in place; contents carry the window's
114// Seq, so the release accounting needs only the newest one.
115//
116// Ownership moves with the batch: the sender must not touch it after the
117// send, and the receiver resets it and gives it back through ContentReturn.
118// Items is a slice, not a map: SurfaceContent is large, and a map would
119// allocate its elements again after every clear.
120type ContentBatch struct {
121	Items []SurfaceContent
122}
123
124// Reset empties the batch, dropping its references to buffers, and keeps its
125// capacity for reuse.
126func (b *ContentBatch) Reset() {
127	clear(b.Items)
128	b.Items = b.Items[:0]
129}
130
131// ContentReturn gives a consumed batch back to wayland. Return never blocks
132// and is safe after the output was detached.
133type ContentReturn interface{ Return(*ContentBatch) }
134
135// BufferTransform is a wl_output.transform value: bit 0 rotates 90°
136// counter-clockwise, bit 1 rotates 180°, bit 2 flips around the vertical
137// axis first.
138type BufferTransform uint8
139
140// Rotated reports whether width and height swap between buffer and surface.
141func (t BufferTransform) Rotated() bool { return t&1 != 0 }
142
143// Size returns the size of a w×h space seen through t: width and height swap
144// when t is Rotated.
145func (t BufferTransform) Size(w, h int) (int, int) {
146	if t.Rotated() {
147		return h, w
148	}
149	return w, h
150}
151
152// ToBuffer maps a point of a w×h surface (logical, before scale) to the
153// same point of its buffer, in the buffer's untransformed w'×h' axes, where
154// w' and h' swap when the transform is Rotated.
155func (t BufferTransform) ToBuffer(x, y, w, h float64) (float64, float64) {
156	if t&4 != 0 {
157		x = w - x
158	}
159	switch t & 3 {
160	case 1:
161		return y, w - x
162	case 2:
163		return w - x, h - y
164	case 3:
165		return h - y, x
166	}
167	return x, y
168}
169
170// Invert is the transform that maps target points back: for a w×h scene and
171// its w'×h' target, t.Invert().ToBuffer(t.ToBuffer(p, w, h), w', h') == p.
172func (t BufferTransform) Invert() BufferTransform {
173	if t&1 != 0 && t&4 == 0 {
174		return t ^ 2
175	}
176	return t
177}
178
179// RectToBuffer maps a rectangle of a w×h surface to the buffer. Integer
180// rectangles stay integer under these transforms; rounding absorbs float noise.
181func (t BufferTransform) RectToBuffer(r image.Rectangle, w, h int) image.Rectangle {
182	ax, ay := t.ToBuffer(float64(r.Min.X), float64(r.Min.Y), float64(w), float64(h))
183	bx, by := t.ToBuffer(float64(r.Max.X), float64(r.Max.Y), float64(w), float64(h))
184	return image.Rect(int(math.Round(ax)), int(math.Round(ay)), int(math.Round(bx)), int(math.Round(by)))
185}
186
187// SeqDamage is what content Seq changed from the one before: Rects in
188// root buffer pixels, or everything when Full.
189type SeqDamage struct {
190	Seq   uint64
191	Full  bool
192	Rects []Rect
193}
194
195// DamageSince is the union of changes after content seq up to this one,
196// and false when the history does not reach back to seq (redraw all).
197func (c SurfaceContent) DamageSince(seq uint64) ([]Rect, bool) {
198	out, ok := c.AppendDamageSince(nil, seq)
199	if !ok {
200		return nil, false
201	}
202	return out, true
203}
204
205// AppendDamageSince is DamageSince appending to dst, so a caller reusing
206// its slice allocates nothing. When the history does not reach back to seq
207// it returns dst unchanged and false.
208func (c SurfaceContent) AppendDamageSince(dst []Rect, seq uint64) ([]Rect, bool) {
209	if seq >= c.Seq {
210		return dst, true
211	}
212	h := c.DamageHistory
213	if len(h) == 0 || h[0].Seq > seq+1 || h[len(h)-1].Seq != c.Seq {
214		return dst, false
215	}
216	n := len(dst)
217	for _, d := range h {
218		if d.Seq <= seq {
219			continue
220		}
221		if d.Full {
222			return dst[:n], false
223		}
224		dst = append(dst, d.Rects...)
225	}
226	return dst, true
227}
228
229// Subsurface is a child surface at X, Y logical pixels from the root
230// surface origin. Below children are drawn under the root surface.
231type Subsurface struct {
232	X, Y  int
233	Below bool
234	SurfaceContent
235}
236
237// HasBuffer reports whether the surface itself carries a client buffer.
238func (c SurfaceContent) HasBuffer() bool {
239	return c.SHM != nil || c.DMABuf != nil || c.Solid != nil
240}
241
242// SolidColor is the color of a single-pixel buffer: premultiplied by alpha,
243// 0 to 1, sRGB-encoded like the pixels of client buffers.
244type SolidColor struct{ R, G, B, A float32 }
245
246// Empty reports whether the content has nothing to draw.
247func (c SurfaceContent) Empty() bool {
248	return !c.HasBuffer() && len(c.Children) == 0
249}
250
251// SHMBuffer is a client wl_shm buffer: B8G8R8A8 pixels (argb8888/xrgb8888
252// little-endian) at Offset in the pool File, Stride bytes per row. The
253// client keeps writing the file, so renderers copy from it when they draw.
254// Pool is unique per wl_shm pool for the session: renderers map a pool
255// once. File stays open while the client's buffer exists and follows the
256// DMABuf rules: duplicate it under File.SyscallConn before keeping it. A
257// client may shrink the file at any time, so readers must survive faults.
258type SHMBuffer struct {
259	Pool           uint64
260	File           *os.File
261	Offset, Stride int
262}
263
264// DMABuf is a client GPU buffer (linux-dmabuf). Its files stay open while
265// the client's buffer exists; a renderer that keeps it must duplicate the
266// descriptors under File.SyscallConn so a concurrent close cannot hand it a
267// reused one. ID is unique per buffer for the whole session: renderers key
268// their imports on it.
269type DMABuf struct {
270	ID            uint64
271	Width, Height int
272	Format        uint32 // DRM fourcc
273	Modifier      uint64
274	Planes        []DMABufPlane
275}
276
277// DMABufPlane is one plane of a DMABuf.
278type DMABufPlane struct {
279	File           *os.File
280	Offset, Stride uint32
281}
282
283// DMABufFormat is a DRM fourcc with a modifier the renderer can import.
284type DMABufFormat struct {
285	Format   uint32
286	Modifier uint64
287}
288
289// DMABufSupport is what the renderer imports: the render device (a dev_t,
290// 0 when unknown) and the formats. No formats means no dmabuf.
291type DMABufSupport struct {
292	Device  uint64
293	Formats []DMABufFormat
294}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 25

Tags 10

↑↓ moveenter openesc close