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