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 | |
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 | |
55 | extern 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 | |
69 | typedef struct { |
70 | EGL_CONTEXT_T *context; |
71 | EGL_SURFACE_T *draw; |
72 | EGL_SURFACE_T *read; |
73 | } EGL_CURRENT_T; |
74 | |
75 | struct 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 | |
129 | extern void client_thread_state_init(CLIENT_THREAD_STATE_T *state); |
130 | extern void client_thread_state_term(CLIENT_THREAD_STATE_T *state); |
131 | |
132 | extern 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 | |
158 | static 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 | |
168 | static 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 | |
181 | struct 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 | |
315 | extern bool client_process_state_init(CLIENT_PROCESS_STATE_T *process); |
316 | extern void client_process_state_term(CLIENT_PROCESS_STATE_T *process); |
317 | |
318 | extern 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 |
326 | extern PLATFORM_TLS_T client_tls_process; |
327 | extern PLATFORM_TLS_T client_tls_mutex; |
328 | extern void *platform_tls_get_process(PLATFORM_TLS_T tls); |
329 | #endif |
330 | static 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 | |
344 | CLIENT_PROCESS_STATE_T *client_egl_get_process_state(CLIENT_THREAD_STATE_T *thread, EGLDisplay dpy, EGLBoolean check_inited); |
345 | EGL_CONTEXT_T *client_egl_get_context(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLContext ctx); |
346 | EGL_SURFACE_T *client_egl_get_surface(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLSurface surf); |
347 | EGL_SURFACE_T *client_egl_get_locked_surface(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLSurface surf); |
348 | |
349 | EGLNativeWindowType 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 */ |
355 | extern void client_send_make_current(CLIENT_THREAD_STATE_T *thread); |
356 | |
357 | extern void client_set_error(uint32_t server_context_name); |
358 | /* |
359 | big giant lock |
360 | */ |
361 | |
362 | extern 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 | |
385 | static 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 | |
409 | static 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 | |
448 | static 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 |
467 | extern "C" { |
468 | #endif |
469 | extern bool client_process_attach(void); |
470 | extern bool client_thread_attach(void); |
471 | extern void client_thread_detach(void *dummy); |
472 | extern void client_process_detach(void); |
473 | |
474 | #ifdef RPC_LIBRARY |
475 | extern KHRONOS_SERVER_CONNECTION_T *client_library_get_connection(void); |
476 | extern void client_library_send_make_current(const KHRONOS_FUNC_TABLE_T *func_table); |
477 | #elif defined(RPC_DIRECT_MULTI) |
478 | extern 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 | |