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 | #include "interface/khronos/common/khrn_int_common.h" |
29 | |
30 | #include "interface/khronos/common/khrn_client_check_types.h" |
31 | #include "interface/khronos/common/khrn_client.h" |
32 | #include "interface/khronos/common/khrn_client_rpc.h" |
33 | #include "interface/khronos/egl/egl_client_config.h" |
34 | #include "interface/khronos/glxx/glxx_client.h" |
35 | |
36 | #if defined(V3D_LEAN) |
37 | #include "interface/khronos/common/khrn_int_misc_impl.h" |
38 | #endif |
39 | |
40 | #if EGL_KHR_sync |
41 | #include "interface/khronos/ext/egl_khr_sync_client.h" |
42 | #endif |
43 | |
44 | #if EGL_BRCM_perf_monitor |
45 | #include "interface/khronos/ext/egl_brcm_perf_monitor_client.h" |
46 | #endif |
47 | |
48 | #if EGL_BRCM_driver_monitor |
49 | #include "interface/khronos/ext/egl_brcm_driver_monitor_client.h" |
50 | #endif |
51 | |
52 | #ifdef RPC_LIBRARY |
53 | #include "middleware/dlloader/dlfcn.h" |
54 | #include "applications/vmcs/khronos/khronos_server.h" |
55 | #endif |
56 | |
57 | VCOS_LOG_CAT_T khrn_client_log = VCOS_LOG_INIT("khrn_client" , VCOS_LOG_WARN); |
58 | |
59 | /* |
60 | void client_try_unload_server(CLIENT_PROCESS_STATE_T *process) |
61 | |
62 | Preconditions: |
63 | |
64 | - |
65 | |
66 | Postconditions: |
67 | |
68 | - |
69 | |
70 | Invariants preserved: |
71 | |
72 | - |
73 | |
74 | Invariants used: |
75 | |
76 | - |
77 | */ |
78 | |
79 | void client_try_unload_server(CLIENT_PROCESS_STATE_T *process) |
80 | { |
81 | if (/* some context is current */ |
82 | (process->context_current_count != 0) || |
83 | /* egl is initialised */ |
84 | process->inited) { |
85 | return; |
86 | } |
87 | |
88 | /* |
89 | Prompt the server to unload Khronos VLL if it can, |
90 | and wait until it is done |
91 | */ |
92 | #ifdef RPC_LIBRARY //TODO: not thread safe |
93 | if (process->connected) { |
94 | const KHRONOS_FUNC_TABLE_T *func_table; |
95 | func_table = khronos_server_lock_func_table(client_library_get_connection()); |
96 | if (func_table != NULL) |
97 | { |
98 | func_table->khrn_misc_try_unload_impl(); |
99 | khronos_server_disconnect(); |
100 | } |
101 | khronos_server_unlock_func_table(); |
102 | |
103 | process->connected = false; |
104 | } |
105 | #else |
106 | { |
107 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
108 | RPC_INT_RES(RPC_CALL0_RES(khrn_misc_try_unload_impl, thread, KHRNMISCTRYUNLOAD_ID)); // return unimportant - read is just to cause blocking |
109 | } |
110 | #endif |
111 | } |
112 | |
113 | /* |
114 | void client_process_state_init(CLIENT_PROCESS_STATE_T *state) |
115 | |
116 | Implementation notes: |
117 | |
118 | Does nothing if already initialised. |
119 | |
120 | Preconditions: |
121 | |
122 | process is a valid pointer |
123 | Thread owns EGL lock |
124 | client_process_state_term must be called at some point after calling this function if we return true. |
125 | |
126 | Postconditions: |
127 | |
128 | Either: |
129 | - an error occurred and false is returned, or |
130 | - process->inited is true |
131 | |
132 | Invariants preserved: |
133 | |
134 | All invariants on CLIENT_PROCESS_STATE_T |
135 | (CLIENT_PROCESS_STATE_INITED_SANITY) |
136 | |
137 | Invariants used: |
138 | |
139 | - |
140 | */ |
141 | |
142 | bool client_process_state_init(CLIENT_PROCESS_STATE_T *process) |
143 | { |
144 | if (!process->inited) { |
145 | if (!khrn_pointer_map_init(&process->contexts, 64)) |
146 | return false; |
147 | |
148 | if (!khrn_pointer_map_init(&process->surfaces, 64)) |
149 | { |
150 | khrn_pointer_map_term(&process->contexts); |
151 | return false; |
152 | } |
153 | if (!khrn_pointer_map_init(&process->windows, 64)) |
154 | { |
155 | khrn_pointer_map_term(&process->contexts); |
156 | khrn_pointer_map_term(&process->surfaces); |
157 | return false; |
158 | } |
159 | |
160 | #if EGL_KHR_sync |
161 | if (!khrn_pointer_map_init(&process->syncs, 64)) |
162 | { |
163 | khrn_pointer_map_term(&process->contexts); |
164 | khrn_pointer_map_term(&process->surfaces); |
165 | khrn_pointer_map_term(&process->windows); |
166 | return false; |
167 | } |
168 | #endif |
169 | #if EGL_BRCM_global_image && EGL_KHR_image |
170 | khrn_global_image_map_init(&process->global_image_egl_images, 8); |
171 | #endif |
172 | process->next_surface = 1; |
173 | process->next_context = 1; |
174 | #if EGL_KHR_sync |
175 | process->next_sync = 0x80000001; |
176 | #endif |
177 | #if EGL_BRCM_global_image && EGL_KHR_image |
178 | process->next_global_image_egl_image = 1 << 31; |
179 | #endif |
180 | |
181 | #if EGL_BRCM_perf_monitor |
182 | process->perf_monitor_inited = false; |
183 | #endif |
184 | |
185 | #ifdef RPC_LIBRARY |
186 | if (!process->connected) { |
187 | process->khrn_connection.make_current_func = client_library_send_make_current; |
188 | khronos_server_lock_func_table(&process->khrn_connection); |
189 | khronos_server_connect(&process->khrn_connection); |
190 | khronos_server_unlock_func_table(); |
191 | RPC_CALL0(khrn_misc_startup_impl, NULL, no_id); |
192 | |
193 | process->connected = true; |
194 | } |
195 | #endif |
196 | |
197 | process->inited = true; |
198 | } |
199 | |
200 | #ifndef ABSTRACT_PLATFORM |
201 | #if defined(ANDROID) && !defined (ANDROID_HWCOMPOSER) |
202 | egl_config_install_configs(1); // T-format configs |
203 | #else |
204 | egl_config_install_configs(0); // RSO configs |
205 | #endif |
206 | #endif |
207 | |
208 | return true; |
209 | } |
210 | |
211 | #include "interface/khronos/common/khrn_client_cr.c" |
212 | |
213 | /* |
214 | void client_process_state_term(CLIENT_PROCESS_STATE_T *process) |
215 | |
216 | Implementation notes: |
217 | |
218 | Does nothing if already terminated. |
219 | |
220 | Preconditions: |
221 | |
222 | process is a valid pointer |
223 | Thread owns EGL lock |
224 | |
225 | Postconditions: |
226 | |
227 | process->inited is false. |
228 | |
229 | Invariants preserved: |
230 | |
231 | (EGL_CONTEXT_IS_DESTROYED) |
232 | (CLIENT_PROCESS_STATE_INITED_SANITY) |
233 | |
234 | Invariants used: |
235 | |
236 | - |
237 | */ |
238 | |
239 | void client_process_state_term(CLIENT_PROCESS_STATE_T *process) |
240 | { |
241 | if (process->inited) { |
242 | khrn_pointer_map_iterate(&process->contexts, callback_destroy_context, NULL); |
243 | khrn_pointer_map_term(&process->contexts); |
244 | |
245 | khrn_pointer_map_iterate(&process->surfaces, callback_destroy_surface, NULL); |
246 | khrn_pointer_map_term(&process->surfaces); |
247 | |
248 | khrn_pointer_map_term(&process->windows); |
249 | |
250 | #if EGL_KHR_sync |
251 | egl_sync_destroy_all(&process->syncs); |
252 | khrn_pointer_map_term(&process->syncs); |
253 | #endif |
254 | |
255 | #if EGL_BRCM_global_image && EGL_KHR_image |
256 | khrn_global_image_map_term(&process->global_image_egl_images); |
257 | #endif |
258 | |
259 | #if EGL_BRCM_perf_monitor |
260 | egl_perf_monitor_term(process); |
261 | #endif |
262 | |
263 | #if EGL_BRCM_driver_monitor |
264 | egl_driver_monitor_term(process); |
265 | #endif |
266 | |
267 | process->inited = false; |
268 | } |
269 | } |
270 | |
271 | CLIENT_PROCESS_STATE_T client_process_state = { |
272 | #ifdef RPC_LIBRARY |
273 | false, /* not connected */ |
274 | #endif |
275 | 0, /* nothing current */ |
276 | false}; /* not inited */ |
277 | |
278 | void client_thread_state_init(CLIENT_THREAD_STATE_T *state) |
279 | { |
280 | state->error = EGL_SUCCESS; |
281 | |
282 | state->bound_api = EGL_OPENGL_ES_API; |
283 | |
284 | state->opengl.context = 0; |
285 | state->opengl.draw = 0; |
286 | state->opengl.read = 0; |
287 | |
288 | state->openvg.context = 0; |
289 | state->openvg.draw = 0; |
290 | state->openvg.read = 0; |
291 | |
292 | state->high_priority = false; |
293 | |
294 | state->merge_pos = 0; |
295 | state->merge_end = 0; |
296 | |
297 | state->glgeterror_hack = 0; |
298 | state->async_error_notification = false; |
299 | } |
300 | |
301 | void client_thread_state_term(CLIENT_THREAD_STATE_T *state) |
302 | { |
303 | // TODO: termination |
304 | platform_term_rpc( state ); |
305 | } |
306 | |
307 | EGL_CONTEXT_T *client_egl_get_context(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLContext ctx) |
308 | { |
309 | EGL_CONTEXT_T *context = (EGL_CONTEXT_T *)khrn_pointer_map_lookup(&process->contexts, (uint32_t)(size_t)ctx); |
310 | |
311 | vcos_assert(!context || !context->is_destroyed); |
312 | |
313 | if (!context) |
314 | thread->error = EGL_BAD_CONTEXT; |
315 | |
316 | return context; |
317 | } |
318 | |
319 | EGL_SURFACE_T *client_egl_get_surface(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLSurface surf) |
320 | { |
321 | EGL_SURFACE_T *surface = (EGL_SURFACE_T *)khrn_pointer_map_lookup(&process->surfaces, (uint32_t)(size_t)surf); |
322 | |
323 | vcos_assert (!surface || !surface->is_destroyed); |
324 | |
325 | if (!surface) |
326 | thread->error = EGL_BAD_SURFACE; |
327 | |
328 | #if EGL_KHR_lock_surface |
329 | if (surface && surface->is_locked) { |
330 | thread->error = EGL_BAD_ACCESS; |
331 | surface = NULL; |
332 | } |
333 | #endif |
334 | |
335 | return surface; |
336 | } |
337 | |
338 | /* |
339 | We don't actually insist that the surface is locked. But unlike client_egl_get_surface, we don't throw an |
340 | error if it isn't. |
341 | */ |
342 | EGL_SURFACE_T *client_egl_get_locked_surface(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLSurface surf) |
343 | { |
344 | EGL_SURFACE_T *surface = (EGL_SURFACE_T *)khrn_pointer_map_lookup(&process->surfaces, (uint32_t)(size_t)surf); |
345 | |
346 | vcos_assert (!surface || !surface->is_destroyed); |
347 | |
348 | if (!surface) |
349 | thread->error = EGL_BAD_SURFACE; |
350 | |
351 | return surface; |
352 | } |
353 | |
354 | /* |
355 | * just return if we've seen window before |
356 | */ |
357 | EGLNativeWindowType client_egl_get_window(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLNativeWindowType window) |
358 | { |
359 | EGLNativeWindowType win = (EGLNativeWindowType)khrn_pointer_map_lookup(&process->windows, (uint32_t)(size_t)window); |
360 | |
361 | return win; |
362 | } |
363 | |
364 | static uint32_t convert_gltype(EGL_CONTEXT_TYPE_T type) |
365 | { |
366 | switch (type) { |
367 | case OPENGL_ES_11: return EGL_SERVER_GL11; |
368 | case OPENGL_ES_20: return EGL_SERVER_GL20; |
369 | default: UNREACHABLE(); return 0; |
370 | } |
371 | } |
372 | |
373 | void client_send_make_current(CLIENT_THREAD_STATE_T *thread) |
374 | { |
375 | uint64_t pid = rpc_get_client_id(thread); |
376 | uint32_t gltype = thread->opengl.context ? convert_gltype(thread->opengl.context->type) : 0; |
377 | EGL_GL_CONTEXT_ID_T servergl = thread->opengl.context ? thread->opengl.context->servercontext : EGL_SERVER_NO_GL_CONTEXT; |
378 | EGL_SURFACE_ID_T servergldraw = thread->opengl.draw ? thread->opengl.draw->serverbuffer : EGL_SERVER_NO_SURFACE; |
379 | EGL_SURFACE_ID_T serverglread = thread->opengl.read ? thread->opengl.read->serverbuffer : EGL_SERVER_NO_SURFACE; |
380 | EGL_VG_CONTEXT_ID_T servervg = thread->openvg.context ? thread->openvg.context->servercontext : EGL_SERVER_NO_VG_CONTEXT; |
381 | EGL_SURFACE_ID_T servervgsurf = thread->openvg.draw ? thread->openvg.draw->serverbuffer : EGL_SERVER_NO_SURFACE; |
382 | |
383 | /* |
384 | if the size of this call in the merge buffer changes, |
385 | CLIENT_MAKE_CURRENT_SIZE in khrn_client.h should be updated |
386 | */ |
387 | |
388 | |
389 | if (!thread->opengl.context || !thread->opengl.draw) |
390 | { |
391 | vcos_log_trace("Send null make current %x %x" , |
392 | (unsigned int)(char *)thread->opengl.context, (unsigned int)(char *)thread->opengl.draw); |
393 | } |
394 | else |
395 | { |
396 | vcos_log_trace("Send make current %d[%d %s%s] %d[%d %d%s]" , |
397 | (int)thread->opengl.context->name, |
398 | thread->opengl.context->servercontext, |
399 | thread->opengl.context->is_current ? " C" : "" , |
400 | thread->opengl.context->is_destroyed ? " D" : "" , |
401 | (int)thread->opengl.draw->name, |
402 | thread->opengl.draw->serverbuffer, |
403 | thread->opengl.draw->context_binding_count, |
404 | thread->opengl.draw->is_destroyed ? " D" : "" ); |
405 | } |
406 | |
407 | RPC_CALL8_MAKECURRENT(eglIntMakeCurrent_impl, |
408 | thread, |
409 | EGLINTMAKECURRENT_ID, |
410 | RPC_UINT((uint32_t)pid), |
411 | RPC_UINT((uint32_t)(pid >> 32)), |
412 | RPC_UINT(gltype), |
413 | RPC_UINT(servergl), |
414 | RPC_UINT(servergldraw), |
415 | RPC_UINT(serverglread), |
416 | RPC_UINT(servervg), |
417 | RPC_UINT(servervgsurf)); |
418 | } |
419 | |
420 | PLATFORM_TLS_T client_tls; |
421 | PLATFORM_MUTEX_T client_mutex; |
422 | #ifdef CLIENT_THREAD_IS_PROCESS |
423 | PLATFORM_TLS_T client_tls_process; |
424 | PLATFORM_TLS_T client_tls_mutex; |
425 | #endif |
426 | |
427 | bool client_process_attach() |
428 | { |
429 | KHR_STATUS_T status; |
430 | status = platform_tls_create(&client_tls); |
431 | if (status != KHR_SUCCESS) { |
432 | return false; |
433 | } |
434 | |
435 | #ifdef CLIENT_THREAD_IS_PROCESS |
436 | status = platform_tls_create(&client_tls_process); |
437 | if (status != KHR_SUCCESS) { |
438 | return false; |
439 | } |
440 | |
441 | status = platform_tls_create(&client_tls_mutex); |
442 | if (status != KHR_SUCCESS) { |
443 | return false; |
444 | } |
445 | #endif |
446 | |
447 | status = platform_mutex_create(&client_mutex); |
448 | |
449 | if (status != KHR_SUCCESS) { |
450 | platform_tls_destroy(client_tls); |
451 | return false; |
452 | } |
453 | if (!RPC_INIT()) { |
454 | platform_mutex_destroy(&client_mutex); |
455 | platform_tls_destroy(client_tls); |
456 | return false; |
457 | } |
458 | return true; |
459 | } |
460 | |
461 | bool client_thread_attach() |
462 | { |
463 | CLIENT_THREAD_STATE_T *state = (CLIENT_THREAD_STATE_T *)khrn_platform_malloc(sizeof(CLIENT_THREAD_STATE_T), "CLIENT_THREAD_STATE_T" ); |
464 | |
465 | if (!state) |
466 | return false; |
467 | |
468 | client_thread_state_init(state); |
469 | |
470 | platform_tls_set(client_tls, state); |
471 | |
472 | #ifdef CLIENT_THREAD_IS_PROCESS |
473 | { //add mutex into thread's tls |
474 | KHR_STATUS_T status; |
475 | PLATFORM_MUTEX_T *local_mutex = (PLATFORM_MUTEX_T*)vcos_tls_get(client_tls_mutex); |
476 | |
477 | if (!local_mutex) |
478 | { |
479 | local_mutex = (PLATFORM_MUTEX_T*)khrn_platform_malloc(sizeof(PLATFORM_MUTEX_T),"thread mutex" ); |
480 | if (!local_mutex) |
481 | return false; |
482 | |
483 | status = platform_mutex_create(local_mutex); |
484 | if (status != KHR_SUCCESS) { |
485 | khrn_platform_free(local_mutex); |
486 | return false; |
487 | } |
488 | |
489 | vcos_tls_set(client_tls_mutex,local_mutex); |
490 | } |
491 | } |
492 | #endif |
493 | |
494 | #ifndef RPC_LIBRARY //TODO |
495 | client_send_make_current(state); |
496 | #endif |
497 | return true; |
498 | } |
499 | |
500 | void client_thread_detach(void *dummy) |
501 | { |
502 | CLIENT_THREAD_STATE_T *state = CLIENT_GET_THREAD_STATE(); |
503 | UNUSED(dummy); |
504 | |
505 | platform_tls_remove(client_tls); |
506 | client_thread_state_term(state); |
507 | |
508 | khrn_platform_free(state); |
509 | platform_maybe_free_process(); |
510 | |
511 | #ifdef CLIENT_THREAD_IS_PROCESS |
512 | { |
513 | CLIENT_PROCESS_STATE_T *process = CLIENT_GET_PROCESS_STATE(); |
514 | khrn_platform_free(process); |
515 | platform_tls_remove(client_tls_process); |
516 | } |
517 | |
518 | { |
519 | PLATFORM_MUTEX_T *local_mutex = (PLATFORM_MUTEX_T*)vcos_tls_get(client_tls_mutex); |
520 | vcos_assert(local_mutex); |
521 | |
522 | platform_mutex_destroy(local_mutex); |
523 | |
524 | khrn_platform_free(local_mutex); |
525 | platform_tls_remove(client_tls_mutex); |
526 | } |
527 | #endif |
528 | } |
529 | |
530 | void client_process_detach() |
531 | { |
532 | RPC_TERM(); |
533 | platform_tls_destroy(client_tls); |
534 | platform_mutex_destroy(&client_mutex); |
535 | |
536 | #ifdef CLIENT_THREAD_IS_PROCESS |
537 | platform_tls_destroy(client_tls_process); |
538 | #endif |
539 | } |
540 | |
541 | #ifdef RPC_LIBRARY |
542 | KHRONOS_SERVER_CONNECTION_T *client_library_get_connection(void) |
543 | { |
544 | return &client_process_state.khrn_connection; |
545 | } |
546 | |
547 | #endif |
548 | |
549 | #if defined(RPC_LIBRARY) || defined(RPC_DIRECT_MULTI) |
550 | |
551 | void client_library_send_make_current(const KHRONOS_FUNC_TABLE_T *func_table) |
552 | { |
553 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
554 | if (thread->opengl.context || thread->openvg.context) |
555 | { |
556 | uint64_t pid = rpc_get_client_id(thread); |
557 | uint32_t gltype = thread->opengl.context ? convert_gltype(thread->opengl.context->type) : 0; |
558 | EGL_GL_CONTEXT_ID_T servergl = thread->opengl.context ? thread->opengl.context->servercontext : EGL_SERVER_NO_GL_CONTEXT; |
559 | EGL_SURFACE_ID_T servergldraw = thread->opengl.draw ? thread->opengl.draw->serverbuffer : EGL_SERVER_NO_SURFACE; |
560 | EGL_SURFACE_ID_T serverglread = thread->opengl.read ? thread->opengl.read->serverbuffer : EGL_SERVER_NO_SURFACE; |
561 | EGL_VG_CONTEXT_ID_T servervg = thread->openvg.context ? thread->openvg.context->servercontext : EGL_SERVER_NO_VG_CONTEXT; |
562 | EGL_SURFACE_ID_T servervgsurf = thread->openvg.draw ? thread->openvg.draw->serverbuffer : EGL_SERVER_NO_SURFACE; |
563 | |
564 | /* |
565 | if the size of this call in the merge buffer changes, |
566 | CLIENT_MAKE_CURRENT_SIZE in khrn_client.h should be updated |
567 | */ |
568 | |
569 | func_table->eglIntMakeCurrent_impl( |
570 | (uint32_t)pid, |
571 | (uint32_t)(pid >> 32), |
572 | gltype, |
573 | servergl, |
574 | servergldraw, |
575 | serverglread, |
576 | servervg, |
577 | servervgsurf); |
578 | } |
579 | } |
580 | |
581 | #endif |
582 | |
583 | #ifdef GL_GET_ERROR_ASYNC |
584 | static void callback_set_error(KHRN_POINTER_MAP_T *map, uint32_t key, void *value, void *data) |
585 | { |
586 | EGL_CONTEXT_T *context = (EGL_CONTEXT_T *)value; |
587 | |
588 | UNUSED(map); |
589 | UNUSED_NDEBUG(key); |
590 | |
591 | vcos_assert( context != NULL ); |
592 | vcos_assert((uintptr_t)key == (uintptr_t)context->name); |
593 | |
594 | if (context->servercontext == *((uint32_t *)data)){ |
595 | CLIENT_THREAD_STATE_T *thread = context->thread; |
596 | /* todo: VG */ |
597 | if (thread && IS_OPENGLES_11_OR_20(thread)) { |
598 | vcos_log_error("GL OOM context %d" , context->servercontext); |
599 | glxx_set_error(GLXX_GET_CLIENT_STATE(thread), GL_OUT_OF_MEMORY); |
600 | } |
601 | } |
602 | } |
603 | |
604 | void client_set_error(uint32_t server_context_name) |
605 | { |
606 | CLIENT_PROCESS_STATE_T *process; |
607 | CLIENT_LOCK(); |
608 | process = CLIENT_GET_PROCESS_STATE(); |
609 | khrn_pointer_map_iterate(&process->contexts, callback_set_error, &server_context_name); |
610 | CLIENT_UNLOCK(); |
611 | } |
612 | #endif |
613 | |