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