Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / state_trackers / egl / common / egl_g3d_sync.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.9
4  *
5  * Copyright (C) 2010 LunarG Inc.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  *
25  * Authors:
26  *    Chia-I Wu <olv@lunarg.com>
27  */
28
29 #include "util/u_memory.h"
30 #include "util/u_atomic.h"
31 #include "os/os_thread.h"
32 #include "eglsync.h"
33 #include "eglcurrent.h"
34
35 #include "egl_g3d.h"
36 #include "egl_g3d_sync.h"
37
38 #ifdef EGL_KHR_reusable_sync
39
40 /**
41  * Wait for the conditional variable.
42  */
43 static EGLint
44 egl_g3d_wait_sync_condvar(struct egl_g3d_sync *gsync, EGLTimeKHR timeout)
45 {
46    _EGLDisplay *dpy = gsync->base.Resource.Display;
47
48    pipe_mutex_lock(gsync->mutex);
49
50    /* unlock display lock just before waiting */
51    _eglUnlockMutex(&dpy->Mutex);
52
53    /* No timed wait.  Always treat timeout as EGL_FOREVER_KHR */
54    pipe_condvar_wait(gsync->condvar, gsync->mutex);
55
56    _eglLockMutex(&dpy->Mutex);
57
58    pipe_mutex_unlock(gsync->mutex);
59
60    return EGL_CONDITION_SATISFIED_KHR;
61 }
62
63 /**
64  * Signal the conditional variable.
65  */
66 static void
67 egl_g3d_signal_sync_condvar(struct egl_g3d_sync *gsync)
68 {
69    pipe_mutex_lock(gsync->mutex);
70    pipe_condvar_broadcast(gsync->condvar);
71    pipe_mutex_unlock(gsync->mutex);
72 }
73
74 /**
75  * Insert a fence command to the command stream of the current context.
76  */
77 static EGLint
78 egl_g3d_insert_fence_sync(struct egl_g3d_sync *gsync)
79 {
80    _EGLContext *ctx = _eglGetCurrentContext();
81    struct egl_g3d_context *gctx = egl_g3d_context(ctx);
82
83    /* already checked in egl_g3d_create_sync */
84    assert(gctx);
85
86    /* insert the fence command */
87    gctx->stctxi->flush(gctx->stctxi, 0x0, &gsync->fence);
88    if (!gsync->fence)
89       gsync->base.SyncStatus = EGL_SIGNALED_KHR;
90
91    return EGL_SUCCESS;
92 }
93
94 /**
95  * Wait for the fence sync to be signaled.
96  */
97 static EGLint
98 egl_g3d_wait_fence_sync(struct egl_g3d_sync *gsync, EGLTimeKHR timeout)
99 {
100    EGLint ret;
101
102    if (gsync->fence) {
103       _EGLDisplay *dpy = gsync->base.Resource.Display;
104       struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
105       struct pipe_screen *screen = gdpy->native->screen;
106       struct pipe_fence_handle *fence = gsync->fence;
107
108       gsync->fence = NULL;
109
110       _eglUnlockMutex(&dpy->Mutex);
111       /* no timed finish? */
112       screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
113       ret = EGL_CONDITION_SATISFIED_KHR;
114       _eglLockMutex(&dpy->Mutex);
115
116       gsync->base.SyncStatus = EGL_SIGNALED_KHR;
117
118       screen->fence_reference(screen, &fence, NULL);
119       egl_g3d_signal_sync_condvar(gsync);
120    }
121    else {
122       ret = egl_g3d_wait_sync_condvar(gsync, timeout);
123    }
124
125    return ret;
126 }
127
128 static INLINE void
129 egl_g3d_ref_sync(struct egl_g3d_sync *gsync)
130 {
131    _eglGetSync(&gsync->base);
132 }
133
134 static INLINE void
135 egl_g3d_unref_sync(struct egl_g3d_sync *gsync)
136 {
137    if (_eglPutSync(&gsync->base)) {
138       pipe_condvar_destroy(gsync->condvar);
139       pipe_mutex_destroy(gsync->mutex);
140
141       if (gsync->fence) {
142          struct egl_g3d_display *gdpy =
143             egl_g3d_display(gsync->base.Resource.Display);
144          struct pipe_screen *screen = gdpy->native->screen;
145
146          screen->fence_reference(screen, &gsync->fence, NULL);
147       }
148
149       FREE(gsync);
150    }
151 }
152
153 _EGLSync *
154 egl_g3d_create_sync(_EGLDriver *drv, _EGLDisplay *dpy,
155                     EGLenum type, const EGLint *attrib_list)
156 {
157    _EGLContext *ctx = _eglGetCurrentContext();
158    struct egl_g3d_sync *gsync;
159    EGLint err;
160
161    if (!ctx || ctx->Resource.Display != dpy) {
162       _eglError(EGL_BAD_MATCH, "eglCreateSyncKHR");
163       return NULL;
164    }
165
166    gsync = CALLOC_STRUCT(egl_g3d_sync);
167    if (!gsync) {
168       _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
169       return NULL;
170    }
171
172    if (!_eglInitSync(&gsync->base, dpy, type, attrib_list)) {
173       FREE(gsync);
174       return NULL;
175    }
176
177    switch (type) {
178    case EGL_SYNC_REUSABLE_KHR:
179       err = EGL_SUCCESS;
180       break;
181    case EGL_SYNC_FENCE_KHR:
182       err = egl_g3d_insert_fence_sync(gsync);
183       break;
184    default:
185       err = EGL_BAD_ATTRIBUTE;
186       break;
187    }
188
189    if (err != EGL_SUCCESS) {
190       _eglError(err, "eglCreateSyncKHR");
191       FREE(gsync);
192       return NULL;
193    }
194
195    pipe_mutex_init(gsync->mutex);
196    pipe_condvar_init(gsync->condvar);
197
198    return &gsync->base;
199 }
200
201 EGLBoolean
202 egl_g3d_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
203 {
204    struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
205
206    switch (gsync->base.Type) {
207    case EGL_SYNC_REUSABLE_KHR:
208       /* signal the waiters */
209       if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) {
210          gsync->base.SyncStatus = EGL_SIGNALED_KHR;
211          egl_g3d_signal_sync_condvar(gsync);
212       }
213       break;
214    default:
215       break;
216    }
217
218    egl_g3d_unref_sync(gsync);
219
220    return EGL_TRUE;
221 }
222
223 EGLint
224 egl_g3d_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
225                          EGLint flags, EGLTimeKHR timeout)
226 {
227    struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
228    EGLint ret = EGL_CONDITION_SATISFIED_KHR;
229
230    if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) {
231       /* flush if there is a current context */
232       if (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) {
233          _EGLContext *ctx = _eglGetCurrentContext();
234          struct egl_g3d_context *gctx = egl_g3d_context(ctx);
235
236          if (gctx)
237             gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
238       }
239
240       if (timeout) {
241          /* reference the sync object in case it is destroyed while waiting */
242          egl_g3d_ref_sync(gsync);
243
244          switch (gsync->base.Type) {
245          case EGL_SYNC_REUSABLE_KHR:
246             ret = egl_g3d_wait_sync_condvar(gsync, timeout);
247             break;
248          case EGL_SYNC_FENCE_KHR:
249             ret = egl_g3d_wait_fence_sync(gsync, timeout);
250          default:
251             break;
252          }
253
254          egl_g3d_unref_sync(gsync);
255       }
256       else {
257          ret = EGL_TIMEOUT_EXPIRED_KHR;
258       }
259    }
260
261    return ret;
262 }
263
264 EGLBoolean
265 egl_g3d_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
266                     EGLenum mode)
267 {
268    struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
269
270    /* only for reusable sync */
271    if (sync->Type != EGL_SYNC_REUSABLE_KHR)
272       return _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR");
273
274    if (gsync->base.SyncStatus != mode) {
275       gsync->base.SyncStatus = mode;
276       if (mode == EGL_SIGNALED_KHR)
277          egl_g3d_signal_sync_condvar(gsync);
278    }
279
280    return EGL_TRUE;
281 }
282
283 #endif /* EGL_KHR_reusable_sync */