1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2009 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci/**
25bf215546Sopenharmony_ci * \file syncobj.c
26bf215546Sopenharmony_ci * Sync object management.
27bf215546Sopenharmony_ci *
28bf215546Sopenharmony_ci * Unlike textures and other objects that are shared between contexts, sync
29bf215546Sopenharmony_ci * objects are not bound to the context.  As a result, the reference counting
30bf215546Sopenharmony_ci * and delete behavior of sync objects is slightly different.  References to
31bf215546Sopenharmony_ci * sync objects are added:
32bf215546Sopenharmony_ci *
33bf215546Sopenharmony_ci *    - By \c glFencSynce.  This sets the initial reference count to 1.
34bf215546Sopenharmony_ci *    - At the start of \c glClientWaitSync.  The reference is held for the
35bf215546Sopenharmony_ci *      duration of the wait call.
36bf215546Sopenharmony_ci *
37bf215546Sopenharmony_ci * References are removed:
38bf215546Sopenharmony_ci *
39bf215546Sopenharmony_ci *    - By \c glDeleteSync.
40bf215546Sopenharmony_ci *    - At the end of \c glClientWaitSync.
41bf215546Sopenharmony_ci *
42bf215546Sopenharmony_ci * Additionally, drivers may call \c _mesa_ref_sync_object and
43bf215546Sopenharmony_ci * \c _mesa_unref_sync_object as needed to implement \c ServerWaitSync.
44bf215546Sopenharmony_ci *
45bf215546Sopenharmony_ci * As with shader objects, sync object names become invalid as soon as
46bf215546Sopenharmony_ci * \c glDeleteSync is called.  For this reason \c glDeleteSync sets the
47bf215546Sopenharmony_ci * \c DeletePending flag.  All functions validate object handles by testing
48bf215546Sopenharmony_ci * this flag.
49bf215546Sopenharmony_ci *
50bf215546Sopenharmony_ci * \note
51bf215546Sopenharmony_ci * Only \c GL_ARB_sync objects are shared between contexts.  If support is ever
52bf215546Sopenharmony_ci * added for either \c GL_NV_fence or \c GL_APPLE_fence different semantics
53bf215546Sopenharmony_ci * will need to be implemented.
54bf215546Sopenharmony_ci *
55bf215546Sopenharmony_ci * \author Ian Romanick <ian.d.romanick@intel.com>
56bf215546Sopenharmony_ci */
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci#include <inttypes.h>
59bf215546Sopenharmony_ci#include "glheader.h"
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci#include "context.h"
62bf215546Sopenharmony_ci#include "macros.h"
63bf215546Sopenharmony_ci#include "get.h"
64bf215546Sopenharmony_ci#include "mtypes.h"
65bf215546Sopenharmony_ci#include "util/hash_table.h"
66bf215546Sopenharmony_ci#include "util/set.h"
67bf215546Sopenharmony_ci#include "util/u_memory.h"
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci#include "syncobj.h"
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci#include "api_exec_decl.h"
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci#include "pipe/p_context.h"
74bf215546Sopenharmony_ci#include "pipe/p_screen.h"
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci/**
77bf215546Sopenharmony_ci * Allocate/init the context state related to sync objects.
78bf215546Sopenharmony_ci */
79bf215546Sopenharmony_civoid
80bf215546Sopenharmony_ci_mesa_init_sync(struct gl_context *ctx)
81bf215546Sopenharmony_ci{
82bf215546Sopenharmony_ci   (void) ctx;
83bf215546Sopenharmony_ci}
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci/**
87bf215546Sopenharmony_ci * Free the context state related to sync objects.
88bf215546Sopenharmony_ci */
89bf215546Sopenharmony_civoid
90bf215546Sopenharmony_ci_mesa_free_sync_data(struct gl_context *ctx)
91bf215546Sopenharmony_ci{
92bf215546Sopenharmony_ci   (void) ctx;
93bf215546Sopenharmony_ci}
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_cistatic struct gl_sync_object *
96bf215546Sopenharmony_cinew_sync_object(struct gl_context *ctx)
97bf215546Sopenharmony_ci{
98bf215546Sopenharmony_ci   struct gl_sync_object *so = CALLOC_STRUCT(gl_sync_object);
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   simple_mtx_init(&so->mutex, mtx_plain);
101bf215546Sopenharmony_ci   return so;
102bf215546Sopenharmony_ci}
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_cistatic void
105bf215546Sopenharmony_cidelete_sync_object(struct gl_context *ctx,
106bf215546Sopenharmony_ci                      struct gl_sync_object *obj)
107bf215546Sopenharmony_ci{
108bf215546Sopenharmony_ci   struct pipe_screen *screen = ctx->pipe->screen;
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci   screen->fence_reference(screen, &obj->fence, NULL);
111bf215546Sopenharmony_ci   simple_mtx_destroy(&obj->mutex);
112bf215546Sopenharmony_ci   free(obj->Label);
113bf215546Sopenharmony_ci   FREE(obj);
114bf215546Sopenharmony_ci}
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_cistatic void
117bf215546Sopenharmony_ci__client_wait_sync(struct gl_context *ctx,
118bf215546Sopenharmony_ci                   struct gl_sync_object *obj,
119bf215546Sopenharmony_ci                   GLbitfield flags, GLuint64 timeout)
120bf215546Sopenharmony_ci{
121bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
122bf215546Sopenharmony_ci   struct pipe_screen *screen = pipe->screen;
123bf215546Sopenharmony_ci   struct pipe_fence_handle *fence = NULL;
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   /* If the fence doesn't exist, assume it's signalled. */
126bf215546Sopenharmony_ci   simple_mtx_lock(&obj->mutex);
127bf215546Sopenharmony_ci   if (!obj->fence) {
128bf215546Sopenharmony_ci      simple_mtx_unlock(&obj->mutex);
129bf215546Sopenharmony_ci      obj->StatusFlag = GL_TRUE;
130bf215546Sopenharmony_ci      return;
131bf215546Sopenharmony_ci   }
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   /* We need a local copy of the fence pointer, so that we can call
134bf215546Sopenharmony_ci    * fence_finish unlocked.
135bf215546Sopenharmony_ci    */
136bf215546Sopenharmony_ci   screen->fence_reference(screen, &fence, obj->fence);
137bf215546Sopenharmony_ci   simple_mtx_unlock(&obj->mutex);
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci   /* Section 4.1.2 of OpenGL 4.5 (Compatibility Profile) says:
140bf215546Sopenharmony_ci    *    [...] if ClientWaitSync is called and all of the following are true:
141bf215546Sopenharmony_ci    *    - the SYNC_FLUSH_COMMANDS_BIT bit is set in flags,
142bf215546Sopenharmony_ci    *    - sync is unsignaled when ClientWaitSync is called,
143bf215546Sopenharmony_ci    *    - and the calls to ClientWaitSync and FenceSync were issued from
144bf215546Sopenharmony_ci    *      the same context,
145bf215546Sopenharmony_ci    *    then the GL will behave as if the equivalent of Flush were inserted
146bf215546Sopenharmony_ci    *    immediately after the creation of sync.
147bf215546Sopenharmony_ci    *
148bf215546Sopenharmony_ci    * Assume GL_SYNC_FLUSH_COMMANDS_BIT is always set, because applications
149bf215546Sopenharmony_ci    * forget to set it.
150bf215546Sopenharmony_ci    */
151bf215546Sopenharmony_ci   if (screen->fence_finish(screen, pipe, fence, timeout)) {
152bf215546Sopenharmony_ci      simple_mtx_lock(&obj->mutex);
153bf215546Sopenharmony_ci      screen->fence_reference(screen, &obj->fence, NULL);
154bf215546Sopenharmony_ci      simple_mtx_unlock(&obj->mutex);
155bf215546Sopenharmony_ci      obj->StatusFlag = GL_TRUE;
156bf215546Sopenharmony_ci   }
157bf215546Sopenharmony_ci   screen->fence_reference(screen, &fence, NULL);
158bf215546Sopenharmony_ci}
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci/**
161bf215546Sopenharmony_ci * Check if the given sync object is:
162bf215546Sopenharmony_ci *  - non-null
163bf215546Sopenharmony_ci *  - not in sync objects hash table
164bf215546Sopenharmony_ci *  - not marked as deleted
165bf215546Sopenharmony_ci *
166bf215546Sopenharmony_ci * Returns the internal gl_sync_object pointer if the sync object is valid
167bf215546Sopenharmony_ci * or NULL if it isn't.
168bf215546Sopenharmony_ci *
169bf215546Sopenharmony_ci * If "incRefCount" is true, the reference count is incremented, which is
170bf215546Sopenharmony_ci * normally what you want; otherwise, a glDeleteSync from another thread
171bf215546Sopenharmony_ci * could delete the sync object while you are still working on it.
172bf215546Sopenharmony_ci */
173bf215546Sopenharmony_cistruct gl_sync_object *
174bf215546Sopenharmony_ci_mesa_get_and_ref_sync(struct gl_context *ctx, GLsync sync, bool incRefCount)
175bf215546Sopenharmony_ci{
176bf215546Sopenharmony_ci   struct gl_sync_object *syncObj = (struct gl_sync_object *) sync;
177bf215546Sopenharmony_ci   simple_mtx_lock(&ctx->Shared->Mutex);
178bf215546Sopenharmony_ci   if (syncObj != NULL
179bf215546Sopenharmony_ci      && _mesa_set_search(ctx->Shared->SyncObjects, syncObj) != NULL
180bf215546Sopenharmony_ci      && !syncObj->DeletePending) {
181bf215546Sopenharmony_ci     if (incRefCount) {
182bf215546Sopenharmony_ci       syncObj->RefCount++;
183bf215546Sopenharmony_ci     }
184bf215546Sopenharmony_ci   } else {
185bf215546Sopenharmony_ci     syncObj = NULL;
186bf215546Sopenharmony_ci   }
187bf215546Sopenharmony_ci   simple_mtx_unlock(&ctx->Shared->Mutex);
188bf215546Sopenharmony_ci   return syncObj;
189bf215546Sopenharmony_ci}
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_civoid
193bf215546Sopenharmony_ci_mesa_unref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj,
194bf215546Sopenharmony_ci                        int amount)
195bf215546Sopenharmony_ci{
196bf215546Sopenharmony_ci   struct set_entry *entry;
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   simple_mtx_lock(&ctx->Shared->Mutex);
199bf215546Sopenharmony_ci   syncObj->RefCount -= amount;
200bf215546Sopenharmony_ci   if (syncObj->RefCount == 0) {
201bf215546Sopenharmony_ci      entry = _mesa_set_search(ctx->Shared->SyncObjects, syncObj);
202bf215546Sopenharmony_ci      assert (entry != NULL);
203bf215546Sopenharmony_ci      _mesa_set_remove(ctx->Shared->SyncObjects, entry);
204bf215546Sopenharmony_ci      simple_mtx_unlock(&ctx->Shared->Mutex);
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci      delete_sync_object(ctx, syncObj);
207bf215546Sopenharmony_ci   } else {
208bf215546Sopenharmony_ci      simple_mtx_unlock(&ctx->Shared->Mutex);
209bf215546Sopenharmony_ci   }
210bf215546Sopenharmony_ci}
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ciGLboolean GLAPIENTRY
214bf215546Sopenharmony_ci_mesa_IsSync(GLsync sync)
215bf215546Sopenharmony_ci{
216bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
217bf215546Sopenharmony_ci   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci   return _mesa_get_and_ref_sync(ctx, sync, false) ? GL_TRUE : GL_FALSE;
220bf215546Sopenharmony_ci}
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_cistatic ALWAYS_INLINE void
224bf215546Sopenharmony_cidelete_sync(struct gl_context *ctx, GLsync sync, bool no_error)
225bf215546Sopenharmony_ci{
226bf215546Sopenharmony_ci   struct gl_sync_object *syncObj;
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci   /* From the GL_ARB_sync spec:
229bf215546Sopenharmony_ci    *
230bf215546Sopenharmony_ci    *    DeleteSync will silently ignore a <sync> value of zero. An
231bf215546Sopenharmony_ci    *    INVALID_VALUE error is generated if <sync> is neither zero nor the
232bf215546Sopenharmony_ci    *    name of a sync object.
233bf215546Sopenharmony_ci    */
234bf215546Sopenharmony_ci   if (sync == 0) {
235bf215546Sopenharmony_ci      return;
236bf215546Sopenharmony_ci   }
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci   syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
239bf215546Sopenharmony_ci   if (!no_error && !syncObj) {
240bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
241bf215546Sopenharmony_ci                  "glDeleteSync (not a valid sync object)");
242bf215546Sopenharmony_ci      return;
243bf215546Sopenharmony_ci   }
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci   /* If there are no client-waits or server-waits pending on this sync, delete
246bf215546Sopenharmony_ci    * the underlying object. Note that we double-unref the object, as
247bf215546Sopenharmony_ci    * _mesa_get_and_ref_sync above took an extra refcount to make sure the
248bf215546Sopenharmony_ci    * pointer is valid for us to manipulate.
249bf215546Sopenharmony_ci    */
250bf215546Sopenharmony_ci   syncObj->DeletePending = GL_TRUE;
251bf215546Sopenharmony_ci   _mesa_unref_sync_object(ctx, syncObj, 2);
252bf215546Sopenharmony_ci}
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_civoid GLAPIENTRY
256bf215546Sopenharmony_ci_mesa_DeleteSync_no_error(GLsync sync)
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
259bf215546Sopenharmony_ci   delete_sync(ctx, sync, true);
260bf215546Sopenharmony_ci}
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_civoid GLAPIENTRY
264bf215546Sopenharmony_ci_mesa_DeleteSync(GLsync sync)
265bf215546Sopenharmony_ci{
266bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
267bf215546Sopenharmony_ci   delete_sync(ctx, sync, false);
268bf215546Sopenharmony_ci}
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_cistatic GLsync
272bf215546Sopenharmony_cifence_sync(struct gl_context *ctx, GLenum condition, GLbitfield flags)
273bf215546Sopenharmony_ci{
274bf215546Sopenharmony_ci   struct gl_sync_object *syncObj;
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   syncObj = new_sync_object(ctx);
277bf215546Sopenharmony_ci   if (syncObj != NULL) {
278bf215546Sopenharmony_ci      /* The name is not currently used, and it is never visible to
279bf215546Sopenharmony_ci       * applications.  If sync support is extended to provide support for
280bf215546Sopenharmony_ci       * NV_fence, this field will be used.  We'll also need to add an object
281bf215546Sopenharmony_ci       * ID hashtable.
282bf215546Sopenharmony_ci       */
283bf215546Sopenharmony_ci      syncObj->Name = 1;
284bf215546Sopenharmony_ci      syncObj->RefCount = 1;
285bf215546Sopenharmony_ci      syncObj->DeletePending = GL_FALSE;
286bf215546Sopenharmony_ci      syncObj->SyncCondition = condition;
287bf215546Sopenharmony_ci      syncObj->Flags = flags;
288bf215546Sopenharmony_ci      syncObj->StatusFlag = 0;
289bf215546Sopenharmony_ci
290bf215546Sopenharmony_ci      assert(condition == GL_SYNC_GPU_COMMANDS_COMPLETE && flags == 0);
291bf215546Sopenharmony_ci      assert(syncObj->fence == NULL);
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci      /* Deferred flush are only allowed when there's a single context. See issue 1430 */
294bf215546Sopenharmony_ci      ctx->pipe->flush(ctx->pipe, &syncObj->fence, ctx->Shared->RefCount == 1 ? PIPE_FLUSH_DEFERRED : 0);
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci      simple_mtx_lock(&ctx->Shared->Mutex);
297bf215546Sopenharmony_ci      _mesa_set_add(ctx->Shared->SyncObjects, syncObj);
298bf215546Sopenharmony_ci      simple_mtx_unlock(&ctx->Shared->Mutex);
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_ci      return (GLsync)syncObj;
301bf215546Sopenharmony_ci   }
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   return NULL;
304bf215546Sopenharmony_ci}
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ciGLsync GLAPIENTRY
308bf215546Sopenharmony_ci_mesa_FenceSync_no_error(GLenum condition, GLbitfield flags)
309bf215546Sopenharmony_ci{
310bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
311bf215546Sopenharmony_ci   return fence_sync(ctx, condition, flags);
312bf215546Sopenharmony_ci}
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ciGLsync GLAPIENTRY
316bf215546Sopenharmony_ci_mesa_FenceSync(GLenum condition, GLbitfield flags)
317bf215546Sopenharmony_ci{
318bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
319bf215546Sopenharmony_ci   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci   if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) {
322bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glFenceSync(condition=0x%x)",
323bf215546Sopenharmony_ci                  condition);
324bf215546Sopenharmony_ci      return 0;
325bf215546Sopenharmony_ci   }
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   if (flags != 0) {
328bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glFenceSync(flags=0x%x)", condition);
329bf215546Sopenharmony_ci      return 0;
330bf215546Sopenharmony_ci   }
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   return fence_sync(ctx, condition, flags);
333bf215546Sopenharmony_ci}
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_cistatic GLenum
337bf215546Sopenharmony_ciclient_wait_sync(struct gl_context *ctx, struct gl_sync_object *syncObj,
338bf215546Sopenharmony_ci                 GLbitfield flags, GLuint64 timeout)
339bf215546Sopenharmony_ci{
340bf215546Sopenharmony_ci   GLenum ret;
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci   /* From the GL_ARB_sync spec:
343bf215546Sopenharmony_ci    *
344bf215546Sopenharmony_ci    *    ClientWaitSync returns one of four status values. A return value of
345bf215546Sopenharmony_ci    *    ALREADY_SIGNALED indicates that <sync> was signaled at the time
346bf215546Sopenharmony_ci    *    ClientWaitSync was called. ALREADY_SIGNALED will always be returned
347bf215546Sopenharmony_ci    *    if <sync> was signaled, even if the value of <timeout> is zero.
348bf215546Sopenharmony_ci    */
349bf215546Sopenharmony_ci   __client_wait_sync(ctx, syncObj, 0, 0);
350bf215546Sopenharmony_ci   if (syncObj->StatusFlag) {
351bf215546Sopenharmony_ci      ret = GL_ALREADY_SIGNALED;
352bf215546Sopenharmony_ci   } else {
353bf215546Sopenharmony_ci      if (timeout == 0) {
354bf215546Sopenharmony_ci         ret = GL_TIMEOUT_EXPIRED;
355bf215546Sopenharmony_ci      } else {
356bf215546Sopenharmony_ci         __client_wait_sync(ctx, syncObj, flags, timeout);
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci         ret = syncObj->StatusFlag
359bf215546Sopenharmony_ci            ? GL_CONDITION_SATISFIED : GL_TIMEOUT_EXPIRED;
360bf215546Sopenharmony_ci      }
361bf215546Sopenharmony_ci   }
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci   _mesa_unref_sync_object(ctx, syncObj, 1);
364bf215546Sopenharmony_ci   return ret;
365bf215546Sopenharmony_ci}
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ciGLenum GLAPIENTRY
369bf215546Sopenharmony_ci_mesa_ClientWaitSync_no_error(GLsync sync, GLbitfield flags, GLuint64 timeout)
370bf215546Sopenharmony_ci{
371bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_ci   struct gl_sync_object *syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
374bf215546Sopenharmony_ci   return client_wait_sync(ctx, syncObj, flags, timeout);
375bf215546Sopenharmony_ci}
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ciGLenum GLAPIENTRY
379bf215546Sopenharmony_ci_mesa_ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
380bf215546Sopenharmony_ci{
381bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
382bf215546Sopenharmony_ci   struct gl_sync_object *syncObj;
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_WAIT_FAILED);
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci   if ((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) != 0) {
387bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glClientWaitSync(flags=0x%x)", flags);
388bf215546Sopenharmony_ci      return GL_WAIT_FAILED;
389bf215546Sopenharmony_ci   }
390bf215546Sopenharmony_ci
391bf215546Sopenharmony_ci   syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
392bf215546Sopenharmony_ci   if (!syncObj) {
393bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
394bf215546Sopenharmony_ci                  "glClientWaitSync (not a valid sync object)");
395bf215546Sopenharmony_ci      return GL_WAIT_FAILED;
396bf215546Sopenharmony_ci   }
397bf215546Sopenharmony_ci
398bf215546Sopenharmony_ci   return client_wait_sync(ctx, syncObj, flags, timeout);
399bf215546Sopenharmony_ci}
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_cistatic void
403bf215546Sopenharmony_ciwait_sync(struct gl_context *ctx, struct gl_sync_object *syncObj,
404bf215546Sopenharmony_ci          GLbitfield flags, GLuint64 timeout)
405bf215546Sopenharmony_ci{
406bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
407bf215546Sopenharmony_ci   struct pipe_screen *screen = pipe->screen;
408bf215546Sopenharmony_ci   struct pipe_fence_handle *fence = NULL;
409bf215546Sopenharmony_ci
410bf215546Sopenharmony_ci   /* Nothing needs to be done here if the driver does not support async
411bf215546Sopenharmony_ci    * flushes. */
412bf215546Sopenharmony_ci   if (!pipe->fence_server_sync) {
413bf215546Sopenharmony_ci      _mesa_unref_sync_object(ctx, syncObj, 1);
414bf215546Sopenharmony_ci      return;
415bf215546Sopenharmony_ci   }
416bf215546Sopenharmony_ci
417bf215546Sopenharmony_ci   /* If the fence doesn't exist, assume it's signalled. */
418bf215546Sopenharmony_ci   simple_mtx_lock(&syncObj->mutex);
419bf215546Sopenharmony_ci   if (!syncObj->fence) {
420bf215546Sopenharmony_ci      simple_mtx_unlock(&syncObj->mutex);
421bf215546Sopenharmony_ci      syncObj->StatusFlag = GL_TRUE;
422bf215546Sopenharmony_ci      _mesa_unref_sync_object(ctx, syncObj, 1);
423bf215546Sopenharmony_ci      return;
424bf215546Sopenharmony_ci   }
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_ci   /* We need a local copy of the fence pointer. */
427bf215546Sopenharmony_ci   screen->fence_reference(screen, &fence, syncObj->fence);
428bf215546Sopenharmony_ci   simple_mtx_unlock(&syncObj->mutex);
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci   pipe->fence_server_sync(pipe, fence);
431bf215546Sopenharmony_ci   screen->fence_reference(screen, &fence, NULL);
432bf215546Sopenharmony_ci   _mesa_unref_sync_object(ctx, syncObj, 1);
433bf215546Sopenharmony_ci}
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_civoid GLAPIENTRY
437bf215546Sopenharmony_ci_mesa_WaitSync_no_error(GLsync sync, GLbitfield flags, GLuint64 timeout)
438bf215546Sopenharmony_ci{
439bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
440bf215546Sopenharmony_ci
441bf215546Sopenharmony_ci   struct gl_sync_object *syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
442bf215546Sopenharmony_ci   wait_sync(ctx, syncObj, flags, timeout);
443bf215546Sopenharmony_ci}
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_civoid GLAPIENTRY
447bf215546Sopenharmony_ci_mesa_WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
448bf215546Sopenharmony_ci{
449bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
450bf215546Sopenharmony_ci   struct gl_sync_object *syncObj;
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_ci   if (flags != 0) {
453bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glWaitSync(flags=0x%x)", flags);
454bf215546Sopenharmony_ci      return;
455bf215546Sopenharmony_ci   }
456bf215546Sopenharmony_ci
457bf215546Sopenharmony_ci   if (timeout != GL_TIMEOUT_IGNORED) {
458bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glWaitSync(timeout=0x%" PRIx64 ")",
459bf215546Sopenharmony_ci                  (uint64_t) timeout);
460bf215546Sopenharmony_ci      return;
461bf215546Sopenharmony_ci   }
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_ci   syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
464bf215546Sopenharmony_ci   if (!syncObj) {
465bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
466bf215546Sopenharmony_ci                  "glWaitSync (not a valid sync object)");
467bf215546Sopenharmony_ci      return;
468bf215546Sopenharmony_ci   }
469bf215546Sopenharmony_ci
470bf215546Sopenharmony_ci   wait_sync(ctx, syncObj, flags, timeout);
471bf215546Sopenharmony_ci}
472bf215546Sopenharmony_ci
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_civoid GLAPIENTRY
475bf215546Sopenharmony_ci_mesa_GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length,
476bf215546Sopenharmony_ci                GLint *values)
477bf215546Sopenharmony_ci{
478bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
479bf215546Sopenharmony_ci   struct gl_sync_object *syncObj;
480bf215546Sopenharmony_ci   GLsizei size = 0;
481bf215546Sopenharmony_ci   GLint v[1];
482bf215546Sopenharmony_ci
483bf215546Sopenharmony_ci   syncObj = _mesa_get_and_ref_sync(ctx, sync, true);
484bf215546Sopenharmony_ci   if (!syncObj) {
485bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
486bf215546Sopenharmony_ci                  "glGetSynciv (not a valid sync object)");
487bf215546Sopenharmony_ci      return;
488bf215546Sopenharmony_ci   }
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_ci   switch (pname) {
491bf215546Sopenharmony_ci   case GL_OBJECT_TYPE:
492bf215546Sopenharmony_ci      v[0] = GL_SYNC_FENCE;
493bf215546Sopenharmony_ci      size = 1;
494bf215546Sopenharmony_ci      break;
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci   case GL_SYNC_CONDITION:
497bf215546Sopenharmony_ci      v[0] = syncObj->SyncCondition;
498bf215546Sopenharmony_ci      size = 1;
499bf215546Sopenharmony_ci      break;
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_ci   case GL_SYNC_STATUS:
502bf215546Sopenharmony_ci      /* Update the state of the sync by dipping into the driver.  Note that
503bf215546Sopenharmony_ci       * this call won't block.  It just updates state in the common object
504bf215546Sopenharmony_ci       * data from the current driver state.
505bf215546Sopenharmony_ci       */
506bf215546Sopenharmony_ci      __client_wait_sync(ctx, syncObj, 0, 0);
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci      v[0] = (syncObj->StatusFlag) ? GL_SIGNALED : GL_UNSIGNALED;
509bf215546Sopenharmony_ci      size = 1;
510bf215546Sopenharmony_ci      break;
511bf215546Sopenharmony_ci
512bf215546Sopenharmony_ci   case GL_SYNC_FLAGS:
513bf215546Sopenharmony_ci      v[0] = syncObj->Flags;
514bf215546Sopenharmony_ci      size = 1;
515bf215546Sopenharmony_ci      break;
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci   default:
518bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glGetSynciv(pname=0x%x)\n", pname);
519bf215546Sopenharmony_ci      _mesa_unref_sync_object(ctx, syncObj, 1);
520bf215546Sopenharmony_ci      return;
521bf215546Sopenharmony_ci   }
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_ci   /* Section 4.1.3 (Sync Object Queries) of the OpenGL ES 3.10 spec says:
524bf215546Sopenharmony_ci    *
525bf215546Sopenharmony_ci    *    "An INVALID_VALUE error is generated if bufSize is negative."
526bf215546Sopenharmony_ci    */
527bf215546Sopenharmony_ci   if (bufSize < 0) {
528bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glGetSynciv(pname=0x%x)\n", pname);
529bf215546Sopenharmony_ci   }
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci   if (size > 0 && bufSize > 0) {
532bf215546Sopenharmony_ci      const GLsizei copy_count = MIN2(size, bufSize);
533bf215546Sopenharmony_ci
534bf215546Sopenharmony_ci      memcpy(values, v, sizeof(GLint) * copy_count);
535bf215546Sopenharmony_ci   }
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci   if (length != NULL) {
538bf215546Sopenharmony_ci      *length = size;
539bf215546Sopenharmony_ci   }
540bf215546Sopenharmony_ci
541bf215546Sopenharmony_ci   _mesa_unref_sync_object(ctx, syncObj, 1);
542bf215546Sopenharmony_ci}
543