Implement mutex/locking around texture object reference counting.
Use new _mesa_reference_texobj() function for referencing/unreferencing textures. Add new assertions/tests to try to detect invalid usage of deleted textures.
This commit is contained in:
@@ -355,6 +355,7 @@ _mesa_PushAttrib(GLbitfield mask)
|
|||||||
ctx->Texture.Unit[u].Current1DArray->RefCount++;
|
ctx->Texture.Unit[u].Current1DArray->RefCount++;
|
||||||
ctx->Texture.Unit[u].Current2DArray->RefCount++;
|
ctx->Texture.Unit[u].Current2DArray->RefCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = MALLOC_STRUCT( gl_texture_attrib );
|
attr = MALLOC_STRUCT( gl_texture_attrib );
|
||||||
MEMCPY( attr, &ctx->Texture, sizeof(struct gl_texture_attrib) );
|
MEMCPY( attr, &ctx->Texture, sizeof(struct gl_texture_attrib) );
|
||||||
/* copy state of the currently bound texture objects */
|
/* copy state of the currently bound texture objects */
|
||||||
|
@@ -475,19 +475,12 @@ alloc_shared_state( GLcontext *ctx )
|
|||||||
if (!ss->Default2DArray)
|
if (!ss->Default2DArray)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* Effectively bind the default textures to all texture units */
|
/* sanity check */
|
||||||
ss->Default1D->RefCount += MAX_TEXTURE_IMAGE_UNITS;
|
assert(ss->Default1D->RefCount == 1);
|
||||||
ss->Default2D->RefCount += MAX_TEXTURE_IMAGE_UNITS;
|
|
||||||
ss->Default3D->RefCount += MAX_TEXTURE_IMAGE_UNITS;
|
|
||||||
ss->DefaultCubeMap->RefCount += MAX_TEXTURE_IMAGE_UNITS;
|
|
||||||
ss->DefaultRect->RefCount += MAX_TEXTURE_IMAGE_UNITS;
|
|
||||||
ss->Default1DArray->RefCount += MAX_TEXTURE_IMAGE_UNITS;
|
|
||||||
ss->Default2DArray->RefCount += MAX_TEXTURE_IMAGE_UNITS;
|
|
||||||
|
|
||||||
_glthread_INIT_MUTEX(ss->TexMutex);
|
_glthread_INIT_MUTEX(ss->TexMutex);
|
||||||
ss->TextureStateStamp = 0;
|
ss->TextureStateStamp = 0;
|
||||||
|
|
||||||
|
|
||||||
#if FEATURE_EXT_framebuffer_object
|
#if FEATURE_EXT_framebuffer_object
|
||||||
ss->FrameBuffers = _mesa_NewHashTable();
|
ss->FrameBuffers = _mesa_NewHashTable();
|
||||||
if (!ss->FrameBuffers)
|
if (!ss->FrameBuffers)
|
||||||
@@ -497,10 +490,9 @@ alloc_shared_state( GLcontext *ctx )
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
return GL_TRUE;
|
return GL_TRUE;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
/* Ran out of memory at some point. Free everything and return NULL */
|
/* Ran out of memory at some point. Free everything and return NULL */
|
||||||
if (ss->DisplayList)
|
if (ss->DisplayList)
|
||||||
_mesa_DeleteHashTable(ss->DisplayList);
|
_mesa_DeleteHashTable(ss->DisplayList);
|
||||||
|
@@ -151,22 +151,18 @@ _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
|
|||||||
{
|
{
|
||||||
if (att->Type == GL_TEXTURE) {
|
if (att->Type == GL_TEXTURE) {
|
||||||
ASSERT(att->Texture);
|
ASSERT(att->Texture);
|
||||||
att->Texture->RefCount--;
|
if (ctx->Driver.FinishRenderTexture) {
|
||||||
if (att->Texture->RefCount == 0) {
|
/* tell driver we're done rendering to this texobj */
|
||||||
ctx->Driver.DeleteTexture(ctx, att->Texture);
|
ctx->Driver.FinishRenderTexture(ctx, att);
|
||||||
}
|
}
|
||||||
else {
|
_mesa_reference_texobj(&att->Texture, NULL); /* unbind */
|
||||||
/* tell driver that we're done rendering to this texture. */
|
ASSERT(!att->Texture);
|
||||||
if (ctx->Driver.FinishRenderTexture) {
|
|
||||||
ctx->Driver.FinishRenderTexture(ctx, att);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
att->Texture = NULL;
|
|
||||||
}
|
}
|
||||||
if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
|
if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
|
||||||
ASSERT(att->Renderbuffer);
|
ASSERT(att->Renderbuffer);
|
||||||
ASSERT(!att->Texture);
|
ASSERT(!att->Texture);
|
||||||
_mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
|
_mesa_reference_renderbuffer(&att->Renderbuffer, NULL); /* unbind */
|
||||||
|
ASSERT(!att->Renderbuffer);
|
||||||
}
|
}
|
||||||
att->Type = GL_NONE;
|
att->Type = GL_NONE;
|
||||||
att->Complete = GL_TRUE;
|
att->Complete = GL_TRUE;
|
||||||
@@ -192,8 +188,8 @@ _mesa_set_texture_attachment(GLcontext *ctx,
|
|||||||
/* new attachment */
|
/* new attachment */
|
||||||
_mesa_remove_attachment(ctx, att);
|
_mesa_remove_attachment(ctx, att);
|
||||||
att->Type = GL_TEXTURE;
|
att->Type = GL_TEXTURE;
|
||||||
att->Texture = texObj;
|
assert(!att->Texture);
|
||||||
texObj->RefCount++;
|
_mesa_reference_texobj(&att->Texture, texObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* always update these fields */
|
/* always update these fields */
|
||||||
|
@@ -38,6 +38,7 @@
|
|||||||
#include "fbobject.h"
|
#include "fbobject.h"
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
#include "renderbuffer.h"
|
#include "renderbuffer.h"
|
||||||
|
#include "texobj.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -192,17 +193,11 @@ _mesa_free_framebuffer_data(struct gl_framebuffer *fb)
|
|||||||
_mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
|
_mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
|
||||||
}
|
}
|
||||||
if (att->Texture) {
|
if (att->Texture) {
|
||||||
/* render to texture */
|
_mesa_reference_texobj(&att->Texture, NULL);
|
||||||
att->Texture->RefCount--;
|
|
||||||
if (att->Texture->RefCount == 0) {
|
|
||||||
GET_CURRENT_CONTEXT(ctx);
|
|
||||||
if (ctx) {
|
|
||||||
ctx->Driver.DeleteTexture(ctx, att->Texture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ASSERT(!att->Renderbuffer);
|
||||||
|
ASSERT(!att->Texture);
|
||||||
att->Type = GL_NONE;
|
att->Type = GL_NONE;
|
||||||
att->Texture = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unbind _Depth/_StencilBuffer to decr ref counts */
|
/* unbind _Depth/_StencilBuffer to decr ref counts */
|
||||||
|
@@ -1400,6 +1400,7 @@ struct gl_texture_image
|
|||||||
*/
|
*/
|
||||||
struct gl_texture_object
|
struct gl_texture_object
|
||||||
{
|
{
|
||||||
|
_glthread_Mutex Mutex; /**< for thread safety */
|
||||||
GLint RefCount; /**< reference count */
|
GLint RefCount; /**< reference count */
|
||||||
GLuint Name; /**< the user-visible texture object ID */
|
GLuint Name; /**< the user-visible texture object ID */
|
||||||
GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */
|
GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */
|
||||||
|
@@ -106,6 +106,7 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj,
|
|||||||
|
|
||||||
_mesa_bzero(obj, sizeof(*obj));
|
_mesa_bzero(obj, sizeof(*obj));
|
||||||
/* init the non-zero fields */
|
/* init the non-zero fields */
|
||||||
|
_glthread_INIT_MUTEX(obj->Mutex);
|
||||||
obj->RefCount = 1;
|
obj->RefCount = 1;
|
||||||
obj->Name = name;
|
obj->Name = name;
|
||||||
obj->Target = target;
|
obj->Target = target;
|
||||||
@@ -151,8 +152,17 @@ _mesa_delete_texture_object( GLcontext *ctx, struct gl_texture_object *texObj )
|
|||||||
{
|
{
|
||||||
GLuint i, face;
|
GLuint i, face;
|
||||||
|
|
||||||
|
/*
|
||||||
|
printf("TEX DELETE %p (%u)\n", (void*) texObj, texObj->Name);
|
||||||
|
*/
|
||||||
|
|
||||||
(void) ctx;
|
(void) ctx;
|
||||||
|
|
||||||
|
/* Set Target to an invalid value. With some assertions elsewhere
|
||||||
|
* we can try to detect possible use of deleted textures.
|
||||||
|
*/
|
||||||
|
texObj->Target = 0x99;
|
||||||
|
|
||||||
_mesa_free_colortable_data(&texObj->Palette);
|
_mesa_free_colortable_data(&texObj->Palette);
|
||||||
|
|
||||||
/* free the texture images */
|
/* free the texture images */
|
||||||
@@ -164,6 +174,9 @@ _mesa_delete_texture_object( GLcontext *ctx, struct gl_texture_object *texObj )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* destroy the mutex -- it may have allocated memory (eg on bsd) */
|
||||||
|
_glthread_DESTROY_MUTEX(texObj->Mutex);
|
||||||
|
|
||||||
/* free this object */
|
/* free this object */
|
||||||
_mesa_free(texObj);
|
_mesa_free(texObj);
|
||||||
}
|
}
|
||||||
@@ -213,6 +226,98 @@ _mesa_copy_texture_object( struct gl_texture_object *dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given texture object is valid by examining its Target field.
|
||||||
|
* For debugging only.
|
||||||
|
*/
|
||||||
|
static GLboolean
|
||||||
|
valid_texture_object(const struct gl_texture_object *tex)
|
||||||
|
{
|
||||||
|
switch (tex->Target) {
|
||||||
|
case 0:
|
||||||
|
case GL_TEXTURE_1D:
|
||||||
|
case GL_TEXTURE_2D:
|
||||||
|
case GL_TEXTURE_3D:
|
||||||
|
case GL_TEXTURE_CUBE_MAP_ARB:
|
||||||
|
case GL_TEXTURE_RECTANGLE_NV:
|
||||||
|
case GL_TEXTURE_1D_ARRAY_EXT:
|
||||||
|
case GL_TEXTURE_2D_ARRAY_EXT:
|
||||||
|
return GL_TRUE;
|
||||||
|
case 0x99:
|
||||||
|
_mesa_problem(NULL, "invalid reference to a deleted texture object");
|
||||||
|
return GL_FALSE;
|
||||||
|
default:
|
||||||
|
_mesa_problem(NULL, "invalid texture object Target value");
|
||||||
|
return GL_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference (or unreference) a texture object.
|
||||||
|
* If '*ptr', decrement *ptr's refcount (and delete if it becomes zero).
|
||||||
|
* If 'tex' is non-null, increment its refcount.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_mesa_reference_texobj(struct gl_texture_object **ptr,
|
||||||
|
struct gl_texture_object *tex)
|
||||||
|
{
|
||||||
|
assert(ptr);
|
||||||
|
if (*ptr == tex) {
|
||||||
|
/* no change */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ptr) {
|
||||||
|
/* Unreference the old texture */
|
||||||
|
GLboolean deleteFlag = GL_FALSE;
|
||||||
|
struct gl_texture_object *oldTex = *ptr;
|
||||||
|
|
||||||
|
assert(valid_texture_object(oldTex));
|
||||||
|
|
||||||
|
_glthread_LOCK_MUTEX(oldTex->Mutex);
|
||||||
|
ASSERT(oldTex->RefCount > 0);
|
||||||
|
oldTex->RefCount--;
|
||||||
|
/*
|
||||||
|
printf("TEX DECR %p (%u) to %d\n",
|
||||||
|
(void*) oldTex, oldTex->Name, oldTex->RefCount);
|
||||||
|
*/
|
||||||
|
deleteFlag = (oldTex->RefCount == 0);
|
||||||
|
_glthread_UNLOCK_MUTEX(oldTex->Mutex);
|
||||||
|
|
||||||
|
if (deleteFlag) {
|
||||||
|
GET_CURRENT_CONTEXT(ctx);
|
||||||
|
ctx->Driver.DeleteTexture(ctx, oldTex);
|
||||||
|
}
|
||||||
|
|
||||||
|
*ptr = NULL;
|
||||||
|
}
|
||||||
|
assert(!*ptr);
|
||||||
|
|
||||||
|
if (tex) {
|
||||||
|
/* reference new texture */
|
||||||
|
assert(valid_texture_object(tex));
|
||||||
|
_glthread_LOCK_MUTEX(tex->Mutex);
|
||||||
|
if (tex->RefCount == 0) {
|
||||||
|
/* this texture's being deleted (look just above) */
|
||||||
|
/* Not sure this can every really happen. Warn if it does. */
|
||||||
|
_mesa_problem(NULL, "referencing deleted texture object");
|
||||||
|
*ptr = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tex->RefCount++;
|
||||||
|
/*
|
||||||
|
printf("TEX INCR %p (%u) to %d\n",
|
||||||
|
(void*) tex, tex->Name, tex->RefCount);
|
||||||
|
*/
|
||||||
|
*ptr = tex;
|
||||||
|
}
|
||||||
|
_glthread_UNLOCK_MUTEX(tex->Mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report why a texture object is incomplete.
|
* Report why a texture object is incomplete.
|
||||||
*
|
*
|
||||||
@@ -609,8 +714,7 @@ unbind_texobj_from_fbo(GLcontext *ctx, struct gl_texture_object *texObj)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the given texture object is bound to any texture image units and
|
* Check if the given texture object is bound to any texture image units and
|
||||||
* unbind it if so.
|
* unbind it if so (revert to default textures).
|
||||||
* XXX all RefCount accesses should be protected by a mutex.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
unbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj)
|
unbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj)
|
||||||
@@ -619,42 +723,26 @@ unbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj)
|
|||||||
|
|
||||||
for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
|
for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
|
||||||
struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
|
struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
|
||||||
struct gl_texture_object **curr = NULL;
|
|
||||||
|
|
||||||
if (texObj == unit->Current1D) {
|
if (texObj == unit->Current1D) {
|
||||||
curr = &unit->Current1D;
|
_mesa_reference_texobj(&unit->Current1D, ctx->Shared->Default1D);
|
||||||
unit->Current1D = ctx->Shared->Default1D;
|
|
||||||
}
|
}
|
||||||
else if (texObj == unit->Current2D) {
|
else if (texObj == unit->Current2D) {
|
||||||
curr = &unit->Current2D;
|
_mesa_reference_texobj(&unit->Current2D, ctx->Shared->Default2D);
|
||||||
unit->Current2D = ctx->Shared->Default2D;
|
|
||||||
}
|
}
|
||||||
else if (texObj == unit->Current3D) {
|
else if (texObj == unit->Current3D) {
|
||||||
curr = &unit->Current3D;
|
_mesa_reference_texobj(&unit->Current3D, ctx->Shared->Default3D);
|
||||||
unit->Current3D = ctx->Shared->Default3D;
|
|
||||||
}
|
}
|
||||||
else if (texObj == unit->CurrentCubeMap) {
|
else if (texObj == unit->CurrentCubeMap) {
|
||||||
curr = &unit->CurrentCubeMap;
|
_mesa_reference_texobj(&unit->CurrentCubeMap, ctx->Shared->DefaultCubeMap);
|
||||||
unit->CurrentCubeMap = ctx->Shared->DefaultCubeMap;
|
|
||||||
}
|
}
|
||||||
else if (texObj == unit->CurrentRect) {
|
else if (texObj == unit->CurrentRect) {
|
||||||
curr = &unit->CurrentRect;
|
_mesa_reference_texobj(&unit->CurrentRect, ctx->Shared->DefaultRect);
|
||||||
unit->CurrentRect = ctx->Shared->DefaultRect;
|
|
||||||
}
|
}
|
||||||
else if (texObj == unit->Current1DArray) {
|
else if (texObj == unit->Current1DArray) {
|
||||||
curr = &unit->Current1DArray;
|
_mesa_reference_texobj(&unit->Current1DArray, ctx->Shared->Default1DArray);
|
||||||
unit->CurrentRect = ctx->Shared->Default1DArray;
|
|
||||||
}
|
}
|
||||||
else if (texObj == unit->Current2DArray) {
|
else if (texObj == unit->Current2DArray) {
|
||||||
curr = &unit->Current1DArray;
|
_mesa_reference_texobj(&unit->Current2DArray, ctx->Shared->Default2DArray);
|
||||||
unit->CurrentRect = ctx->Shared->Default2DArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curr) {
|
|
||||||
(*curr)->RefCount++;
|
|
||||||
texObj->RefCount--;
|
|
||||||
if (texObj == unit->_Current)
|
|
||||||
unit->_Current = *curr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -690,8 +778,6 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
|
|||||||
= _mesa_lookup_texture(ctx, textures[i]);
|
= _mesa_lookup_texture(ctx, textures[i]);
|
||||||
|
|
||||||
if (delObj) {
|
if (delObj) {
|
||||||
GLboolean deleted;
|
|
||||||
|
|
||||||
_mesa_lock_texture(ctx, delObj);
|
_mesa_lock_texture(ctx, delObj);
|
||||||
|
|
||||||
/* Check if texture is bound to any framebuffer objects.
|
/* Check if texture is bound to any framebuffer objects.
|
||||||
@@ -701,10 +787,12 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
|
|||||||
unbind_texobj_from_fbo(ctx, delObj);
|
unbind_texobj_from_fbo(ctx, delObj);
|
||||||
|
|
||||||
/* Check if this texture is currently bound to any texture units.
|
/* Check if this texture is currently bound to any texture units.
|
||||||
* If so, unbind it and decrement the reference count.
|
* If so, unbind it.
|
||||||
*/
|
*/
|
||||||
unbind_texobj_from_texunits(ctx, delObj);
|
unbind_texobj_from_texunits(ctx, delObj);
|
||||||
|
|
||||||
|
_mesa_unlock_texture(ctx, delObj);
|
||||||
|
|
||||||
ctx->NewState |= _NEW_TEXTURE;
|
ctx->NewState |= _NEW_TEXTURE;
|
||||||
|
|
||||||
/* The texture _name_ is now free for re-use.
|
/* The texture _name_ is now free for re-use.
|
||||||
@@ -714,23 +802,10 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
|
|||||||
_mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
|
_mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
|
||||||
_glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
|
_glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
|
||||||
|
|
||||||
/* The actual texture object will not be freed until it's no
|
/* Unrefernce the texobj. If refcount hits zero, the texture
|
||||||
* longer bound in any context.
|
* will be deleted.
|
||||||
* XXX all RefCount accesses should be protected by a mutex.
|
|
||||||
*/
|
*/
|
||||||
delObj->RefCount--;
|
_mesa_reference_texobj(&delObj, NULL);
|
||||||
deleted = (delObj->RefCount == 0);
|
|
||||||
_mesa_unlock_texture(ctx, delObj);
|
|
||||||
|
|
||||||
/* We know that refcount went to zero above, so this is
|
|
||||||
* the only pointer left to delObj, so we don't have to
|
|
||||||
* worry about locking any more:
|
|
||||||
*/
|
|
||||||
if (deleted) {
|
|
||||||
ASSERT(delObj->Name != 0); /* Never delete default tex objs */
|
|
||||||
ASSERT(ctx->Driver.DeleteTexture);
|
|
||||||
(*ctx->Driver.DeleteTexture)(ctx, delObj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -758,7 +833,6 @@ _mesa_BindTexture( GLenum target, GLuint texName )
|
|||||||
GET_CURRENT_CONTEXT(ctx);
|
GET_CURRENT_CONTEXT(ctx);
|
||||||
const GLuint unit = ctx->Texture.CurrentUnit;
|
const GLuint unit = ctx->Texture.CurrentUnit;
|
||||||
struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
|
struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
|
||||||
struct gl_texture_object *oldTexObj;
|
|
||||||
struct gl_texture_object *newTexObj = NULL;
|
struct gl_texture_object *newTexObj = NULL;
|
||||||
ASSERT_OUTSIDE_BEGIN_END(ctx);
|
ASSERT_OUTSIDE_BEGIN_END(ctx);
|
||||||
|
|
||||||
@@ -766,62 +840,6 @@ _mesa_BindTexture( GLenum target, GLuint texName )
|
|||||||
_mesa_debug(ctx, "glBindTexture %s %d\n",
|
_mesa_debug(ctx, "glBindTexture %s %d\n",
|
||||||
_mesa_lookup_enum_by_nr(target), (GLint) texName);
|
_mesa_lookup_enum_by_nr(target), (GLint) texName);
|
||||||
|
|
||||||
/*
|
|
||||||
* Get pointer to currently bound texture object (oldTexObj)
|
|
||||||
*/
|
|
||||||
switch (target) {
|
|
||||||
case GL_TEXTURE_1D:
|
|
||||||
oldTexObj = texUnit->Current1D;
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_2D:
|
|
||||||
oldTexObj = texUnit->Current2D;
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_3D:
|
|
||||||
oldTexObj = texUnit->Current3D;
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_CUBE_MAP_ARB:
|
|
||||||
if (!ctx->Extensions.ARB_texture_cube_map) {
|
|
||||||
_mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
oldTexObj = texUnit->CurrentCubeMap;
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_RECTANGLE_NV:
|
|
||||||
if (!ctx->Extensions.NV_texture_rectangle) {
|
|
||||||
_mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
oldTexObj = texUnit->CurrentRect;
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_1D_ARRAY_EXT:
|
|
||||||
if (!ctx->Extensions.MESA_texture_array) {
|
|
||||||
_mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
oldTexObj = texUnit->Current1DArray;
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_2D_ARRAY_EXT:
|
|
||||||
if (!ctx->Extensions.MESA_texture_array) {
|
|
||||||
_mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
oldTexObj = texUnit->Current2DArray;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldTexObj->Name == texName) {
|
|
||||||
/* XXX this might be wrong. If the texobj is in use by another
|
|
||||||
* context and a texobj parameter was changed, this might be our
|
|
||||||
* only chance to update this context's hardware state.
|
|
||||||
* Note that some applications re-bind the same texture a lot so we
|
|
||||||
* want to handle that case quickly.
|
|
||||||
*/
|
|
||||||
return; /* rebinding the same texture- no change */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get pointer to new texture object (newTexObj)
|
* Get pointer to new texture object (newTexObj)
|
||||||
*/
|
*/
|
||||||
@@ -896,28 +914,30 @@ _mesa_BindTexture( GLenum target, GLuint texName )
|
|||||||
newTexObj->Target = target;
|
newTexObj->Target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX all RefCount accesses should be protected by a mutex. */
|
assert(valid_texture_object(newTexObj));
|
||||||
newTexObj->RefCount++;
|
|
||||||
|
|
||||||
/* do the actual binding, but first flush outstanding vertices:
|
/* flush before changing binding */
|
||||||
*/
|
|
||||||
FLUSH_VERTICES(ctx, _NEW_TEXTURE);
|
FLUSH_VERTICES(ctx, _NEW_TEXTURE);
|
||||||
|
|
||||||
|
/* Do the actual binding. The refcount on the previously bound
|
||||||
|
* texture object will be decremented. It'll be deleted if the
|
||||||
|
* count hits zero.
|
||||||
|
*/
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case GL_TEXTURE_1D:
|
case GL_TEXTURE_1D:
|
||||||
texUnit->Current1D = newTexObj;
|
_mesa_reference_texobj(&texUnit->Current1D, newTexObj);
|
||||||
break;
|
break;
|
||||||
case GL_TEXTURE_2D:
|
case GL_TEXTURE_2D:
|
||||||
texUnit->Current2D = newTexObj;
|
_mesa_reference_texobj(&texUnit->Current2D, newTexObj);
|
||||||
break;
|
break;
|
||||||
case GL_TEXTURE_3D:
|
case GL_TEXTURE_3D:
|
||||||
texUnit->Current3D = newTexObj;
|
_mesa_reference_texobj(&texUnit->Current3D, newTexObj);
|
||||||
break;
|
break;
|
||||||
case GL_TEXTURE_CUBE_MAP_ARB:
|
case GL_TEXTURE_CUBE_MAP_ARB:
|
||||||
texUnit->CurrentCubeMap = newTexObj;
|
_mesa_reference_texobj(&texUnit->CurrentCubeMap, newTexObj);
|
||||||
break;
|
break;
|
||||||
case GL_TEXTURE_RECTANGLE_NV:
|
case GL_TEXTURE_RECTANGLE_NV:
|
||||||
texUnit->CurrentRect = newTexObj;
|
_mesa_reference_texobj(&texUnit->CurrentRect, newTexObj);
|
||||||
break;
|
break;
|
||||||
case GL_TEXTURE_1D_ARRAY_EXT:
|
case GL_TEXTURE_1D_ARRAY_EXT:
|
||||||
texUnit->Current1DArray = newTexObj;
|
texUnit->Current1DArray = newTexObj;
|
||||||
@@ -933,18 +953,6 @@ _mesa_BindTexture( GLenum target, GLuint texName )
|
|||||||
/* Pass BindTexture call to device driver */
|
/* Pass BindTexture call to device driver */
|
||||||
if (ctx->Driver.BindTexture)
|
if (ctx->Driver.BindTexture)
|
||||||
(*ctx->Driver.BindTexture)( ctx, target, newTexObj );
|
(*ctx->Driver.BindTexture)( ctx, target, newTexObj );
|
||||||
|
|
||||||
/* Decrement the reference count on the old texture and check if it's
|
|
||||||
* time to delete it.
|
|
||||||
*/
|
|
||||||
/* XXX all RefCount accesses should be protected by a mutex. */
|
|
||||||
oldTexObj->RefCount--;
|
|
||||||
ASSERT(oldTexObj->RefCount >= 0);
|
|
||||||
if (oldTexObj->RefCount == 0) {
|
|
||||||
ASSERT(oldTexObj->Name != 0);
|
|
||||||
ASSERT(ctx->Driver.DeleteTexture);
|
|
||||||
(*ctx->Driver.DeleteTexture)( ctx, oldTexObj );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -57,6 +57,10 @@ extern void
|
|||||||
_mesa_copy_texture_object( struct gl_texture_object *dest,
|
_mesa_copy_texture_object( struct gl_texture_object *dest,
|
||||||
const struct gl_texture_object *src );
|
const struct gl_texture_object *src );
|
||||||
|
|
||||||
|
extern void
|
||||||
|
_mesa_reference_texobj(struct gl_texture_object **ptr,
|
||||||
|
struct gl_texture_object *tex);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
_mesa_test_texobj_completeness( const GLcontext *ctx,
|
_mesa_test_texobj_completeness( const GLcontext *ctx,
|
||||||
struct gl_texture_object *obj );
|
struct gl_texture_object *obj );
|
||||||
|
@@ -63,31 +63,6 @@ static const struct gl_tex_env_combine_state default_combine_state = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy a texture binding. Helper used by _mesa_copy_texture_state().
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
copy_texture_binding(const GLcontext *ctx,
|
|
||||||
struct gl_texture_object **dst,
|
|
||||||
struct gl_texture_object *src)
|
|
||||||
{
|
|
||||||
/* only copy if names differ (per OpenGL SI) */
|
|
||||||
if ((*dst)->Name != src->Name) {
|
|
||||||
/* unbind/delete dest binding which we're changing */
|
|
||||||
(*dst)->RefCount--;
|
|
||||||
if ((*dst)->RefCount == 0) {
|
|
||||||
/* time to delete this texture object */
|
|
||||||
ASSERT((*dst)->Name != 0);
|
|
||||||
ASSERT(ctx->Driver.DeleteTexture);
|
|
||||||
/* XXX cast-away const, unfortunately */
|
|
||||||
(*ctx->Driver.DeleteTexture)((GLcontext *) ctx, *dst);
|
|
||||||
}
|
|
||||||
/* make new binding, incrementing ref count */
|
|
||||||
*dst = src;
|
|
||||||
src->RefCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by glXCopyContext to copy texture state from one context to another.
|
* Used by glXCopyContext to copy texture state from one context to another.
|
||||||
@@ -144,20 +119,20 @@ _mesa_copy_texture_state( const GLcontext *src, GLcontext *dst )
|
|||||||
/* copy texture object bindings, not contents of texture objects */
|
/* copy texture object bindings, not contents of texture objects */
|
||||||
_mesa_lock_context_textures(dst);
|
_mesa_lock_context_textures(dst);
|
||||||
|
|
||||||
copy_texture_binding(src, &dst->Texture.Unit[i].Current1D,
|
_mesa_reference_texobj(&dst->Texture.Unit[i].Current1D,
|
||||||
src->Texture.Unit[i].Current1D);
|
src->Texture.Unit[i].Current1D);
|
||||||
copy_texture_binding(src, &dst->Texture.Unit[i].Current2D,
|
_mesa_reference_texobj(&dst->Texture.Unit[i].Current2D,
|
||||||
src->Texture.Unit[i].Current2D);
|
src->Texture.Unit[i].Current2D);
|
||||||
copy_texture_binding(src, &dst->Texture.Unit[i].Current3D,
|
_mesa_reference_texobj(&dst->Texture.Unit[i].Current3D,
|
||||||
src->Texture.Unit[i].Current3D);
|
src->Texture.Unit[i].Current3D);
|
||||||
copy_texture_binding(src, &dst->Texture.Unit[i].CurrentCubeMap,
|
_mesa_reference_texobj(&dst->Texture.Unit[i].CurrentCubeMap,
|
||||||
src->Texture.Unit[i].CurrentCubeMap);
|
src->Texture.Unit[i].CurrentCubeMap);
|
||||||
copy_texture_binding(src, &dst->Texture.Unit[i].CurrentRect,
|
_mesa_reference_texobj(&dst->Texture.Unit[i].CurrentRect,
|
||||||
src->Texture.Unit[i].CurrentRect);
|
src->Texture.Unit[i].CurrentRect);
|
||||||
copy_texture_binding(src, &dst->Texture.Unit[i].Current1DArray,
|
_mesa_reference_texobj(&dst->Texture.Unit[i].Current1DArray,
|
||||||
src->Texture.Unit[i].Current1DArray);
|
src->Texture.Unit[i].Current1DArray);
|
||||||
copy_texture_binding(src, &dst->Texture.Unit[i].Current2DArray,
|
_mesa_reference_texobj(&dst->Texture.Unit[i].Current2DArray,
|
||||||
src->Texture.Unit[i].Current2DArray);
|
src->Texture.Unit[i].Current2DArray);
|
||||||
|
|
||||||
_mesa_unlock_context_textures(dst);
|
_mesa_unlock_context_textures(dst);
|
||||||
}
|
}
|
||||||
@@ -3113,6 +3088,8 @@ alloc_proxy_textures( GLcontext *ctx )
|
|||||||
if (!ctx->Texture.Proxy2DArray)
|
if (!ctx->Texture.Proxy2DArray)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
assert(ctx->Texture.Proxy1D->RefCount == 1);
|
||||||
|
|
||||||
return GL_TRUE;
|
return GL_TRUE;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@@ -3172,13 +3149,14 @@ init_texture_unit( GLcontext *ctx, GLuint unit )
|
|||||||
ASSIGN_4V( texUnit->EyePlaneR, 0.0, 0.0, 0.0, 0.0 );
|
ASSIGN_4V( texUnit->EyePlaneR, 0.0, 0.0, 0.0, 0.0 );
|
||||||
ASSIGN_4V( texUnit->EyePlaneQ, 0.0, 0.0, 0.0, 0.0 );
|
ASSIGN_4V( texUnit->EyePlaneQ, 0.0, 0.0, 0.0, 0.0 );
|
||||||
|
|
||||||
texUnit->Current1D = ctx->Shared->Default1D;
|
/* initialize current texture object ptrs to the shared default objects */
|
||||||
texUnit->Current2D = ctx->Shared->Default2D;
|
_mesa_reference_texobj(&texUnit->Current1D, ctx->Shared->Default1D);
|
||||||
texUnit->Current3D = ctx->Shared->Default3D;
|
_mesa_reference_texobj(&texUnit->Current2D, ctx->Shared->Default2D);
|
||||||
texUnit->CurrentCubeMap = ctx->Shared->DefaultCubeMap;
|
_mesa_reference_texobj(&texUnit->Current3D, ctx->Shared->Default3D);
|
||||||
texUnit->CurrentRect = ctx->Shared->DefaultRect;
|
_mesa_reference_texobj(&texUnit->CurrentCubeMap, ctx->Shared->DefaultCubeMap);
|
||||||
texUnit->Current1DArray = ctx->Shared->Default1DArray;
|
_mesa_reference_texobj(&texUnit->CurrentRect, ctx->Shared->DefaultRect);
|
||||||
texUnit->Current2DArray = ctx->Shared->Default2DArray;
|
_mesa_reference_texobj(&texUnit->Current1DArray, ctx->Shared->Default1DArray);
|
||||||
|
_mesa_reference_texobj(&texUnit->Current2DArray, ctx->Shared->Default2DArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3193,23 +3171,20 @@ _mesa_init_texture(GLcontext *ctx)
|
|||||||
assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS);
|
assert(MAX_TEXTURE_LEVELS >= MAX_3D_TEXTURE_LEVELS);
|
||||||
assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS);
|
assert(MAX_TEXTURE_LEVELS >= MAX_CUBE_TEXTURE_LEVELS);
|
||||||
|
|
||||||
/* Effectively bind the default textures to all texture units */
|
|
||||||
ctx->Shared->Default1D->RefCount += MAX_TEXTURE_UNITS;
|
|
||||||
ctx->Shared->Default2D->RefCount += MAX_TEXTURE_UNITS;
|
|
||||||
ctx->Shared->Default3D->RefCount += MAX_TEXTURE_UNITS;
|
|
||||||
ctx->Shared->DefaultCubeMap->RefCount += MAX_TEXTURE_UNITS;
|
|
||||||
ctx->Shared->DefaultRect->RefCount += MAX_TEXTURE_UNITS;
|
|
||||||
ctx->Shared->Default1DArray->RefCount += MAX_TEXTURE_UNITS;
|
|
||||||
ctx->Shared->Default2DArray->RefCount += MAX_TEXTURE_UNITS;
|
|
||||||
|
|
||||||
/* Texture group */
|
/* Texture group */
|
||||||
ctx->Texture.CurrentUnit = 0; /* multitexture */
|
ctx->Texture.CurrentUnit = 0; /* multitexture */
|
||||||
ctx->Texture._EnabledUnits = 0;
|
ctx->Texture._EnabledUnits = 0;
|
||||||
for (i=0; i<MAX_TEXTURE_UNITS; i++)
|
|
||||||
init_texture_unit( ctx, i );
|
|
||||||
ctx->Texture.SharedPalette = GL_FALSE;
|
ctx->Texture.SharedPalette = GL_FALSE;
|
||||||
_mesa_init_colortable(&ctx->Texture.Palette);
|
_mesa_init_colortable(&ctx->Texture.Palette);
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_TEXTURE_UNITS; i++)
|
||||||
|
init_texture_unit( ctx, i );
|
||||||
|
|
||||||
|
/* After we're done initializing the context's texture state the default
|
||||||
|
* texture objects' refcounts should be at least MAX_TEXTURE_UNITS + 1.
|
||||||
|
*/
|
||||||
|
assert(ctx->Shared->Default1D->RefCount >= MAX_TEXTURE_UNITS + 1);
|
||||||
|
|
||||||
_mesa_TexEnvProgramCacheInit( ctx );
|
_mesa_TexEnvProgramCacheInit( ctx );
|
||||||
|
|
||||||
/* Allocate proxy textures */
|
/* Allocate proxy textures */
|
||||||
|
Reference in New Issue
Block a user