1package ports
2
3import (
4 "image"
5 "math"
6 "os"
7)
8
9// Scene carries core → renderer immutable snapshots with fresh Windows slices,
10// one per output. Rects and the output size are logical and local to the
11// output; the renderer multiplies by Scale.
12type Scene struct {
13 // Security is the owner epoch captured when this scene was published.
14 // Output owners reject stale scenes rather than showing a queued desktop
15 // or accepting old locker buffers across acquisition/release.
16 Security SecurityState
17 Output string
18 Seq uint64
19 OutputWidth, OutputHeight int
20 Scale float64
21 // Transform is how the output target holds this scene
22 // (wl_output.transform); 0 for capture child scenes. OutputWidth and
23 // OutputHeight are already in the transformed (logical) orientation.
24 Transform BufferTransform
25 // Off turns the display off (output power management): nothing is
26 // drawn until a scene without it.
27 Off bool
28 Background string
29 Border Border
30 // WorkspaceClip bounds workspace windows, their popups and separators
31 // in logical output coordinates. Zero inherits the full output. Layers
32 // remain output-wide; overview previews do not use this clip.
33 WorkspaceClip Rect
34 // Dim darkens the background, bottom layers and tiles (tile lines
35 // included) inside WorkspaceClip when set, with black at this opacity,
36 // 0 to 1, under the first
37 // visible float. 0 draws nothing.
38 Dim float64
39 // DimBehind draws the Dim veil under every window instead, right over
40 // the background and bottom layers (the overview).
41 DimBehind bool
42 Windows []SceneWindow
43 // Separators are the lines between windows, drawn in slice order with
44 // the Border colors: tile lines over the tiles, under the floats; a
45 // float's border right after the float.
46 Separators []Separator
47 // DropHints show where a dragged tile lands, filled with Border.Active
48 // over the windows of the workspace, under the top layers. Only the
49 // output under the pointer has them, during a drag.
50 DropHints []Rect
51 // Layers are the shown layer surfaces, drawn in slice order: background
52 // and bottom before windows, top and overlay after. Core leaves out
53 // those a fullscreen window hides (all but the background and a surface
54 // taking the keyboard exclusively); adapters draw every layer given.
55 // Window popups are drawn after the windows, layer popups
56 // (SceneWindow.OverLayers) last, over every layer.
57 Layers []SceneLayer
58 // Capture is the capture state of this output: exclusion and hidden
59 // workspace; nil while nothing is captured (capture.go).
60 Capture *SceneCapture
61 // CaptureScene is the workspace captured off screen (Capture.Workspace)
62 // drawn for capture only: a workspace that is not on screen. Only the
63 // root scene carries it; CaptureScene.Capture and .CaptureScene are nil.
64 CaptureScene *Scene
65 // CaptureIndicators are the marks of live captures of this output,
66 // drawn over everything; nil when none. Captures never hold them: the
67 // capture pipeline serves requests from a scene without them.
68 CaptureIndicators []CaptureIndicator
69}
70
71// Shows reports whether the scene draws the surface of id: only its
72// content changes need a new frame. A window scrolled off the output is
73// not drawn. WorkspaceClip also excludes off-viewport windows; OverLayers
74// popups remain output-wide.
75func (s Scene) Shows(id WindowID) bool {
76 for _, w := range s.Windows {
77 if w.ID == id && !w.Hidden && w.Rect.Overlaps(Rect{W: s.OutputWidth, H: s.OutputHeight}) &&
78 (w.OverLayers || s.WorkspaceClip == (Rect{}) || w.Rect.Overlaps(s.WorkspaceClip)) {
79 return true
80 }
81 }
82 for _, l := range s.Layers {
83 if l.ID == id {
84 return true
85 }
86 }
87 return false
88}
89
90// Border carries the window border style; colors are #rrggbb, "" skips
91// drawing. Width is in logical pixels.
92type Border struct {
93 Width int
94 Active, Inactive string
95}
96
97// Separator is a line between windows, in logical pixels. Active lines
98// mark the focused window and use Border.Active, others Border.Inactive.
99// Window is the float whose border it is; 0 for lines between tiles.
100type Separator struct {
101 Rect Rect
102 Active bool
103 Window WindowID
104}
105
106// SceneLayer carries core → renderer layer surface placement.
107type SceneLayer struct {
108 ID WindowID
109 Layer Layer
110 Rect Rect
111}
112
113// SurfaceColor is the committed encoding of a surface. Zero means sRGB.
114// PQ+BT.2020 and extended-linear sRGB are color-managed; zero is legacy
115// sRGB. MaxCLL/MaxFALL are in nits. YUV metadata is per surface commit.
116type SurfaceColor struct {
117 TF, Primaries uint8
118 MaxCLL, MaxFALL uint16
119 // Coefficients/range follow wp_color_representation_v1 (zero =
120 // unspecified, for YUV interpreted as BT.709 limited). Chroma is a
121 // H.273 Chroma420SampleLocType + 1 (zero defaults to type 0).
122 Coefficients, Range, Chroma uint8
123}
124
125const (
126 ColorTFPQ uint8 = 11 // wp_color_manager_v1 ST2084 PQ
127 ColorTFExtendedLinear uint8 = 5 // wp_color_manager_v1 ext_linear
128 ColorPrimariesBT2020 uint8 = 6 // wp_color_manager_v1 BT.2020
129 ColorPrimariesSRGB uint8 = 1
130)
131
132func (c SurfaceColor) IsPQ2020() bool {
133 return c.TF == ColorTFPQ && c.Primaries == ColorPrimariesBT2020
134}
135
136func (c SurfaceColor) IsExtendedLinear() bool {
137 return c.TF == ColorTFExtendedLinear && c.Primaries == ColorPrimariesSRGB
138}
139
140// ContentType is the committed wp_content_type_v1 hint.
141type ContentType uint8
142
143const (
144 ContentNone ContentType = iota
145 ContentPhoto
146 ContentVideo
147 ContentGame
148)
149
150// SurfaceContent carries wayland → output the latest committed content of a
151// window: SHM, a client shared-memory buffer, or DMABuf, a GPU buffer.
152// Renderers read both in place and never modify them. Empty means the window
153// has no content. LogicalW and LogicalH are the surface size in logical
154// pixels (buffer scale and viewport applied). Subsurfaces come in Children;
155// Geometry is the part of the surface that is the window (xdg window
156// geometry), the rest being client shadows.
157type SurfaceContent struct {
158 ID WindowID
159 ContentType ContentType
160 // Surface is a never-reused wl_surface identity; Version identifies its
161 // applied buffer content independently of the window publication Seq.
162 Surface, Version uint64
163 // Seq counts the window's contents (wayland sets it), for release.
164 Seq uint64
165 Width, Height int
166 LogicalW, LogicalH int
167 // Source is the committed crop in buffer pixels: x, y, width, height.
168 // Zero width means the entire buffer is used.
169 Source [4]float32
170 // Transform is the wl_output.transform the client applied to the
171 // buffer: readers apply its inverse. Width and Height stay the buffer's.
172 Transform BufferTransform
173 // Opaque ignores the alpha byte: an x format, or an opaque region that
174 // covers the whole surface. It is false while Fade is set.
175 Opaque bool
176 // Fade is how much wp_alpha_modifier_v1 fades the surface: 0 none,
177 // 1 invisible. Its opacity is multiplied by 1-Fade.
178 Fade float32
179 Color SurfaceColor
180 SHM *SHMBuffer
181 DMABuf *DMABuf
182 // Children are the subsurfaces, bottom to top, flattened.
183 Children []Subsurface
184 // Geometry is in logical pixels from the surface origin; empty means
185 // the whole surface.
186 Geometry Rect
187 // Async asks for tearing presentation (wp_tearing_control_v1); outputs
188 // honour it only in direct scanout.
189 Async bool
190 // Acquire is the explicit-sync fence of this content's root buffer
191 // (wp_linux_drm_syncobj_v1): readers wait on it before reading the
192 // buffer, instead of the buffer's implicit fences. Wayland owns it and
193 // closes it when the buffer is released; a reader that keeps it past
194 // the call duplicates it under Acquire.SyscallConn. nil: implicit sync.
195 // Wayland closes it only after every output reported a later content of
196 // the window as seen, so a reader never gets it already closed.
197 Acquire *os.File
198 // DamageHistory is what changed in the root surface's buffer over the
199 // window's last contents, oldest first, ending with this one (Seq).
200 // A renderer holding an older content redraws the union of the
201 // entries after it, or everything when the history does not reach it.
202 DamageHistory []SeqDamage
203}
204
205// BufferTransform is a wl_output.transform value: bit 0 rotates 90°
206// counter-clockwise, bit 1 rotates 180°, bit 2 flips around the vertical
207// axis first.
208type BufferTransform uint8
209
210// Rotated reports whether width and height swap between buffer and surface.
211func (t BufferTransform) Rotated() bool { return t&1 != 0 }
212
213// Size returns the size of a w×h space seen through t: width and height swap
214// when t is Rotated.
215func (t BufferTransform) Size(w, h int) (int, int) {
216 if t.Rotated() {
217 return h, w
218 }
219 return w, h
220}
221
222// ToBuffer maps a point of a w×h surface (logical, before scale) to the
223// same point of its buffer, in the buffer's untransformed w'×h' axes, where
224// w' and h' swap when the transform is Rotated.
225func (t BufferTransform) ToBuffer(x, y, w, h float64) (float64, float64) {
226 if t&4 != 0 {
227 x = w - x
228 }
229 switch t & 3 {
230 case 1:
231 return y, w - x
232 case 2:
233 return w - x, h - y
234 case 3:
235 return h - y, x
236 }
237 return x, y
238}
239
240// Invert is the transform that maps target points back: for a w×h scene and
241// its w'×h' target, t.Invert().ToBuffer(t.ToBuffer(p, w, h), w', h') == p.
242func (t BufferTransform) Invert() BufferTransform {
243 if t&1 != 0 && t&4 == 0 {
244 return t ^ 2
245 }
246 return t
247}
248
249// RectToBuffer maps a rectangle of a w×h surface to the buffer. Integer
250// rectangles stay integer under these transforms; rounding absorbs float noise.
251func (t BufferTransform) RectToBuffer(r image.Rectangle, w, h int) image.Rectangle {
252 ax, ay := t.ToBuffer(float64(r.Min.X), float64(r.Min.Y), float64(w), float64(h))
253 bx, by := t.ToBuffer(float64(r.Max.X), float64(r.Max.Y), float64(w), float64(h))
254 return image.Rect(int(math.Round(ax)), int(math.Round(ay)), int(math.Round(bx)), int(math.Round(by)))
255}
256
257// SeqDamage is what content Seq changed from the one before: Rects in
258// root buffer pixels, or everything when Full.
259type SeqDamage struct {
260 Seq uint64
261 Full bool
262 Rects []Rect
263}
264
265// DamageSince is the union of changes after content seq up to this one,
266// and false when the history does not reach back to seq (redraw all).
267func (c SurfaceContent) DamageSince(seq uint64) ([]Rect, bool) {
268 if seq >= c.Seq {
269 return nil, true
270 }
271 h := c.DamageHistory
272 if len(h) == 0 || h[0].Seq > seq+1 || h[len(h)-1].Seq != c.Seq {
273 return nil, false
274 }
275 var out []Rect
276 for _, d := range h {
277 if d.Seq <= seq {
278 continue
279 }
280 if d.Full {
281 return nil, false
282 }
283 out = append(out, d.Rects...)
284 }
285 return out, true
286}
287
288// Subsurface is a child surface at X, Y logical pixels from the root
289// surface origin. Below children are drawn under the root surface.
290type Subsurface struct {
291 X, Y int
292 Below bool
293 SurfaceContent
294}
295
296// Empty reports whether the content has nothing to draw.
297func (c SurfaceContent) Empty() bool {
298 return c.SHM == nil && c.DMABuf == nil && len(c.Children) == 0
299}
300
301// SHMBuffer is a client wl_shm buffer: B8G8R8A8 pixels (argb8888/xrgb8888
302// little-endian) at Offset in the pool File, Stride bytes per row. The
303// client keeps writing the file, so renderers copy from it when they draw.
304// Pool is unique per wl_shm pool for the session: renderers map a pool
305// once. File stays open while the client's buffer exists and follows the
306// DMABuf rules: duplicate it under File.SyscallConn before keeping it. A
307// client may shrink the file at any time, so readers must survive faults.
308type SHMBuffer struct {
309 Pool uint64
310 File *os.File
311 Offset, Stride int
312}
313
314// DMABuf is a client GPU buffer (linux-dmabuf). Its files stay open while
315// the client's buffer exists; a renderer that keeps it must duplicate the
316// descriptors under File.SyscallConn so a concurrent close cannot hand it a
317// reused one. ID is unique per buffer for the whole session: renderers key
318// their imports on it.
319type DMABuf struct {
320 ID uint64
321 Width, Height int
322 Format uint32 // DRM fourcc
323 Modifier uint64
324 Planes []DMABufPlane
325}
326
327// DMABufPlane is one plane of a DMABuf.
328type DMABufPlane struct {
329 File *os.File
330 Offset, Stride uint32
331}
332
333// DMABufFormat is a DRM fourcc with a modifier the renderer can import.
334type DMABufFormat struct {
335 Format uint32
336 Modifier uint64
337}
338
339// DMABufSupport is what the renderer imports: the render device (a dev_t,
340// 0 when unknown) and the formats. No formats means no dmabuf.
341type DMABufSupport struct {
342 Device uint64
343 Formats []DMABufFormat
344}
345
346// SceneWindow carries core → renderer window placement.
347type SceneWindow struct {
348 ID WindowID
349 Rect Rect
350 Focused, Fullscreen, Hidden bool
351 // Inset sides carry a separator line inside Rect: the client is drawn
352 // inside it.
353 Inset Sides
354 // Floating windows draw at their placed size. Below marks a native
355 // covering float behind the column group.
356 Floating, Below bool
357 // Dim darkens the window, border included, with black at this
358 // opacity, 0 to 1: a stashed window peeking in. 0 draws nothing.
359 Dim float64
360 // FocusEffect, above 0, is the focus indicator's effect at this frame
361 // (focus.animation, focus.effect): the window's surfaces are lifted
362 // toward white by that fraction (screen blend). Renderers without the
363 // effect ignore it.
364 //
365 // Only focus.effect = screen exists, so the effect kind is not carried:
366 // core ignores Config.Focus.Effect and the shaders always apply screen
367 // (compose.frag, compose_hdr.frag, push constant mapy.z). A second effect
368 // needs its kind here and in the push constants (a misc flag).
369 FocusEffect float64
370 // Preview, above 0, draws the window's surfaces that much smaller in
371 // Rect (an overview thumbnail): the client keeps its size.
372 Preview float64
373 // Popups are drawn from their content only: no border, no background.
374 Popup bool
375 // OverLayers popups hang from a layer surface: drawn over the top and
376 // overlay layers. Window popups stay with the windows, under them.
377 OverLayers bool
378}