feat/data-dnd e05cb15

props.go RawHistoryFolder

1package drm
2
3import (
4	"runtime"
5	"unsafe"
6
7	"golang.org/x/sys/unix"
8)
9
10// KMS object properties, read by name; atomic commits set them.
11
12const (
13	ioctlObjGetProps = 0xC02064B9 // DRM_IOWR('d', 0xB9, struct drm_mode_obj_get_properties)
14	ioctlGetProp     = 0xC04064AA // DRM_IOWR('d', 0xAA, struct drm_mode_get_property)
15
16	objCrtc      = 0xcccccccc
17	objConnector = 0xc0c0c0c0
18	objColorop   = 0xfafafafa // DRM_MODE_OBJECT_COLOROP
19)
20
21type objGetProps struct {
22	props, values uint64
23	count, objID  uint32
24	objType, _    uint32
25}
26
27type propEnum struct {
28	value uint64
29	name  [32]byte
30}
31
32type getProp struct {
33	values, enumBlobs    uint64
34	propID, flags        uint32
35	name                 [32]byte
36	countValues, countEn uint32
37}
38
39// objProps returns an object's property IDs and values by name.
40func objProps(fd int, obj, typ uint32) (map[string][2]uint64, error) {
41	q := objGetProps{objID: obj, objType: typ}
42	if err := ioctl(fd, ioctlObjGetProps, unsafe.Pointer(&q)); err != nil {
43		return nil, err
44	}
45	out := map[string][2]uint64{}
46	if q.count == 0 {
47		return out, nil
48	}
49	ids := make([]uint32, q.count)
50	vals := make([]uint64, q.count)
51	q.props, q.values = uint64(uintptr(unsafe.Pointer(&ids[0]))), uint64(uintptr(unsafe.Pointer(&vals[0])))
52	if err := ioctl(fd, ioctlObjGetProps, unsafe.Pointer(&q)); err != nil {
53		return nil, err
54	}
55	for i := range min(int(q.count), len(ids)) {
56		p := getProp{propID: ids[i]}
57		if ioctl(fd, ioctlGetProp, unsafe.Pointer(&p)) != nil {
58			continue
59		}
60		out[unix.ByteSliceToString(p.name[:])] = [2]uint64{uint64(ids[i]), vals[i]}
61	}
62	return out, nil
63}
64
65// propEnums returns the enum names of property id with their values.
66func propEnums(fd int, id uint32) (map[string]uint64, error) {
67	p := getProp{propID: id}
68	if err := ioctl(fd, ioctlGetProp, unsafe.Pointer(&p)); err != nil {
69		return nil, err
70	}
71	if p.countEn == 0 {
72		return nil, nil
73	}
74	enums := make([]propEnum, p.countEn)
75	// The kernel also copies an enum's values when countValues is set: a
76	// nil values pointer makes the whole call fail (EFAULT).
77	v := make([]uint64, max(p.countValues, 1))
78	p.enumBlobs = uint64(uintptr(unsafe.Pointer(&enums[0])))
79	p.values = uint64(uintptr(unsafe.Pointer(&v[0])))
80	if err := ioctl(fd, ioctlGetProp, unsafe.Pointer(&p)); err != nil {
81		return nil, err
82	}
83	out := make(map[string]uint64, p.countEn)
84	for _, e := range enums[:min(int(p.countEn), len(enums))] {
85		out[unix.ByteSliceToString(e.name[:])] = e.value
86	}
87	runtime.KeepAlive(enums)
88	runtime.KeepAlive(v)
89	return out, nil
90}
91
92// readContentTypeProp records the connector's content type enum values.
93func readContentTypeProp(fd int, props map[string][2]uint64) (uint32, [5]uint64) {
94	id := uint32(props["content type"][0])
95	var values [5]uint64
96	if id == 0 {
97		return 0, values
98	}
99	enums, err := propEnums(fd, id)
100	if err != nil || len(enums) == 0 {
101		return 0, values
102	}
103	for i, name := range [...]string{"No Data", "Graphics", "Photo", "Cinema", "Game"} {
104		values[i] = enums[name]
105	}
106	return id, values
107}
108
109// connectorHDRProps retains connector property IDs, enum values and the
110// original max bpc for SDR modesets and restoration.
111type connectorHDRProps struct {
112	Metadata, Colorspace, MaxBPC uint32
113	BT2020Value                  uint64
114	DefaultValue                 uint64 // connector Colorspace "Default" enum
115	HasDefault                   bool
116	MaxBPCValue                  uint64 // current value for eventual restoration
117}
118
119// readConnectorHDRProps checks property metadata, not only current values.
120func readConnectorHDRProps(fd int, props map[string][2]uint64) connectorHDRProps {
121	var out connectorHDRProps
122	out.Metadata = uint32(props["HDR_OUTPUT_METADATA"][0])
123	if id := uint32(props["Colorspace"][0]); id != 0 {
124		p := getProp{propID: id}
125		if ioctl(fd, ioctlGetProp, unsafe.Pointer(&p)) == nil && p.countEn > 0 {
126			enums := make([]propEnum, p.countEn)
127			p.enumBlobs = uint64(uintptr(unsafe.Pointer(&enums[0])))
128			// The kernel also copies an enum's values when countValues is
129			// set: a nil values pointer makes the whole call fail (EFAULT).
130			values := make([]uint64, max(p.countValues, 1))
131			p.values = uint64(uintptr(unsafe.Pointer(&values[0])))
132			if ioctl(fd, ioctlGetProp, unsafe.Pointer(&p)) == nil {
133				out.Colorspace, out.BT2020Value = bt2020Enum(id, enums[:min(int(p.countEn), len(enums))])
134				for _, e := range enums[:min(int(p.countEn), len(enums))] {
135					if unix.ByteSliceToString(e.name[:]) == "Default" {
136						out.DefaultValue, out.HasDefault = e.value, true
137					}
138				}
139			}
140			runtime.KeepAlive(enums)
141			runtime.KeepAlive(values)
142		}
143	}
144	if id := uint32(props["max bpc"][0]); id != 0 {
145		p := getProp{propID: id}
146		if ioctl(fd, ioctlGetProp, unsafe.Pointer(&p)) == nil && p.countValues >= 2 {
147			values := make([]uint64, p.countValues)
148			p.values = uint64(uintptr(unsafe.Pointer(&values[0])))
149			if ioctl(fd, ioctlGetProp, unsafe.Pointer(&p)) == nil && p.countValues >= 2 && bpcAllows10(values) {
150				out.MaxBPC, out.MaxBPCValue = id, props["max bpc"][1]
151			}
152			runtime.KeepAlive(values)
153		}
154	}
155	return out
156}
157
158func bt2020Enum(id uint32, enums []propEnum) (uint32, uint64) {
159	for _, e := range enums {
160		if unix.ByteSliceToString(e.name[:]) == "BT2020_RGB" {
161			return id, e.value
162		}
163	}
164	return 0, 0
165}
166
167func bpcAllows10(values []uint64) bool {
168	return len(values) >= 2 && values[0] <= 10 && values[1] >= 10
169}
170
171// hdrCapability combines EDID and connector support, retaining the first reason.
172type hdrCapability struct {
173	Capable bool
174	Reason  string
175	HDRMetadata
176}
177
178func detectHDR(m Monitor, p connectorHDRProps) hdrCapability {
179	c := hdrCapability{HDRMetadata: m.HDR}
180	switch {
181	case !m.HDR.PQ:
182		c.Reason = "edid: no PQ"
183	case !m.HDR.StaticType1:
184		c.Reason = "edid: no static metadata type 1"
185	case !m.HDR.BT2020RGB:
186		c.Reason = "edid: no BT2020RGB"
187	case p.Metadata == 0:
188		c.Reason = "connector: no HDR_OUTPUT_METADATA"
189	case p.Colorspace == 0:
190		c.Reason = "connector: no BT2020_RGB Colorspace"
191	case p.MaxBPC == 0:
192		c.Reason = "connector: max bpc below 10"
193	case !p.HasDefault:
194		c.Reason = "connector: no Default Colorspace"
195	default:
196		c.Capable = true
197	}
198	return c
199}
200
201// vrrProperty returns the CRTC's VRR_ENABLED property when the connector
202// is VRR capable, else 0.
203func vrrProperty(k kms, conn, crtc uint32) uint32 {
204	cp, err := k.objProps(conn, objConnector)
205	if err != nil || cp["vrr_capable"][1] != 1 {
206		return 0
207	}
208	rp, err := k.objProps(crtc, objCrtc)
209	if err != nil {
210		return 0
211	}
212	return uint32(rp["VRR_ENABLED"][0])
213}

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