Home | History | Annotate | Download | only in main
      1 /*
      2  * Copyright  2009 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  */
     23 
     24 /**
     25  * \file syncobj.c
     26  * Sync object management.
     27  *
     28  * Unlike textures and other objects that are shared between contexts, sync
     29  * objects are not bound to the context.  As a result, the reference counting
     30  * and delete behavior of sync objects is slightly different.  References to
     31  * sync objects are added:
     32  *
     33  *    - By \c glFencSynce.  This sets the initial reference count to 1.
     34  *    - At the start of \c glClientWaitSync.  The reference is held for the
     35  *      duration of the wait call.
     36  *
     37  * References are removed:
     38  *
     39  *    - By \c glDeleteSync.
     40  *    - At the end of \c glClientWaitSync.
     41  *
     42  * Additionally, drivers may call \c _mesa_ref_sync_object and
     43  * \c _mesa_unref_sync_object as needed to implement \c ServerWaitSync.
     44  *
     45  * As with shader objects, sync object names become invalid as soon as
     46  * \c glDeleteSync is called.  For this reason \c glDeleteSync sets the
     47  * \c DeletePending flag.  All functions validate object handles by testing
     48  * this flag.
     49  *
     50  * \note
     51  * Only \c GL_ARB_sync objects are shared between contexts.  If support is ever
     52  * added for either \c GL_NV_fence or \c GL_APPLE_fence different semantics
     53  * will need to be implemented.
     54  *
     55  * \author Ian Romanick <ian.d.romanick (at) intel.com>
     56  */
     57 
     58 #include <inttypes.h>
     59 #include "glheader.h"
     60 #include "imports.h"
     61 #include "context.h"
     62 #include "macros.h"
     63 #include "get.h"
     64 #include "dispatch.h"
     65 #include "mtypes.h"
     66 #include "util/hash_table.h"
     67 #include "util/set.h"
     68 
     69 #include "syncobj.h"
     70 
     71 static struct gl_sync_object *
     72 _mesa_new_sync_object(struct gl_context *ctx, GLenum type)
     73 {
     74    struct gl_sync_object *s = CALLOC_STRUCT(gl_sync_object);
     75    (void) ctx;
     76    (void) type;
     77 
     78    return s;
     79 }
     80 
     81 
     82 static void
     83 _mesa_delete_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj)
     84 {
     85    (void) ctx;
     86    free(syncObj->Label);
     87    free(syncObj);
     88 }
     89 
     90 
     91 static void
     92 _mesa_fence_sync(struct gl_context *ctx, struct gl_sync_object *syncObj,
     93 		 GLenum condition, GLbitfield flags)
     94 {
     95    (void) ctx;
     96    (void) condition;
     97    (void) flags;
     98 
     99    syncObj->StatusFlag = 1;
    100 }
    101 
    102 
    103 static void
    104 _mesa_check_sync(struct gl_context *ctx, struct gl_sync_object *syncObj)
    105 {
    106    (void) ctx;
    107    (void) syncObj;
    108 
    109    /* No-op for software rendering.  Hardware drivers will need to determine
    110     * whether the state of the sync object has changed.
    111     */
    112 }
    113 
    114 
    115 static void
    116 _mesa_wait_sync(struct gl_context *ctx, struct gl_sync_object *syncObj,
    117 		GLbitfield flags, GLuint64 timeout)
    118 {
    119    (void) ctx;
    120    (void) syncObj;
    121    (void) flags;
    122    (void) timeout;
    123 
    124    /* No-op for software rendering.  Hardware drivers will need to wait until
    125     * the state of the sync object changes or the timeout expires.
    126     */
    127 }
    128 
    129 
    130 void
    131 _mesa_init_sync_object_functions(struct dd_function_table *driver)
    132 {
    133    driver->NewSyncObject = _mesa_new_sync_object;
    134    driver->FenceSync = _mesa_fence_sync;
    135    driver->DeleteSyncObject = _mesa_delete_sync_object;
    136    driver->CheckSync = _mesa_check_sync;
    137 
    138    /* Use the same no-op wait function for both.
    139     */
    140    driver->ClientWaitSync = _mesa_wait_sync;
    141    driver->ServerWaitSync = _mesa_wait_sync;
    142 }
    143 
    144 /**
    145  * Allocate/init the context state related to sync objects.
    146  */
    147 void
    148 _mesa_init_sync(struct gl_context *ctx)
    149 {
    150    (void) ctx;
    151 }
    152 
    153 
    154 /**
    155  * Free the context state related to sync objects.
    156  */
    157 void
    158 _mesa_free_sync_data(struct gl_context *ctx)
    159 {
    160    (void) ctx;
    161 }
    162 
    163 
    164 /**
    165  * Check if the given sync object is:
    166  *  - non-null
    167  *  - not in sync objects hash table
    168  *  - type is GL_SYNC_FENCE
    169  *  - not marked as deleted
    170  *
    171  * Returns the internal gl_sync_object pointer if the sync object is valid
    172  * or NULL if it isn't.
    173  *
    174  * If "incRefCount" is true, the reference count is incremented, which is
    175  * normally what you want; otherwise, a glDeleteSync from another thread
    176  * could delete the sync object while you are still working on it.
    177  */
    178 struct gl_sync_object *
    179 _mesa_get_and_ref_sync(struct gl_context *ctx, GLsync sync, bool incRefCount)
    180 {
    181    struct gl_sync_object *syncObj = (struct gl_sync_object *) sync;
    182    mtx_lock(&ctx->Shared->Mutex);
    183    if (syncObj != NULL
    184       && _mesa_set_search(ctx->Shared->SyncObjects, syncObj) != NULL
    185       && (syncObj->Type == GL_SYNC_FENCE)
    186       && !syncObj->DeletePending) {
    187      if (incRefCount) {
    188        syncObj->RefCount++;
    189      }
    190    } else {
    191      syncObj = NULL;
    192    }
    193    mtx_unlock(&ctx->Shared->Mutex);
    194    return syncObj;
    195 }
    196 
    197 
    198 void
    199 _mesa_unref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj,
    200                         int amount)
    201 {
    202    struct set_entry *entry;
    203 
    204    mtx_lock(&ctx->Shared->Mutex);
    205    syncObj->RefCount -= amount;
    206    if (syncObj->RefCount == 0) {
    207       entry = _mesa_set_search(ctx->Shared->SyncObjects, syncObj);
    208       assert (entry != NULL);
    209       _mesa_set_remove(ctx->Shared->SyncObjects, entry);
    210       mtx_unlock(&ctx->Shared->Mutex);
    211 
    212       ctx->Driver.DeleteSyncObject(ctx, syncObj);
    213    } else {
    214       mtx_unlock(&ctx->Shared->Mutex);
    215    }
    216 }
    217 
    218 
    219 GLboolean GLAPIENTRY
    220 _mesa_IsSync(GLsync sync)
    221 {
    222    GET_CURRENT_CONTEXT(ctx);
    223    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
    224 
    225    return _mesa_get_and_ref_sync(ctx, sync, false) ? GL_TRUE : GL_FALSE;
    226 }
    227 
    228 
    229 void GLAPIENTRY
    230 _mesa_DeleteSync(GLsync sync)
    231 {
    232    GET_CURRENT_CONTEXT(ctx);
    233    struct gl_sync_object *syncObj;
    234 
    235    /* From the GL_ARB_sync spec:
    236     *
    237     *    DeleteSync will silently ignore a <sync> value of zero. An
    238     *    INVALID_VALUE error is generated if <sync> is neither zero nor the
    239     *    name of a sync object.
    240     */
    241    if (sync == 0) {
    242       return;
    243    }
    244 
    245    syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
    246    if (!syncObj) {
    247       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteSync (not a valid sync object)");
    248       return;
    249    }
    250 
    251    /* If there are no client-waits or server-waits pending on this sync, delete
    252     * the underlying object. Note that we double-unref the object, as
    253     * _mesa_get_and_ref_sync above took an extra refcount to make sure the pointer
    254     * is valid for us to manipulate.
    255     */
    256    syncObj->DeletePending = GL_TRUE;
    257    _mesa_unref_sync_object(ctx, syncObj, 2);
    258 }
    259 
    260 
    261 GLsync GLAPIENTRY
    262 _mesa_FenceSync(GLenum condition, GLbitfield flags)
    263 {
    264    GET_CURRENT_CONTEXT(ctx);
    265    struct gl_sync_object *syncObj;
    266    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
    267 
    268    if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) {
    269       _mesa_error(ctx, GL_INVALID_ENUM, "glFenceSync(condition=0x%x)",
    270 		  condition);
    271       return 0;
    272    }
    273 
    274    if (flags != 0) {
    275       _mesa_error(ctx, GL_INVALID_VALUE, "glFenceSync(flags=0x%x)",
    276 		  condition);
    277       return 0;
    278    }
    279 
    280    syncObj = ctx->Driver.NewSyncObject(ctx, GL_SYNC_FENCE);
    281    if (syncObj != NULL) {
    282       syncObj->Type = GL_SYNC_FENCE;
    283       /* The name is not currently used, and it is never visible to
    284        * applications.  If sync support is extended to provide support for
    285        * NV_fence, this field will be used.  We'll also need to add an object
    286        * ID hashtable.
    287        */
    288       syncObj->Name = 1;
    289       syncObj->RefCount = 1;
    290       syncObj->DeletePending = GL_FALSE;
    291       syncObj->SyncCondition = condition;
    292       syncObj->Flags = flags;
    293       syncObj->StatusFlag = 0;
    294 
    295       ctx->Driver.FenceSync(ctx, syncObj, condition, flags);
    296 
    297       mtx_lock(&ctx->Shared->Mutex);
    298       _mesa_set_add(ctx->Shared->SyncObjects, syncObj);
    299       mtx_unlock(&ctx->Shared->Mutex);
    300 
    301       return (GLsync) syncObj;
    302    }
    303 
    304    return NULL;
    305 }
    306 
    307 
    308 GLenum GLAPIENTRY
    309 _mesa_ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
    310 {
    311    GET_CURRENT_CONTEXT(ctx);
    312    struct gl_sync_object *syncObj;
    313    GLenum ret;
    314    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_WAIT_FAILED);
    315 
    316    if ((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) != 0) {
    317       _mesa_error(ctx, GL_INVALID_VALUE, "glClientWaitSync(flags=0x%x)", flags);
    318       return GL_WAIT_FAILED;
    319    }
    320 
    321    syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
    322    if (!syncObj) {
    323       _mesa_error(ctx, GL_INVALID_VALUE, "glClientWaitSync (not a valid sync object)");
    324       return GL_WAIT_FAILED;
    325    }
    326 
    327    /* From the GL_ARB_sync spec:
    328     *
    329     *    ClientWaitSync returns one of four status values. A return value of
    330     *    ALREADY_SIGNALED indicates that <sync> was signaled at the time
    331     *    ClientWaitSync was called. ALREADY_SIGNALED will always be returned
    332     *    if <sync> was signaled, even if the value of <timeout> is zero.
    333     */
    334    ctx->Driver.CheckSync(ctx, syncObj);
    335    if (syncObj->StatusFlag) {
    336       ret = GL_ALREADY_SIGNALED;
    337    } else {
    338       if (timeout == 0) {
    339          ret = GL_TIMEOUT_EXPIRED;
    340       } else {
    341          ctx->Driver.ClientWaitSync(ctx, syncObj, flags, timeout);
    342 
    343          ret = syncObj->StatusFlag ? GL_CONDITION_SATISFIED : GL_TIMEOUT_EXPIRED;
    344       }
    345    }
    346 
    347    _mesa_unref_sync_object(ctx, syncObj, 1);
    348    return ret;
    349 }
    350 
    351 
    352 void GLAPIENTRY
    353 _mesa_WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
    354 {
    355    GET_CURRENT_CONTEXT(ctx);
    356    struct gl_sync_object *syncObj;
    357 
    358    if (flags != 0) {
    359       _mesa_error(ctx, GL_INVALID_VALUE, "glWaitSync(flags=0x%x)", flags);
    360       return;
    361    }
    362 
    363    if (timeout != GL_TIMEOUT_IGNORED) {
    364       _mesa_error(ctx, GL_INVALID_VALUE, "glWaitSync(timeout=0x%" PRIx64 ")",
    365                   (uint64_t) timeout);
    366       return;
    367    }
    368 
    369    syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
    370    if (!syncObj) {
    371       _mesa_error(ctx, GL_INVALID_VALUE, "glWaitSync (not a valid sync object)");
    372       return;
    373    }
    374 
    375    ctx->Driver.ServerWaitSync(ctx, syncObj, flags, timeout);
    376    _mesa_unref_sync_object(ctx, syncObj, 1);
    377 }
    378 
    379 
    380 void GLAPIENTRY
    381 _mesa_GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length,
    382 		GLint *values)
    383 {
    384    GET_CURRENT_CONTEXT(ctx);
    385    struct gl_sync_object *syncObj;
    386    GLsizei size = 0;
    387    GLint v[1];
    388 
    389    syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
    390    if (!syncObj) {
    391       _mesa_error(ctx, GL_INVALID_VALUE, "glGetSynciv (not a valid sync object)");
    392       return;
    393    }
    394 
    395    switch (pname) {
    396    case GL_OBJECT_TYPE:
    397       v[0] = syncObj->Type;
    398       size = 1;
    399       break;
    400 
    401    case GL_SYNC_CONDITION:
    402       v[0] = syncObj->SyncCondition;
    403       size = 1;
    404       break;
    405 
    406    case GL_SYNC_STATUS:
    407       /* Update the state of the sync by dipping into the driver.  Note that
    408        * this call won't block.  It just updates state in the common object
    409        * data from the current driver state.
    410        */
    411       ctx->Driver.CheckSync(ctx, syncObj);
    412 
    413       v[0] = (syncObj->StatusFlag) ? GL_SIGNALED : GL_UNSIGNALED;
    414       size = 1;
    415       break;
    416 
    417    case GL_SYNC_FLAGS:
    418       v[0] = syncObj->Flags;
    419       size = 1;
    420       break;
    421 
    422    default:
    423       _mesa_error(ctx, GL_INVALID_ENUM, "glGetSynciv(pname=0x%x)\n", pname);
    424       _mesa_unref_sync_object(ctx, syncObj, 1);
    425       return;
    426    }
    427 
    428    /* Section 4.1.3 (Sync Object Queries) of the OpenGL ES 3.10 spec says:
    429     *
    430     *    "An INVALID_VALUE error is generated if bufSize is negative."
    431     */
    432    if (bufSize < 0) {
    433       _mesa_error(ctx, GL_INVALID_VALUE, "glGetSynciv(pname=0x%x)\n", pname);
    434    }
    435 
    436    if (size > 0 && bufSize > 0) {
    437       const GLsizei copy_count = MIN2(size, bufSize);
    438 
    439       memcpy(values, v, sizeof(GLint) * copy_count);
    440    }
    441 
    442    if (length != NULL) {
    443       *length = size;
    444    }
    445 
    446    _mesa_unref_sync_object(ctx, syncObj, 1);
    447 }
    448