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 "glheader.h" 59 #include "imports.h" 60 #include "context.h" 61 #include "macros.h" 62 #include "mfeatures.h" 63 #include "get.h" 64 #include "dispatch.h" 65 #include "mtypes.h" 66 67 #if FEATURE_ARB_sync 68 #include "syncobj.h" 69 70 static struct gl_sync_object * 71 _mesa_new_sync_object(struct gl_context *ctx, GLenum type) 72 { 73 struct gl_sync_object *s = MALLOC_STRUCT(gl_sync_object); 74 (void) ctx; 75 (void) type; 76 77 return s; 78 } 79 80 81 static void 82 _mesa_delete_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj) 83 { 84 (void) ctx; 85 free(syncObj); 86 } 87 88 89 static 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 101 static 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 113 static 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 128 void 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 void 144 _mesa_init_sync_dispatch(struct _glapi_table *disp) 145 { 146 SET_IsSync(disp, _mesa_IsSync); 147 SET_DeleteSync(disp, _mesa_DeleteSync); 148 SET_FenceSync(disp, _mesa_FenceSync); 149 SET_ClientWaitSync(disp, _mesa_ClientWaitSync); 150 SET_WaitSync(disp, _mesa_WaitSync); 151 SET_GetInteger64v(disp, _mesa_GetInteger64v); 152 SET_GetSynciv(disp, _mesa_GetSynciv); 153 } 154 155 156 /** 157 * Allocate/init the context state related to sync objects. 158 */ 159 void 160 _mesa_init_sync(struct gl_context *ctx) 161 { 162 (void) ctx; 163 } 164 165 166 /** 167 * Free the context state related to sync objects. 168 */ 169 void 170 _mesa_free_sync_data(struct gl_context *ctx) 171 { 172 (void) ctx; 173 } 174 175 176 static int 177 _mesa_validate_sync(struct gl_sync_object *syncObj) 178 { 179 return (syncObj != NULL) 180 && (syncObj->Type == GL_SYNC_FENCE) 181 && !syncObj->DeletePending; 182 } 183 184 185 void 186 _mesa_ref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj) 187 { 188 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 189 syncObj->RefCount++; 190 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 191 } 192 193 194 void 195 _mesa_unref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj) 196 { 197 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 198 syncObj->RefCount--; 199 if (syncObj->RefCount == 0) { 200 remove_from_list(& syncObj->link); 201 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 202 203 ctx->Driver.DeleteSyncObject(ctx, syncObj); 204 } else { 205 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 206 } 207 } 208 209 210 GLboolean GLAPIENTRY 211 _mesa_IsSync(GLsync sync) 212 { 213 GET_CURRENT_CONTEXT(ctx); 214 struct gl_sync_object *const syncObj = (struct gl_sync_object *) sync; 215 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 216 217 return _mesa_validate_sync(syncObj) ? GL_TRUE : GL_FALSE; 218 } 219 220 221 void GLAPIENTRY 222 _mesa_DeleteSync(GLsync sync) 223 { 224 GET_CURRENT_CONTEXT(ctx); 225 struct gl_sync_object *const syncObj = (struct gl_sync_object *) sync; 226 ASSERT_OUTSIDE_BEGIN_END(ctx); 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 if (!_mesa_validate_sync(syncObj)) { 239 _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteSync"); 240 return; 241 } 242 243 /* If there are no client-waits or server-waits pending on this sync, delete 244 * the underlying object. 245 */ 246 syncObj->DeletePending = GL_TRUE; 247 _mesa_unref_sync_object(ctx, syncObj); 248 } 249 250 251 GLsync GLAPIENTRY 252 _mesa_FenceSync(GLenum condition, GLbitfield flags) 253 { 254 GET_CURRENT_CONTEXT(ctx); 255 struct gl_sync_object *syncObj; 256 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 257 258 if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) { 259 _mesa_error(ctx, GL_INVALID_ENUM, "glFenceSync(condition=0x%x)", 260 condition); 261 return 0; 262 } 263 264 if (flags != 0) { 265 _mesa_error(ctx, GL_INVALID_VALUE, "glFenceSync(flags=0x%x)", 266 condition); 267 return 0; 268 } 269 270 syncObj = ctx->Driver.NewSyncObject(ctx, GL_SYNC_FENCE); 271 if (syncObj != NULL) { 272 syncObj->Type = GL_SYNC_FENCE; 273 /* The name is not currently used, and it is never visible to 274 * applications. If sync support is extended to provide support for 275 * NV_fence, this field will be used. We'll also need to add an object 276 * ID hashtable. 277 */ 278 syncObj->Name = 1; 279 syncObj->RefCount = 1; 280 syncObj->DeletePending = GL_FALSE; 281 syncObj->SyncCondition = condition; 282 syncObj->Flags = flags; 283 syncObj->StatusFlag = 0; 284 285 ctx->Driver.FenceSync(ctx, syncObj, condition, flags); 286 287 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 288 insert_at_tail(& ctx->Shared->SyncObjects, & syncObj->link); 289 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 290 291 return (GLsync) syncObj; 292 } 293 294 return NULL; 295 } 296 297 298 GLenum GLAPIENTRY 299 _mesa_ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) 300 { 301 GET_CURRENT_CONTEXT(ctx); 302 struct gl_sync_object *const syncObj = (struct gl_sync_object *) sync; 303 GLenum ret; 304 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_WAIT_FAILED); 305 306 if (!_mesa_validate_sync(syncObj)) { 307 _mesa_error(ctx, GL_INVALID_OPERATION, "glClientWaitSync"); 308 return GL_WAIT_FAILED; 309 } 310 311 if ((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) != 0) { 312 _mesa_error(ctx, GL_INVALID_ENUM, "glClientWaitSync(flags=0x%x)", flags); 313 return GL_WAIT_FAILED; 314 } 315 316 _mesa_ref_sync_object(ctx, syncObj); 317 318 /* From the GL_ARB_sync spec: 319 * 320 * ClientWaitSync returns one of four status values. A return value of 321 * ALREADY_SIGNALED indicates that <sync> was signaled at the time 322 * ClientWaitSync was called. ALREADY_SIGNALED will always be returned 323 * if <sync> was signaled, even if the value of <timeout> is zero. 324 */ 325 ctx->Driver.CheckSync(ctx, syncObj); 326 if (syncObj->StatusFlag) { 327 ret = GL_ALREADY_SIGNALED; 328 } else { 329 if (timeout == 0) { 330 ret = GL_TIMEOUT_EXPIRED; 331 } else { 332 ctx->Driver.ClientWaitSync(ctx, syncObj, flags, timeout); 333 334 ret = syncObj->StatusFlag ? GL_CONDITION_SATISFIED : GL_TIMEOUT_EXPIRED; 335 } 336 } 337 338 _mesa_unref_sync_object(ctx, syncObj); 339 return ret; 340 } 341 342 343 void GLAPIENTRY 344 _mesa_WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) 345 { 346 GET_CURRENT_CONTEXT(ctx); 347 struct gl_sync_object *const syncObj = (struct gl_sync_object *) sync; 348 ASSERT_OUTSIDE_BEGIN_END(ctx); 349 350 if (!_mesa_validate_sync(syncObj)) { 351 _mesa_error(ctx, GL_INVALID_OPERATION, "glWaitSync"); 352 return; 353 } 354 355 if (flags != 0) { 356 _mesa_error(ctx, GL_INVALID_ENUM, "glWaitSync(flags=0x%x)", flags); 357 return; 358 } 359 360 /* From the GL_ARB_sync spec: 361 * 362 * If the value of <timeout> is zero, then WaitSync does nothing. 363 */ 364 if (timeout == 0) { 365 return; 366 } 367 368 ctx->Driver.ServerWaitSync(ctx, syncObj, flags, timeout); 369 } 370 371 372 void GLAPIENTRY 373 _mesa_GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, 374 GLint *values) 375 { 376 GET_CURRENT_CONTEXT(ctx); 377 struct gl_sync_object *const syncObj = (struct gl_sync_object *) sync; 378 GLsizei size = 0; 379 GLint v[1]; 380 ASSERT_OUTSIDE_BEGIN_END(ctx); 381 382 if (!_mesa_validate_sync(syncObj)) { 383 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetSynciv"); 384 return; 385 } 386 387 switch (pname) { 388 case GL_OBJECT_TYPE: 389 v[0] = syncObj->Type; 390 size = 1; 391 break; 392 393 case GL_SYNC_CONDITION: 394 v[0] = syncObj->SyncCondition; 395 size = 1; 396 break; 397 398 case GL_SYNC_STATUS: 399 /* Update the state of the sync by dipping into the driver. Note that 400 * this call won't block. It just updates state in the common object 401 * data from the current driver state. 402 */ 403 ctx->Driver.CheckSync(ctx, syncObj); 404 405 v[0] = (syncObj->StatusFlag) ? GL_SIGNALED : GL_UNSIGNALED; 406 size = 1; 407 break; 408 409 case GL_SYNC_FLAGS: 410 v[0] = syncObj->Flags; 411 size = 1; 412 break; 413 414 default: 415 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSynciv(pname=0x%x)\n", pname); 416 return; 417 } 418 419 if (size > 0) { 420 const GLsizei copy_count = MIN2(size, bufSize); 421 422 memcpy(values, v, sizeof(GLint) * copy_count); 423 } 424 425 if (length != NULL) { 426 *length = size; 427 } 428 } 429 430 #endif /* FEATURE_ARB_sync */ 431