xref: /third_party/mesa3d/src/mesa/main/syncobj.c (revision bf215546)
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 */
79void
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 */
89void
90_mesa_free_sync_data(struct gl_context *ctx)
91{
92   (void) ctx;
93}
94
95static struct gl_sync_object *
96new_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
104static void
105delete_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
116static void
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 */
173struct gl_sync_object *
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
192void
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
213GLboolean GLAPIENTRY
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
223static ALWAYS_INLINE void
224delete_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
255void GLAPIENTRY
256_mesa_DeleteSync_no_error(GLsync sync)
257{
258   GET_CURRENT_CONTEXT(ctx);
259   delete_sync(ctx, sync, true);
260}
261
262
263void GLAPIENTRY
264_mesa_DeleteSync(GLsync sync)
265{
266   GET_CURRENT_CONTEXT(ctx);
267   delete_sync(ctx, sync, false);
268}
269
270
271static GLsync
272fence_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
307GLsync GLAPIENTRY
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
315GLsync GLAPIENTRY
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
336static GLenum
337client_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
368GLenum GLAPIENTRY
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
378GLenum GLAPIENTRY
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
402static void
403wait_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
436void GLAPIENTRY
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
446void GLAPIENTRY
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
474void GLAPIENTRY
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