Home | History | Annotate | Download | only in common
      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 (at) 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 /**
     39  * Wait for the conditional variable.
     40  */
     41 static EGLint
     42 egl_g3d_wait_sync_condvar(struct egl_g3d_sync *gsync, EGLTimeKHR timeout)
     43 {
     44    _EGLDisplay *dpy = gsync->base.Resource.Display;
     45 
     46    pipe_mutex_lock(gsync->mutex);
     47 
     48    /* unlock display lock just before waiting */
     49    _eglUnlockMutex(&dpy->Mutex);
     50 
     51    /* No timed wait.  Always treat timeout as EGL_FOREVER_KHR */
     52    pipe_condvar_wait(gsync->condvar, gsync->mutex);
     53 
     54    _eglLockMutex(&dpy->Mutex);
     55 
     56    pipe_mutex_unlock(gsync->mutex);
     57 
     58    return EGL_CONDITION_SATISFIED_KHR;
     59 }
     60 
     61 /**
     62  * Signal the conditional variable.
     63  */
     64 static void
     65 egl_g3d_signal_sync_condvar(struct egl_g3d_sync *gsync)
     66 {
     67    pipe_mutex_lock(gsync->mutex);
     68    pipe_condvar_broadcast(gsync->condvar);
     69    pipe_mutex_unlock(gsync->mutex);
     70 }
     71 
     72 /**
     73  * Insert a fence command to the command stream of the current context.
     74  */
     75 static EGLint
     76 egl_g3d_insert_fence_sync(struct egl_g3d_sync *gsync)
     77 {
     78    _EGLContext *ctx = _eglGetCurrentContext();
     79    struct egl_g3d_context *gctx = egl_g3d_context(ctx);
     80 
     81    /* already checked in egl_g3d_create_sync */
     82    assert(gctx);
     83 
     84    /* insert the fence command */
     85    gctx->stctxi->flush(gctx->stctxi, 0x0, &gsync->fence);
     86    if (!gsync->fence)
     87       gsync->base.SyncStatus = EGL_SIGNALED_KHR;
     88 
     89    return EGL_SUCCESS;
     90 }
     91 
     92 /**
     93  * Wait for the fence sync to be signaled.
     94  */
     95 static EGLint
     96 egl_g3d_wait_fence_sync(struct egl_g3d_sync *gsync, EGLTimeKHR timeout)
     97 {
     98    EGLint ret;
     99 
    100    if (gsync->fence) {
    101       _EGLDisplay *dpy = gsync->base.Resource.Display;
    102       struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
    103       struct pipe_screen *screen = gdpy->native->screen;
    104       struct pipe_fence_handle *fence = gsync->fence;
    105 
    106       gsync->fence = NULL;
    107 
    108       _eglUnlockMutex(&dpy->Mutex);
    109       /* no timed finish? */
    110       screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
    111       ret = EGL_CONDITION_SATISFIED_KHR;
    112       _eglLockMutex(&dpy->Mutex);
    113 
    114       gsync->base.SyncStatus = EGL_SIGNALED_KHR;
    115 
    116       screen->fence_reference(screen, &fence, NULL);
    117       egl_g3d_signal_sync_condvar(gsync);
    118    }
    119    else {
    120       ret = egl_g3d_wait_sync_condvar(gsync, timeout);
    121    }
    122 
    123    return ret;
    124 }
    125 
    126 static INLINE void
    127 egl_g3d_ref_sync(struct egl_g3d_sync *gsync)
    128 {
    129    _eglGetSync(&gsync->base);
    130 }
    131 
    132 static INLINE void
    133 egl_g3d_unref_sync(struct egl_g3d_sync *gsync)
    134 {
    135    if (_eglPutSync(&gsync->base)) {
    136       pipe_condvar_destroy(gsync->condvar);
    137       pipe_mutex_destroy(gsync->mutex);
    138 
    139       if (gsync->fence) {
    140          struct egl_g3d_display *gdpy =
    141             egl_g3d_display(gsync->base.Resource.Display);
    142          struct pipe_screen *screen = gdpy->native->screen;
    143 
    144          screen->fence_reference(screen, &gsync->fence, NULL);
    145       }
    146 
    147       FREE(gsync);
    148    }
    149 }
    150 
    151 _EGLSync *
    152 egl_g3d_create_sync(_EGLDriver *drv, _EGLDisplay *dpy,
    153                     EGLenum type, const EGLint *attrib_list)
    154 {
    155    _EGLContext *ctx = _eglGetCurrentContext();
    156    struct egl_g3d_sync *gsync;
    157    EGLint err;
    158 
    159    if (!ctx || ctx->Resource.Display != dpy) {
    160       _eglError(EGL_BAD_MATCH, "eglCreateSyncKHR");
    161       return NULL;
    162    }
    163 
    164    gsync = CALLOC_STRUCT(egl_g3d_sync);
    165    if (!gsync) {
    166       _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 
    199 EGLBoolean
    200 egl_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 
    221 EGLint
    222 egl_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 
    262 EGLBoolean
    263 egl_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