1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON 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
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27#ifndef KHRN_CLIENT_H
28#define KHRN_CLIENT_H
29
30typedef struct CLIENT_PROCESS_STATE CLIENT_PROCESS_STATE_T;
31typedef struct CLIENT_THREAD_STATE CLIENT_THREAD_STATE_T;
32
33
34#include "interface/khronos/common/khrn_client_platform.h"
35
36#include "interface/khronos/egl/egl_client_context.h"
37#include "interface/khronos/egl/egl_client_surface.h"
38#include "interface/khronos/include/EGL/eglext.h"
39
40#include "interface/khronos/common/khrn_client_pointermap.h"
41
42#ifdef RPC_LIBRARY
43#include "middleware/khronos/common/khrn_misc.h"
44#include "applications/vmcs/khronos/khronos_server.h"
45#elif defined(RPC_DIRECT_MULTI)
46#include "middleware/khronos/common/khrn_misc.h"
47#endif
48
49
50/* must be after EGL/eglext.h */
51#if EGL_BRCM_global_image && EGL_KHR_image
52 #include "interface/khronos/common/khrn_client_global_image_map.h"
53#endif
54
55extern void client_try_unload_server(CLIENT_PROCESS_STATE_T *process);
56
57/*
58 per-thread state
59
60 - EGL error
61 - EGL bound API
62 - EGL context and surfaces for each API
63
64 - RPC merge buffer
65*/
66
67#define MERGE_BUFFER_SIZE 4080
68
69typedef struct {
70 EGL_CONTEXT_T *context;
71 EGL_SURFACE_T *draw;
72 EGL_SURFACE_T *read;
73} EGL_CURRENT_T;
74
75struct CLIENT_THREAD_STATE {
76 /*
77 error
78
79 Invariant:
80 (CLIENT_THREAD_STATE_ERROR)
81 error is one of
82 EGL_SUCCESS
83 EGL_NOT_INITIALIZED
84 EGL_BAD_ACCESS
85 EGL_BAD_ALLOC
86 EGL_BAD_ATTRIBUTE
87 EGL_BAD_CONTEXT
88 EGL_BAD_CONFIG
89 EGL_BAD_CURRENT SURFACE
90 EGL_BAD_DISPLAY
91 EGL_BAD_SURFACE
92 EGL_BAD_MATCH
93 EGL_BAD_PARAMETER
94 EGL_BAD_NATIVE PIXMAP
95 EGL_BAD_NATIVE WINDOW
96 EGL_CONTEXT_LOST
97 */
98 EGLint error;
99
100 EGLenum bound_api;
101
102 /*
103 handles to current display, context and surfaces for each API
104
105 Availability:
106
107 Thread owns EGL lock
108 */
109
110 EGL_CURRENT_T opengl;
111 EGL_CURRENT_T openvg;
112
113 /*
114 rpc stuff
115 */
116
117 bool high_priority;
118
119 uint8_t merge_buffer[MERGE_BUFFER_SIZE];
120
121 uint32_t merge_pos;
122 uint32_t merge_end;
123
124 /* Try to reduce impact of repeated consecutive glGetError() calls */
125 int32_t glgeterror_hack;
126 bool async_error_notification;
127};
128
129extern void client_thread_state_init(CLIENT_THREAD_STATE_T *state);
130extern void client_thread_state_term(CLIENT_THREAD_STATE_T *state);
131
132extern PLATFORM_TLS_T client_tls;
133
134/*
135 CLIENT_GET_THREAD_STATE
136
137 Implementation notes:
138
139 TODO: make sure this gets code-reviewed
140
141 Preconditions:
142
143 -
144
145 Postconditions:
146
147 Result is a valid pointer to a thread-local CLIENT_THREAD_STATE_T structure.
148
149 Invariants preserved:
150
151 -
152
153 Invariants used:
154
155 -
156*/
157
158static INLINE CLIENT_THREAD_STATE_T *CLIENT_GET_THREAD_STATE(void)
159{
160 CLIENT_THREAD_STATE_T *tls;
161 tls = (CLIENT_THREAD_STATE_T *)platform_tls_get(client_tls);
162 if( tls && tls->glgeterror_hack ) {
163 tls->glgeterror_hack--;
164 }
165 return tls;
166}
167
168static INLINE CLIENT_THREAD_STATE_T *CLIENT_GET_CHECK_THREAD_STATE(void)
169{
170 return (CLIENT_THREAD_STATE_T *)platform_tls_get_check(client_tls);
171}
172
173/*
174 per-process state
175
176 - EGL initialization stage
177 - EGL contexts and surfaces
178 - EGL counters
179*/
180
181struct CLIENT_PROCESS_STATE {
182#ifdef RPC_LIBRARY
183 /*
184 called khronos_server_connect? this is valid even if !inited
185 */
186 bool connected;
187#endif
188
189 /*
190 number of current contexts across all threads in this process. this is valid
191 even if !inited
192 */
193 uint32_t context_current_count;
194
195 /*
196 inited
197
198 Specifies whether the structure has been initialised and all of the other members are valid.
199 inited is true between eglInitialise/eglTerminate. threads can still have
200 things current when !inited
201
202 Invariants:
203 (CLIENT_PROCESS_STATE_INITED_SANITY)
204 Only client_process_state_init/client_process_state_term modify this value
205 */
206 bool inited;
207
208 /*
209 contexts
210
211 A map from context id (EGLContext) to EGL_CONTEXT_T
212 TODO: use pointers as key rather than integers
213
214 Validity: inited is true
215
216 Invariants:
217 (CLIENT_PROCESS_STATE_CONTEXTS)
218 If id is a key in contexts:
219 contexts[id].name == id
220 contexts[id].is_destroyed == false
221 */
222 KHRN_POINTER_MAP_T contexts;
223
224 /*
225 surfaces
226
227 A map from context id (EGLContext) to EGL_SURFACE_T
228
229 Validity: inited is true
230
231 Invariants:
232 (CLIENT_PROCESS_STATE_SURFACES)
233 If id is a key in surfaces:
234 surfaces[id].name == id
235 surfaces[id].is_destroyed == false
236 */
237 KHRN_POINTER_MAP_T surfaces;
238
239
240 /*
241 * some platforms (e.g. Android) need to maintain a list of
242 * known windows
243 */
244 KHRN_POINTER_MAP_T windows;
245
246#if EGL_KHR_sync
247
248 /*
249 syncs
250
251 Validity: inited is true
252 */
253 KHRN_POINTER_MAP_T syncs;
254#endif
255#if EGL_BRCM_global_image && EGL_KHR_image
256 KHRN_GLOBAL_IMAGE_MAP_T global_image_egl_images;
257#endif
258
259
260 /*
261 next_surface
262
263 Implementation notes:
264 TODO: these could theoretically overflow
265
266 Validity: inited is true
267
268 Invariant:
269 (CLIENT_PROCESS_STATE_NEXT_SURFACE)
270 next_surface is greater than every key in surfaces
271 next_surface >= 1
272 */
273 uint32_t next_surface;
274 /*
275 next_context
276
277 Validity: inited is true
278 */
279 uint32_t next_context;
280#if EGL_KHR_sync
281 /*
282 next_sync
283
284 Validity: inited is true
285 */
286 uint32_t next_sync;
287#endif
288#if EGL_BRCM_global_image && EGL_KHR_image
289 uint32_t next_global_image_egl_image;
290#endif
291
292#if EGL_BRCM_perf_monitor
293 /*
294 perf_monitor_inited
295
296 Validity: inited is true
297 */
298 bool perf_monitor_inited;
299#endif
300
301#if EGL_BRCM_driver_monitor
302 /*
303 driver_monitor_inited
304
305 Validity: inited is true
306 */
307 bool driver_monitor_inited;
308#endif
309
310#ifdef RPC_LIBRARY
311 KHRONOS_SERVER_CONNECTION_T khrn_connection;
312#endif
313};
314
315extern bool client_process_state_init(CLIENT_PROCESS_STATE_T *process);
316extern void client_process_state_term(CLIENT_PROCESS_STATE_T *process);
317
318extern CLIENT_PROCESS_STATE_T client_process_state;
319
320/*
321 CLIENT_GET_PROCESS_STATE()
322
323 Returns the process-global CLIENT_PROCESS_STATE_T object.
324*/
325#ifdef CLIENT_THREAD_IS_PROCESS
326extern PLATFORM_TLS_T client_tls_process;
327extern PLATFORM_TLS_T client_tls_mutex;
328extern void *platform_tls_get_process(PLATFORM_TLS_T tls);
329#endif
330static INLINE CLIENT_PROCESS_STATE_T *CLIENT_GET_PROCESS_STATE(void)
331{
332#ifdef CLIENT_THREAD_IS_PROCESS
333 //each thread has its own client_process_state
334 return (CLIENT_PROCESS_STATE_T *)platform_tls_get_process(client_tls_process);
335#else
336 return &client_process_state;
337#endif
338}
339
340/*
341 exposed bits of EGL
342*/
343
344CLIENT_PROCESS_STATE_T *client_egl_get_process_state(CLIENT_THREAD_STATE_T *thread, EGLDisplay dpy, EGLBoolean check_inited);
345EGL_CONTEXT_T *client_egl_get_context(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLContext ctx);
346EGL_SURFACE_T *client_egl_get_surface(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLSurface surf);
347EGL_SURFACE_T *client_egl_get_locked_surface(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLSurface surf);
348
349EGLNativeWindowType client_egl_get_window(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLNativeWindowType window);
350/*
351 client state
352*/
353
354#define CLIENT_MAKE_CURRENT_SIZE 36 /* RPC_CALL8 */
355extern void client_send_make_current(CLIENT_THREAD_STATE_T *thread);
356
357extern void client_set_error(uint32_t server_context_name);
358/*
359 big giant lock
360*/
361
362extern PLATFORM_MUTEX_T client_mutex;
363
364/*
365 CLIENT_LOCK()
366
367 Acquires EGL lock.
368
369 Implementation notes:
370
371 TODO make sure this gets reviewed
372
373 Preconditions:
374
375 TODO: check mutex hierarchy methodology
376 Mutex: >(MUTEX_EGL_LOCK)
377 Is being called from a function which _always_ subsequently calls CLIENT_UNLOCK()
378
379 Postconditions:
380
381 Mutex: (MUTEX_EGL_LOCK)
382 Thread owns EGL lock
383*/
384
385static INLINE void CLIENT_LOCK(void)
386{
387 platform_client_lock();
388}
389
390/*
391 CLIENT_UNLOCK()
392
393 Releases EGL lock.
394
395 Implementation notes:
396
397 TODO make sure this gets reviewed
398
399 Preconditions:
400
401 Mutex: (MUTEX_EGL_LOCK)
402 Thread owns EGL lock
403 Is being called from a function which has _always_ previously called CLIENT_LOCK()
404
405 Postconditions:
406 Mutex: >(MUTEX_EGL_LOCK)
407*/
408
409static INLINE void CLIENT_UNLOCK(void)
410{
411 platform_client_release();
412}
413
414/*
415 bool CLIENT_LOCK_AND_GET_STATES(EGLDisplay dpy, CLIENT_THREAD_STATE_T **thread, CLIENT_PROCESS_STATE_T **process)
416
417 Try to acquire EGL lock and get thread and process state.
418
419 Implementation notes:
420
421 TODO make sure this gets reviewed
422
423 Preconditions:
424
425 thread is a valid pointer to a thread*
426 process is a valid pointer to a process*
427 Mutex: >(MUTEX_EGL_LOCK)
428 Is being called from a function which calls CLIENT_UNLOCK() if we return true
429
430 Postconditions:
431
432 The following conditions cause error to assume the specified value
433
434 EGL_BAD_DISPLAY An EGLDisplay argument does not name a valid EGLDisplay
435 EGL_NOT_INITIALIZED EGL is not initialized for the specified display.
436
437 if more than one condition holds, the first error is generated.
438
439 Either:
440 Mutex: (MUTEX_EGL_LOCK)
441 Thread owns EGL lock
442 result is true
443 Or:
444 Nothing changes
445 result is false
446*/
447
448static INLINE bool CLIENT_LOCK_AND_GET_STATES(EGLDisplay dpy, CLIENT_THREAD_STATE_T **thread, CLIENT_PROCESS_STATE_T **process)
449{
450 *thread = CLIENT_GET_THREAD_STATE();
451 CLIENT_LOCK();
452 *process = client_egl_get_process_state(*thread, dpy, EGL_TRUE);
453 if (*process != NULL)
454 return true;
455 else
456 {
457 CLIENT_UNLOCK();
458 return false;
459 }
460}
461
462/*
463 process and thread attach/detach hooks
464*/
465
466#ifdef __cplusplus
467extern "C" {
468#endif
469extern bool client_process_attach(void);
470extern bool client_thread_attach(void);
471extern void client_thread_detach(void *dummy);
472extern void client_process_detach(void);
473
474#ifdef RPC_LIBRARY
475extern KHRONOS_SERVER_CONNECTION_T *client_library_get_connection(void);
476extern void client_library_send_make_current(const KHRONOS_FUNC_TABLE_T *func_table);
477#elif defined(RPC_DIRECT_MULTI)
478extern void client_library_send_make_current(const KHRONOS_FUNC_TABLE_T *func_table);
479#endif
480
481#ifdef __cplusplus
482}
483#endif
484
485#endif
486