summaryrefslogtreecommitdiff
path: root/py/pykms/__init__.py
blob: 258b4e00ab220984aff0ce11b4475e3eb67b3960 (plain)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
from .pykms import *
from enum import Enum
import os
import struct

#
# Common RGB colours
#

red = RGB(255, 0, 0)
green = RGB(0, 255, 0)
blue = RGB(0, 0, 255)
yellow = RGB(255, 255, 0)
purple = RGB(255, 0, 255)
white = RGB(255, 255, 255)
cyan = RGB(0, 255, 255)

#
# Rotation enum
#

class Rotation(int, Enum):
    ROTATE_0 = 1 << 0
    ROTATE_90 = 1 << 1
    ROTATE_180 = 1 << 2
    ROTATE_270 = 1 << 3
    ROTATE_MASK = ROTATE_0 | ROTATE_90 | ROTATE_180 | ROTATE_270
    REFLECT_X = 1 << 4
    REFLECT_Y = 1 << 5
    REFLECT_MASK = REFLECT_X | REFLECT_Y

#
# DrmObject API extensions
#

def __obj_set_prop(self, prop, value):
    if self.card.has_atomic:
        areq = AtomicReq(self.card)
        areq.add(self, prop, value)
        if areq.commit_sync() != 0:
            print("commit failed")
    else:
        if self.set_prop_value(prop, value) != 0:
            print("setting property failed")

def __obj_set_props(self, map):
    if self.card.has_atomic:
        areq = AtomicReq(self.card)

        for key, value in map.items():
            areq.add(self, key, value)

        if areq.commit_sync() != 0:
            print("commit failed")
    else:
        for propid,propval in map.items():
            if self.set_prop_value(propid, propval) != 0:
                print("setting property failed")

DrmObject.set_prop = __obj_set_prop
DrmObject.set_props = __obj_set_props

#
# Card API extensions
#

def __card_disable_planes(self):
    areq = AtomicReq(self)

    for p in self.planes:
        areq.add(p, "FB_ID", 0)
        areq.add(p, "CRTC_ID", 0)

    if areq.commit_sync() != 0:
        print("disabling planes failed")

Card.disable_planes = __card_disable_planes

class DrmEventType(Enum):
    VBLANK = 0x01
    FLIP_COMPLETE = 0x02

#
# AtomicReq API extensions
#

def __atomic_req_add_connector(req, conn, crtc):
    req.add(conn, "CRTC_ID", crtc.id if crtc else 0)

def __atomic_req_add_crtc(req, crtc, mode_blob):
    if mode_blob:
        req.add(crtc, {"ACTIVE": 1, "MODE_ID": mode_blob.id})
    else:
        req.add(crtc, {"ACTIVE": 0, "MODE_ID": 0})

def __atomic_req_add_plane(req, plane, fb, crtc,
                           src=None, dst=None, zpos=None,
                           params={}):
    if not src and fb:
        src = (0, 0, fb.width, fb.height)

    if not dst:
        dst = src

    m = {"FB_ID": fb.id if fb else 0,
         "CRTC_ID": crtc.id if crtc else 0}

    if src is not None:
        src_x = int(round(src[0] * 65536))
        src_y = int(round(src[1] * 65536))
        src_w = int(round(src[2] * 65536))
        src_h = int(round(src[3] * 65536))

        m["SRC_X"] = src_x
        m["SRC_Y"] = src_y
        m["SRC_W"] = src_w
        m["SRC_H"] = src_h

    if dst is not None:
        crtc_x = int(round(dst[0]))
        crtc_y = int(round(dst[1]))
        crtc_w = int(round(dst[2]))
        crtc_h = int(round(dst[3]))

        m["CRTC_X"] = crtc_x
        m["CRTC_Y"] = crtc_y
        m["CRTC_W"] = crtc_w
        m["CRTC_H"] = crtc_h

    if zpos is not None:
        m["zpos"] = zpos

    m.update(params)

    req.add(plane, m)

pykms.AtomicReq.add_connector = __atomic_req_add_connector
pykms.AtomicReq.add_crtc = __atomic_req_add_crtc
pykms.AtomicReq.add_plane = __atomic_req_add_plane

# struct drm_event {
#   __u32 type;
#   __u32 length;
#};
#

_drm_ev = struct.Struct("II")

#struct drm_event_vblank {
#   struct drm_event base;
#   __u64 user_data;
#   __u32 tv_sec;
#   __u32 tv_usec;
#   __u32 sequence;
#   __u32 reserved;
#};

_drm_ev_vbl = struct.Struct("QIIII") # Note: doesn't contain drm_event

class DrmEvent:
    def __init__(self, type, seq, time, data):
        self.type = type
        self.seq = seq
        self.time = time
        self.data = data

# Return DrmEvents. Note: blocks if there's nothing to read
def __card_read_events(self):
    buf = os.read(self.fd, _drm_ev_vbl.size * 20)

    if len(buf) == 0:
        return

    if len(buf) < _drm_ev.size:
        raise RuntimeError("Partial DRM event")

    idx = 0

    while idx < len(buf):
        ev_tuple = _drm_ev.unpack_from(buf, idx)

        type = DrmEventType(ev_tuple[0])

        if type != DrmEventType.VBLANK and type != DrmEventType.FLIP_COMPLETE:
            raise RuntimeError("Illegal DRM event type")

        vbl_tuple = _drm_ev_vbl.unpack_from(buf, idx + _drm_ev.size)

        seq = vbl_tuple[3]
        time = vbl_tuple[1] + vbl_tuple[2] / 1000000.0;
        udata = vbl_tuple[0]

        yield DrmEvent(type, seq, time, udata)

        idx += ev_tuple[1]

Card.read_events = __card_read_events