egl_g3d_sync.c revision f945cb651518025159499999527ff5d4536acaf8
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); 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 p_atomic_inc(&gsync->refs); 132} 133 134static INLINE void 135egl_g3d_unref_sync(struct egl_g3d_sync *gsync) 136{ 137 if (p_atomic_dec_zero(&gsync->refs)) { 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 p_atomic_set(&gsync->refs, 1); 198 199 return &gsync->base; 200} 201 202EGLBoolean 203egl_g3d_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) 204{ 205 struct egl_g3d_sync *gsync = egl_g3d_sync(sync); 206 207 switch (gsync->base.Type) { 208 case EGL_SYNC_REUSABLE_KHR: 209 /* signal the waiters */ 210 if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) { 211 gsync->base.SyncStatus = EGL_SIGNALED_KHR; 212 egl_g3d_signal_sync_condvar(gsync); 213 } 214 break; 215 default: 216 break; 217 } 218 219 egl_g3d_unref_sync(gsync); 220 221 return EGL_TRUE; 222} 223 224EGLint 225egl_g3d_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, 226 EGLint flags, EGLTimeKHR timeout) 227{ 228 struct egl_g3d_sync *gsync = egl_g3d_sync(sync); 229 EGLint ret = EGL_CONDITION_SATISFIED_KHR; 230 231 if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) { 232 /* flush if there is a current context */ 233 if (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) { 234 _EGLContext *ctx = _eglGetCurrentContext(); 235 struct egl_g3d_context *gctx = egl_g3d_context(ctx); 236 237 if (gctx) 238 gctx->stctxi->flush(gctx->stctxi, PIPE_FLUSH_RENDER_CACHE , NULL); 239 } 240 241 if (timeout) { 242 /* reference the sync object in case it is destroyed while waiting */ 243 egl_g3d_ref_sync(gsync); 244 245 switch (gsync->base.Type) { 246 case EGL_SYNC_REUSABLE_KHR: 247 ret = egl_g3d_wait_sync_condvar(gsync, timeout); 248 break; 249 case EGL_SYNC_FENCE_KHR: 250 ret = egl_g3d_wait_fence_sync(gsync, timeout); 251 default: 252 break; 253 } 254 255 egl_g3d_unref_sync(gsync); 256 } 257 else { 258 ret = EGL_TIMEOUT_EXPIRED_KHR; 259 } 260 } 261 262 return ret; 263} 264 265EGLBoolean 266egl_g3d_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, 267 EGLenum mode) 268{ 269 struct egl_g3d_sync *gsync = egl_g3d_sync(sync); 270 271 /* only for reusable sync */ 272 if (sync->Type != EGL_SYNC_REUSABLE_KHR) 273 return _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR"); 274 275 if (gsync->base.SyncStatus != mode) { 276 gsync->base.SyncStatus = mode; 277 if (mode == EGL_SIGNALED_KHR) 278 egl_g3d_signal_sync_condvar(gsync); 279 } 280 281 return EGL_TRUE; 282} 283 284#endif /* EGL_KHR_reusable_sync */ 285