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 | |
28 | #define EGL_EGLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */ |
29 | |
30 | #ifndef SYNC_FENCE_KHR_SHORTCUT |
31 | //#define SYNC_FENCE_KHR_SHORTCUT 0 /* notifications made in driver back-end */ |
32 | #define SYNC_FENCE_KHR_SHORTCUT 1 /* notifications made in dispatch */ |
33 | #endif |
34 | |
35 | //============================================================================== |
36 | |
37 | #include "interface/khronos/common/khrn_client_mangle.h" |
38 | #include "interface/khronos/common/khrn_client_rpc.h" |
39 | |
40 | #include "interface/khronos/ext/egl_khr_sync_client.h" |
41 | #include "interface/khronos/include/EGL/egl.h" |
42 | #include "interface/khronos/include/EGL/eglext.h" |
43 | |
44 | #if defined(V3D_LEAN) |
45 | #include "interface/khronos/common/khrn_int_misc_impl.h" |
46 | #endif |
47 | |
48 | //============================================================================== |
49 | |
50 | typedef struct { |
51 | EGLint condition; |
52 | EGLint threshold; |
53 | EGLint status; |
54 | EGLenum type; |
55 | |
56 | int name[3]; // Used as ID in khronos_platform_semaphore_create |
57 | |
58 | EGL_SYNC_ID_T serversync; |
59 | |
60 | /* |
61 | we keep one master handle to the named semaphore in existence for the |
62 | lifetime of the sync object, allowing both wait functions and the KHAN |
63 | message handler to "open, post/wait, close". |
64 | */ |
65 | |
66 | PLATFORM_SEMAPHORE_T master; |
67 | } EGL_SYNC_T; |
68 | |
69 | //============================================================================== |
70 | |
71 | static EGL_SYNC_T *egl_sync_create(EGLSyncKHR sync, EGLenum type, |
72 | EGLint condition, EGLint threshold, EGLint status) |
73 | { |
74 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
75 | EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *)khrn_platform_malloc(sizeof(EGL_SYNC_T), "EGL_SYNC_T" ); |
76 | uint64_t pid = rpc_get_client_id(thread); |
77 | uint32_t sem; |
78 | |
79 | if (!sync_ptr) |
80 | return 0; |
81 | |
82 | sync_ptr->condition = condition; |
83 | sync_ptr->threshold = threshold; |
84 | sync_ptr->type = type; |
85 | sync_ptr->status = status; |
86 | |
87 | sync_ptr->name[0] = (int)pid; |
88 | sync_ptr->name[1] = (int)(pid >> 32); |
89 | sync_ptr->name[2] = (int)sync; |
90 | |
91 | if (khronos_platform_semaphore_create(&sync_ptr->master, sync_ptr->name, 0) != KHR_SUCCESS) { |
92 | khrn_platform_free(sync_ptr); |
93 | return 0; |
94 | } |
95 | |
96 | sem = (uint32_t) sync; |
97 | #if SYNC_FENCE_KHR_SHORTCUT == 1 |
98 | if (type == EGL_SYNC_FENCE_KHR){ |
99 | RPC_CALL3(eglIntCreateSyncFence_impl, |
100 | thread, |
101 | EGLINTCREATESYNCFENCE_ID, |
102 | RPC_UINT(condition), |
103 | RPC_INT(threshold), |
104 | RPC_UINT(sem)); |
105 | } else |
106 | #endif |
107 | { |
108 | sync_ptr->serversync = RPC_UINT_RES(RPC_CALL4_RES(eglIntCreateSync_impl, |
109 | thread, |
110 | EGLINTCREATESYNC_ID, |
111 | RPC_UINT(type), |
112 | RPC_UINT(condition), |
113 | RPC_INT(threshold), |
114 | RPC_UINT(sem))); |
115 | if (!sync_ptr->serversync) { |
116 | khronos_platform_semaphore_destroy(&sync_ptr->master); |
117 | khrn_platform_free(sync_ptr); |
118 | return 0; |
119 | } |
120 | } |
121 | return sync_ptr; |
122 | } |
123 | |
124 | //------------------------------------------------------------------------------ |
125 | |
126 | static void egl_sync_term(EGL_SYNC_T *sync_master) |
127 | { |
128 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
129 | #if SYNC_FENCE_KHR_SHORTCUT == 1 |
130 | if (sync_master->type != EGL_SYNC_FENCE_KHR) |
131 | #endif |
132 | { |
133 | RPC_CALL1(eglIntDestroySync_impl, |
134 | thread, |
135 | EGLINTDESTROYSYNC_ID, |
136 | RPC_UINT(sync_master->serversync)); |
137 | } |
138 | khronos_platform_semaphore_destroy(&sync_master->master); |
139 | } |
140 | |
141 | //------------------------------------------------------------------------------ |
142 | |
143 | static void egl_sync_destroy_iterator |
144 | (KHRN_POINTER_MAP_T *sync_map, uint32_t sync, void *sync_handle, void *data) |
145 | { |
146 | EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *) sync; |
147 | |
148 | UNUSED(sync_map); |
149 | UNUSED(sync_handle); |
150 | UNUSED(data); |
151 | |
152 | vcos_assert(sync_ptr != NULL); |
153 | |
154 | egl_sync_term(sync_ptr); |
155 | khrn_platform_free(sync_ptr); |
156 | } |
157 | |
158 | //------------------------------------------------------------------------------ |
159 | |
160 | static EGLBoolean egl_sync_check_attribs(const EGLint *attrib_list, EGLenum type, |
161 | EGLint *condition, EGLint *threshold, EGLint *status) |
162 | { |
163 | switch (type) { |
164 | case EGL_SYNC_FENCE_KHR: |
165 | *condition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR; |
166 | *threshold = 0; |
167 | *status = EGL_UNSIGNALED_KHR; |
168 | break; |
169 | default : |
170 | *condition = EGL_NONE; |
171 | *threshold = 0; |
172 | *status = 0; |
173 | break; |
174 | } |
175 | |
176 | if (attrib_list) { |
177 | while (1) { |
178 | int name = *attrib_list++; |
179 | if (name == EGL_NONE) |
180 | break; |
181 | else { |
182 | /* int value = * */attrib_list++; /* at present no name/value pairs are handled */ |
183 | switch (name) { |
184 | default: |
185 | return EGL_FALSE; |
186 | } |
187 | } |
188 | } |
189 | } |
190 | |
191 | return ((type == EGL_SYNC_FENCE_KHR) || (type == 0)); |
192 | } |
193 | |
194 | //------------------------------------------------------------------------------ |
195 | |
196 | static EGLBoolean egl_sync_get_attrib(EGL_SYNC_T *sync, EGLint attrib, EGLint *value) |
197 | { |
198 | switch (attrib) { |
199 | case EGL_SYNC_TYPE_KHR: |
200 | *value = sync->type; |
201 | return EGL_TRUE; |
202 | case EGL_SYNC_STATUS_KHR: |
203 | *value = sync->status; |
204 | return EGL_TRUE; |
205 | case EGL_SYNC_CONDITION_KHR: |
206 | *value = sync->condition; |
207 | return EGL_TRUE; |
208 | default: |
209 | return EGL_FALSE; |
210 | } |
211 | } |
212 | |
213 | //============================================================================== |
214 | |
215 | EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) |
216 | { |
217 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
218 | EGLSyncKHR sync = EGL_NO_SYNC_KHR; |
219 | |
220 | CLIENT_LOCK(); |
221 | |
222 | { |
223 | CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE); |
224 | |
225 | EGLint condition; |
226 | EGLint threshold; |
227 | EGLint status; |
228 | |
229 | if (process) |
230 | { |
231 | if (egl_sync_check_attribs(attrib_list, type, &condition, &threshold, &status)) { |
232 | EGL_SYNC_T *sync_ptr = egl_sync_create((EGLSyncKHR)(size_t)process->next_sync, type, condition, threshold, status); |
233 | |
234 | if (sync_ptr) { |
235 | if (khrn_pointer_map_insert(&process->syncs, process->next_sync, sync_ptr)) { |
236 | thread->error = EGL_SUCCESS; |
237 | sync = (EGLSurface)(size_t)process->next_sync++; |
238 | } else { |
239 | thread->error = EGL_BAD_ALLOC; |
240 | egl_sync_term(sync_ptr); |
241 | khrn_platform_free(sync_ptr); |
242 | } |
243 | } else |
244 | thread->error = EGL_BAD_ALLOC; |
245 | } |
246 | } |
247 | } |
248 | |
249 | CLIENT_UNLOCK(); |
250 | |
251 | return sync; |
252 | } |
253 | |
254 | //------------------------------------------------------------------------------ |
255 | // TODO: should we make sure any syncs have come back before destroying the object? |
256 | |
257 | EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) |
258 | { |
259 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
260 | EGLBoolean result; |
261 | |
262 | CLIENT_LOCK(); |
263 | |
264 | { |
265 | CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE); |
266 | |
267 | if (process) { |
268 | EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *)khrn_pointer_map_lookup(&process->syncs, (uint32_t)(size_t)sync); |
269 | |
270 | if (sync_ptr) { |
271 | thread->error = EGL_SUCCESS; |
272 | |
273 | khrn_pointer_map_delete(&process->syncs, (uint32_t)(uintptr_t)sync); |
274 | |
275 | egl_sync_term(sync_ptr); |
276 | khrn_platform_free(sync_ptr); |
277 | } else |
278 | thread->error = EGL_BAD_PARAMETER; |
279 | |
280 | result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE); |
281 | } else { |
282 | result = EGL_FALSE; |
283 | } |
284 | } |
285 | |
286 | CLIENT_UNLOCK(); |
287 | |
288 | return result; |
289 | } |
290 | |
291 | //------------------------------------------------------------------------------ |
292 | |
293 | EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) |
294 | { |
295 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
296 | |
297 | UNUSED(timeout); |
298 | |
299 | CLIENT_LOCK(); |
300 | |
301 | { |
302 | CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE); |
303 | |
304 | if (process) { |
305 | EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *)khrn_pointer_map_lookup(&process->syncs, (uint32_t)(size_t)sync); |
306 | |
307 | if (sync_ptr) { |
308 | PLATFORM_SEMAPHORE_T semaphore; |
309 | if( khronos_platform_semaphore_create(&semaphore, sync_ptr->name, 1) == KHR_SUCCESS) { |
310 | if (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) |
311 | RPC_FLUSH(thread); |
312 | |
313 | CLIENT_UNLOCK(); |
314 | |
315 | khronos_platform_semaphore_acquire(&semaphore); |
316 | khronos_platform_semaphore_release(&semaphore); |
317 | khronos_platform_semaphore_destroy(&semaphore); |
318 | return EGL_CONDITION_SATISFIED_KHR; |
319 | } else |
320 | thread->error = EGL_BAD_ALLOC; // not strictly allowed by the spec, but indicates that we failed to create a reference to the named semaphore |
321 | } else |
322 | thread->error = EGL_BAD_PARAMETER; |
323 | } |
324 | } |
325 | |
326 | CLIENT_UNLOCK(); |
327 | |
328 | return EGL_FALSE; |
329 | } |
330 | |
331 | //------------------------------------------------------------------------------ |
332 | |
333 | EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) |
334 | { |
335 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
336 | |
337 | UNUSED(mode); |
338 | |
339 | CLIENT_LOCK(); |
340 | |
341 | { |
342 | CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE); |
343 | |
344 | if (process) { |
345 | EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *)khrn_pointer_map_lookup(&process->syncs, (uint32_t)(size_t)sync); |
346 | |
347 | if (sync_ptr) |
348 | thread->error = EGL_BAD_MATCH; |
349 | else |
350 | thread->error = EGL_BAD_PARAMETER; |
351 | } |
352 | } |
353 | |
354 | CLIENT_UNLOCK(); |
355 | |
356 | return EGL_FALSE; |
357 | } |
358 | |
359 | //------------------------------------------------------------------------------ |
360 | |
361 | EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) |
362 | { |
363 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
364 | EGLBoolean result = EGL_FALSE; |
365 | |
366 | CLIENT_LOCK(); |
367 | |
368 | { |
369 | CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE); |
370 | |
371 | if (process) |
372 | { |
373 | if (value) |
374 | { |
375 | EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *)khrn_pointer_map_lookup(&process->syncs, (uint32_t)(size_t)sync); |
376 | |
377 | if (sync_ptr) { |
378 | if (egl_sync_get_attrib(sync_ptr, attribute, value)) { |
379 | thread->error = EGL_SUCCESS; |
380 | result = EGL_TRUE; |
381 | } else |
382 | thread->error = EGL_BAD_ATTRIBUTE; |
383 | } else |
384 | thread->error = EGL_BAD_PARAMETER; |
385 | } |
386 | else |
387 | { |
388 | thread->error = EGL_BAD_PARAMETER; |
389 | } |
390 | } |
391 | } |
392 | |
393 | CLIENT_UNLOCK(); |
394 | |
395 | return result; |
396 | } |
397 | |
398 | //------------------------------------------------------------------------------ |
399 | |
400 | void egl_sync_destroy_all(KHRN_POINTER_MAP_T *sync_map) |
401 | { |
402 | khrn_pointer_map_iterate(sync_map, egl_sync_destroy_iterator, NULL); |
403 | } |
404 | |
405 | //============================================================================== |
406 | |