egl_g3d_sync.c revision b39bccbd4ed71e9585da4cf5acf7b887b2e90899
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 */
43static EGLint
44egl_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 */
66static void
67egl_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 */
77static EGLint
78egl_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 */
97static EGLint
98egl_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, 0x0, 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
128static INLINE void
129egl_g3d_ref_sync(struct egl_g3d_sync *gsync)
130{
131   _eglGetSync(&gsync->base);
132}
133
134static INLINE void
135egl_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 *
154egl_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
201EGLBoolean
202egl_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
223EGLint
224egl_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, PIPE_FLUSH_RENDER_CACHE , 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
264EGLBoolean
265egl_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 */
284