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:
@@ -40,6 +40,7 @@
|
|||||||
#include "main/mfeatures.h"
|
#include "main/mfeatures.h"
|
||||||
#include "glapi/glapi.h"
|
#include "glapi/glapi.h"
|
||||||
#include "math/m_matrix.h" /* GLmatrix */
|
#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 */
|
/** Sync object state */
|
||||||
struct gl_sync_object {
|
struct gl_sync_object {
|
||||||
|
struct simple_node link;
|
||||||
GLenum Type; /**< GL_SYNC_FENCE */
|
GLenum Type; /**< GL_SYNC_FENCE */
|
||||||
GLuint Name; /**< Fence name */
|
GLuint Name; /**< Fence name */
|
||||||
GLint RefCount; /**< Reference count */
|
GLint RefCount; /**< Reference count */
|
||||||
@@ -2145,6 +2147,10 @@ struct gl_shared_state
|
|||||||
struct _mesa_HashTable *FrameBuffers;
|
struct _mesa_HashTable *FrameBuffers;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if FEATURE_ARB_sync
|
||||||
|
struct simple_node SyncObjects;
|
||||||
|
#endif
|
||||||
|
|
||||||
void *DriverData; /**< Device driver shared state */
|
void *DriverData; /**< Device driver shared state */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -43,7 +43,9 @@
|
|||||||
#if FEATURE_ATI_fragment_shader
|
#if FEATURE_ATI_fragment_shader
|
||||||
#include "shader/atifragshader.h"
|
#include "shader/atifragshader.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if FEATURE_ARB_sync
|
||||||
|
#include "syncobj.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate and initialize a shared context state structure.
|
* Allocate and initialize a shared context state structure.
|
||||||
@@ -127,6 +129,10 @@ _mesa_alloc_shared_state(GLcontext *ctx)
|
|||||||
shared->RenderBuffers = _mesa_NewHashTable();
|
shared->RenderBuffers = _mesa_NewHashTable();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if FEATURE_ARB_sync
|
||||||
|
make_empty_list(& shared->SyncObjects);
|
||||||
|
#endif
|
||||||
|
|
||||||
return shared;
|
return shared;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,6 +342,17 @@ _mesa_free_shared_state(GLcontext *ctx, struct gl_shared_state *shared)
|
|||||||
ctx->Driver.DeleteBuffer(ctx, shared->NullBufferObj);
|
ctx->Driver.DeleteBuffer(ctx, shared->NullBufferObj);
|
||||||
#endif
|
#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
|
* Free texture objects (after FBOs since some textures might have
|
||||||
* been bound to FBOs).
|
* been bound to FBOs).
|
||||||
|
@@ -25,6 +25,33 @@
|
|||||||
* \file syncobj.c
|
* \file syncobj.c
|
||||||
* Sync object management.
|
* 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>
|
* \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
|
GLboolean
|
||||||
_mesa_IsSync(GLsync sync)
|
_mesa_IsSync(GLsync sync)
|
||||||
{
|
{
|
||||||
@@ -138,20 +199,7 @@ _mesa_IsSync(GLsync sync)
|
|||||||
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
|
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
|
||||||
|
|
||||||
|
|
||||||
return ((syncObj != NULL) && (syncObj->Type == GL_SYNC_FENCE))
|
return _mesa_validate_sync(syncObj) ? GL_TRUE : GL_FALSE;
|
||||||
? 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -173,7 +221,7 @@ _mesa_DeleteSync(GLsync sync)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (syncObj->Type != GL_SYNC_FENCE) {
|
if (!_mesa_validate_sync(syncObj)) {
|
||||||
_mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteSync");
|
_mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteSync");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -182,6 +230,7 @@ _mesa_DeleteSync(GLsync sync)
|
|||||||
/* If there are no client-waits or server-waits pending on this sync, delete
|
/* If there are no client-waits or server-waits pending on this sync, delete
|
||||||
* the underlying object.
|
* the underlying object.
|
||||||
*/
|
*/
|
||||||
|
syncObj->DeletePending = GL_TRUE;
|
||||||
_mesa_unref_sync_object(ctx, syncObj);
|
_mesa_unref_sync_object(ctx, syncObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +273,10 @@ _mesa_FenceSync(GLenum condition, GLbitfield flags)
|
|||||||
|
|
||||||
(*ctx->Driver.FenceSync)(ctx, syncObj, condition, 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;
|
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);
|
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");
|
_mesa_error(ctx, GL_INVALID_OPERATION, "glClientWaitSync");
|
||||||
return GL_WAIT_FAILED;
|
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:
|
/* From the GL_ARB_sync spec:
|
||||||
*
|
*
|
||||||
* ClientWaitSync returns one of four status values. A return value of
|
* 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.
|
* if <sync> was signaled, even if the value of <timeout> is zero.
|
||||||
*/
|
*/
|
||||||
(*ctx->Driver.CheckSync)(ctx, syncObj);
|
(*ctx->Driver.CheckSync)(ctx, syncObj);
|
||||||
|
|
||||||
if (syncObj->Status) {
|
if (syncObj->Status) {
|
||||||
return GL_ALREADY_SIGNALED;
|
ret = GL_ALREADY_SIGNALED;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
|
|
||||||
(*ctx->Driver.ClientWaitSync)(ctx, syncObj, flags, timeout);
|
(*ctx->Driver.ClientWaitSync)(ctx, syncObj, flags, timeout);
|
||||||
|
|
||||||
ret = syncObj->Status ? GL_CONDITION_SATISFIED : GL_TIMEOUT_EXPIRED;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +335,7 @@ _mesa_WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
|
|||||||
ASSERT_OUTSIDE_BEGIN_END(ctx);
|
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");
|
_mesa_error(ctx, GL_INVALID_OPERATION, "glWaitSync");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -318,7 +368,7 @@ _mesa_GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length,
|
|||||||
ASSERT_OUTSIDE_BEGIN_END(ctx);
|
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");
|
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetSynciv");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,12 @@ _mesa_init_sync(GLcontext *);
|
|||||||
extern void
|
extern void
|
||||||
_mesa_free_sync_data(GLcontext *);
|
_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
|
extern GLboolean
|
||||||
_mesa_IsSync(GLsync sync);
|
_mesa_IsSync(GLsync sync);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user