egl_g3d_sync.c revision f957cac772d34b3406be3236b81571e456ee40e8
15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Mesa 3-D graphics library
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Version:  7.9
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (C) 2010 LunarG Inc.
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Permission is hereby granted, free of charge, to any person obtaining a
85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * copy of this software and associated documentation files (the "Software"),
95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * to deal in the Software without restriction, including without limitation
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * the rights to use, copy, modify, merge, publish, distribute, sublicense,
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * and/or sell copies of the Software, and to permit persons to whom the
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Software is furnished to do so, subject to the following conditions:
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * The above copyright notice and this permission notice shall be included
155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * in all copies or substantial portions of the Software.
165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
219b3a4b03315af9bcdf282243059e8fd1ce1c5c70David 'Digit' Turner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2226b47fe632cf0de7962e79a1113d8a5d93459262David 'Digit' Turner * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2334c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner * DEALINGS IN THE SOFTWARE.
246af6765e2f3bc930d0dce21d752bea570a1b1362David 'Digit' Turner *
255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Authors:
265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *    Chia-I Wu <olv@lunarg.com>
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "util/u_memory.h"
305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "util/u_atomic.h"
315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "os/os_thread.h"
325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "eglsync.h"
335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "eglcurrent.h"
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
35bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turner#include "egl_g3d.h"
365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "egl_g3d_sync.h"
375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/**
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Wait for the conditional variable.
405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic EGLint
425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneregl_g3d_wait_sync_condvar(struct egl_g3d_sync *gsync, EGLTimeKHR timeout)
43bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turner{
445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   _EGLDisplay *dpy = gsync->base.Resource.Display;
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   pipe_mutex_lock(gsync->mutex);
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   /* unlock display lock just before waiting */
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   _eglUnlockMutex(&dpy->Mutex);
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   /* No timed wait.  Always treat timeout as EGL_FOREVER_KHR */
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   pipe_condvar_wait(gsync->condvar, gsync->mutex);
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   _eglLockMutex(&dpy->Mutex);
555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   pipe_mutex_unlock(gsync->mutex);
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   return EGL_CONDITION_SATISFIED_KHR;
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/**
625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Signal the conditional variable.
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneregl_g3d_signal_sync_condvar(struct egl_g3d_sync *gsync)
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   pipe_mutex_lock(gsync->mutex);
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   pipe_condvar_broadcast(gsync->condvar);
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   pipe_mutex_unlock(gsync->mutex);
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/**
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Insert a fence command to the command stream of the current context.
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic EGLint
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneregl_g3d_insert_fence_sync(struct egl_g3d_sync *gsync)
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   _EGLContext *ctx = _eglGetCurrentContext();
79bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turner   struct egl_g3d_context *gctx = egl_g3d_context(ctx);
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   /* already checked in egl_g3d_create_sync */
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   assert(gctx);
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   /* insert the fence command */
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   gctx->stctxi->flush(gctx->stctxi, 0x0, &gsync->fence);
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   if (!gsync->fence)
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      gsync->base.SyncStatus = EGL_SIGNALED_KHR;
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   return EGL_SUCCESS;
90bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turner}
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/**
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Wait for the fence sync to be signaled.
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic EGLint
965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneregl_g3d_wait_fence_sync(struct egl_g3d_sync *gsync, EGLTimeKHR timeout)
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   EGLint ret;
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   if (gsync->fence) {
1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      _EGLDisplay *dpy = gsync->base.Resource.Display;
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      struct pipe_screen *screen = gdpy->native->screen;
1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      struct pipe_fence_handle *fence = gsync->fence;
1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      gsync->fence = NULL;
1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      _eglUnlockMutex(&dpy->Mutex);
1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      /* no timed finish? */
1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      ret = EGL_CONDITION_SATISFIED_KHR;
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      _eglLockMutex(&dpy->Mutex);
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      gsync->base.SyncStatus = EGL_SIGNALED_KHR;
1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      screen->fence_reference(screen, &fence, NULL);
1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      egl_g3d_signal_sync_condvar(gsync);
1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   }
1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   else {
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      ret = egl_g3d_wait_sync_condvar(gsync, timeout);
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   }
122aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner
123aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner   return ret;
1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic INLINE void
1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneregl_g3d_ref_sync(struct egl_g3d_sync *gsync)
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   _eglGetSync(&gsync->base);
130bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turner}
1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic INLINE void
1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneregl_g3d_unref_sync(struct egl_g3d_sync *gsync)
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   if (_eglPutSync(&gsync->base)) {
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      pipe_condvar_destroy(gsync->condvar);
1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      pipe_mutex_destroy(gsync->mutex);
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      if (gsync->fence) {
1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         struct egl_g3d_display *gdpy =
141bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turner            egl_g3d_display(gsync->base.Resource.Display);
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         struct pipe_screen *screen = gdpy->native->screen;
1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         screen->fence_reference(screen, &gsync->fence, NULL);
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      }
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      FREE(gsync);
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   }
1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner_EGLSync *
1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turneregl_g3d_create_sync(_EGLDriver *drv, _EGLDisplay *dpy,
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    EGLenum type, const EGLint *attrib_list)
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   _EGLContext *ctx = _eglGetCurrentContext();
1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   struct egl_g3d_sync *gsync;
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   EGLint err;
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   if (!ctx || ctx->Resource.Display != dpy) {
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      _eglError(EGL_BAD_MATCH, "eglCreateSyncKHR");
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      return NULL;
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   }
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   gsync = CALLOC_STRUCT(egl_g3d_sync);
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   if (!gsync) {
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
167      return NULL;
168   }
169
170   if (!_eglInitSync(&gsync->base, dpy, type, attrib_list)) {
171      FREE(gsync);
172      return NULL;
173   }
174
175   switch (type) {
176   case EGL_SYNC_REUSABLE_KHR:
177      err = EGL_SUCCESS;
178      break;
179   case EGL_SYNC_FENCE_KHR:
180      err = egl_g3d_insert_fence_sync(gsync);
181      break;
182   default:
183      err = EGL_BAD_ATTRIBUTE;
184      break;
185   }
186
187   if (err != EGL_SUCCESS) {
188      _eglError(err, "eglCreateSyncKHR");
189      FREE(gsync);
190      return NULL;
191   }
192
193   pipe_mutex_init(gsync->mutex);
194   pipe_condvar_init(gsync->condvar);
195
196   return &gsync->base;
197}
198
199EGLBoolean
200egl_g3d_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
201{
202   struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
203
204   switch (gsync->base.Type) {
205   case EGL_SYNC_REUSABLE_KHR:
206      /* signal the waiters */
207      if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) {
208         gsync->base.SyncStatus = EGL_SIGNALED_KHR;
209         egl_g3d_signal_sync_condvar(gsync);
210      }
211      break;
212   default:
213      break;
214   }
215
216   egl_g3d_unref_sync(gsync);
217
218   return EGL_TRUE;
219}
220
221EGLint
222egl_g3d_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
223                         EGLint flags, EGLTimeKHR timeout)
224{
225   struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
226   EGLint ret = EGL_CONDITION_SATISFIED_KHR;
227
228   if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) {
229      /* flush if there is a current context */
230      if (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) {
231         _EGLContext *ctx = _eglGetCurrentContext();
232         struct egl_g3d_context *gctx = egl_g3d_context(ctx);
233
234         if (gctx)
235            gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
236      }
237
238      if (timeout) {
239         /* reference the sync object in case it is destroyed while waiting */
240         egl_g3d_ref_sync(gsync);
241
242         switch (gsync->base.Type) {
243         case EGL_SYNC_REUSABLE_KHR:
244            ret = egl_g3d_wait_sync_condvar(gsync, timeout);
245            break;
246         case EGL_SYNC_FENCE_KHR:
247            ret = egl_g3d_wait_fence_sync(gsync, timeout);
248         default:
249            break;
250         }
251
252         egl_g3d_unref_sync(gsync);
253      }
254      else {
255         ret = EGL_TIMEOUT_EXPIRED_KHR;
256      }
257   }
258
259   return ret;
260}
261
262EGLBoolean
263egl_g3d_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
264                    EGLenum mode)
265{
266   struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
267
268   /* only for reusable sync */
269   if (sync->Type != EGL_SYNC_REUSABLE_KHR)
270      return _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR");
271
272   if (gsync->base.SyncStatus != mode) {
273      gsync->base.SyncStatus = mode;
274      if (mode == EGL_SIGNALED_KHR)
275         egl_g3d_signal_sync_condvar(gsync);
276   }
277
278   return EGL_TRUE;
279}
280