1package drm
2
3import (
4 "errors"
5 "fmt"
6 "unsafe"
7
8 "golang.org/x/sys/unix"
9)
10
11// KMS dumb buffers: the driver allocates a linear buffer the CPU maps and
12// the display scans out. Cursor images use them (see cursor_images.go).
13
14const (
15 ioctlCreateDumb = 0xC02064B2 // DRM_IOWR('d', 0xB2, struct drm_mode_create_dumb)
16 ioctlMapDumb = 0xC01064B3 // DRM_IOWR('d', 0xB3, struct drm_mode_map_dumb)
17 ioctlDestroyDumb = 0xC00464B4 // DRM_IOWR('d', 0xB4, struct drm_mode_destroy_dumb)
18)
19
20type createDumb struct {
21 height, width, bpp, flags uint32
22 handle, pitch uint32
23 size uint64
24}
25
26type mapDumb struct {
27 handle, pad uint32
28 offset uint64
29}
30
31// dumbBuffer is a dumb buffer's GEM handle, row pitch and size in bytes.
32type dumbBuffer struct {
33 handle, pitch uint32
34 size uint64
35}
36
37func (k kmsDevice) createDumb(width, height int) (dumbBuffer, error) {
38 if width <= 0 || height <= 0 {
39 return dumbBuffer{}, fmt.Errorf("dumb buffer size %dx%d", width, height)
40 }
41 c := createDumb{height: uint32(height), width: uint32(width), bpp: 32}
42 if err := ioctl(k.fd, ioctlCreateDumb, unsafe.Pointer(&c)); err != nil {
43 return dumbBuffer{}, err
44 }
45 return dumbBuffer{handle: c.handle, pitch: c.pitch, size: c.size}, nil
46}
47
48func (k kmsDevice) mapDumb(b dumbBuffer) ([]byte, error) {
49 m := mapDumb{handle: b.handle}
50 if err := ioctl(k.fd, ioctlMapDumb, unsafe.Pointer(&m)); err != nil {
51 return nil, err
52 }
53 if b.size == 0 || b.size > 1<<30 {
54 return nil, fmt.Errorf("dumb buffer size %d", b.size)
55 }
56 return unix.Mmap(k.fd, int64(m.offset), int(b.size), unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED)
57}
58
59func (k kmsDevice) unmapDumb(mem []byte) error { return unix.Munmap(mem) }
60
61// addFBHandle makes a framebuffer of format over the dumb buffer, without
62// modifier (the driver's linear layout).
63func (k kmsDevice) addFBHandle(b dumbBuffer, width, height int, format uint32) (uint32, error) {
64 if b.handle == 0 {
65 return 0, errors.New("no dumb buffer")
66 }
67 cmd := fbCmd2{width: uint32(width), height: uint32(height), format: format}
68 cmd.handles[0], cmd.pitches[0] = b.handle, b.pitch
69 if err := ioctl(k.fd, ioctlAddFB2, unsafe.Pointer(&cmd)); err != nil {
70 return 0, errors.Join(errors.New("add fb2"), err)
71 }
72 return cmd.fbID, nil
73}
74
75func (k kmsDevice) destroyDumb(handle uint32) error {
76 return ioctl(k.fd, ioctlDestroyDumb, unsafe.Pointer(&handle))
77}