• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3
2
3import pykms
4import random
5import time
6import sys
7import select
8import argparse
9import selectors
10
11black = pykms.RGB(0, 0, 0)
12
13parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
14parser.add_argument('--flipmode', choices=['single', 'separate'], default='single', required=False,
15    help="""Page flip method to use:
16    single: Page flip on all displays with one request (default)
17    separate: Separate page flip on the displays""")
18
19args = parser.parse_args()
20
21card = pykms.Card()
22
23if not card.has_atomic:
24    print('Atomic mode settings is not supported :(')
25    sys.exit()
26
27if args.flipmode == 'single':
28    print('Page flip on all displays with one request')
29elif args.flipmode == 'separate':
30    print('Page flip on all displays with separate requests')
31
32res = pykms.ResourceManager(card)
33
34conn_list = []
35crtc_list = []
36mode_list = []
37plane_list = []
38big_fb_list = []
39
40for conn in card.connectors:
41    if conn.connected() == 1:
42        conn_list.append(conn)
43
44print('Have {} connected connectors:'.format(len(conn_list)))
45for conn in conn_list:
46    crtc = res.reserve_crtc(conn)
47    crtc_list.append(crtc)
48
49    mode = conn.get_default_mode()
50    mode_list.append(mode)
51
52    print(' {}: {} ({}x{})'.format(conn.idx, conn.fullname,
53        mode.hdisplay, mode.vdisplay))
54
55fbX = sum(mode.hdisplay for mode in mode_list)
56fbY = max(mode.vdisplay for mode in mode_list)
57
58print('FB Resolution: {}x{}\n'.format(fbX, fbY))
59
60# Create the (big)framebuffer(s)
61for x in range(2):
62    fb_tmp = pykms.DumbFramebuffer(card, fbX, fbY, 'XR24');
63    big_fb_list.append(fb_tmp)
64
65fb = big_fb_list[0]
66screen_offset = 0
67
68card.disable_planes()
69for i in range(0, len(conn_list)):
70    conn = conn_list[i]
71    crtc = crtc_list[i]
72    mode = mode_list[i]
73
74    plane = res.reserve_generic_plane(crtc)
75    plane_list.append(plane)
76
77    modeb = mode.to_blob(card)
78    req = pykms.AtomicReq(card)
79    req.add(conn, 'CRTC_ID', crtc.id)
80    req.add(crtc, {'ACTIVE': 1,
81                    'MODE_ID': modeb.id})
82    req.add(plane, {'FB_ID': fb.id,
83                    'CRTC_ID': crtc.id,
84                    'SRC_X': screen_offset << 16,
85                    'SRC_Y': 0 << 16,
86                    'SRC_W': mode.hdisplay << 16,
87                    'SRC_H': mode.vdisplay << 16,
88                    'CRTC_X': 0,
89                    'CRTC_Y': 0,
90                    'CRTC_W': mode.hdisplay,
91                    'CRTC_H': mode.vdisplay,
92                    'zorder': 0})
93
94    req.commit_sync(allow_modeset = True)
95
96    screen_offset += mode.hdisplay
97
98# Double buffering, page flipping
99class bigFB_db:
100    def __init__(self, fb1, fb2):
101        self.speed_y = random.randrange(1, 10, 1)
102        self.dir_y = random.randrange(-1, 3, 2)
103        self.first_run = True
104        self.fbs = [fb1,fb2]
105        self.draw_buf = 0
106        self.fbX = fb1.width
107        self.fbY = fb1.height
108        self.pos_y = self.fbY // 2
109        self.old_pos_y = -1
110        # 5 + 10 + 15 + 10 + 5 = 45
111        self.bar_size = 45
112        self.flips = 0
113        self.frames = 0
114        self.time = 0
115        self.flip_count = 100
116
117    def new_color(self):
118        r = random.randrange(255)
119        g = random.randrange(255)
120        b = random.randrange(255)
121        self.color = pykms.RGB(r, g, b)
122        self.color2 = pykms.RGB(r // 2, g // 2, b // 2)
123        self.color3 = pykms.RGB(r // 3, g // 3, b // 3)
124    def move_stripe(self):
125        if self.first_run:
126            self.new_color()
127            self.first_run = False
128
129        fb = self.fbs[self.draw_buf]
130
131        old_box_y = self.old_pos_y
132        self.old_pos_y = self.pos_y
133        change_speed = 0
134
135        self.pos_y = int(self.pos_y + (self.dir_y * self.speed_y))
136
137        if self.pos_y < 0:
138            self.pos_y = 0
139            change_speed = 1
140            self.dir_y = 1
141        elif self.pos_y > (self.fbY - self.bar_size):
142            self.pos_y = self.fbY - self.bar_size
143            change_speed = 1
144            self.dir_y = -1
145
146        if change_speed == 1:
147            self.new_color()
148            self.speed_y = random.randrange(1, 10, 1)
149
150        # Erease the old box
151        if old_box_y >= 0:
152            pykms.draw_rect(fb, 0, old_box_y, self.fbX, self.bar_size, black)
153
154        pos_y = self.pos_y
155        pykms.draw_rect(fb, 0, pos_y, self.fbX, 5, self.color3)
156        pos_y += 5
157        pykms.draw_rect(fb, 0, pos_y, self.fbX, 10, self.color2)
158        pos_y += 10
159        pykms.draw_rect(fb, 0, pos_y, self.fbX, 15, self.color)
160        pos_y += 15
161        pykms.draw_rect(fb, 0, pos_y, self.fbX, 10, self.color2)
162        pos_y += 10
163        pykms.draw_rect(fb, 0, pos_y, self.fbX, 5, self.color3)
164
165    def handle_page_flip_single(self):
166        self.draw_buf ^= 1
167        self.move_stripe()
168
169        # one atomic request to flip on all displays/crtcs
170        fb = self.fbs[self.draw_buf]
171        screen_offset = 0
172
173        req = pykms.AtomicReq(card)
174        for i in range(0, len(conn_list)):
175            crtc = crtc_list[i]
176            mode = mode_list[i]
177
178            plane = plane_list[i]
179
180            req.add(plane, {'FB_ID': fb.id,
181                            'CRTC_ID': crtc.id,
182                            'SRC_X': screen_offset << 16,
183                            'SRC_Y': 0 << 16,
184                            'SRC_W': mode.hdisplay << 16,
185                            'SRC_H': mode.vdisplay << 16,
186                            'CRTC_X': 0,
187                            'CRTC_Y': 0,
188                            'CRTC_W': mode.hdisplay,
189                            'CRTC_H': mode.vdisplay,
190                            'zorder': 0})
191
192            screen_offset += mode.hdisplay
193
194        req.commit(0)
195
196    def handle_page_flip_separate(self):
197        self.draw_buf ^= 1
198        self.move_stripe()
199
200        # ask to flip the first screen
201        fb = self.fbs[self.draw_buf]
202        screen_offset = 0
203
204        # add separate atomic request for each display (crtc)
205        for i in range(0, len(conn_list)):
206            req = pykms.AtomicReq(card)
207            crtc = crtc_list[i]
208            mode = mode_list[i]
209
210            plane = plane_list[i]
211
212            req.add(plane, {'FB_ID': fb.id,
213                            'CRTC_ID': crtc.id,
214                            'SRC_X': screen_offset << 16,
215                            'SRC_Y': 0 << 16,
216                            'SRC_W': mode.hdisplay << 16,
217                            'SRC_H': mode.vdisplay << 16,
218                            'CRTC_X': 0,
219                            'CRTC_Y': 0,
220                            'CRTC_W': mode.hdisplay,
221                            'CRTC_H': mode.vdisplay,
222                            'zorder': 0})
223
224            screen_offset += mode.hdisplay
225
226            req.commit(0)
227
228    def handle_page_flip_main(self, frame, time):
229        self.flip_count += 1
230
231        if self.flip_count < len(conn_list):
232            return
233
234        self.flip_count = 0
235
236        # statistics
237        self.flips += 1
238        if self.time == 0:
239            self.frames = frame
240            self.time = time
241
242        time_delta = time - self.time
243        if time_delta >= 5:
244            frame_delta = frame - self.frames
245            print('Frame rate: %f (%u/%u frames in %f s)' %
246                  (frame_delta / time_delta, self.flips, frame_delta, time_delta))
247
248            self.flips = 0
249            self.frames = frame
250            self.time = time
251
252        if args.flipmode == 'single':
253            self.handle_page_flip_single()
254        elif args.flipmode == 'separate':
255            self.handle_page_flip_separate()
256
257print('Press ENTER to exit\n')
258
259box_db = bigFB_db(big_fb_list[0], big_fb_list[1])
260box_db.handle_page_flip_main(0, 0)
261
262def readdrm(fileobj, mask):
263    for ev in card.read_events():
264        if ev.type == pykms.DrmEventType.FLIP_COMPLETE:
265            box_db.handle_page_flip_main(ev.seq, ev.time)
266
267def readkey(fileobj, mask):
268    sys.stdin.readline()
269    exit(0)
270
271sel = selectors.DefaultSelector()
272sel.register(card.fd, selectors.EVENT_READ, readdrm)
273sel.register(sys.stdin, selectors.EVENT_READ, readkey)
274
275while True:
276    events = sel.select()
277    for key, mask in events:
278        callback = key.data
279        callback(key.fileobj, mask)
280