From 16f78ec8e87a44c966feb57d799dcbd2aded29f6 Mon Sep 17 00:00:00 2001 From: Georg Wechslberger Date: Fri, 5 Jan 2024 15:17:09 +0100 Subject: [PATCH 01/13] support AddFB2 command --- mode/mode.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/mode/mode.go b/mode/mode.go index 6234b7a..ab30119 100644 --- a/mode/mode.go +++ b/mode/mode.go @@ -144,6 +144,17 @@ type ( handle uint32 } + sysFBCmd2 struct { + fbID uint32 + width, height uint32 + pixelFormat uint32 + flags uint32 + handles [4]uint32 + pitches [4]uint32 + offsets [4]uint32 + modifier [4]uint64 + } + sysRmFB struct { handle uint32 } @@ -211,6 +222,10 @@ var ( IOCTLModeAddFB = ioctl.NewCode(ioctl.Read|ioctl.Write, uint16(unsafe.Sizeof(sysFBCmd{})), drm.IOCTLBase, 0xAE) + // DRM_IOWR(0xAE, struct drm_mode_fb_cmd) + IOCTLModeAddFB2 = ioctl.NewCode(ioctl.Read|ioctl.Write, + uint16(unsafe.Sizeof(sysFBCmd2{})), drm.IOCTLBase, 0xB8) + // DRM_IOWR(0xAF, unsigned int) IOCTLModeRmFB = ioctl.NewCode(ioctl.Read|ioctl.Write, uint16(unsafe.Sizeof(uint32(0))), drm.IOCTLBase, 0xAF) @@ -397,6 +412,25 @@ func AddFB(file *os.File, width, height uint16, return f.fbID, nil } +func AddFB2SinglePlane(file *os.File, width, height uint16, + pixelFormat uint32, flags, pitch, offset, boHandle uint32, modifier uint64) (uint32, error) { + f := &sysFBCmd2{} + f.width = uint32(width) + f.height = uint32(height) + f.pixelFormat = pixelFormat + f.flags = flags + f.handles[0] = boHandle + f.pitches[0] = pitch + f.offsets[0] = offset + f.modifier[0] = modifier + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeAddFB2), + uintptr(unsafe.Pointer(f))) + if err != nil { + return 0, err + } + return f.fbID, nil +} + func RmFB(file *os.File, bufferid uint32) error { return ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeRmFB), uintptr(unsafe.Pointer(&sysRmFB{bufferid}))) From 3c99be2a499c02ccc99f068a93fcb9a9c8ac20fc Mon Sep 17 00:00:00 2001 From: Georg Wechslberger Date: Sat, 20 Jan 2024 13:54:45 +0100 Subject: [PATCH 02/13] add GetPlaneRessources, GetPlane and SetPlane ioctls --- go.mod | 5 ++ go.sum | 2 + mode/mode.go | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..224186a --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/NeowayLabs/drm + +go 1.21.5 + +require launchpad.net/gommap v0.0.0-20121012075617-000000000015 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..348baa4 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +launchpad.net/gommap v0.0.0-20121012075617-000000000015 h1:ROjpWoAwfoub5UmgCuZwFvM/kWU+UFfuBXbJ6lz/awU= +launchpad.net/gommap v0.0.0-20121012075617-000000000015/go.mod h1:+rB9VlRTGlxdpc/nkCoOe0Qxgn/pyVwo9lGtVndZbOo= diff --git a/mode/mode.go b/mode/mode.go index ab30119..308ba3c 100644 --- a/mode/mode.go +++ b/mode/mode.go @@ -63,6 +63,36 @@ type ( possibleClones uint32 } + sysGetPlaneResources struct { + planeIdPtr uint64 + countPlanes uint32 + } + + sysGetPlane struct { + planeId uint32 + crtcId uint32 + fbId uint32 + possibleCrtcs uint32 + gammaSize uint32 + countFormatTypes uint32 + formatTypePtr uint64 + } + + sysSetPlane struct { + planeId uint32 + crtcId uint32 + fbId uint32 + flags uint32 + crtcX int32 + crtcY int32 + crtcW uint32 + crtcH uint32 + srcX uint32 + srcY uint32 + srcH uint32 + srcW uint32 + } + Info struct { Clock uint32 Hdisplay, HsyncStart, HsyncEnd, Htotal, Hskew uint16 @@ -113,6 +143,23 @@ type ( PossibleClones uint32 } + PlaneResources struct { + sysGetPlaneResources + + Planes []uint32 + } + + Plane struct { + sysGetPlane + + ID uint32 + CrtcID uint32 + FbID uint32 + PossibleCrtcs uint32 + GammaSize uint32 + FormatTypes []uint32 + } + sysCreateDumb struct { height, width uint32 bpp uint32 @@ -241,6 +288,18 @@ var ( // DRM_IOWR(0xB4, struct drm_mode_destroy_dumb) IOCTLModeDestroyDumb = ioctl.NewCode(ioctl.Read|ioctl.Write, uint16(unsafe.Sizeof(sysDestroyDumb{})), drm.IOCTLBase, 0xB4) + + // DRM_IOWR(0xB5, struct drm_mode_get_plane_res) + IOCTLModeGetPlaneResources = ioctl.NewCode(ioctl.Read|ioctl.Write, + uint16(unsafe.Sizeof(sysGetPlaneResources{})), drm.IOCTLBase, 0xB5) + + // DRM_IOWR(0xB6, struct drm_mode_get_plane) + IOCTLModeGetPlane = ioctl.NewCode(ioctl.Read|ioctl.Write, + uint16(unsafe.Sizeof(sysGetPlane{})), drm.IOCTLBase, 0xB6) + + // DRM_IOWR(0xB7, struct drm_mode_set_plane) + IOCTLModeSetPlane = ioctl.NewCode(ioctl.Read|ioctl.Write, + uint16(unsafe.Sizeof(sysSetPlane{})), drm.IOCTLBase, 0xB7) ) func GetResources(file *os.File) (*Resources, error) { @@ -375,6 +434,89 @@ func GetEncoder(file *os.File, id uint32) (*Encoder, error) { }, nil } +func GetPlaneResources(file *os.File) (*PlaneResources, error) { + mPlaneRes := &sysGetPlaneResources{} + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeGetPlaneResources), + uintptr(unsafe.Pointer(mPlaneRes))) + if err != nil { + return nil, err + } + + var ( + planeIds []uint32 + ) + + if mPlaneRes.countPlanes > 0 { + planeIds = make([]uint32, mPlaneRes.countPlanes) + mPlaneRes.planeIdPtr = uint64(uintptr(unsafe.Pointer(&planeIds[0]))) + } + + err = ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeGetPlaneResources), + uintptr(unsafe.Pointer(mPlaneRes))) + if err != nil { + return nil, err + } + + return &PlaneResources{ + sysGetPlaneResources: *mPlaneRes, + Planes: planeIds, + }, nil +} + +func GetPlane(file *os.File, id uint32) (*Plane, error) { + mPlaneRes := &sysGetPlane{planeId: id} + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeGetPlane), + uintptr(unsafe.Pointer(mPlaneRes))) + if err != nil { + return nil, err + } + + var ( + formatTypes []uint32 + ) + + if mPlaneRes.countFormatTypes > 0 { + formatTypes = make([]uint32, mPlaneRes.countFormatTypes) + mPlaneRes.formatTypePtr = uint64(uintptr(unsafe.Pointer(&formatTypes[0]))) + } + + err = ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeGetPlane), + uintptr(unsafe.Pointer(mPlaneRes))) + if err != nil { + return nil, err + } + + return &Plane{ + sysGetPlane: *mPlaneRes, + ID: mPlaneRes.planeId, + CrtcID: mPlaneRes.crtcId, + FbID: mPlaneRes.fbId, + PossibleCrtcs: mPlaneRes.possibleCrtcs, + GammaSize: mPlaneRes.gammaSize, + FormatTypes: formatTypes, + }, nil +} + +func SetPlane(file *os.File, planeId, crtcId, fbId uint32, flags uint32, crtcX, crtcY int32, crtcW, crtcH, srcX, srcY, srcH, srcW uint32) error { + mPlaneRes := &sysSetPlane{ + planeId: planeId, + crtcId: crtcId, + fbId: fbId, + flags: flags, + crtcX: crtcX, + crtcY: crtcY, + crtcW: crtcW, + crtcH: crtcH, + srcX: srcX, + srcY: srcY, + srcW: srcW, + srcH: srcH, + } + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeSetPlane), + uintptr(unsafe.Pointer(mPlaneRes))) + return err +} + func CreateFB(file *os.File, width, height uint16, bpp uint32) (*FB, error) { fb := &sysCreateDumb{} fb.width = uint32(width) @@ -431,6 +573,25 @@ func AddFB2SinglePlane(file *os.File, width, height uint16, return f.fbID, nil } +func AddFB2(file *os.File, width, height uint16, + pixelFormat uint32, flags uint32, pitches, offsets, boHandles []uint32, modifier []uint64) (uint32, error) { + f := &sysFBCmd2{} + f.width = uint32(width) + f.height = uint32(height) + f.pixelFormat = pixelFormat + f.flags = flags + copy(f.handles[:], boHandles) + copy(f.pitches[:], pitches) + copy(f.offsets[:], offsets) + copy(f.modifier[:], modifier) + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeAddFB2), + uintptr(unsafe.Pointer(f))) + if err != nil { + return 0, err + } + return f.fbID, nil +} + func RmFB(file *os.File, bufferid uint32) error { return ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeRmFB), uintptr(unsafe.Pointer(&sysRmFB{bufferid}))) From 1008d02a3f251ab5dcf5e9cdac2a9fb728095e41 Mon Sep 17 00:00:00 2001 From: Georg Wechslberger Date: Sat, 20 Jan 2024 14:11:17 +0100 Subject: [PATCH 03/13] format source --- mode/mode.go | 82 ++++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/mode/mode.go b/mode/mode.go index 308ba3c..aa83cc4 100644 --- a/mode/mode.go +++ b/mode/mode.go @@ -69,28 +69,28 @@ type ( } sysGetPlane struct { - planeId uint32 - crtcId uint32 - fbId uint32 - possibleCrtcs uint32 - gammaSize uint32 + planeId uint32 + crtcId uint32 + fbId uint32 + possibleCrtcs uint32 + gammaSize uint32 countFormatTypes uint32 - formatTypePtr uint64 + formatTypePtr uint64 } sysSetPlane struct { - planeId uint32 - crtcId uint32 - fbId uint32 - flags uint32 - crtcX int32 - crtcY int32 - crtcW uint32 - crtcH uint32 - srcX uint32 - srcY uint32 - srcH uint32 - srcW uint32 + planeId uint32 + crtcId uint32 + fbId uint32 + flags uint32 + crtcX int32 + crtcY int32 + crtcW uint32 + crtcH uint32 + srcX uint32 + srcY uint32 + srcH uint32 + srcW uint32 } Info struct { @@ -146,18 +146,18 @@ type ( PlaneResources struct { sysGetPlaneResources - Planes []uint32 + Planes []uint32 } Plane struct { sysGetPlane - ID uint32 + ID uint32 CrtcID uint32 - FbID uint32 - PossibleCrtcs uint32 - GammaSize uint32 - FormatTypes []uint32 + FbID uint32 + PossibleCrtcs uint32 + GammaSize uint32 + FormatTypes []uint32 } sysCreateDumb struct { @@ -459,7 +459,7 @@ func GetPlaneResources(file *os.File) (*PlaneResources, error) { return &PlaneResources{ sysGetPlaneResources: *mPlaneRes, - Planes: planeIds, + Planes: planeIds, }, nil } @@ -487,12 +487,12 @@ func GetPlane(file *os.File, id uint32) (*Plane, error) { } return &Plane{ - sysGetPlane: *mPlaneRes, - ID: mPlaneRes.planeId, - CrtcID: mPlaneRes.crtcId, - FbID: mPlaneRes.fbId, + sysGetPlane: *mPlaneRes, + ID: mPlaneRes.planeId, + CrtcID: mPlaneRes.crtcId, + FbID: mPlaneRes.fbId, PossibleCrtcs: mPlaneRes.possibleCrtcs, - GammaSize: mPlaneRes.gammaSize, + GammaSize: mPlaneRes.gammaSize, FormatTypes: formatTypes, }, nil } @@ -500,17 +500,17 @@ func GetPlane(file *os.File, id uint32) (*Plane, error) { func SetPlane(file *os.File, planeId, crtcId, fbId uint32, flags uint32, crtcX, crtcY int32, crtcW, crtcH, srcX, srcY, srcH, srcW uint32) error { mPlaneRes := &sysSetPlane{ planeId: planeId, - crtcId: crtcId, - fbId: fbId, - flags: flags, - crtcX: crtcX, - crtcY: crtcY, - crtcW: crtcW, - crtcH: crtcH, - srcX: srcX, - srcY: srcY, - srcW: srcW, - srcH: srcH, + crtcId: crtcId, + fbId: fbId, + flags: flags, + crtcX: crtcX, + crtcY: crtcY, + crtcW: crtcW, + crtcH: crtcH, + srcX: srcX, + srcY: srcY, + srcW: srcW, + srcH: srcH, } err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeSetPlane), uintptr(unsafe.Pointer(mPlaneRes))) From 11bf2b7f49c9c101160ae53d79efda8490d32d23 Mon Sep 17 00:00:00 2001 From: Georg Wechslberger Date: Sat, 20 Jan 2024 18:57:22 +0100 Subject: [PATCH 04/13] feat: add GetProperty and GetBlob ioctl --- mode/mode.go | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/mode/mode.go b/mode/mode.go index aa83cc4..f231d9b 100644 --- a/mode/mode.go +++ b/mode/mode.go @@ -1,6 +1,7 @@ package mode import ( + "bytes" "os" "unsafe" @@ -17,6 +18,21 @@ const ( Connected = 1 Disconnected = 2 UnknownConnection = 3 + + // deprecated + PropPending = 1 << 0 + // legacy types + PropRagen = 1 << 1 + PropImmutable = 1 << 2 + PropEnum = 1 << 3 + PropBlob = 1 << 4 + PropBitmask = 1 << 5 + // extended types + PropExtended = 0x0000ffc0 + PropObject = 1 << 6 + PropSignedrange = 2 << 6 + // atomic flag + PropAtomic = 0x80000000 ) type ( @@ -93,6 +109,27 @@ type ( srcW uint32 } + sysGetProperty struct { + valuesPtr uint64 + enumBlobPtr uint64 + propId uint32 + flags uint32 + name [PropNameLen]uint8 + countValues uint32 + countEnumBlobs uint32 + } + + sysPropertyEnum struct { + value uint64 + name [PropNameLen]uint8 + } + + sysGetBlob struct { + blobId uint32 + length uint32 + data uint64 + } + Info struct { Clock uint32 Hdisplay, HsyncStart, HsyncEnd, Htotal, Hskew uint16 @@ -160,6 +197,24 @@ type ( FormatTypes []uint32 } + Property struct { + ID uint32 + Values []uint64 + EnumBlobs []PropertyEnum + Flags uint32 + Name string + } + + PropertyEnum struct { + Value uint64 + Name string + } + + Blob struct { + ID uint32 + Data []byte + } + sysCreateDumb struct { height, width uint32 bpp uint32 @@ -300,6 +355,14 @@ var ( // DRM_IOWR(0xB7, struct drm_mode_set_plane) IOCTLModeSetPlane = ioctl.NewCode(ioctl.Read|ioctl.Write, uint16(unsafe.Sizeof(sysSetPlane{})), drm.IOCTLBase, 0xB7) + + // DRM_IOWR(0xAA, struct drm_mode_get_property) + IOCTLModeGetProperty = ioctl.NewCode(ioctl.Read|ioctl.Write, + uint16(unsafe.Sizeof(sysGetProperty{})), drm.IOCTLBase, 0xAA) + + // DRM_IOWR(0xAC, struct drm_mode_get_blob) + IOCTLModeGetPropBlob = ioctl.NewCode(ioctl.Read|ioctl.Write, + uint16(unsafe.Sizeof(sysGetBlob{})), drm.IOCTLBase, 0xAC) ) func GetResources(file *os.File) (*Resources, error) { @@ -517,6 +580,90 @@ func SetPlane(file *os.File, planeId, crtcId, fbId uint32, flags uint32, crtcX, return err } +func GetProperty(file *os.File, id uint32) (*Property, error) { + propertyRes := &sysGetProperty{propId: id, countValues: 0, countEnumBlobs: 0} + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeGetProperty), + uintptr(unsafe.Pointer(propertyRes))) + if err != nil { + return nil, err + } + + // Create arrays to store the values and enums. + var ( + values []uint64 + enumBlobs []sysPropertyEnum + ) + + if propertyRes.countValues > 0 { + values = make([]uint64, propertyRes.countValues) + propertyRes.valuesPtr = uint64(uintptr(unsafe.Pointer(&values[0]))) + } + + if propertyRes.countEnumBlobs > 0 { + enumBlobs = make([]sysPropertyEnum, propertyRes.countEnumBlobs) + propertyRes.enumBlobPtr = uint64(uintptr(unsafe.Pointer(&enumBlobs[0]))) + } + + // Repeat the ioctl command to fill the arrays. + err = ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeGetProperty), + uintptr(unsafe.Pointer(propertyRes))) + if err != nil { + return nil, err + } + + // Create enum value array for output. + enums := make([]PropertyEnum, propertyRes.countEnumBlobs) + for i, enumBlob := range enumBlobs { + // Name is null termninated, so we remove the trailing 0s. + name, _, _ := bytes.Cut(enumBlob.name[:], []byte{0}) + enums[i] = PropertyEnum{ + Value: enumBlob.value, + Name: string(name), + } + } + + // Name is null termninated, so we remove the trailing 0s. + name, _, _ := bytes.Cut(propertyRes.name[:], []byte{0}) + return &Property{ + ID: propertyRes.propId, + Values: values, + EnumBlobs: enums, + Flags: propertyRes.flags, + Name: string(name), + }, nil +} + +func GetBlob(file *os.File, id uint32) (*Blob, error) { + propertyBlob := &sysGetBlob{blobId: id, length: 0} + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeGetPropBlob), + uintptr(unsafe.Pointer(propertyBlob))) + if err != nil { + return nil, err + } + + // Create array to store the blob data. + var ( + data []uint8 + ) + + if propertyBlob.length > 0 { + data = make([]uint8, propertyBlob.length) + propertyBlob.data = uint64(uintptr(unsafe.Pointer(&data[0]))) + } + + // Repeat the ioctl command to fill the array. + err = ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeGetPropBlob), + uintptr(unsafe.Pointer(propertyBlob))) + if err != nil { + return nil, err + } + + return &Blob{ + ID: id, + Data: data, + }, nil +} + func CreateFB(file *os.File, width, height uint16, bpp uint32) (*FB, error) { fb := &sysCreateDumb{} fb.width = uint32(width) From a444254fc99e56210384274e2e008c6bb43643f1 Mon Sep 17 00:00:00 2001 From: Georg Wechslberger Date: Thu, 1 Feb 2024 22:37:53 +0100 Subject: [PATCH 05/13] feat: support set_client_cap and get_properties --- mode/mode.go | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/mode/mode.go b/mode/mode.go index f231d9b..a9d10b7 100644 --- a/mode/mode.go +++ b/mode/mode.go @@ -33,6 +33,24 @@ const ( PropSignedrange = 2 << 6 // atomic flag PropAtomic = 0x80000000 + + // Client Capabilities + ClientCapStereo3D = 1 + ClientCapUniversalPlanes = 2 + ClientCapAtomic = 3 + ClientCapAspectRatio = 4 + ClientCapWritebackConnectors = 5 + + // Object Types + ObjectCRTC = 0xcccccccc + ObjectConnector = 0xc0c0c0c0 + ObjectEncoder = 0xe0e0e0e0 + ObjectMode = 0xdededede + ObjectProperty = 0xb0b0b0b0 + ObjectFB = 0xfbfbfbfb + ObjectBLOB = 0xbbbbbbbb + ObjectPlane = 0xeeeeeeee + ObjectAny = 0 ) type ( @@ -130,6 +148,19 @@ type ( data uint64 } + sysSetClientCap struct { + capability uint64 + value uint64 + } + + sysObjGetProperties struct { + propsPtr uint64 + propValuesPtr uint64 + countProps uint32 + objID uint32 + objType uint32 + } + Info struct { Clock uint32 Hdisplay, HsyncStart, HsyncEnd, Htotal, Hskew uint16 @@ -215,6 +246,14 @@ type ( Data []byte } + Properties struct { + ObjectID uint32 + ObjectType uint32 + + Props []uint32 + PropValues []uint64 + } + sysCreateDumb struct { height, width uint32 bpp uint32 @@ -363,6 +402,14 @@ var ( // DRM_IOWR(0xAC, struct drm_mode_get_blob) IOCTLModeGetPropBlob = ioctl.NewCode(ioctl.Read|ioctl.Write, uint16(unsafe.Sizeof(sysGetBlob{})), drm.IOCTLBase, 0xAC) + + // DRM_IOW(0x0D, struct drm_set_client_cap) + IOCTLSetClientCap = ioctl.NewCode(ioctl.Write, + uint16(unsafe.Sizeof(sysSetClientCap{})), drm.IOCTLBase, 0x0D) + + // DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) + IOCTLModeObjGetProperties = ioctl.NewCode(ioctl.Read|ioctl.Write, + uint16(unsafe.Sizeof(sysObjGetProperties{})), drm.IOCTLBase, 0xB9) ) func GetResources(file *os.File) (*Resources, error) { @@ -664,6 +711,58 @@ func GetBlob(file *os.File, id uint32) (*Blob, error) { }, nil } +func SetClientCap(file *os.File, capability, value uint64) error { + setClientCap := &sysSetClientCap{ + capability: capability, + value: value, + } + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLSetClientCap), + uintptr(unsafe.Pointer(setClientCap))) + return err +} + +func GetProperties(file *os.File, objectID uint32, objectType uint32) (*Properties, error) { + objGetProperties := &sysObjGetProperties{} + objGetProperties.objID = objectID + objGetProperties.objType = objectType + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeObjGetProperties), + uintptr(unsafe.Pointer(objGetProperties))) + if err != nil { + return nil, err + } + + var ( + props []uint32 + propValues []uint64 + ) + + if objGetProperties.countProps > 0 { + props = make([]uint32, objGetProperties.countProps) + objGetProperties.propsPtr = uint64(uintptr(unsafe.Pointer(&props[0]))) + + propValues = make([]uint64, objGetProperties.countProps) + objGetProperties.propValuesPtr = uint64(uintptr(unsafe.Pointer(&propValues[0]))) + } + + err = ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeObjGetProperties), + uintptr(unsafe.Pointer(objGetProperties))) + if err != nil { + return nil, err + } + + ret := &Properties{ + ObjectID: objectID, + ObjectType: objectType, + } + + ret.Props = make([]uint32, len(props)) + copy(ret.Props, props) + ret.PropValues = make([]uint64, len(propValues)) + copy(ret.PropValues, propValues) + + return ret, nil +} + func CreateFB(file *os.File, width, height uint16, bpp uint32) (*FB, error) { fb := &sysCreateDumb{} fb.width = uint32(width) From 8123f75a0b6ce0bc4036d6329e47a61c2a6563dc Mon Sep 17 00:00:00 2001 From: Georg Wechslberger Date: Tue, 6 Feb 2024 01:42:32 +0100 Subject: [PATCH 06/13] feat: add support for atomic modesetting --- mode/mode.go | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/mode/mode.go b/mode/mode.go index a9d10b7..813f483 100644 --- a/mode/mode.go +++ b/mode/mode.go @@ -3,6 +3,7 @@ package mode import ( "bytes" "os" + "slices" "unsafe" "github.com/NeowayLabs/drm" @@ -51,6 +52,13 @@ const ( ObjectBLOB = 0xbbbbbbbb ObjectPlane = 0xeeeeeeee ObjectAny = 0 + + // Atomic Flags + PageFlipEvent = 0x01 + PageFlipAsync = 0x02 + AtomicTestOnly = 0x0100 + AtomicNonBlock = 0x0200 + AtomicAllowModeSet = 0x0400 ) type ( @@ -143,9 +151,19 @@ type ( } sysGetBlob struct { - blobId uint32 + data uint64 length uint32 + blobId uint32 + } + + sysCreateBlob struct { data uint64 + length uint32 + blobId uint32 + } + + sysDestroyBlob struct { + blobId uint32 } sysSetClientCap struct { @@ -161,6 +179,17 @@ type ( objType uint32 } + sysAtomic struct { + flags uint32 + countObjs uint32 + objsPtr uint64 + countPropsPtr uint64 + propsPtr uint64 + propValuesPtr uint64 + reserved uint64 + userData uint64 + } + Info struct { Clock uint32 Hdisplay, HsyncStart, HsyncEnd, Htotal, Hskew uint16 @@ -254,6 +283,12 @@ type ( PropValues []uint64 } + AtomicProperty struct { + ObjectID uint32 + PropertyID uint32 + Value uint64 + } + sysCreateDumb struct { height, width uint32 bpp uint32 @@ -410,6 +445,18 @@ var ( // DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) IOCTLModeObjGetProperties = ioctl.NewCode(ioctl.Read|ioctl.Write, uint16(unsafe.Sizeof(sysObjGetProperties{})), drm.IOCTLBase, 0xB9) + + // DRM_IOWR(0xBC, struct drm_mode_atomic) + IOCTLModeAtomic = ioctl.NewCode(ioctl.Read|ioctl.Write, + uint16(unsafe.Sizeof(sysAtomic{})), drm.IOCTLBase, 0xBC) + + // DRM_IOWR(0xBD, struct drm_mode_create_blob) + IOCTLModeCreateBlob = ioctl.NewCode(ioctl.Read|ioctl.Write, + uint16(unsafe.Sizeof(sysCreateBlob{})), drm.IOCTLBase, 0xBD) + + // DRM_IOWR(0xBE, struct drm_mode_destroy_blob) + IOCTLModeDestroyBlob = ioctl.NewCode(ioctl.Read|ioctl.Write, + uint16(unsafe.Sizeof(sysDestroyBlob{})), drm.IOCTLBase, 0xBE) ) func GetResources(file *os.File) (*Resources, error) { @@ -711,6 +758,40 @@ func GetBlob(file *os.File, id uint32) (*Blob, error) { }, nil } +func CreateBlob(file *os.File, data []uint8) (uint32, error) { + createBlob := &sysCreateBlob{ + data: uint64(uintptr(unsafe.Pointer(&data[0]))), + length: uint32(len(data)), + } + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeCreateBlob), + uintptr(unsafe.Pointer(createBlob))) + if err != nil { + return 0, err + } + return createBlob.blobId, nil +} + +func CreateInfoBlob(file *os.File, info Info) (uint32, error) { + createBlob := &sysCreateBlob{ + data: uint64(uintptr(unsafe.Pointer(&info))), + length: uint32(unsafe.Sizeof(info)), + } + err := ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeCreateBlob), + uintptr(unsafe.Pointer(createBlob))) + if err != nil { + return 0, err + } + return createBlob.blobId, nil +} + +func DestroyBlob(file *os.File, id uint32) error { + destroyBlob := &sysDestroyBlob{ + blobId: id, + } + return ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeDestroyBlob), + uintptr(unsafe.Pointer(destroyBlob))) +} + func SetClientCap(file *os.File, capability, value uint64) error { setClientCap := &sysSetClientCap{ capability: capability, @@ -763,6 +844,66 @@ func GetProperties(file *os.File, objectID uint32, objectType uint32) (*Properti return ret, nil } +func Atomic(file *os.File, flags uint32, atomicProperties []AtomicProperty) error { + // There is nothing to do if no properties are specified. + if len(atomicProperties) == 0 { + return nil + } + + // Sort the properties in the input according to the object id. + properties := make([]AtomicProperty, len(atomicProperties)) + copy(properties, atomicProperties) + slices.SortFunc[[]AtomicProperty](properties, func(a, b AtomicProperty) int { + if a.ObjectID < b.ObjectID { + return -1 + } else if a.ObjectID == b.ObjectID { + return 0 + } else { + return 1 + } + }) + + // Create individual arrays required by the syscall structure. + objs := make([]uint32, len(atomicProperties)) + countProps := make([]uint32, len(atomicProperties)) + props := make([]uint32, len(atomicProperties)) + propValues := make([]uint64, len(atomicProperties)) + // Set the first object ID. + objsIndex := 0 + objs[0] = properties[0].ObjectID + curObj := objs[0] + countPropsObj := uint32(0) + for i, property := range properties { + if property.ObjectID != curObj { + // Set the number of properties for the current object. + countProps[objsIndex] = countPropsObj + // Advance to the next object. + countPropsObj = 0 + objsIndex++ + objs[objsIndex] = property.ObjectID + } + // Set the property id and value. + props[i] = property.PropertyID + propValues[i] = property.Value + // Increase the number of properties for the object. + countPropsObj++ + } + // Set the property count for the last object. + countProps[objsIndex] = countPropsObj + + // Assemble atomic request. + sysAtomic := &sysAtomic{ + flags: flags, + countObjs: uint32(objsIndex) + 1, + objsPtr: uint64(uintptr(unsafe.Pointer(&objs[0]))), + countPropsPtr: uint64(uintptr(unsafe.Pointer(&countProps[0]))), + propValuesPtr: uint64(uintptr(unsafe.Pointer(&propValues[0]))), + propsPtr: uint64(uintptr(unsafe.Pointer(&props[0]))), + } + return ioctl.Do(uintptr(file.Fd()), uintptr(IOCTLModeAtomic), + uintptr(unsafe.Pointer(sysAtomic))) +} + func CreateFB(file *os.File, width, height uint16, bpp uint32) (*FB, error) { fb := &sysCreateDumb{} fb.width = uint32(width) From 26fbe0c725a5d66b870181b2c75885ae2abc7d68 Mon Sep 17 00:00:00 2001 From: simon place Date: Sun, 7 Apr 2024 16:34:01 +0100 Subject: [PATCH 07/13] change from launchpad.net to github.com --- _examples/draw/drawpicture.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_examples/draw/drawpicture.go b/_examples/draw/drawpicture.go index f80d4e9..0f0c5f3 100644 --- a/_examples/draw/drawpicture.go +++ b/_examples/draw/drawpicture.go @@ -7,7 +7,7 @@ import ( "time" "unsafe" - "launchpad.net/gommap" + "github.com/tysonmote/gommap" _ "image/jpeg" From b91cd16a3acbdaeec1a5517c1d2763550f6f1319 Mon Sep 17 00:00:00 2001 From: simon place Date: Sun, 7 Apr 2024 16:41:46 +0100 Subject: [PATCH 08/13] change from launchpad.net to github.com --- _examples/modeset/modeset-double-buffered.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_examples/modeset/modeset-double-buffered.go b/_examples/modeset/modeset-double-buffered.go index 4afc118..3ff3830 100644 --- a/_examples/modeset/modeset-double-buffered.go +++ b/_examples/modeset/modeset-double-buffered.go @@ -10,7 +10,7 @@ import ( "time" "unsafe" - "launchpad.net/gommap" + "github.com/tysonmote/gommap" "github.com/NeowayLabs/drm" "github.com/NeowayLabs/drm/mode" From f011ed6d22984a0a0f2568bda054c8471161c477 Mon Sep 17 00:00:00 2001 From: simon place Date: Sun, 7 Apr 2024 16:43:36 +0100 Subject: [PATCH 09/13] change from launchpad.net to github.com --- _examples/modeset/modeset.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_examples/modeset/modeset.go b/_examples/modeset/modeset.go index d122e2a..ebe6d57 100644 --- a/_examples/modeset/modeset.go +++ b/_examples/modeset/modeset.go @@ -9,7 +9,7 @@ import ( "time" "unsafe" - "launchpad.net/gommap" + "github.com/tysonmote/gommap" "github.com/NeowayLabs/drm" "github.com/NeowayLabs/drm/mode" From 02c24c7cd6b50fbdc7fbf489497c7ebae3f5d0df Mon Sep 17 00:00:00 2001 From: simon place Date: Mon, 8 Apr 2024 23:27:50 +0100 Subject: [PATCH 10/13] Update go.sum --- go.sum | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/go.sum b/go.sum index 348baa4..8b13789 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1 @@ -launchpad.net/gommap v0.0.0-20121012075617-000000000015 h1:ROjpWoAwfoub5UmgCuZwFvM/kWU+UFfuBXbJ6lz/awU= -launchpad.net/gommap v0.0.0-20121012075617-000000000015/go.mod h1:+rB9VlRTGlxdpc/nkCoOe0Qxgn/pyVwo9lGtVndZbOo= + From 0da5b66c893c23daa3bba6fa82c01f0402193899 Mon Sep 17 00:00:00 2001 From: simon place Date: Mon, 8 Apr 2024 23:31:24 +0100 Subject: [PATCH 11/13] Update go.mod --- go.mod | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 224186a..215808c 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,4 @@ -module github.com/NeowayLabs/drm +module github.com/splace/drm go 1.21.5 -require launchpad.net/gommap v0.0.0-20121012075617-000000000015 // indirect From 372a8ddcbeed872f04c12db40de891663a3b8188 Mon Sep 17 00:00:00 2001 From: simon place Date: Mon, 8 Apr 2024 23:34:04 +0100 Subject: [PATCH 12/13] Update go.mod --- go.mod | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 224186a..215808c 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,4 @@ -module github.com/NeowayLabs/drm +module github.com/splace/drm go 1.21.5 -require launchpad.net/gommap v0.0.0-20121012075617-000000000015 // indirect From 9292c7f35485f72e6bc828af93c26f50db52fa0b Mon Sep 17 00:00:00 2001 From: simon place Date: Mon, 8 Apr 2024 23:34:27 +0100 Subject: [PATCH 13/13] Update go.sum --- go.sum | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/go.sum b/go.sum index 348baa4..8b13789 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1 @@ -launchpad.net/gommap v0.0.0-20121012075617-000000000015 h1:ROjpWoAwfoub5UmgCuZwFvM/kWU+UFfuBXbJ6lz/awU= -launchpad.net/gommap v0.0.0-20121012075617-000000000015/go.mod h1:+rB9VlRTGlxdpc/nkCoOe0Qxgn/pyVwo9lGtVndZbOo= +