Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 2010 LunarG Inc.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22.  * DEALINGS IN THE SOFTWARE.
  23.  *
  24.  * Authors:
  25.  *    Chia-I Wu <olv@lunarg.com>
  26.  */
  27.  
  28. #include "util/u_memory.h"
  29. #include "util/u_atomic.h"
  30. #include "os/os_thread.h"
  31. #include "eglsync.h"
  32. #include "eglcurrent.h"
  33.  
  34. #include "egl_g3d.h"
  35. #include "egl_g3d_sync.h"
  36.  
  37. /**
  38.  * Wait for the conditional variable.
  39.  */
  40. static EGLint
  41. egl_g3d_wait_sync_condvar(struct egl_g3d_sync *gsync, EGLTimeKHR timeout)
  42. {
  43.    _EGLDisplay *dpy = gsync->base.Resource.Display;
  44.  
  45.    pipe_mutex_lock(gsync->mutex);
  46.  
  47.    /* unlock display lock just before waiting */
  48.    _eglUnlockMutex(&dpy->Mutex);
  49.  
  50.    /* No timed wait.  Always treat timeout as EGL_FOREVER_KHR */
  51.    pipe_condvar_wait(gsync->condvar, gsync->mutex);
  52.  
  53.    _eglLockMutex(&dpy->Mutex);
  54.  
  55.    pipe_mutex_unlock(gsync->mutex);
  56.  
  57.    return EGL_CONDITION_SATISFIED_KHR;
  58. }
  59.  
  60. /**
  61.  * Signal the conditional variable.
  62.  */
  63. static void
  64. egl_g3d_signal_sync_condvar(struct egl_g3d_sync *gsync)
  65. {
  66.    pipe_mutex_lock(gsync->mutex);
  67.    pipe_condvar_broadcast(gsync->condvar);
  68.    pipe_mutex_unlock(gsync->mutex);
  69. }
  70.  
  71. /**
  72.  * Insert a fence command to the command stream of the current context.
  73.  */
  74. static EGLint
  75. egl_g3d_insert_fence_sync(struct egl_g3d_sync *gsync)
  76. {
  77.    _EGLContext *ctx = _eglGetCurrentContext();
  78.    struct egl_g3d_context *gctx = egl_g3d_context(ctx);
  79.  
  80.    /* already checked in egl_g3d_create_sync */
  81.    assert(gctx);
  82.  
  83.    /* insert the fence command */
  84.    gctx->stctxi->flush(gctx->stctxi, 0x0, &gsync->fence);
  85.    if (!gsync->fence)
  86.       gsync->base.SyncStatus = EGL_SIGNALED_KHR;
  87.  
  88.    return EGL_SUCCESS;
  89. }
  90.  
  91. /**
  92.  * Wait for the fence sync to be signaled.
  93.  */
  94. static EGLint
  95. egl_g3d_wait_fence_sync(struct egl_g3d_sync *gsync, EGLTimeKHR timeout)
  96. {
  97.    EGLint ret;
  98.  
  99.    if (gsync->fence) {
  100.       _EGLDisplay *dpy = gsync->base.Resource.Display;
  101.       struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
  102.       struct pipe_screen *screen = gdpy->native->screen;
  103.       struct pipe_fence_handle *fence = gsync->fence;
  104.  
  105.       gsync->fence = NULL;
  106.  
  107.       _eglUnlockMutex(&dpy->Mutex);
  108.       /* no timed finish? */
  109.       screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
  110.       ret = EGL_CONDITION_SATISFIED_KHR;
  111.       _eglLockMutex(&dpy->Mutex);
  112.  
  113.       gsync->base.SyncStatus = EGL_SIGNALED_KHR;
  114.  
  115.       screen->fence_reference(screen, &fence, NULL);
  116.       egl_g3d_signal_sync_condvar(gsync);
  117.    }
  118.    else {
  119.       ret = egl_g3d_wait_sync_condvar(gsync, timeout);
  120.    }
  121.  
  122.    return ret;
  123. }
  124.  
  125. static INLINE void
  126. egl_g3d_ref_sync(struct egl_g3d_sync *gsync)
  127. {
  128.    _eglGetSync(&gsync->base);
  129. }
  130.  
  131. static INLINE void
  132. egl_g3d_unref_sync(struct egl_g3d_sync *gsync)
  133. {
  134.    if (_eglPutSync(&gsync->base)) {
  135.       pipe_condvar_destroy(gsync->condvar);
  136.       pipe_mutex_destroy(gsync->mutex);
  137.  
  138.       if (gsync->fence) {
  139.          struct egl_g3d_display *gdpy =
  140.             egl_g3d_display(gsync->base.Resource.Display);
  141.          struct pipe_screen *screen = gdpy->native->screen;
  142.  
  143.          screen->fence_reference(screen, &gsync->fence, NULL);
  144.       }
  145.  
  146.       FREE(gsync);
  147.    }
  148. }
  149.  
  150. _EGLSync *
  151. egl_g3d_create_sync(_EGLDriver *drv, _EGLDisplay *dpy,
  152.                     EGLenum type, const EGLint *attrib_list)
  153. {
  154.    _EGLContext *ctx = _eglGetCurrentContext();
  155.    struct egl_g3d_sync *gsync;
  156.    EGLint err;
  157.  
  158.    if (!ctx || ctx->Resource.Display != dpy) {
  159.       _eglError(EGL_BAD_MATCH, "eglCreateSyncKHR");
  160.       return NULL;
  161.    }
  162.  
  163.    gsync = CALLOC_STRUCT(egl_g3d_sync);
  164.    if (!gsync) {
  165.       _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
  166.       return NULL;
  167.    }
  168.  
  169.    if (!_eglInitSync(&gsync->base, dpy, type, attrib_list)) {
  170.       FREE(gsync);
  171.       return NULL;
  172.    }
  173.  
  174.    switch (type) {
  175.    case EGL_SYNC_REUSABLE_KHR:
  176.       err = EGL_SUCCESS;
  177.       break;
  178.    case EGL_SYNC_FENCE_KHR:
  179.       err = egl_g3d_insert_fence_sync(gsync);
  180.       break;
  181.    default:
  182.       err = EGL_BAD_ATTRIBUTE;
  183.       break;
  184.    }
  185.  
  186.    if (err != EGL_SUCCESS) {
  187.       _eglError(err, "eglCreateSyncKHR");
  188.       FREE(gsync);
  189.       return NULL;
  190.    }
  191.  
  192.    pipe_mutex_init(gsync->mutex);
  193.    pipe_condvar_init(gsync->condvar);
  194.  
  195.    return &gsync->base;
  196. }
  197.  
  198. EGLBoolean
  199. egl_g3d_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
  200. {
  201.    struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
  202.  
  203.    switch (gsync->base.Type) {
  204.    case EGL_SYNC_REUSABLE_KHR:
  205.       /* signal the waiters */
  206.       if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) {
  207.          gsync->base.SyncStatus = EGL_SIGNALED_KHR;
  208.          egl_g3d_signal_sync_condvar(gsync);
  209.       }
  210.       break;
  211.    default:
  212.       break;
  213.    }
  214.  
  215.    egl_g3d_unref_sync(gsync);
  216.  
  217.    return EGL_TRUE;
  218. }
  219.  
  220. EGLint
  221. egl_g3d_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
  222.                          EGLint flags, EGLTimeKHR timeout)
  223. {
  224.    struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
  225.    EGLint ret = EGL_CONDITION_SATISFIED_KHR;
  226.  
  227.    if (gsync->base.SyncStatus != EGL_SIGNALED_KHR) {
  228.       /* flush if there is a current context */
  229.       if (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) {
  230.          _EGLContext *ctx = _eglGetCurrentContext();
  231.          struct egl_g3d_context *gctx = egl_g3d_context(ctx);
  232.  
  233.          if (gctx)
  234.             gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
  235.       }
  236.  
  237.       if (timeout) {
  238.          /* reference the sync object in case it is destroyed while waiting */
  239.          egl_g3d_ref_sync(gsync);
  240.  
  241.          switch (gsync->base.Type) {
  242.          case EGL_SYNC_REUSABLE_KHR:
  243.             ret = egl_g3d_wait_sync_condvar(gsync, timeout);
  244.             break;
  245.          case EGL_SYNC_FENCE_KHR:
  246.             ret = egl_g3d_wait_fence_sync(gsync, timeout);
  247.          default:
  248.             break;
  249.          }
  250.  
  251.          egl_g3d_unref_sync(gsync);
  252.       }
  253.       else {
  254.          ret = EGL_TIMEOUT_EXPIRED_KHR;
  255.       }
  256.    }
  257.  
  258.    return ret;
  259. }
  260.  
  261. EGLBoolean
  262. egl_g3d_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
  263.                     EGLenum mode)
  264. {
  265.    struct egl_g3d_sync *gsync = egl_g3d_sync(sync);
  266.  
  267.    /* only for reusable sync */
  268.    if (sync->Type != EGL_SYNC_REUSABLE_KHR)
  269.       return _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR");
  270.  
  271.    if (gsync->base.SyncStatus != mode) {
  272.       gsync->base.SyncStatus = mode;
  273.       if (mode == EGL_SIGNALED_KHR)
  274.          egl_g3d_signal_sync_condvar(gsync);
  275.    }
  276.  
  277.    return EGL_TRUE;
  278. }
  279.