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
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
50typedef 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
71static 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
126static 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
143static 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
160static 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
196static 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
215EGLAPI 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
257EGLAPI 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
293EGLAPI 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
333EGLAPI 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
361EGLAPI 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
400void 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