1 /*
2 Copyright (c) 2012, Broadcom Europe Ltd
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above copyright
10       notice, this list of conditions and the following disclaimer in the
11       documentation and/or other materials provided with the distribution.
12     * Neither the name of the copyright holder nor the
13       names of its contributors may be used to endorse or promote products
14       derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #define VCOS_LOG_CATEGORY (&khrn_client_log)
28 
29 #include "vchiq.h"
30 #include "interface/khronos/common/khrn_int_common.h"
31 #include "interface/khronos/common/khrn_int_ids.h"
32 
33 #include "interface/khronos/common/khrn_client.h"
34 #include "interface/khronos/common/khrn_client_rpc.h"
35 
36 #include <string.h>
37 #include <stdio.h>
38 
39 extern VCOS_LOG_CAT_T khrn_client_log;
40 
41 static void *workspace; /* for scatter/gather bulks */
42 static PLATFORM_MUTEX_T mutex;
43 
44 #define FOURCC_KHAN VCHIQ_MAKE_FOURCC('K', 'H', 'A', 'N')
45 #define FOURCC_KHRN VCHIQ_MAKE_FOURCC('K', 'H', 'R', 'N')
46 #define FOURCC_KHHN VCHIQ_MAKE_FOURCC('K', 'H', 'H', 'N')
47 
48 static VCHIQ_INSTANCE_T khrn_vchiq_instance;
49 
50 static VCHIQ_SERVICE_HANDLE_T vchiq_khan_service;
51 static VCHIQ_SERVICE_HANDLE_T vchiq_khrn_service;
52 static VCHIQ_SERVICE_HANDLE_T vchiq_khhn_service;
53 
54 static VCHIU_QUEUE_T khrn_queue;
55 static VCHIU_QUEUE_T khhn_queue;
56 
57 static VCOS_EVENT_T bulk_event;
58 
khrn_callback(VCHIQ_REASON_T reason,VCHIQ_HEADER_T * header,VCHIQ_SERVICE_HANDLE_T handle,void * bulk_userdata)59 VCHIQ_STATUS_T khrn_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
60                   VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
61 {
62    switch (reason) {
63    case VCHIQ_MESSAGE_AVAILABLE:
64       vchiu_queue_push(&khrn_queue, header);
65       break;
66    case VCHIQ_BULK_TRANSMIT_DONE:
67    case VCHIQ_BULK_RECEIVE_DONE:
68       vcos_event_signal(&bulk_event);
69       break;
70    case VCHIQ_SERVICE_OPENED:
71    case VCHIQ_SERVICE_CLOSED:
72    case VCHIQ_BULK_TRANSMIT_ABORTED:
73    case VCHIQ_BULK_RECEIVE_ABORTED:
74       UNREACHABLE(); /* not implemented */
75    }
76 
77    return VCHIQ_SUCCESS;
78 }
79 
khhn_callback(VCHIQ_REASON_T reason,VCHIQ_HEADER_T * header,VCHIQ_SERVICE_HANDLE_T handle,void * bulk_userdata)80 VCHIQ_STATUS_T khhn_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
81                   VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
82 {
83    switch (reason) {
84    case VCHIQ_MESSAGE_AVAILABLE:
85       vchiu_queue_push(&khhn_queue, header);
86       break;
87    case VCHIQ_BULK_TRANSMIT_DONE:
88    case VCHIQ_BULK_RECEIVE_DONE:
89       vcos_event_signal(&bulk_event);
90       break;
91    case VCHIQ_SERVICE_OPENED:
92    case VCHIQ_SERVICE_CLOSED:
93    case VCHIQ_BULK_TRANSMIT_ABORTED:
94    case VCHIQ_BULK_RECEIVE_ABORTED:
95       UNREACHABLE(); /* not implemented */
96    }
97 
98    return VCHIQ_SUCCESS;
99 }
100 
khan_callback(VCHIQ_REASON_T reason,VCHIQ_HEADER_T * header,VCHIQ_SERVICE_HANDLE_T handle,void * bulk_userdata)101 VCHIQ_STATUS_T khan_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
102                   VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
103 {
104    switch (reason) {
105    case VCHIQ_MESSAGE_AVAILABLE:
106    {
107       int32_t *data = (int32_t *) header->data;
108       int32_t command = data[0];
109       int32_t *msg = &data[1];
110       vcos_assert(header->size == 16);
111 
112       // TODO should be able to remove this eventually.
113       // If incoming message is not addressed to this process, then ignore it.
114       // Correct process should then pick it up.
115       uint64_t pid = vchiq_get_client_id(handle);
116       if((msg[0] != (uint32_t) pid) || (msg[1] != (uint32_t) (pid >> 32)))
117       {
118          printf("khan_callback: message for wrong process; pid = %X, msg pid = %X\n",
119             (uint32_t) pid, msg[0]);
120          return VCHIQ_SUCCESS;
121       } // if
122 
123       if (command == ASYNC_COMMAND_DESTROY)
124       {
125          /* todo: destroy */
126       }
127       else
128       {
129          PLATFORM_SEMAPHORE_T sem;
130          if (khronos_platform_semaphore_create(&sem, msg, 1) == KHR_SUCCESS)
131          {
132             switch (command) {
133             case ASYNC_COMMAND_WAIT:
134                khronos_platform_semaphore_acquire(&sem);
135                break;
136             case ASYNC_COMMAND_POST:
137                khronos_platform_semaphore_release(&sem);
138                break;
139             default:
140                vcos_assert_msg(0, "khan_callback: unknown message type");
141                break;
142             }
143             khronos_platform_semaphore_destroy(&sem);
144          }
145       } // else
146       vchiq_release_message(handle, header);
147       break;
148    }
149    case VCHIQ_BULK_TRANSMIT_DONE:
150    case VCHIQ_BULK_RECEIVE_DONE:
151       UNREACHABLE();
152       break;
153    case VCHIQ_SERVICE_OPENED:
154       vcos_assert_msg(0, "khan_callback: VCHIQ_SERVICE_OPENED");
155       break;
156    case VCHIQ_SERVICE_CLOSED:
157       vcos_assert_msg(0, "khan_callback: VCHIQ_SERVICE_CLOSED");
158       break;
159    case VCHIQ_BULK_TRANSMIT_ABORTED:
160    case VCHIQ_BULK_RECEIVE_ABORTED:
161    default:
162       UNREACHABLE(); /* not implemented */
163    }
164 
165    return VCHIQ_SUCCESS;
166 }
167 
vc_vchi_khronos_init()168 void vc_vchi_khronos_init()
169 {
170    VCOS_STATUS_T status = vcos_event_create(&bulk_event, NULL);
171    UNUSED_NDEBUG(status);
172    vcos_assert(status == VCOS_SUCCESS);
173 
174    if (vchiq_initialise(&khrn_vchiq_instance) != VCHIQ_SUCCESS)
175    {
176       vcos_log_error("* failed to open vchiq device");
177 
178       exit(1);
179    }
180 
181    vcos_log_trace("gldemo: connecting");
182 
183    if (vchiq_connect(khrn_vchiq_instance) != VCHIQ_SUCCESS)
184    {
185       vcos_log_error("* failed to connect");
186 
187       exit(1);
188    }
189 
190    VCHIQ_STATUS_T khan_return, khrn_return, khhn_return;
191    VCHIQ_SERVICE_PARAMS_T params;
192 
193    params.userdata = NULL;
194    params.version = VC_KHRN_VERSION;
195    params.version_min = VC_KHRN_VERSION;
196 
197    params.fourcc = FOURCC_KHAN;
198    params.callback = khan_callback;
199    khan_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khan_service);
200 
201    params.fourcc = FOURCC_KHRN;
202    params.callback = khrn_callback;
203    khrn_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khrn_service);
204 
205    params.fourcc = FOURCC_KHHN;
206    params.callback = khhn_callback;
207    khhn_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khhn_service);
208 
209    if (khan_return != VCHIQ_SUCCESS ||
210        khrn_return != VCHIQ_SUCCESS ||
211        khhn_return != VCHIQ_SUCCESS)
212    {
213       vcos_log_error("* failed to add service - already in use?");
214 
215       exit(1);
216    }
217    vchiu_queue_init(&khrn_queue, 64);
218    vchiu_queue_init(&khhn_queue, 64);
219 
220    vcos_log_trace("gldemo: connected");
221 
222    /*
223       attach to process (there's just one)
224    */
225 
226 //   bool success = client_process_attach();
227 //   vcos_assert(success);
228 }
229 
khclient_rpc_init(void)230 bool khclient_rpc_init(void)
231 {
232    workspace = NULL;
233    return platform_mutex_create(&mutex) == KHR_SUCCESS;
234 }
235 
rpc_term(void)236 void rpc_term(void)
237 {
238    if (workspace) { khrn_platform_free(workspace); }
239    platform_mutex_destroy(&mutex);
240 }
241 
get_handle(CLIENT_THREAD_STATE_T * thread)242 static VCHIQ_SERVICE_HANDLE_T get_handle(CLIENT_THREAD_STATE_T *thread)
243 {
244    VCHIQ_SERVICE_HANDLE_T result = (thread->high_priority ? vchiq_khhn_service : vchiq_khrn_service);
245    	return result;
246 }
247 
get_queue(CLIENT_THREAD_STATE_T * thread)248 static VCHIU_QUEUE_T *get_queue(CLIENT_THREAD_STATE_T *thread)
249 {
250    return thread->high_priority ? &khhn_queue : &khrn_queue;
251 }
252 
check_workspace(uint32_t size)253 static void check_workspace(uint32_t size)
254 {
255    /* todo: find a better way to handle scatter/gather bulks */
256    vcos_assert(size <= KHDISPATCH_WORKSPACE_SIZE);
257    if (!workspace) {
258       workspace = khrn_platform_malloc(KHDISPATCH_WORKSPACE_SIZE, "rpc_workspace");
259       vcos_assert(workspace);
260    }
261 }
262 
merge_flush(CLIENT_THREAD_STATE_T * thread)263 static void merge_flush(CLIENT_THREAD_STATE_T *thread)
264 {
265    vcos_log_trace("merge_flush start");
266 
267    vcos_assert(thread->merge_pos >= CLIENT_MAKE_CURRENT_SIZE);
268 
269    /*
270       don't transmit just a make current -- in the case that there is only a
271       make current in the merge buffer, we have already sent a control message
272       for the rpc call (and with it a make current) and own the big lock
273    */
274 
275    if (thread->merge_pos > CLIENT_MAKE_CURRENT_SIZE) {
276       VCHIQ_ELEMENT_T element;
277 
278       rpc_begin(thread);
279 
280       element.data = thread->merge_buffer;
281       element.size = thread->merge_pos;
282 
283       VCHIQ_STATUS_T success = vchiq_queue_message(get_handle(thread), &element, 1);
284       UNUSED_NDEBUG(success);
285       vcos_assert(success == VCHIQ_SUCCESS);
286 
287       thread->merge_pos = 0;
288 
289       client_send_make_current(thread);
290 
291       vcos_assert(thread->merge_pos == CLIENT_MAKE_CURRENT_SIZE);
292 
293       rpc_end(thread);
294    }
295    vcos_log_trace( "merge_flush end");
296 
297 }
298 
rpc_flush(CLIENT_THREAD_STATE_T * thread)299 void rpc_flush(CLIENT_THREAD_STATE_T *thread)
300 {
301    merge_flush(thread);
302 }
303 
rpc_high_priority_begin(CLIENT_THREAD_STATE_T * thread)304 void rpc_high_priority_begin(CLIENT_THREAD_STATE_T *thread)
305 {
306    vcos_assert(!thread->high_priority);
307    merge_flush(thread);
308    thread->high_priority = true;
309 }
310 
rpc_high_priority_end(CLIENT_THREAD_STATE_T * thread)311 void rpc_high_priority_end(CLIENT_THREAD_STATE_T *thread)
312 {
313    vcos_assert(thread->high_priority);
314    merge_flush(thread);
315    thread->high_priority = false;
316 }
317 
rpc_send_ctrl_longest(CLIENT_THREAD_STATE_T * thread,uint32_t len_min)318 uint32_t rpc_send_ctrl_longest(CLIENT_THREAD_STATE_T *thread, uint32_t len_min)
319 {
320    uint32_t len = MERGE_BUFFER_SIZE - thread->merge_pos;
321    if (len < len_min) {
322       len = MERGE_BUFFER_SIZE - CLIENT_MAKE_CURRENT_SIZE;
323    }
324    return len;
325 }
326 
rpc_send_ctrl_begin(CLIENT_THREAD_STATE_T * thread,uint32_t len)327 void rpc_send_ctrl_begin(CLIENT_THREAD_STATE_T *thread, uint32_t len)
328 {
329    //CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
330 
331    vcos_assert(len == rpc_pad_ctrl(len));
332    if ((thread->merge_pos + len) > MERGE_BUFFER_SIZE) {
333       merge_flush(thread);
334    }
335 
336    thread->merge_end = thread->merge_pos + len;
337 }
338 
rpc_send_ctrl_write(CLIENT_THREAD_STATE_T * thread,const uint32_t in[],uint32_t len)339 void rpc_send_ctrl_write(CLIENT_THREAD_STATE_T *thread, const uint32_t in[], uint32_t len) /* len bytes read, rpc_pad_ctrl(len) bytes written */
340 {
341    //CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
342 
343    memcpy(thread->merge_buffer + thread->merge_pos, in, len);
344    thread->merge_pos += rpc_pad_ctrl(len);
345    vcos_assert(thread->merge_pos <= MERGE_BUFFER_SIZE);
346 }
347 
rpc_send_ctrl_end(CLIENT_THREAD_STATE_T * thread)348 void rpc_send_ctrl_end(CLIENT_THREAD_STATE_T *thread)
349 {
350    //CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
351 
352    vcos_assert(thread->merge_pos == thread->merge_end);
353 }
354 
send_bulk(CLIENT_THREAD_STATE_T * thread,const void * in,uint32_t len)355 static void send_bulk(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len)
356 {
357    if (len <= KHDISPATCH_CTRL_THRESHOLD) {
358       VCHIQ_ELEMENT_T element;
359 
360       element.data = in;
361       element.size = len;
362 
363       VCHIQ_STATUS_T vchiq_status = vchiq_queue_message(get_handle(thread), &element, 1);
364       UNUSED_NDEBUG(vchiq_status);
365       vcos_assert(vchiq_status == VCHIQ_SUCCESS);
366    } else {
367       VCHIQ_STATUS_T vchiq_status = vchiq_queue_bulk_transmit(get_handle(thread), in, rpc_pad_bulk(len), NULL);
368       UNUSED_NDEBUG(vchiq_status);
369       vcos_assert(vchiq_status == VCHIQ_SUCCESS);
370       VCOS_STATUS_T vcos_status = vcos_event_wait(&bulk_event);
371       UNUSED_NDEBUG(vcos_status);
372       vcos_assert(vcos_status == VCOS_SUCCESS);
373    }
374 }
375 
recv_bulk(CLIENT_THREAD_STATE_T * thread,void * out,uint32_t len)376 static void recv_bulk(CLIENT_THREAD_STATE_T *thread, void *out, uint32_t len)
377 {
378    if (len <= KHDISPATCH_CTRL_THRESHOLD) {
379       VCHIQ_HEADER_T *header = vchiu_queue_pop(get_queue(thread));
380       vcos_assert(header->size == len);
381       memcpy(out, header->data, len);
382       vchiq_release_message(get_handle(thread), header);
383    } else {
384       VCHIQ_STATUS_T vchiq_status = vchiq_queue_bulk_receive(get_handle(thread), out, rpc_pad_bulk(len), NULL);
385       UNUSED_NDEBUG(vchiq_status);
386       vcos_assert(vchiq_status == VCHIQ_SUCCESS);
387       VCOS_STATUS_T vcos_status = vcos_event_wait(&bulk_event);
388       UNUSED_NDEBUG(vcos_status);
389       vcos_assert(vcos_status == VCOS_SUCCESS);
390    }
391 }
392 
rpc_send_bulk(CLIENT_THREAD_STATE_T * thread,const void * in,uint32_t len)393 void rpc_send_bulk(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len)
394 {
395    if (in && len) {
396       //CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
397 
398       merge_flush(thread);
399 
400       send_bulk(thread, in, len);
401    }
402 }
403 
rpc_send_bulk_gather(CLIENT_THREAD_STATE_T * thread,const void * in,uint32_t len,int32_t stride,uint32_t n)404 void rpc_send_bulk_gather(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len, int32_t stride, uint32_t n)
405 {
406 #if 1
407    if (in && len) {
408       //CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
409 
410       merge_flush(thread);
411 
412       if (len == stride) {
413          /* hopefully should be the common case */
414          send_bulk(thread, in, n * len);
415       } else {
416          check_workspace(n * len);
417          rpc_gather(workspace, in, len, stride, n);
418          send_bulk(thread, workspace, n * len);
419       }
420    }
421 #else
422    UNREACHABLE();
423 #endif
424 }
425 
rpc_recv(CLIENT_THREAD_STATE_T * thread,void * out,uint32_t * len_io,RPC_RECV_FLAG_T flags)426 uint32_t rpc_recv(CLIENT_THREAD_STATE_T *thread, void *out, uint32_t *len_io, RPC_RECV_FLAG_T flags)
427 {
428    uint32_t res = 0;
429    uint32_t len;
430    bool recv_ctrl;
431 
432    if (!len_io) { len_io = &len; }
433 
434    recv_ctrl = flags & (RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN); /* do we want to receive anything in the control channel at all? */
435    vcos_assert(recv_ctrl || (flags & RPC_RECV_FLAG_BULK)); /* must receive something... */
436    vcos_assert(!(flags & RPC_RECV_FLAG_CTRL) || !(flags & RPC_RECV_FLAG_BULK)); /* can't receive user data over both bulk and control... */
437 
438    if (recv_ctrl || len_io[0]) { /* do nothing if we're just receiving bulk of length 0 */
439       merge_flush(thread);
440 
441       if (recv_ctrl) {
442          VCHIQ_HEADER_T *header = vchiu_queue_pop(get_queue(thread));
443          uint8_t *ctrl = (uint8_t *)header->data;
444          vcos_assert(header->size >= (!!(flags & RPC_RECV_FLAG_LEN)*4 + !!(flags & RPC_RECV_FLAG_RES)*4) );
445          if (flags & RPC_RECV_FLAG_LEN) {
446             len_io[0] = *((uint32_t *)ctrl);
447             ctrl += 4;
448          }
449          if (flags & RPC_RECV_FLAG_RES) {
450             res = *((uint32_t *)ctrl);
451             ctrl += 4;
452          }
453          if (flags & RPC_RECV_FLAG_CTRL) {
454             memcpy(out, ctrl, len_io[0]);
455             ctrl += len_io[0];
456          }
457          vcos_assert(ctrl == ((uint8_t *)header->data + header->size));
458          vchiq_release_message(get_handle(thread), header);
459       }
460 
461       if ((flags & RPC_RECV_FLAG_BULK) && len_io[0]) {
462          if (flags & RPC_RECV_FLAG_BULK_SCATTER) {
463             if ((len_io[0] == len_io[1]) && !len_io[3] && !len_io[4]) {
464                /* hopefully should be the common case */
465                recv_bulk(thread, out, len_io[2] * len_io[0]);
466             } else {
467                check_workspace(len_io[2] * len_io[0]);
468                recv_bulk(thread, workspace, len_io[2] * len_io[0]);
469                rpc_scatter(out, len_io[0], len_io[1], len_io[2], len_io[3], len_io[4], workspace);
470             }
471          } else {
472             recv_bulk(thread, out, len_io[0]);
473          }
474       }
475    }
476 
477    return res;
478 }
479 
rpc_begin(CLIENT_THREAD_STATE_T * thread)480 void rpc_begin(CLIENT_THREAD_STATE_T *thread)
481 {
482    UNUSED(thread);
483    platform_mutex_acquire(&mutex);
484 }
485 
rpc_end(CLIENT_THREAD_STATE_T * thread)486 void rpc_end(CLIENT_THREAD_STATE_T *thread)
487 {
488    UNUSED(thread);
489    platform_mutex_release(&mutex);
490 }
491 
rpc_use(CLIENT_THREAD_STATE_T * thread)492 void rpc_use(CLIENT_THREAD_STATE_T *thread)
493 { // TODO - implement this for linux
494    UNUSED(thread);
495 }
496 
rpc_release(CLIENT_THREAD_STATE_T * thread)497 void rpc_release(CLIENT_THREAD_STATE_T *thread)
498 { // TODO - implement this for linux
499    UNUSED(thread);
500 }
501 
rpc_call8_makecurrent(CLIENT_THREAD_STATE_T * thread,uint32_t id,uint32_t p0,uint32_t p1,uint32_t p2,uint32_t p3,uint32_t p4,uint32_t p5,uint32_t p6,uint32_t p7)502 void rpc_call8_makecurrent(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0,
503    uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7)
504 {
505    uint32_t data;
506    if (thread->merge_pos == CLIENT_MAKE_CURRENT_SIZE && (memcpy(&data,thread->merge_buffer,sizeof(data)), data == EGLINTMAKECURRENT_ID))
507    {
508       rpc_begin(thread);
509       vcos_log_trace("rpc_call8_makecurrent collapse onto previous makecurrent");
510 
511       thread->merge_pos = 0;
512 
513       RPC_CALL8(eglIntMakeCurrent_impl, thread, EGLINTMAKECURRENT_ID, p0, p1, p2, p3, p4, p5, p6, p7);
514       vcos_assert(thread->merge_pos == CLIENT_MAKE_CURRENT_SIZE);
515 
516       rpc_end(thread);
517    }
518    else
519    {
520       RPC_CALL8(eglIntMakeCurrent_impl, thread, EGLINTMAKECURRENT_ID, p0, p1, p2, p3, p4, p5, p6, p7);
521    }
522 }
523 
rpc_get_client_id(CLIENT_THREAD_STATE_T * thread)524 uint64_t rpc_get_client_id(CLIENT_THREAD_STATE_T *thread)
525 {
526    return vchiq_get_client_id(get_handle(thread));
527 }
528