xref: /aosp_15_r20/external/mesa3d/src/vulkan/overlay-layer/mesa-overlay-control.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*61046927SAndroid Build Coastguard Workerimport socket
3*61046927SAndroid Build Coastguard Workerimport sys
4*61046927SAndroid Build Coastguard Workerimport select
5*61046927SAndroid Build Coastguard Workerfrom select import EPOLLIN, EPOLLPRI, EPOLLERR
6*61046927SAndroid Build Coastguard Workerimport time
7*61046927SAndroid Build Coastguard Workerimport argparse
8*61046927SAndroid Build Coastguard Worker
9*61046927SAndroid Build Coastguard WorkerTIMEOUT = 1.0 # seconds
10*61046927SAndroid Build Coastguard Worker
11*61046927SAndroid Build Coastguard WorkerVERSION_HEADER = bytearray('MesaOverlayControlVersion', 'utf-8')
12*61046927SAndroid Build Coastguard WorkerDEVICE_NAME_HEADER = bytearray('DeviceName', 'utf-8')
13*61046927SAndroid Build Coastguard WorkerMESA_VERSION_HEADER = bytearray('MesaVersion', 'utf-8')
14*61046927SAndroid Build Coastguard Worker
15*61046927SAndroid Build Coastguard WorkerDEFAULT_SERVER_ADDRESS = "\0mesa_overlay"
16*61046927SAndroid Build Coastguard Worker
17*61046927SAndroid Build Coastguard Workerclass Connection:
18*61046927SAndroid Build Coastguard Worker    def __init__(self, path):
19*61046927SAndroid Build Coastguard Worker        # Create a Unix Domain socket and connect
20*61046927SAndroid Build Coastguard Worker        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
21*61046927SAndroid Build Coastguard Worker        try:
22*61046927SAndroid Build Coastguard Worker            sock.connect(path)
23*61046927SAndroid Build Coastguard Worker        except socket.error as msg:
24*61046927SAndroid Build Coastguard Worker            print(msg)
25*61046927SAndroid Build Coastguard Worker            sys.exit(1)
26*61046927SAndroid Build Coastguard Worker
27*61046927SAndroid Build Coastguard Worker        self.sock = sock
28*61046927SAndroid Build Coastguard Worker
29*61046927SAndroid Build Coastguard Worker        # initialize poll interface and register socket
30*61046927SAndroid Build Coastguard Worker        epoll = select.epoll()
31*61046927SAndroid Build Coastguard Worker        epoll.register(sock, EPOLLIN | EPOLLPRI | EPOLLERR)
32*61046927SAndroid Build Coastguard Worker        self.epoll = epoll
33*61046927SAndroid Build Coastguard Worker
34*61046927SAndroid Build Coastguard Worker    def recv(self, timeout):
35*61046927SAndroid Build Coastguard Worker        '''
36*61046927SAndroid Build Coastguard Worker        timeout as float in seconds
37*61046927SAndroid Build Coastguard Worker        returns:
38*61046927SAndroid Build Coastguard Worker            - None on error or disconnection
39*61046927SAndroid Build Coastguard Worker            - bytes() (empty) on timeout
40*61046927SAndroid Build Coastguard Worker        '''
41*61046927SAndroid Build Coastguard Worker
42*61046927SAndroid Build Coastguard Worker        events = self.epoll.poll(timeout)
43*61046927SAndroid Build Coastguard Worker        for ev in events:
44*61046927SAndroid Build Coastguard Worker            (fd, event) = ev
45*61046927SAndroid Build Coastguard Worker            if fd != self.sock.fileno():
46*61046927SAndroid Build Coastguard Worker                continue
47*61046927SAndroid Build Coastguard Worker
48*61046927SAndroid Build Coastguard Worker            # check for socket error
49*61046927SAndroid Build Coastguard Worker            if event & EPOLLERR:
50*61046927SAndroid Build Coastguard Worker                return None
51*61046927SAndroid Build Coastguard Worker
52*61046927SAndroid Build Coastguard Worker            # EPOLLIN or EPOLLPRI, just read the message
53*61046927SAndroid Build Coastguard Worker            msg = self.sock.recv(4096)
54*61046927SAndroid Build Coastguard Worker
55*61046927SAndroid Build Coastguard Worker            # socket disconnected
56*61046927SAndroid Build Coastguard Worker            if len(msg) == 0:
57*61046927SAndroid Build Coastguard Worker                return None
58*61046927SAndroid Build Coastguard Worker
59*61046927SAndroid Build Coastguard Worker            return msg
60*61046927SAndroid Build Coastguard Worker
61*61046927SAndroid Build Coastguard Worker        return bytes()
62*61046927SAndroid Build Coastguard Worker
63*61046927SAndroid Build Coastguard Worker    def send(self, msg):
64*61046927SAndroid Build Coastguard Worker        self.sock.send(msg)
65*61046927SAndroid Build Coastguard Worker
66*61046927SAndroid Build Coastguard Workerclass MsgParser:
67*61046927SAndroid Build Coastguard Worker    MSGBEGIN = bytes(':', 'utf-8')[0]
68*61046927SAndroid Build Coastguard Worker    MSGEND = bytes(';', 'utf-8')[0]
69*61046927SAndroid Build Coastguard Worker    MSGSEP = bytes('=', 'utf-8')[0]
70*61046927SAndroid Build Coastguard Worker
71*61046927SAndroid Build Coastguard Worker    def __init__(self, conn):
72*61046927SAndroid Build Coastguard Worker        self.cmdpos = 0
73*61046927SAndroid Build Coastguard Worker        self.parampos = 0
74*61046927SAndroid Build Coastguard Worker        self.bufferpos = 0
75*61046927SAndroid Build Coastguard Worker        self.reading_cmd = False
76*61046927SAndroid Build Coastguard Worker        self.reading_param = False
77*61046927SAndroid Build Coastguard Worker        self.buffer = None
78*61046927SAndroid Build Coastguard Worker        self.cmd = bytearray(4096)
79*61046927SAndroid Build Coastguard Worker        self.param = bytearray(4096)
80*61046927SAndroid Build Coastguard Worker
81*61046927SAndroid Build Coastguard Worker        self.conn = conn
82*61046927SAndroid Build Coastguard Worker
83*61046927SAndroid Build Coastguard Worker    def readCmd(self, ncmds, timeout=TIMEOUT):
84*61046927SAndroid Build Coastguard Worker        '''
85*61046927SAndroid Build Coastguard Worker        returns:
86*61046927SAndroid Build Coastguard Worker            - None on error or disconnection
87*61046927SAndroid Build Coastguard Worker            - bytes() (empty) on timeout
88*61046927SAndroid Build Coastguard Worker        '''
89*61046927SAndroid Build Coastguard Worker
90*61046927SAndroid Build Coastguard Worker        parsed = []
91*61046927SAndroid Build Coastguard Worker
92*61046927SAndroid Build Coastguard Worker        remaining = timeout
93*61046927SAndroid Build Coastguard Worker
94*61046927SAndroid Build Coastguard Worker        while remaining > 0 and ncmds > 0:
95*61046927SAndroid Build Coastguard Worker            now = time.monotonic()
96*61046927SAndroid Build Coastguard Worker
97*61046927SAndroid Build Coastguard Worker            if self.buffer is None:
98*61046927SAndroid Build Coastguard Worker                self.buffer = self.conn.recv(remaining)
99*61046927SAndroid Build Coastguard Worker                self.bufferpos = 0
100*61046927SAndroid Build Coastguard Worker
101*61046927SAndroid Build Coastguard Worker            # disconnected or error
102*61046927SAndroid Build Coastguard Worker            if self.buffer is None:
103*61046927SAndroid Build Coastguard Worker                return None
104*61046927SAndroid Build Coastguard Worker
105*61046927SAndroid Build Coastguard Worker            for i in range(self.bufferpos, len(self.buffer)):
106*61046927SAndroid Build Coastguard Worker                c = self.buffer[i]
107*61046927SAndroid Build Coastguard Worker                self.bufferpos += 1
108*61046927SAndroid Build Coastguard Worker                if c == self.MSGBEGIN:
109*61046927SAndroid Build Coastguard Worker                    self.cmdpos = 0
110*61046927SAndroid Build Coastguard Worker                    self.parampos = 0
111*61046927SAndroid Build Coastguard Worker                    self.reading_cmd = True
112*61046927SAndroid Build Coastguard Worker                    self.reading_param = False
113*61046927SAndroid Build Coastguard Worker                elif c == self.MSGEND:
114*61046927SAndroid Build Coastguard Worker                    if not self.reading_cmd:
115*61046927SAndroid Build Coastguard Worker                        continue
116*61046927SAndroid Build Coastguard Worker                    self.reading_cmd = False
117*61046927SAndroid Build Coastguard Worker                    self.reading_param = False
118*61046927SAndroid Build Coastguard Worker
119*61046927SAndroid Build Coastguard Worker                    cmd = self.cmd[0:self.cmdpos]
120*61046927SAndroid Build Coastguard Worker                    param = self.param[0:self.parampos]
121*61046927SAndroid Build Coastguard Worker                    self.reading_cmd = False
122*61046927SAndroid Build Coastguard Worker                    self.reading_param = False
123*61046927SAndroid Build Coastguard Worker
124*61046927SAndroid Build Coastguard Worker                    parsed.append((cmd, param))
125*61046927SAndroid Build Coastguard Worker                    ncmds -= 1
126*61046927SAndroid Build Coastguard Worker                    if ncmds == 0:
127*61046927SAndroid Build Coastguard Worker                        break
128*61046927SAndroid Build Coastguard Worker                elif c == self.MSGSEP:
129*61046927SAndroid Build Coastguard Worker                    if self.reading_cmd:
130*61046927SAndroid Build Coastguard Worker                        self.reading_param = True
131*61046927SAndroid Build Coastguard Worker                else:
132*61046927SAndroid Build Coastguard Worker                    if self.reading_param:
133*61046927SAndroid Build Coastguard Worker                        self.param[self.parampos] = c
134*61046927SAndroid Build Coastguard Worker                        self.parampos += 1
135*61046927SAndroid Build Coastguard Worker                    elif self.reading_cmd:
136*61046927SAndroid Build Coastguard Worker                        self.cmd[self.cmdpos] = c
137*61046927SAndroid Build Coastguard Worker                        self.cmdpos += 1
138*61046927SAndroid Build Coastguard Worker
139*61046927SAndroid Build Coastguard Worker            # if we read the entire buffer and didn't finish the command,
140*61046927SAndroid Build Coastguard Worker            # throw it away
141*61046927SAndroid Build Coastguard Worker            self.buffer = None
142*61046927SAndroid Build Coastguard Worker
143*61046927SAndroid Build Coastguard Worker            # check if we have time for another iteration
144*61046927SAndroid Build Coastguard Worker            elapsed = time.monotonic() - now
145*61046927SAndroid Build Coastguard Worker            remaining = max(0, remaining - elapsed)
146*61046927SAndroid Build Coastguard Worker
147*61046927SAndroid Build Coastguard Worker        # timeout
148*61046927SAndroid Build Coastguard Worker        return parsed
149*61046927SAndroid Build Coastguard Worker
150*61046927SAndroid Build Coastguard Workerdef control(args):
151*61046927SAndroid Build Coastguard Worker    if args.socket:
152*61046927SAndroid Build Coastguard Worker        address = '\0' + args.socket
153*61046927SAndroid Build Coastguard Worker    else:
154*61046927SAndroid Build Coastguard Worker        address = DEFAULT_SERVER_ADDRESS
155*61046927SAndroid Build Coastguard Worker
156*61046927SAndroid Build Coastguard Worker    conn = Connection(address)
157*61046927SAndroid Build Coastguard Worker    msgparser = MsgParser(conn)
158*61046927SAndroid Build Coastguard Worker
159*61046927SAndroid Build Coastguard Worker    version = None
160*61046927SAndroid Build Coastguard Worker    name = None
161*61046927SAndroid Build Coastguard Worker    mesa_version = None
162*61046927SAndroid Build Coastguard Worker
163*61046927SAndroid Build Coastguard Worker    msgs = msgparser.readCmd(3)
164*61046927SAndroid Build Coastguard Worker
165*61046927SAndroid Build Coastguard Worker    for m in msgs:
166*61046927SAndroid Build Coastguard Worker        cmd, param = m
167*61046927SAndroid Build Coastguard Worker        if cmd == VERSION_HEADER:
168*61046927SAndroid Build Coastguard Worker            version = int(param)
169*61046927SAndroid Build Coastguard Worker        elif cmd == DEVICE_NAME_HEADER:
170*61046927SAndroid Build Coastguard Worker            name = param.decode('utf-8')
171*61046927SAndroid Build Coastguard Worker        elif cmd == MESA_VERSION_HEADER:
172*61046927SAndroid Build Coastguard Worker            mesa_version = param.decode('utf-8')
173*61046927SAndroid Build Coastguard Worker
174*61046927SAndroid Build Coastguard Worker    if version != 1 or name is None or mesa_version is None:
175*61046927SAndroid Build Coastguard Worker        print('ERROR: invalid protocol')
176*61046927SAndroid Build Coastguard Worker        sys.exit(1)
177*61046927SAndroid Build Coastguard Worker
178*61046927SAndroid Build Coastguard Worker    if args.info:
179*61046927SAndroid Build Coastguard Worker        print(f"Protocol Version: {version}")
180*61046927SAndroid Build Coastguard Worker        print(f"Device Name: {name}")
181*61046927SAndroid Build Coastguard Worker        print(f"Mesa Version: {mesa_version}")
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker    if args.cmd == 'start-capture':
184*61046927SAndroid Build Coastguard Worker        conn.send(bytearray(':capture=1;', 'utf-8'))
185*61046927SAndroid Build Coastguard Worker    elif args.cmd == 'stop-capture':
186*61046927SAndroid Build Coastguard Worker        conn.send(bytearray(':capture=0;', 'utf-8'))
187*61046927SAndroid Build Coastguard Worker
188*61046927SAndroid Build Coastguard Workerif __name__ == '__main__':
189*61046927SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(description='MESA_overlay control client')
190*61046927SAndroid Build Coastguard Worker    parser.add_argument('--info', action='store_true', help='Print info from socket')
191*61046927SAndroid Build Coastguard Worker    parser.add_argument('--socket', '-s', type=str, help='Path to socket')
192*61046927SAndroid Build Coastguard Worker
193*61046927SAndroid Build Coastguard Worker    commands = parser.add_subparsers(help='commands to run', dest='cmd')
194*61046927SAndroid Build Coastguard Worker    commands.add_parser('start-capture')
195*61046927SAndroid Build Coastguard Worker    commands.add_parser('stop-capture')
196*61046927SAndroid Build Coastguard Worker
197*61046927SAndroid Build Coastguard Worker    args = parser.parse_args()
198*61046927SAndroid Build Coastguard Worker
199*61046927SAndroid Build Coastguard Worker    control(args)
200