~emersion/go-drm

go-drm/blob.go -rw-r--r-- 3.1 KiB
7088ebfeSimon Ser Add support for Amlogic format modifiers a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package drm

import (
	"fmt"
	"reflect"
	"runtime"
	"unsafe"
)

const formatModifierCurrentVersion = 1

type formatModifierHeader struct {
	version         uint32
	flags           uint32
	formatsLen      uint32
	formatsOffset   uint32 // bytes
	modifiersLen    uint32
	modifiersOffset uint32 // bytes
}

type formatModifier struct {
	formats uint64
	offset  uint32
	_       uint32

	modifier uint64
}

type FormatModifierSet struct {
	h         formatModifierHeader
	formats   []uint32
	modifiers []formatModifier
}

func ParseFormatModifierSet(b []byte) (*FormatModifierSet, error) {
	if len(b) < int(unsafe.Sizeof(formatModifierHeader{})) {
		return nil, fmt.Errorf("drm: format modifier blob too short")
	}

	hPtr := (*formatModifierHeader)(unsafe.Pointer(&b[0]))
	h := *hPtr
	runtime.KeepAlive(&b)

	if h.version != formatModifierCurrentVersion {
		return nil, fmt.Errorf("drm: unsupported format modifier blob version")
	}

	var formats []uint32
	if h.formatsLen > 0 {
		formats = make([]uint32, h.formatsLen)
		size := len(formats) * int(unsafe.Sizeof(formats[0]))
		if len(b) < int(h.formatsOffset)+size {
			return nil, fmt.Errorf("drm: format modifier blob too short")
		}
		sh := reflect.SliceHeader{
			Data: uintptr(unsafe.Pointer(&formats[0])),
			Len:  size,
			Cap:  size,
		}
		copy(*(*[]byte)(unsafe.Pointer(&sh)), b[h.formatsOffset:])
	}

	var modifiers []formatModifier
	if h.modifiersLen > 0 {
		modifiers = make([]formatModifier, h.modifiersLen)
		size := len(modifiers) * int(unsafe.Sizeof(modifiers[0]))
		if len(b) < int(h.modifiersOffset)+size {
			return nil, fmt.Errorf("drm: format modifier blob too short")
		}
		sh := reflect.SliceHeader{
			Data: uintptr(unsafe.Pointer(&modifiers[0])),
			Len:  size,
			Cap:  size,
		}
		copy(*(*[]byte)(unsafe.Pointer(&sh)), b[h.modifiersOffset:])
	}

	return &FormatModifierSet{
		h:         h,
		formats:   formats,
		modifiers: modifiers,
	}, nil
}

func (set *FormatModifierSet) Map() map[Modifier][]Format {
	m := make(map[Modifier][]Format, len(set.modifiers))
	for _, mod := range set.modifiers {
		var formats []Format
		for i := 0; i < 64; i++ {
			if mod.formats&(1<<uint(i)) != 0 {
				fmt := set.formats[int(mod.offset)+i]
				formats = append(formats, Format(fmt))
			}
		}
		m[Modifier(mod.modifier)] = formats
	}
	return m
}

func ParseModeModeInfo(b []byte) (*ModeModeInfo, error) {
	if len(b) < int(unsafe.Sizeof(modeModeInfo{})) {
		return nil, fmt.Errorf("drm: mode info blob too short")
	}

	infoPtr := (*modeModeInfo)(unsafe.Pointer(&b[0]))
	info := newModeModeInfo(infoPtr)
	runtime.KeepAlive(&b)
	return info, nil
}

func ParseFormats(b []byte) ([]Format, error) {
	formatSize := int(unsafe.Sizeof(uint32(0)))
	if len(b)%formatSize != 0 {
		return nil, fmt.Errorf("drm: malformed writeback pixel formats blob")
	}
	formatsLen := len(b) / formatSize

	var formats []Format
	if formatsLen > 0 {
		formats = make([]Format, formatsLen)
		sh := reflect.SliceHeader{
			Data: uintptr(unsafe.Pointer(&formats[0])),
			Len:  len(b),
			Cap:  len(b),
		}
		copy(*(*[]byte)(unsafe.Pointer(&sh)), b)
	}

	return formats, nil
}

func ParsePath(b []byte) (string, error) {
	return newString(b), nil
}