~emersion/go-drm

92b993fbec3a72fbaecf4c1db0dcd29db26faadb — Simon Ser 2 years ago ca8c813
Split props and objects out of node.go
4 files changed, 408 insertions(+), 402 deletions(-)

A blob.go
M node.go
A object.go
M prop.go
A blob.go => blob.go +134 -0
@@ 0,0 1,134 @@
package drm

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

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
}

M node.go => node.go +0 -299
@@ 5,159 5,6 @@ import (
	"unsafe"
)

type ObjectType uint32

const (
	ObjectAny       ObjectType = 0
	ObjectCRTC      ObjectType = 0xCCCCCCCC
	ObjectConnector ObjectType = 0xC0C0C0C0
	ObjectEncoder   ObjectType = 0xE0E0E0E0
	ObjectMode      ObjectType = 0xDEDEDEDE
	ObjectProperty  ObjectType = 0xB0B0B0B0
	ObjectFB        ObjectType = 0xFBFBFBFB
	ObjectBlob      ObjectType = 0xBBBBBBBB
	ObjectPlane     ObjectType = 0xEEEEEEEE
)

func (t ObjectType) String() string {
	switch t {
	case ObjectAny:
		return "any"
	case ObjectCRTC:
		return "CRTC"
	case ObjectConnector:
		return "connector"
	case ObjectEncoder:
		return "encoder"
	case ObjectMode:
		return "mode"
	case ObjectProperty:
		return "property"
	case ObjectFB:
		return "FB"
	case ObjectBlob:
		return "blob"
	case ObjectPlane:
		return "plane"
	default:
		return "unknown"
	}
}

type (
	ObjectID    uint32
	CRTCID      ObjectID
	ConnectorID ObjectID
	EncoderID   ObjectID
	ModeID      ObjectID
	PropertyID  ObjectID
	FBID        ObjectID
	BlobID      ObjectID
	PlaneID     ObjectID
)

type AnyID interface {
	Type() ObjectType
	Object() ObjectID
}

func NewAnyID(id ObjectID, t ObjectType) AnyID {
	switch t {
	case ObjectAny:
		return id
	case ObjectCRTC:
		return CRTCID(id)
	case ObjectConnector:
		return ConnectorID(id)
	case ObjectEncoder:
		return EncoderID(id)
	case ObjectMode:
		return ModeID(id)
	case ObjectProperty:
		return PropertyID(id)
	case ObjectFB:
		return FBID(id)
	case ObjectBlob:
		return BlobID(id)
	case ObjectPlane:
		return PlaneID(id)
	default:
		panic(fmt.Sprintf("drm: unknown object type %v", t))
	}
}

func (id ObjectID) Type() ObjectType {
	return ObjectAny
}

func (id ObjectID) Object() ObjectID {
	return id
}

func (id CRTCID) Type() ObjectType {
	return ObjectCRTC
}

func (id CRTCID) Object() ObjectID {
	return ObjectID(id)
}

func (id ConnectorID) Type() ObjectType {
	return ObjectConnector
}

func (id ConnectorID) Object() ObjectID {
	return ObjectID(id)
}

func (id EncoderID) Type() ObjectType {
	return ObjectEncoder
}

func (id EncoderID) Object() ObjectID {
	return ObjectID(id)
}

func (id ModeID) Type() ObjectType {
	return ObjectMode
}

func (id ModeID) Object() ObjectID {
	return ObjectID(id)
}

func (id PropertyID) Type() ObjectType {
	return ObjectProperty
}

func (id PropertyID) Object() ObjectID {
	return ObjectID(id)
}

func (id FBID) Type() ObjectType {
	return ObjectFB
}

func (id FBID) Object() ObjectID {
	return ObjectID(id)
}

func (id BlobID) Type() ObjectType {
	return ObjectBlob
}

func (id BlobID) Object() ObjectID {
	return ObjectID(id)
}

func (id PlaneID) Type() ObjectType {
	return ObjectPlane
}

func (id PlaneID) Object() ObjectID {
	return ObjectID(id)
}

type Node struct {
	fd uintptr
}


@@ 549,152 396,6 @@ func (n *Node) ModeObjectGetProperties(id AnyID) (map[PropertyID]uint64, error) 
	}
}

const (
	propertyPending   uint32 = 1 << 0 // deprecated
	propertyImmutable uint32 = 1 << 2
	propertyAtomic    uint32 = 1 << 31

	propertyLegacyTypeMask   uint32 = 0x0000003A
	propertyExtendedTypeMask uint32 = 0x0000FFC0
)

type PropertyType uint32

func newPropertyType(flags uint32) PropertyType {
	return PropertyType(flags & (propertyLegacyTypeMask | propertyExtendedTypeMask))
}

const (
	// Legacy types
	PropertyRange   PropertyType = 1 << 1
	PropertyEnum    PropertyType = 1 << 3
	PropertyBlob    PropertyType = 1 << 4
	PropertyBitmask PropertyType = 1 << 5

	// Extended types
	PropertyObject      PropertyType = 1 << 6
	PropertySignedRange PropertyType = 2 << 6
)

func (t PropertyType) String() string {
	switch t {
	case PropertyRange:
		return "range"
	case PropertyEnum:
		return "enum"
	case PropertyBlob:
		return "blob"
	case PropertyBitmask:
		return "bitmask"
	case PropertyObject:
		return "object"
	case PropertySignedRange:
		return "signed range"
	default:
		return "unknown"
	}
}

type ModePropertyEnum struct {
	Name  string
	Value uint64
}

func newModePropertyEnum(e modePropertyEnum) ModePropertyEnum {
	return ModePropertyEnum{
		Name:  newString(e.name[:]),
		Value: e.value,
	}
}

func newModePropertyEnumList(enums []modePropertyEnum) []ModePropertyEnum {
	l := make([]ModePropertyEnum, len(enums))
	for i, e := range enums {
		l[i] = newModePropertyEnum(e)
	}
	return l
}

type ModePropertyBlob struct {
	ID   BlobID
	Size uint32
}

func newModePropertyBlobList(blobIDs []BlobID, blobSizes []uint32) []ModePropertyBlob {
	if len(blobSizes) != len(blobIDs) {
		panic("drm: blob sizes and IDs length mismatch")
	}
	l := make([]ModePropertyBlob, len(blobSizes))
	for i := 0; i < len(blobIDs); i++ {
		l[i] = ModePropertyBlob{
			ID:   blobIDs[i],
			Size: blobSizes[i],
		}
	}
	return l
}

type ModeProperty struct {
	ID   PropertyID
	Name string

	flags  uint32
	values []uint64
	enums  []ModePropertyEnum
	blobs  []ModePropertyBlob
}

func (prop *ModeProperty) Type() PropertyType {
	return newPropertyType(prop.flags)
}

func (prop *ModeProperty) Immutable() bool {
	return prop.flags&propertyImmutable != 0
}

func (prop *ModeProperty) Atomic() bool {
	return prop.flags&propertyAtomic != 0
}

func (prop *ModeProperty) Range() (low, high uint64, ok bool) {
	if prop.Type() != PropertyRange || len(prop.values) != 2 {
		return 0, 0, false
	}
	return prop.values[0], prop.values[1], true
}

func (prop *ModeProperty) Enums() ([]ModePropertyEnum, bool) {
	switch prop.Type() {
	case PropertyEnum, PropertyBitmask:
		return prop.enums, true
	default:
		return nil, false
	}
}

func (prop *ModeProperty) Blobs() ([]ModePropertyBlob, bool) {
	switch prop.Type() {
	case PropertyBlob:
		return prop.blobs, true
	default:
		return nil, false
	}
}

func (prop *ModeProperty) ObjectType() (ObjectType, bool) {
	if prop.Type() != PropertyObject || len(prop.values) != 1 {
		return 0, false
	}
	return ObjectType(prop.values[0]), true
}

func (prop *ModeProperty) SignedRange() (low, high int64, ok bool) {
	if prop.Type() != PropertyRange || len(prop.values) != 2 {
		return 0, 0, false
	}
	return int64(prop.values[0]), int64(prop.values[1]), true
}

func (n *Node) ModeGetProperty(id PropertyID) (*ModeProperty, error) {
	r := modeGetPropertyResp{id: uint32(id)}
	if err := modeGetProperty(n.fd, &r); err != nil {

A object.go => object.go +158 -0
@@ 0,0 1,158 @@
package drm

import (
	"fmt"
)

type ObjectType uint32

const (
	ObjectAny       ObjectType = 0
	ObjectCRTC      ObjectType = 0xCCCCCCCC
	ObjectConnector ObjectType = 0xC0C0C0C0
	ObjectEncoder   ObjectType = 0xE0E0E0E0
	ObjectMode      ObjectType = 0xDEDEDEDE
	ObjectProperty  ObjectType = 0xB0B0B0B0
	ObjectFB        ObjectType = 0xFBFBFBFB
	ObjectBlob      ObjectType = 0xBBBBBBBB
	ObjectPlane     ObjectType = 0xEEEEEEEE
)

func (t ObjectType) String() string {
	switch t {
	case ObjectAny:
		return "any"
	case ObjectCRTC:
		return "CRTC"
	case ObjectConnector:
		return "connector"
	case ObjectEncoder:
		return "encoder"
	case ObjectMode:
		return "mode"
	case ObjectProperty:
		return "property"
	case ObjectFB:
		return "FB"
	case ObjectBlob:
		return "blob"
	case ObjectPlane:
		return "plane"
	default:
		return "unknown"
	}
}

type (
	ObjectID    uint32
	CRTCID      ObjectID
	ConnectorID ObjectID
	EncoderID   ObjectID
	ModeID      ObjectID
	PropertyID  ObjectID
	FBID        ObjectID
	BlobID      ObjectID
	PlaneID     ObjectID
)

type AnyID interface {
	Type() ObjectType
	Object() ObjectID
}

func NewAnyID(id ObjectID, t ObjectType) AnyID {
	switch t {
	case ObjectAny:
		return id
	case ObjectCRTC:
		return CRTCID(id)
	case ObjectConnector:
		return ConnectorID(id)
	case ObjectEncoder:
		return EncoderID(id)
	case ObjectMode:
		return ModeID(id)
	case ObjectProperty:
		return PropertyID(id)
	case ObjectFB:
		return FBID(id)
	case ObjectBlob:
		return BlobID(id)
	case ObjectPlane:
		return PlaneID(id)
	default:
		panic(fmt.Sprintf("drm: unknown object type %v", t))
	}
}

func (id ObjectID) Type() ObjectType {
	return ObjectAny
}

func (id ObjectID) Object() ObjectID {
	return id
}

func (id CRTCID) Type() ObjectType {
	return ObjectCRTC
}

func (id CRTCID) Object() ObjectID {
	return ObjectID(id)
}

func (id ConnectorID) Type() ObjectType {
	return ObjectConnector
}

func (id ConnectorID) Object() ObjectID {
	return ObjectID(id)
}

func (id EncoderID) Type() ObjectType {
	return ObjectEncoder
}

func (id EncoderID) Object() ObjectID {
	return ObjectID(id)
}

func (id ModeID) Type() ObjectType {
	return ObjectMode
}

func (id ModeID) Object() ObjectID {
	return ObjectID(id)
}

func (id PropertyID) Type() ObjectType {
	return ObjectProperty
}

func (id PropertyID) Object() ObjectID {
	return ObjectID(id)
}

func (id FBID) Type() ObjectType {
	return ObjectFB
}

func (id FBID) Object() ObjectID {
	return ObjectID(id)
}

func (id BlobID) Type() ObjectType {
	return ObjectBlob
}

func (id BlobID) Object() ObjectID {
	return ObjectID(id)
}

func (id PlaneID) Type() ObjectType {
	return ObjectPlane
}

func (id PlaneID) Object() ObjectID {
	return ObjectID(id)
}

M prop.go => prop.go +116 -103
@@ 1,134 1,147 @@
package drm

import (
	"fmt"
	"reflect"
	"runtime"
	"unsafe"
const (
	propertyPending   uint32 = 1 << 0 // deprecated
	propertyImmutable uint32 = 1 << 2
	propertyAtomic    uint32 = 1 << 31

	propertyLegacyTypeMask   uint32 = 0x0000003A
	propertyExtendedTypeMask uint32 = 0x0000FFC0
)

const formatModifierCurrentVersion = 1
type PropertyType uint32

type formatModifierHeader struct {
	version         uint32
	flags           uint32
	formatsLen      uint32
	formatsOffset   uint32 // bytes
	modifiersLen    uint32
	modifiersOffset uint32 // bytes
func newPropertyType(flags uint32) PropertyType {
	return PropertyType(flags & (propertyLegacyTypeMask | propertyExtendedTypeMask))
}

type formatModifier struct {
	formats uint64
	offset  uint32
	_       uint32
const (
	// Legacy types
	PropertyRange   PropertyType = 1 << 1
	PropertyEnum    PropertyType = 1 << 3
	PropertyBlob    PropertyType = 1 << 4
	PropertyBitmask PropertyType = 1 << 5

	// Extended types
	PropertyObject      PropertyType = 1 << 6
	PropertySignedRange PropertyType = 2 << 6
)

	modifier uint64
func (t PropertyType) String() string {
	switch t {
	case PropertyRange:
		return "range"
	case PropertyEnum:
		return "enum"
	case PropertyBlob:
		return "blob"
	case PropertyBitmask:
		return "bitmask"
	case PropertyObject:
		return "object"
	case PropertySignedRange:
		return "signed range"
	default:
		return "unknown"
	}
}

type FormatModifierSet struct {
	h         formatModifierHeader
	formats   []uint32
	modifiers []formatModifier
type ModePropertyEnum struct {
	Name  string
	Value uint64
}

func ParseFormatModifierSet(b []byte) (*FormatModifierSet, error) {
	if len(b) < int(unsafe.Sizeof(formatModifierHeader{})) {
		return nil, fmt.Errorf("drm: format modifier blob too short")
func newModePropertyEnum(e modePropertyEnum) ModePropertyEnum {
	return ModePropertyEnum{
		Name:  newString(e.name[:]),
		Value: e.value,
	}
}

	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")
func newModePropertyEnumList(enums []modePropertyEnum) []ModePropertyEnum {
	l := make([]ModePropertyEnum, len(enums))
	for i, e := range enums {
		l[i] = newModePropertyEnum(e)
	}
	return l
}

	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:])
	}
type ModePropertyBlob struct {
	ID   BlobID
	Size uint32
}

	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:])
func newModePropertyBlobList(blobIDs []BlobID, blobSizes []uint32) []ModePropertyBlob {
	if len(blobSizes) != len(blobIDs) {
		panic("drm: blob sizes and IDs length mismatch")
	}

	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))
			}
	l := make([]ModePropertyBlob, len(blobSizes))
	for i := 0; i < len(blobIDs); i++ {
		l[i] = ModePropertyBlob{
			ID:   blobIDs[i],
			Size: blobSizes[i],
		}
		m[Modifier(mod.modifier)] = formats
	}
	return m
	return l
}

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

	infoPtr := (*modeModeInfo)(unsafe.Pointer(&b[0]))
	info := newModeModeInfo(infoPtr)
	runtime.KeepAlive(&b)
	return info, nil
	flags  uint32
	values []uint64
	enums  []ModePropertyEnum
	blobs  []ModePropertyBlob
}

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")
func (prop *ModeProperty) Type() PropertyType {
	return newPropertyType(prop.flags)
}

func (prop *ModeProperty) Immutable() bool {
	return prop.flags&propertyImmutable != 0
}

func (prop *ModeProperty) Atomic() bool {
	return prop.flags&propertyAtomic != 0
}

func (prop *ModeProperty) Range() (low, high uint64, ok bool) {
	if prop.Type() != PropertyRange || len(prop.values) != 2 {
		return 0, 0, false
	}
	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 prop.values[0], prop.values[1], true
}

func (prop *ModeProperty) Enums() ([]ModePropertyEnum, bool) {
	switch prop.Type() {
	case PropertyEnum, PropertyBitmask:
		return prop.enums, true
	default:
		return nil, false
	}
}

	return formats, nil
func (prop *ModeProperty) Blobs() ([]ModePropertyBlob, bool) {
	switch prop.Type() {
	case PropertyBlob:
		return prop.blobs, true
	default:
		return nil, false
	}
}

func ParsePath(b []byte) (string, error) {
	return newString(b), nil
func (prop *ModeProperty) ObjectType() (ObjectType, bool) {
	if prop.Type() != PropertyObject || len(prop.values) != 1 {
		return 0, false
	}
	return ObjectType(prop.values[0]), true
}

func (prop *ModeProperty) SignedRange() (low, high int64, ok bool) {
	if prop.Type() != PropertyRange || len(prop.values) != 2 {
		return 0, 0, false
	}
	return int64(prop.values[0]), int64(prop.values[1]), true
}