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