• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@intel.com>
56  */
57 
58 #include <inttypes.h>
59 #include "glheader.h"
60 
61 #include "context.h"
62 #include "macros.h"
63 #include "get.h"
64 #include "mtypes.h"
65 #include "util/hash_table.h"
66 #include "util/set.h"
67 #include "util/u_memory.h"
68 
69 #include "syncobj.h"
70 
71 #include "api_exec_decl.h"
72 
73 #include "pipe/p_context.h"
74 #include "pipe/p_screen.h"
75 
76 /**
77  * Allocate/init the context state related to sync objects.
78  */
79 void
_mesa_init_sync(struct gl_context * ctx)80 _mesa_init_sync(struct gl_context *ctx)
81 {
82    (void) ctx;
83 }
84 
85 
86 /**
87  * Free the context state related to sync objects.
88  */
89 void
_mesa_free_sync_data(struct gl_context * ctx)90 _mesa_free_sync_data(struct gl_context *ctx)
91 {
92    (void) ctx;
93 }
94 
95 static struct gl_sync_object *
new_sync_object(struct gl_context * ctx)96 new_sync_object(struct gl_context *ctx)
97 {
98    struct gl_sync_object *so = CALLOC_STRUCT(gl_sync_object);
99 
100    simple_mtx_init(&so->mutex, mtx_plain);
101    return so;
102 }
103 
104 static void
delete_sync_object(struct gl_context * ctx,struct gl_sync_object * obj)105 delete_sync_object(struct gl_context *ctx,
106                       struct gl_sync_object *obj)
107 {
108    struct pipe_screen *screen = ctx->pipe->screen;
109 
110    screen->fence_reference(screen, &obj->fence, NULL);
111    simple_mtx_destroy(&obj->mutex);
112    free(obj->Label);
113    FREE(obj);
114 }
115 
116 static void
__client_wait_sync(struct gl_context * ctx,struct gl_sync_object * obj,GLbitfield flags,GLuint64 timeout)117 __client_wait_sync(struct gl_context *ctx,
118                    struct gl_sync_object *obj,
119                    GLbitfield flags, GLuint64 timeout)
120 {
121    struct pipe_context *pipe = ctx->pipe;
122    struct pipe_screen *screen = pipe->screen;
123    struct pipe_fence_handle *fence = NULL;
124 
125    /* If the fence doesn't exist, assume it's signalled. */
126    simple_mtx_lock(&obj->mutex);
127    if (!obj->fence) {
128       simple_mtx_unlock(&obj->mutex);
129       obj->StatusFlag = GL_TRUE;
130       return;
131    }
132 
133    /* We need a local copy of the fence pointer, so that we can call
134     * fence_finish unlocked.
135     */
136    screen->fence_reference(screen, &fence, obj->fence);
137    simple_mtx_unlock(&obj->mutex);
138 
139    /* Section 4.1.2 of OpenGL 4.5 (Compatibility Profile) says:
140     *    [...] if ClientWaitSync is called and all of the following are true:
141     *    - the SYNC_FLUSH_COMMANDS_BIT bit is set in flags,
142     *    - sync is unsignaled when ClientWaitSync is called,
143     *    - and the calls to ClientWaitSync and FenceSync were issued from
144     *      the same context,
145     *    then the GL will behave as if the equivalent of Flush were inserted
146     *    immediately after the creation of sync.
147     *
148     * Assume GL_SYNC_FLUSH_COMMANDS_BIT is always set, because applications
149     * forget to set it.
150     */
151    if (screen->fence_finish(screen, pipe, fence, timeout)) {
152       simple_mtx_lock(&obj->mutex);
153       screen->fence_reference(screen, &obj->fence, NULL);
154       simple_mtx_unlock(&obj->mutex);
155       obj->StatusFlag = GL_TRUE;
156    }
157    screen->fence_reference(screen, &fence, NULL);
158 }
159 
160 /**
161  * Check if the given sync object is:
162  *  - non-null
163  *  - not in sync objects hash table
164  *  - not marked as deleted
165  *
166  * Returns the internal gl_sync_object pointer if the sync object is valid
167  * or NULL if it isn't.
168  *
169  * If "incRefCount" is true, the reference count is incremented, which is
170  * normally what you want; otherwise, a glDeleteSync from another thread
171  * could delete the sync object while you are still working on it.
172  */
173 struct gl_sync_object *
_mesa_get_and_ref_sync(struct gl_context * ctx,GLsync sync,bool incRefCount)174 _mesa_get_and_ref_sync(struct gl_context *ctx, GLsync sync, bool incRefCount)
175 {
176    struct gl_sync_object *syncObj = (struct gl_sync_object *) sync;
177    simple_mtx_lock(&ctx->Shared->Mutex);
178    if (syncObj != NULL
179       && _mesa_set_search(ctx->Shared->SyncObjects, syncObj) != NULL
180       && !syncObj->DeletePending) {
181      if (incRefCount) {
182        syncObj->RefCount++;
183      }
184    } else {
185      syncObj = NULL;
186    }
187    simple_mtx_unlock(&ctx->Shared->Mutex);
188    return syncObj;
189 }
190 
191 
192 void
_mesa_unref_sync_object(struct gl_context * ctx,struct gl_sync_object * syncObj,int amount)193 _mesa_unref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj,
194                         int amount)
195 {
196    struct set_entry *entry;
197 
198    simple_mtx_lock(&ctx->Shared->Mutex);
199    syncObj->RefCount -= amount;
200    if (syncObj->RefCount == 0) {
201       entry = _mesa_set_search(ctx->Shared->SyncObjects, syncObj);
202       assert (entry != NULL);
203       _mesa_set_remove(ctx->Shared->SyncObjects, entry);
204       simple_mtx_unlock(&ctx->Shared->Mutex);
205 
206       delete_sync_object(ctx, syncObj);
207    } else {
208       simple_mtx_unlock(&ctx->Shared->Mutex);
209    }
210 }
211 
212 
213 GLboolean GLAPIENTRY
_mesa_IsSync(GLsync sync)214 _mesa_IsSync(GLsync sync)
215 {
216    GET_CURRENT_CONTEXT(ctx);
217    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
218 
219    return _mesa_get_and_ref_sync(ctx, sync, false) ? GL_TRUE : GL_FALSE;
220 }
221 
222 
223 static ALWAYS_INLINE void
delete_sync(struct gl_context * ctx,GLsync sync,bool no_error)224 delete_sync(struct gl_context *ctx, GLsync sync, bool no_error)
225 {
226    struct gl_sync_object *syncObj;
227 
228    /* From the GL_ARB_sync spec:
229     *
230     *    DeleteSync will silently ignore a <sync> value of zero. An
231     *    INVALID_VALUE error is generated if <sync> is neither zero nor the
232     *    name of a sync object.
233     */
234    if (sync == 0) {
235       return;
236    }
237 
238    syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
239    if (!no_error && !syncObj) {
240       _mesa_error(ctx, GL_INVALID_VALUE,
241                   "glDeleteSync (not a valid sync object)");
242       return;
243    }
244 
245    /* If there are no client-waits or server-waits pending on this sync, delete
246     * the underlying object. Note that we double-unref the object, as
247     * _mesa_get_and_ref_sync above took an extra refcount to make sure the
248     * pointer is valid for us to manipulate.
249     */
250    syncObj->DeletePending = GL_TRUE;
251    _mesa_unref_sync_object(ctx, syncObj, 2);
252 }
253 
254 
255 void GLAPIENTRY
_mesa_DeleteSync_no_error(GLsync sync)256 _mesa_DeleteSync_no_error(GLsync sync)
257 {
258    GET_CURRENT_CONTEXT(ctx);
259    delete_sync(ctx, sync, true);
260 }
261 
262 
263 void GLAPIENTRY
_mesa_DeleteSync(GLsync sync)264 _mesa_DeleteSync(GLsync sync)
265 {
266    GET_CURRENT_CONTEXT(ctx);
267    delete_sync(ctx, sync, false);
268 }
269 
270 
271 static GLsync
fence_sync(struct gl_context * ctx,GLenum condition,GLbitfield flags)272 fence_sync(struct gl_context *ctx, GLenum condition, GLbitfield flags)
273 {
274    struct gl_sync_object *syncObj;
275 
276    syncObj = new_sync_object(ctx);
277    if (syncObj != NULL) {
278       /* The name is not currently used, and it is never visible to
279        * applications.  If sync support is extended to provide support for
280        * NV_fence, this field will be used.  We'll also need to add an object
281        * ID hashtable.
282        */
283       syncObj->Name = 1;
284       syncObj->RefCount = 1;
285       syncObj->DeletePending = GL_FALSE;
286       syncObj->SyncCondition = condition;
287       syncObj->Flags = flags;
288       syncObj->StatusFlag = 0;
289 
290       assert(condition == GL_SYNC_GPU_COMMANDS_COMPLETE && flags == 0);
291       assert(syncObj->fence == NULL);
292 
293       /* Deferred flush are only allowed when there's a single context. See issue 1430 */
294       ctx->pipe->flush(ctx->pipe, &syncObj->fence, ctx->Shared->RefCount == 1 ? PIPE_FLUSH_DEFERRED : 0);
295 
296       simple_mtx_lock(&ctx->Shared->Mutex);
297       _mesa_set_add(ctx->Shared->SyncObjects, syncObj);
298       simple_mtx_unlock(&ctx->Shared->Mutex);
299 
300       return (GLsync)syncObj;
301    }
302 
303    return NULL;
304 }
305 
306 
307 GLsync GLAPIENTRY
_mesa_FenceSync_no_error(GLenum condition,GLbitfield flags)308 _mesa_FenceSync_no_error(GLenum condition, GLbitfield flags)
309 {
310    GET_CURRENT_CONTEXT(ctx);
311    return fence_sync(ctx, condition, flags);
312 }
313 
314 
315 GLsync GLAPIENTRY
_mesa_FenceSync(GLenum condition,GLbitfield flags)316 _mesa_FenceSync(GLenum condition, GLbitfield flags)
317 {
318    GET_CURRENT_CONTEXT(ctx);
319    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
320 
321    if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) {
322       _mesa_error(ctx, GL_INVALID_ENUM, "glFenceSync(condition=0x%x)",
323                   condition);
324       return 0;
325    }
326 
327    if (flags != 0) {
328       _mesa_error(ctx, GL_INVALID_VALUE, "glFenceSync(flags=0x%x)", condition);
329       return 0;
330    }
331 
332    return fence_sync(ctx, condition, flags);
333 }
334 
335 
336 static GLenum
client_wait_sync(struct gl_context * ctx,struct gl_sync_object * syncObj,GLbitfield flags,GLuint64 timeout)337 client_wait_sync(struct gl_context *ctx, struct gl_sync_object *syncObj,
338                  GLbitfield flags, GLuint64 timeout)
339 {
340    GLenum ret;
341 
342    /* From the GL_ARB_sync spec:
343     *
344     *    ClientWaitSync returns one of four status values. A return value of
345     *    ALREADY_SIGNALED indicates that <sync> was signaled at the time
346     *    ClientWaitSync was called. ALREADY_SIGNALED will always be returned
347     *    if <sync> was signaled, even if the value of <timeout> is zero.
348     */
349    __client_wait_sync(ctx, syncObj, 0, 0);
350    if (syncObj->StatusFlag) {
351       ret = GL_ALREADY_SIGNALED;
352    } else {
353       if (timeout == 0) {
354          ret = GL_TIMEOUT_EXPIRED;
355       } else {
356          __client_wait_sync(ctx, syncObj, flags, timeout);
357 
358          ret = syncObj->StatusFlag
359             ? GL_CONDITION_SATISFIED : GL_TIMEOUT_EXPIRED;
360       }
361    }
362 
363    _mesa_unref_sync_object(ctx, syncObj, 1);
364    return ret;
365 }
366 
367 
368 GLenum GLAPIENTRY
_mesa_ClientWaitSync_no_error(GLsync sync,GLbitfield flags,GLuint64 timeout)369 _mesa_ClientWaitSync_no_error(GLsync sync, GLbitfield flags, GLuint64 timeout)
370 {
371    GET_CURRENT_CONTEXT(ctx);
372 
373    struct gl_sync_object *syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
374    return client_wait_sync(ctx, syncObj, flags, timeout);
375 }
376 
377 
378 GLenum GLAPIENTRY
_mesa_ClientWaitSync(GLsync sync,GLbitfield flags,GLuint64 timeout)379 _mesa_ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
380 {
381    GET_CURRENT_CONTEXT(ctx);
382    struct gl_sync_object *syncObj;
383 
384    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_WAIT_FAILED);
385 
386    if ((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) != 0) {
387       _mesa_error(ctx, GL_INVALID_VALUE, "glClientWaitSync(flags=0x%x)", flags);
388       return GL_WAIT_FAILED;
389    }
390 
391    syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
392    if (!syncObj) {
393       _mesa_error(ctx, GL_INVALID_VALUE,
394                   "glClientWaitSync (not a valid sync object)");
395       return GL_WAIT_FAILED;
396    }
397 
398    return client_wait_sync(ctx, syncObj, flags, timeout);
399 }
400 
401 
402 static void
wait_sync(struct gl_context * ctx,struct gl_sync_object * syncObj,GLbitfield flags,GLuint64 timeout)403 wait_sync(struct gl_context *ctx, struct gl_sync_object *syncObj,
404           GLbitfield flags, GLuint64 timeout)
405 {
406    struct pipe_context *pipe = ctx->pipe;
407    struct pipe_screen *screen = pipe->screen;
408    struct pipe_fence_handle *fence = NULL;
409 
410    /* Nothing needs to be done here if the driver does not support async
411     * flushes. */
412    if (!pipe->fence_server_sync) {
413       _mesa_unref_sync_object(ctx, syncObj, 1);
414       return;
415    }
416 
417    /* If the fence doesn't exist, assume it's signalled. */
418    simple_mtx_lock(&syncObj->mutex);
419    if (!syncObj->fence) {
420       simple_mtx_unlock(&syncObj->mutex);
421       syncObj->StatusFlag = GL_TRUE;
422       _mesa_unref_sync_object(ctx, syncObj, 1);
423       return;
424    }
425 
426    /* We need a local copy of the fence pointer. */
427    screen->fence_reference(screen, &fence, syncObj->fence);
428    simple_mtx_unlock(&syncObj->mutex);
429 
430    pipe->fence_server_sync(pipe, fence);
431    screen->fence_reference(screen, &fence, NULL);
432    _mesa_unref_sync_object(ctx, syncObj, 1);
433 }
434 
435 
436 void GLAPIENTRY
_mesa_WaitSync_no_error(GLsync sync,GLbitfield flags,GLuint64 timeout)437 _mesa_WaitSync_no_error(GLsync sync, GLbitfield flags, GLuint64 timeout)
438 {
439    GET_CURRENT_CONTEXT(ctx);
440 
441    struct gl_sync_object *syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
442    wait_sync(ctx, syncObj, flags, timeout);
443 }
444 
445 
446 void GLAPIENTRY
_mesa_WaitSync(GLsync sync,GLbitfield flags,GLuint64 timeout)447 _mesa_WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
448 {
449    GET_CURRENT_CONTEXT(ctx);
450    struct gl_sync_object *syncObj;
451 
452    if (flags != 0) {
453       _mesa_error(ctx, GL_INVALID_VALUE, "glWaitSync(flags=0x%x)", flags);
454       return;
455    }
456 
457    if (timeout != GL_TIMEOUT_IGNORED) {
458       _mesa_error(ctx, GL_INVALID_VALUE, "glWaitSync(timeout=0x%" PRIx64 ")",
459                   (uint64_t) timeout);
460       return;
461    }
462 
463    syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
464    if (!syncObj) {
465       _mesa_error(ctx, GL_INVALID_VALUE,
466                   "glWaitSync (not a valid sync object)");
467       return;
468    }
469 
470    wait_sync(ctx, syncObj, flags, timeout);
471 }
472 
473 
474 void GLAPIENTRY
_mesa_GetSynciv(GLsync sync,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * values)475 _mesa_GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length,
476                 GLint *values)
477 {
478    GET_CURRENT_CONTEXT(ctx);
479    struct gl_sync_object *syncObj;
480    GLsizei size = 0;
481    GLint v[1];
482 
483    syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
484    if (!syncObj) {
485       _mesa_error(ctx, GL_INVALID_VALUE,
486                   "glGetSynciv (not a valid sync object)");
487       return;
488    }
489 
490    switch (pname) {
491    case GL_OBJECT_TYPE:
492       v[0] = GL_SYNC_FENCE;
493       size = 1;
494       break;
495 
496    case GL_SYNC_CONDITION:
497       v[0] = syncObj->SyncCondition;
498       size = 1;
499       break;
500 
501    case GL_SYNC_STATUS:
502       /* Update the state of the sync by dipping into the driver.  Note that
503        * this call won't block.  It just updates state in the common object
504        * data from the current driver state.
505        */
506       __client_wait_sync(ctx, syncObj, 0, 0);
507 
508       v[0] = (syncObj->StatusFlag) ? GL_SIGNALED : GL_UNSIGNALED;
509       size = 1;
510       break;
511 
512    case GL_SYNC_FLAGS:
513       v[0] = syncObj->Flags;
514       size = 1;
515       break;
516 
517    default:
518       _mesa_error(ctx, GL_INVALID_ENUM, "glGetSynciv(pname=0x%x)\n", pname);
519       _mesa_unref_sync_object(ctx, syncObj, 1);
520       return;
521    }
522 
523    /* Section 4.1.3 (Sync Object Queries) of the OpenGL ES 3.10 spec says:
524     *
525     *    "An INVALID_VALUE error is generated if bufSize is negative."
526     */
527    if (bufSize < 0) {
528       _mesa_error(ctx, GL_INVALID_VALUE, "glGetSynciv(pname=0x%x)\n", pname);
529    }
530 
531    if (size > 0 && bufSize > 0) {
532       const GLsizei copy_count = MIN2(size, bufSize);
533 
534       memcpy(values, v, sizeof(GLint) * copy_count);
535    }
536 
537    if (length != NULL) {
538       *length = size;
539    }
540 
541    _mesa_unref_sync_object(ctx, syncObj, 1);
542 }
543