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