egl_g3d_sync.c revision 4b2495661f3a5ac8ed07b68c5d5bf90adee2c37d
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
74static INLINE void
75egl_g3d_ref_sync(struct egl_g3d_sync *gsync)
76{
77   p_atomic_inc(&gsync->refs);
78}
79
80static INLINE void
81egl_g3d_unref_sync(struct egl_g3d_sync *gsync)
82{
83   if (p_atomic_dec_zero(&gsync->refs)) {
84      pipe_condvar_destroy(gsync->condvar);
85      pipe_mutex_destroy(gsync->mutex);
86
87      FREE(gsync);
88   }
89}
90
91_EGLSync *
92egl_g3d_create_sync(_EGLDriver *drv, _EGLDisplay *dpy,
93                    EGLenum type, const EGLint *attrib_list)
94{
95   _EGLContext *ctx = _eglGetCurrentContext();
96   struct egl_g3d_sync *gsync;
97   EGLint err;
98
99   if (!ctx || ctx->Resource.Display != dpy) {
100      _eglError(EGL_BAD_MATCH, "eglCreateSyncKHR");
101      return NULL;
102   }
103
104   gsync = CALLOC_STRUCT(egl_g3d_sync);
105   if (!gsync) {
106      _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
107      return NULL;
108   }
109
110   if (!_eglInitSync(&gsync->base, dpy, type, attrib_list)) {
111      FREE(gsync);
112      return NULL;
113   }
114
115   switch (type) {
116   case EGL_SYNC_REUSABLE_KHR:
117      err = EGL_SUCCESS;
118      break;
119   default:
120      err = EGL_BAD_ATTRIBUTE;
121      break;
122   }
123
124   if (err != EGL_SUCCESS) {
125      _eglError(err, "eglCreateSyncKHR");
126      FREE(gsync);
127      return NULL;
128   }
129
130   pipe_mutex_init(gsync->mutex);
131   pipe_condvar_init(gsync->condvar);
132   p_atomic_set(&gsync->refs, 1);
133
134   return &gsync->base;
135}
136
137EGLBoolean
138egl_g3d_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
139{
140   struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
141
142   switch (gsync->base.Type) {
143   case EGL_SYNC_REUSABLE_KHR:
144      /* signal the waiters */
145      if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) {
146         gsync->base.SyncStatus = EGL_SIGNALED_KHR;
147         egl_g3d_signal_sync_condvar(gsync);
148      }
149      break;
150   default:
151      break;
152   }
153
154   egl_g3d_unref_sync(gsync);
155
156   return EGL_TRUE;
157}
158
159EGLint
160egl_g3d_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
161                         EGLint flags, EGLTimeKHR timeout)
162{
163   struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
164   EGLint ret = EGL_CONDITION_SATISFIED_KHR;
165
166   if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) {
167      /* flush if there is a current context */
168      if (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) {
169         _EGLContext *ctx = _eglGetCurrentContext();
170         struct egl_g3d_context *gctx = egl_g3d_context(ctx);
171
172         if (gctx)
173            gctx->stctxi->flush(gctx->stctxi, PIPE_FLUSH_RENDER_CACHE , NULL);
174      }
175
176      if (timeout) {
177         /* reference the sync object in case it is destroyed while waiting */
178         egl_g3d_ref_sync(gsync);
179
180         switch (gsync->base.Type) {
181         case EGL_SYNC_REUSABLE_KHR:
182            ret = egl_g3d_wait_sync_condvar(gsync, timeout);
183            break;
184         default:
185            break;
186         }
187
188         egl_g3d_unref_sync(gsync);
189      }
190      else {
191         ret = EGL_TIMEOUT_EXPIRED_KHR;
192      }
193   }
194
195   return ret;
196}
197
198EGLBoolean
199egl_g3d_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
200                    EGLenum mode)
201{
202   struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
203
204   /* only for reusable sync */
205   if (sync->Type != EGL_SYNC_REUSABLE_KHR)
206      return _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR");
207
208   if (gsync->base.SyncStatus != mode) {
209      gsync->base.SyncStatus = mode;
210      if (mode == EGL_SIGNALED_KHR)
211         egl_g3d_signal_sync_condvar(gsync);
212   }
213
214   return EGL_TRUE;
215}
216
217#endif /* EGL_KHR_reusable_sync */
218