ARB sync: Fix delete behavior and context destruction behavior

I believe this resolves the outstanding issues WRT sync object
deletetion.  I have also added a large comment at the top of syncobj.c
describing the expected memory management behavior.  I'm still a
little uncertain about the locking on ctx->Shared.
This commit is contained in:
Ian Romanick
2009-08-31 14:57:50 -07:00
parent f5a22721c5
commit 16b393d059
4 changed files with 109 additions and 30 deletions

View File

@@ -40,6 +40,7 @@
#include "main/mfeatures.h"
#include "glapi/glapi.h"
#include "math/m_matrix.h" /* GLmatrix */
#include "main/simple_list.h" /* struct simple_node */
/**
@@ -1988,6 +1989,7 @@ struct gl_query_state
/** Sync object state */
struct gl_sync_object {
struct simple_node link;
GLenum Type; /**< GL_SYNC_FENCE */
GLuint Name; /**< Fence name */
GLint RefCount; /**< Reference count */
@@ -2145,6 +2147,10 @@ struct gl_shared_state
struct _mesa_HashTable *FrameBuffers;
#endif
#if FEATURE_ARB_sync
struct simple_node SyncObjects;
#endif
void *DriverData; /**< Device driver shared state */
};

View File

@@ -43,7 +43,9 @@
#if FEATURE_ATI_fragment_shader
#include "shader/atifragshader.h"
#endif
#if FEATURE_ARB_sync
#include "syncobj.h"
#endif
/**
* Allocate and initialize a shared context state structure.
@@ -127,6 +129,10 @@ _mesa_alloc_shared_state(GLcontext *ctx)
shared->RenderBuffers = _mesa_NewHashTable();
#endif
#if FEATURE_ARB_sync
make_empty_list(& shared->SyncObjects);
#endif
return shared;
}
@@ -336,6 +342,17 @@ _mesa_free_shared_state(GLcontext *ctx, struct gl_shared_state *shared)
ctx->Driver.DeleteBuffer(ctx, shared->NullBufferObj);
#endif
#if FEATURE_ARB_sync
{
struct simple_node *node;
struct simple_node *temp;
foreach_s(node, temp, & shared->SyncObjects) {
_mesa_unref_sync_object(ctx, (struct gl_sync_object *) node);
}
}
#endif
/*
* Free texture objects (after FBOs since some textures might have
* been bound to FBOs).

View File

@@ -25,6 +25,33 @@
* \file syncobj.c
* Sync object management.
*
* Unlike textures and other objects that are shared between contexts, sync
* objects are not bound to the context. As a result, the reference counting
* and delete behavior of sync objects is slightly different. References to
* sync objects are added:
*
* - By \c glFencSynce. This sets the initial reference count to 1.
* - At the start of \c glClientWaitSync. The reference is held for the
* duration of the wait call.
*
* References are removed:
*
* - By \c glDeleteSync.
* - At the end of \c glClientWaitSync.
*
* Additionally, drivers may call \c _mesa_ref_sync_object and
* \c _mesa_unref_sync_object as needed to implement \c ServerWaitSync.
*
* As with shader objects, sync object names become invalid as soon as
* \c glDeleteSync is called. For this reason \c glDeleteSync sets the
* \c DeletePending flag. All functions validate object handles by testing
* this flag.
*
* \note
* Only \c GL_ARB_sync objects are shared between contexts. If support is ever
* added for either \c GL_NV_fence or \c GL_APPLE_fence different semantics
* will need to be implemented.
*
* \author Ian Romanick <ian.d.romanick@intel.com>
*/
@@ -130,6 +157,40 @@ _mesa_free_sync_data(GLcontext *ctx)
}
static int
_mesa_validate_sync(struct gl_sync_object *syncObj)
{
return (syncObj != NULL)
&& (syncObj->Type == GL_SYNC_FENCE)
&& !syncObj->DeletePending;
}
void
_mesa_ref_sync_object(GLcontext *ctx, struct gl_sync_object *syncObj)
{
_glthread_LOCK_MUTEX(ctx->Shared->Mutex);
syncObj->RefCount++;
_glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
}
void
_mesa_unref_sync_object(GLcontext *ctx, struct gl_sync_object *syncObj)
{
_glthread_LOCK_MUTEX(ctx->Shared->Mutex);
syncObj->RefCount--;
if (syncObj->RefCount == 0) {
remove_from_list(& syncObj->link);
_glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
(*ctx->Driver.DeleteSyncObject)(ctx, syncObj);
} else {
_glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
}
}
GLboolean
_mesa_IsSync(GLsync sync)
{
@@ -138,20 +199,7 @@ _mesa_IsSync(GLsync sync)
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
return ((syncObj != NULL) && (syncObj->Type == GL_SYNC_FENCE))
? GL_TRUE : GL_FALSE;
}
static void
_mesa_unref_sync_object(GLcontext *ctx, struct gl_sync_object *syncObj)
{
syncObj->RefCount--;
if (syncObj->RefCount == 0) {
(*ctx->Driver.DeleteSyncObject)(ctx, syncObj);
} else {
syncObj->DeletePending = 1;
}
return _mesa_validate_sync(syncObj) ? GL_TRUE : GL_FALSE;
}
@@ -173,7 +221,7 @@ _mesa_DeleteSync(GLsync sync)
return;
}
if (syncObj->Type != GL_SYNC_FENCE) {
if (!_mesa_validate_sync(syncObj)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteSync");
return;
}
@@ -182,6 +230,7 @@ _mesa_DeleteSync(GLsync sync)
/* If there are no client-waits or server-waits pending on this sync, delete
* the underlying object.
*/
syncObj->DeletePending = GL_TRUE;
_mesa_unref_sync_object(ctx, syncObj);
}
@@ -224,6 +273,10 @@ _mesa_FenceSync(GLenum condition, GLbitfield flags)
(*ctx->Driver.FenceSync)(ctx, syncObj, condition, flags);
_glthread_LOCK_MUTEX(ctx->Shared->Mutex);
insert_at_tail(& ctx->Shared->SyncObjects, & syncObj->link);
_glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
return (GLsync) syncObj;
}
@@ -240,7 +293,7 @@ _mesa_ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_WAIT_FAILED);
if ((syncObj == NULL) || (syncObj->Type != GL_SYNC_FENCE)) {
if (!_mesa_validate_sync(syncObj)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glClientWaitSync");
return GL_WAIT_FAILED;
}
@@ -251,6 +304,8 @@ _mesa_ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
}
_mesa_ref_sync_object(ctx, syncObj);
/* From the GL_ARB_sync spec:
*
* ClientWaitSync returns one of four status values. A return value of
@@ -259,20 +314,15 @@ _mesa_ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
* if <sync> was signaled, even if the value of <timeout> is zero.
*/
(*ctx->Driver.CheckSync)(ctx, syncObj);
if (syncObj->Status) {
return GL_ALREADY_SIGNALED;
}
ret = GL_ALREADY_SIGNALED;
} else {
(*ctx->Driver.ClientWaitSync)(ctx, syncObj, flags, timeout);
ret = syncObj->Status ? GL_CONDITION_SATISFIED : GL_TIMEOUT_EXPIRED;
if (syncObj->DeletePending && syncObj->Status) {
_mesa_unref_sync_object(ctx, syncObj);
}
_mesa_unref_sync_object(ctx, syncObj);
return ret;
}
@@ -285,7 +335,7 @@ _mesa_WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
ASSERT_OUTSIDE_BEGIN_END(ctx);
if ((syncObj == NULL) || (syncObj->Type != GL_SYNC_FENCE)) {
if (!_mesa_validate_sync(syncObj)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glWaitSync");
return;
}
@@ -318,7 +368,7 @@ _mesa_GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length,
ASSERT_OUTSIDE_BEGIN_END(ctx);
if ((syncObj == NULL) || (syncObj->Type != GL_SYNC_FENCE)) {
if (!_mesa_validate_sync(syncObj)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetSynciv");
return;
}

View File

@@ -42,6 +42,12 @@ _mesa_init_sync(GLcontext *);
extern void
_mesa_free_sync_data(GLcontext *);
extern void
_mesa_ref_sync_object(GLcontext *ctx, struct gl_sync_object *syncObj);
extern void
_mesa_unref_sync_object(GLcontext *ctx, struct gl_sync_object *syncObj);
extern GLboolean
_mesa_IsSync(GLsync sync);