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