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