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// BufferTransform is a wl_output.transform value: bit 0 rotates 90°
112// counter-clockwise, bit 1 rotates 180°, bit 2 flips around the vertical
113// axis first.
114type BufferTransform uint8
115
116// Rotated reports whether width and height swap between buffer and surface.
117func (t BufferTransform) Rotated() bool { return t&1 != 0 }
118
119// Size returns the size of a w×h space seen through t: width and height swap
120// when t is Rotated.
121func (t BufferTransform) Size(w, h int) (int, int) {
122 if t.Rotated() {
123 return h, w
124 }
125 return w, h
126}
127
128// ToBuffer maps a point of a w×h surface (logical, before scale) to the
129// same point of its buffer, in the buffer's untransformed w'×h' axes, where
130// w' and h' swap when the transform is Rotated.
131func (t BufferTransform) ToBuffer(x, y, w, h float64) (float64, float64) {
132 if t&4 != 0 {
133 x = w - x
134 }
135 switch t & 3 {
136 case 1:
137 return y, w - x
138 case 2:
139 return w - x, h - y
140 case 3:
141 return h - y, x
142 }
143 return x, y
144}
145
146// Invert is the transform that maps target points back: for a w×h scene and
147// its w'×h' target, t.Invert().ToBuffer(t.ToBuffer(p, w, h), w', h') == p.
148func (t BufferTransform) Invert() BufferTransform {
149 if t&1 != 0 && t&4 == 0 {
150 return t ^ 2
151 }
152 return t
153}
154
155// RectToBuffer maps a rectangle of a w×h surface to the buffer. Integer
156// rectangles stay integer under these transforms; rounding absorbs float noise.
157func (t BufferTransform) RectToBuffer(r image.Rectangle, w, h int) image.Rectangle {
158 ax, ay := t.ToBuffer(float64(r.Min.X), float64(r.Min.Y), float64(w), float64(h))
159 bx, by := t.ToBuffer(float64(r.Max.X), float64(r.Max.Y), float64(w), float64(h))
160 return image.Rect(int(math.Round(ax)), int(math.Round(ay)), int(math.Round(bx)), int(math.Round(by)))
161}
162
163// SeqDamage is what content Seq changed from the one before: Rects in
164// root buffer pixels, or everything when Full.
165type SeqDamage struct {
166 Seq uint64
167 Full bool
168 Rects []Rect
169}
170
171// DamageSince is the union of changes after content seq up to this one,
172// and false when the history does not reach back to seq (redraw all).
173func (c SurfaceContent) DamageSince(seq uint64) ([]Rect, bool) {
174 out, ok := c.AppendDamageSince(nil, seq)
175 if !ok {
176 return nil, false
177 }
178 return out, true
179}
180
181// AppendDamageSince is DamageSince appending to dst, so a caller reusing
182// its slice allocates nothing. When the history does not reach back to seq
183// it returns dst unchanged and false.
184func (c SurfaceContent) AppendDamageSince(dst []Rect, seq uint64) ([]Rect, bool) {
185 if seq >= c.Seq {
186 return dst, true
187 }
188 h := c.DamageHistory
189 if len(h) == 0 || h[0].Seq > seq+1 || h[len(h)-1].Seq != c.Seq {
190 return dst, false
191 }
192 n := len(dst)
193 for _, d := range h {
194 if d.Seq <= seq {
195 continue
196 }
197 if d.Full {
198 return dst[:n], false
199 }
200 dst = append(dst, d.Rects...)
201 }
202 return dst, true
203}
204
205// Subsurface is a child surface at X, Y logical pixels from the root
206// surface origin. Below children are drawn under the root surface.
207type Subsurface struct {
208 X, Y int
209 Below bool
210 SurfaceContent
211}
212
213// HasBuffer reports whether the surface itself carries a client buffer.
214func (c SurfaceContent) HasBuffer() bool {
215 return c.SHM != nil || c.DMABuf != nil || c.Solid != nil
216}
217
218// SolidColor is the color of a single-pixel buffer: premultiplied by alpha,
219// 0 to 1, sRGB-encoded like the pixels of client buffers.
220type SolidColor struct{ R, G, B, A float32 }
221
222// Empty reports whether the content has nothing to draw.
223func (c SurfaceContent) Empty() bool {
224 return !c.HasBuffer() && len(c.Children) == 0
225}
226
227// SHMBuffer is a client wl_shm buffer: B8G8R8A8 pixels (argb8888/xrgb8888
228// little-endian) at Offset in the pool File, Stride bytes per row. The
229// client keeps writing the file, so renderers copy from it when they draw.
230// Pool is unique per wl_shm pool for the session: renderers map a pool
231// once. File stays open while the client's buffer exists and follows the
232// DMABuf rules: duplicate it under File.SyscallConn before keeping it. A
233// client may shrink the file at any time, so readers must survive faults.
234type SHMBuffer struct {
235 Pool uint64
236 File *os.File
237 Offset, Stride int
238}
239
240// DMABuf is a client GPU buffer (linux-dmabuf). Its files stay open while
241// the client's buffer exists; a renderer that keeps it must duplicate the
242// descriptors under File.SyscallConn so a concurrent close cannot hand it a
243// reused one. ID is unique per buffer for the whole session: renderers key
244// their imports on it.
245type DMABuf struct {
246 ID uint64
247 Width, Height int
248 Format uint32 // DRM fourcc
249 Modifier uint64
250 Planes []DMABufPlane
251}
252
253// DMABufPlane is one plane of a DMABuf.
254type DMABufPlane struct {
255 File *os.File
256 Offset, Stride uint32
257}
258
259// DMABufFormat is a DRM fourcc with a modifier the renderer can import.
260type DMABufFormat struct {
261 Format uint32
262 Modifier uint64
263}
264
265// DMABufSupport is what the renderer imports: the render device (a dev_t,
266// 0 when unknown) and the formats. No formats means no dmabuf.
267type DMABufSupport struct {
268 Device uint64
269 Formats []DMABufFormat
270}