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