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 71static struct gl_sync_object * 72_mesa_new_sync_object(struct gl_context *ctx) 73{ 74 struct gl_sync_object *s = CALLOC_STRUCT(gl_sync_object); 75 (void) ctx; 76 77 return s; 78} 79 80 81static void 82_mesa_delete_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj) 83{ 84 (void) ctx; 85 free(syncObj->Label); 86 free(syncObj); 87} 88 89 90static void 91_mesa_fence_sync(struct gl_context *ctx, struct gl_sync_object *syncObj, 92 GLenum condition, GLbitfield flags) 93{ 94 (void) ctx; 95 (void) condition; 96 (void) flags; 97 98 syncObj->StatusFlag = 1; 99} 100 101 102static void 103_mesa_check_sync(struct gl_context *ctx, struct gl_sync_object *syncObj) 104{ 105 (void) ctx; 106 (void) syncObj; 107 108 /* No-op for software rendering. Hardware drivers will need to determine 109 * whether the state of the sync object has changed. 110 */ 111} 112 113 114static void 115_mesa_wait_sync(struct gl_context *ctx, struct gl_sync_object *syncObj, 116 GLbitfield flags, GLuint64 timeout) 117{ 118 (void) ctx; 119 (void) syncObj; 120 (void) flags; 121 (void) timeout; 122 123 /* No-op for software rendering. Hardware drivers will need to wait until 124 * the state of the sync object changes or the timeout expires. 125 */ 126} 127 128 129void 130_mesa_init_sync_object_functions(struct dd_function_table *driver) 131{ 132 driver->NewSyncObject = _mesa_new_sync_object; 133 driver->FenceSync = _mesa_fence_sync; 134 driver->DeleteSyncObject = _mesa_delete_sync_object; 135 driver->CheckSync = _mesa_check_sync; 136 137 /* Use the same no-op wait function for both. 138 */ 139 driver->ClientWaitSync = _mesa_wait_sync; 140 driver->ServerWaitSync = _mesa_wait_sync; 141} 142 143/** 144 * Allocate/init the context state related to sync objects. 145 */ 146void 147_mesa_init_sync(struct gl_context *ctx) 148{ 149 (void) ctx; 150} 151 152 153/** 154 * Free the context state related to sync objects. 155 */ 156void 157_mesa_free_sync_data(struct gl_context *ctx) 158{ 159 (void) ctx; 160} 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 */ 176struct gl_sync_object * 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 195void 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 ctx->Driver.DeleteSyncObject(ctx, syncObj); 210 } else { 211 simple_mtx_unlock(&ctx->Shared->Mutex); 212 } 213} 214 215 216GLboolean GLAPIENTRY 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 226static ALWAYS_INLINE void 227delete_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 258void GLAPIENTRY 259_mesa_DeleteSync_no_error(GLsync sync) 260{ 261 GET_CURRENT_CONTEXT(ctx); 262 delete_sync(ctx, sync, true); 263} 264 265 266void GLAPIENTRY 267_mesa_DeleteSync(GLsync sync) 268{ 269 GET_CURRENT_CONTEXT(ctx); 270 delete_sync(ctx, sync, false); 271} 272 273 274static GLsync 275fence_sync(struct gl_context *ctx, GLenum condition, GLbitfield flags) 276{ 277 struct gl_sync_object *syncObj; 278 279 syncObj = ctx->Driver.NewSyncObject(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 ctx->Driver.FenceSync(ctx, syncObj, condition, flags); 294 295 simple_mtx_lock(&ctx->Shared->Mutex); 296 _mesa_set_add(ctx->Shared->SyncObjects, syncObj); 297 simple_mtx_unlock(&ctx->Shared->Mutex); 298 299 return (GLsync)syncObj; 300 } 301 302 return NULL; 303} 304 305 306GLsync GLAPIENTRY 307_mesa_FenceSync_no_error(GLenum condition, GLbitfield flags) 308{ 309 GET_CURRENT_CONTEXT(ctx); 310 return fence_sync(ctx, condition, flags); 311} 312 313 314GLsync GLAPIENTRY 315_mesa_FenceSync(GLenum condition, GLbitfield flags) 316{ 317 GET_CURRENT_CONTEXT(ctx); 318 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 319 320 if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) { 321 _mesa_error(ctx, GL_INVALID_ENUM, "glFenceSync(condition=0x%x)", 322 condition); 323 return 0; 324 } 325 326 if (flags != 0) { 327 _mesa_error(ctx, GL_INVALID_VALUE, "glFenceSync(flags=0x%x)", condition); 328 return 0; 329 } 330 331 return fence_sync(ctx, condition, flags); 332} 333 334 335static GLenum 336client_wait_sync(struct gl_context *ctx, struct gl_sync_object *syncObj, 337 GLbitfield flags, GLuint64 timeout) 338{ 339 GLenum ret; 340 341 /* From the GL_ARB_sync spec: 342 * 343 * ClientWaitSync returns one of four status values. A return value of 344 * ALREADY_SIGNALED indicates that <sync> was signaled at the time 345 * ClientWaitSync was called. ALREADY_SIGNALED will always be returned 346 * if <sync> was signaled, even if the value of <timeout> is zero. 347 */ 348 ctx->Driver.CheckSync(ctx, syncObj); 349 if (syncObj->StatusFlag) { 350 ret = GL_ALREADY_SIGNALED; 351 } else { 352 if (timeout == 0) { 353 ret = GL_TIMEOUT_EXPIRED; 354 } else { 355 ctx->Driver.ClientWaitSync(ctx, syncObj, flags, timeout); 356 357 ret = syncObj->StatusFlag 358 ? GL_CONDITION_SATISFIED : GL_TIMEOUT_EXPIRED; 359 } 360 } 361 362 _mesa_unref_sync_object(ctx, syncObj, 1); 363 return ret; 364} 365 366 367GLenum GLAPIENTRY 368_mesa_ClientWaitSync_no_error(GLsync sync, GLbitfield flags, GLuint64 timeout) 369{ 370 GET_CURRENT_CONTEXT(ctx); 371 372 struct gl_sync_object *syncObj = _mesa_get_and_ref_sync(ctx, sync, true); 373 return client_wait_sync(ctx, syncObj, flags, timeout); 374} 375 376 377GLenum GLAPIENTRY 378_mesa_ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) 379{ 380 GET_CURRENT_CONTEXT(ctx); 381 struct gl_sync_object *syncObj; 382 383 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_WAIT_FAILED); 384 385 if ((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) != 0) { 386 _mesa_error(ctx, GL_INVALID_VALUE, "glClientWaitSync(flags=0x%x)", flags); 387 return GL_WAIT_FAILED; 388 } 389 390 syncObj = _mesa_get_and_ref_sync(ctx, sync, true); 391 if (!syncObj) { 392 _mesa_error(ctx, GL_INVALID_VALUE, 393 "glClientWaitSync (not a valid sync object)"); 394 return GL_WAIT_FAILED; 395 } 396 397 return client_wait_sync(ctx, syncObj, flags, timeout); 398} 399 400 401static void 402wait_sync(struct gl_context *ctx, struct gl_sync_object *syncObj, 403 GLbitfield flags, GLuint64 timeout) 404{ 405 ctx->Driver.ServerWaitSync(ctx, syncObj, flags, timeout); 406 _mesa_unref_sync_object(ctx, syncObj, 1); 407} 408 409 410void GLAPIENTRY 411_mesa_WaitSync_no_error(GLsync sync, GLbitfield flags, GLuint64 timeout) 412{ 413 GET_CURRENT_CONTEXT(ctx); 414 415 struct gl_sync_object *syncObj = _mesa_get_and_ref_sync(ctx, sync, true); 416 wait_sync(ctx, syncObj, flags, timeout); 417} 418 419 420void GLAPIENTRY 421_mesa_WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) 422{ 423 GET_CURRENT_CONTEXT(ctx); 424 struct gl_sync_object *syncObj; 425 426 if (flags != 0) { 427 _mesa_error(ctx, GL_INVALID_VALUE, "glWaitSync(flags=0x%x)", flags); 428 return; 429 } 430 431 if (timeout != GL_TIMEOUT_IGNORED) { 432 _mesa_error(ctx, GL_INVALID_VALUE, "glWaitSync(timeout=0x%" PRIx64 ")", 433 (uint64_t) timeout); 434 return; 435 } 436 437 syncObj = _mesa_get_and_ref_sync(ctx, sync, true); 438 if (!syncObj) { 439 _mesa_error(ctx, GL_INVALID_VALUE, 440 "glWaitSync (not a valid sync object)"); 441 return; 442 } 443 444 wait_sync(ctx, syncObj, flags, timeout); 445} 446 447 448void GLAPIENTRY 449_mesa_GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, 450 GLint *values) 451{ 452 GET_CURRENT_CONTEXT(ctx); 453 struct gl_sync_object *syncObj; 454 GLsizei size = 0; 455 GLint v[1]; 456 457 syncObj = _mesa_get_and_ref_sync(ctx, sync, true); 458 if (!syncObj) { 459 _mesa_error(ctx, GL_INVALID_VALUE, 460 "glGetSynciv (not a valid sync object)"); 461 return; 462 } 463 464 switch (pname) { 465 case GL_OBJECT_TYPE: 466 v[0] = GL_SYNC_FENCE; 467 size = 1; 468 break; 469 470 case GL_SYNC_CONDITION: 471 v[0] = syncObj->SyncCondition; 472 size = 1; 473 break; 474 475 case GL_SYNC_STATUS: 476 /* Update the state of the sync by dipping into the driver. Note that 477 * this call won't block. It just updates state in the common object 478 * data from the current driver state. 479 */ 480 ctx->Driver.CheckSync(ctx, syncObj); 481 482 v[0] = (syncObj->StatusFlag) ? GL_SIGNALED : GL_UNSIGNALED; 483 size = 1; 484 break; 485 486 case GL_SYNC_FLAGS: 487 v[0] = syncObj->Flags; 488 size = 1; 489 break; 490 491 default: 492 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSynciv(pname=0x%x)\n", pname); 493 _mesa_unref_sync_object(ctx, syncObj, 1); 494 return; 495 } 496 497 /* Section 4.1.3 (Sync Object Queries) of the OpenGL ES 3.10 spec says: 498 * 499 * "An INVALID_VALUE error is generated if bufSize is negative." 500 */ 501 if (bufSize < 0) { 502 _mesa_error(ctx, GL_INVALID_VALUE, "glGetSynciv(pname=0x%x)\n", pname); 503 } 504 505 if (size > 0 && bufSize > 0) { 506 const GLsizei copy_count = MIN2(size, bufSize); 507 508 memcpy(values, v, sizeof(GLint) * copy_count); 509 } 510 511 if (length != NULL) { 512 *length = size; 513 } 514 515 _mesa_unref_sync_object(ctx, syncObj, 1); 516} 517