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