mesa: 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.

cherry-picked from master (9e01b915f1)
This commit is contained in:
Brian Paul 2008-07-04 10:29:15 -06:00
parent 9ca1c62a96
commit 2fa7b3f786
8 changed files with 194 additions and 213 deletions

View file

@ -361,6 +361,7 @@ _mesa_PushAttrib(GLbitfield mask)
ctx->Texture.Unit[u].Current1DArray->RefCount++;
ctx->Texture.Unit[u].Current2DArray->RefCount++;
}
attr = MALLOC_STRUCT( gl_texture_attrib );
MEMCPY( attr, &ctx->Texture, sizeof(struct gl_texture_attrib) );
/* copy state of the currently bound texture objects */

View file

@ -500,19 +500,12 @@ alloc_shared_state( GLcontext *ctx )
if (!ss->Default2DArray)
goto cleanup;
/* Effectively bind the default textures to all texture units */
ss->Default1D->RefCount += MAX_TEXTURE_IMAGE_UNITS;
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;
/* sanity check */
assert(ss->Default1D->RefCount == 1);
_glthread_INIT_MUTEX(ss->TexMutex);
ss->TextureStateStamp = 0;
#if FEATURE_EXT_framebuffer_object
ss->FrameBuffers = _mesa_NewHashTable();
if (!ss->FrameBuffers)
@ -522,10 +515,9 @@ alloc_shared_state( GLcontext *ctx )
goto cleanup;
#endif
return GL_TRUE;
cleanup:
cleanup:
/* Ran out of memory at some point. Free everything and return NULL */
if (ss->DisplayList)
_mesa_DeleteHashTable(ss->DisplayList);

View file

@ -172,17 +172,12 @@ _mesa_remove_attachment(GLcontext *ctx, struct gl_renderbuffer_attachment *att)
{
if (att->Type == GL_TEXTURE) {
ASSERT(att->Texture);
att->Texture->RefCount--;
if (att->Texture->RefCount == 0) {
ctx->Driver.DeleteTexture(ctx, att->Texture);
}
else {
if (ctx->Driver.FinishRenderTexture) {
/* tell driver that we're done rendering to this texture. */
if (ctx->Driver.FinishRenderTexture) {
ctx->Driver.FinishRenderTexture(ctx, att);
}
ctx->Driver.FinishRenderTexture(ctx, att);
}
att->Texture = NULL;
_mesa_reference_texobj(&att->Texture, NULL); /* unbind */
ASSERT(!att->Texture);
}
if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
ASSERT(!att->Texture);
@ -213,8 +208,8 @@ _mesa_set_texture_attachment(GLcontext *ctx,
/* new attachment */
_mesa_remove_attachment(ctx, att);
att->Type = GL_TEXTURE;
att->Texture = texObj;
texObj->RefCount++;
assert(!att->Texture);
_mesa_reference_texobj(&att->Texture, texObj);
}
/* always update these fields */

View file

@ -38,6 +38,7 @@
#include "fbobject.h"
#include "framebuffer.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);
}
if (att->Texture) {
/* render to texture */
att->Texture->RefCount--;
if (att->Texture->RefCount == 0) {
GET_CURRENT_CONTEXT(ctx);
if (ctx) {
ctx->Driver.DeleteTexture(ctx, att->Texture);
}
}
_mesa_reference_texobj(&att->Texture, NULL);
}
ASSERT(!att->Renderbuffer);
ASSERT(!att->Texture);
att->Type = GL_NONE;
att->Texture = NULL;
}
/* unbind _Depth/_StencilBuffer to decr ref counts */

View file

@ -1404,6 +1404,7 @@ struct gl_texture_image
*/
struct gl_texture_object
{
_glthread_Mutex Mutex; /**< for thread safety */
GLint RefCount; /**< reference count */
GLuint Name; /**< the user-visible texture object ID */
GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */

View file

@ -5,9 +5,9 @@
/*
* Mesa 3-D graphics library
* Version: 6.5
* Version: 7.1
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -108,6 +108,7 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj,
_mesa_bzero(obj, sizeof(*obj));
/* init the non-zero fields */
_glthread_INIT_MUTEX(obj->Mutex);
obj->RefCount = 1;
obj->Name = name;
obj->Target = target;
@ -155,6 +156,11 @@ _mesa_delete_texture_object( GLcontext *ctx, struct gl_texture_object *texObj )
(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;
#if FEATURE_colortable
_mesa_free_colortable_data(&texObj->Palette);
#endif
@ -168,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 */
_mesa_free(texObj);
}
@ -186,6 +195,7 @@ void
_mesa_copy_texture_object( struct gl_texture_object *dest,
const struct gl_texture_object *src )
{
dest->Target = src->Target;
dest->Name = src->Name;
dest->Priority = src->Priority;
dest->BorderColor[0] = src->BorderColor[0];
@ -217,6 +227,94 @@ _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--;
deleteFlag = (oldTex->RefCount == 0);
_glthread_UNLOCK_MUTEX(oldTex->Mutex);
if (deleteFlag) {
GET_CURRENT_CONTEXT(ctx);
if (ctx)
ctx->Driver.DeleteTexture(ctx, oldTex);
else
_mesa_problem(NULL, "Unable to delete texture, no context");
}
*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++;
*ptr = tex;
}
_glthread_UNLOCK_MUTEX(tex->Mutex);
}
}
/**
* Report why a texture object is incomplete.
*
@ -613,8 +711,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
* unbind it if so.
* XXX all RefCount accesses should be protected by a mutex.
* unbind it if so (revert to default textures).
*/
static void
unbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj)
@ -623,42 +720,26 @@ unbind_texobj_from_texunits(GLcontext *ctx, struct gl_texture_object *texObj)
for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
struct gl_texture_object **curr = NULL;
if (texObj == unit->Current1D) {
curr = &unit->Current1D;
unit->Current1D = ctx->Shared->Default1D;
_mesa_reference_texobj(&unit->Current1D, ctx->Shared->Default1D);
}
else if (texObj == unit->Current2D) {
curr = &unit->Current2D;
unit->Current2D = ctx->Shared->Default2D;
_mesa_reference_texobj(&unit->Current2D, ctx->Shared->Default2D);
}
else if (texObj == unit->Current3D) {
curr = &unit->Current3D;
unit->Current3D = ctx->Shared->Default3D;
_mesa_reference_texobj(&unit->Current3D, ctx->Shared->Default3D);
}
else if (texObj == unit->CurrentCubeMap) {
curr = &unit->CurrentCubeMap;
unit->CurrentCubeMap = ctx->Shared->DefaultCubeMap;
_mesa_reference_texobj(&unit->CurrentCubeMap, ctx->Shared->DefaultCubeMap);
}
else if (texObj == unit->CurrentRect) {
curr = &unit->CurrentRect;
unit->CurrentRect = ctx->Shared->DefaultRect;
_mesa_reference_texobj(&unit->CurrentRect, ctx->Shared->DefaultRect);
}
else if (texObj == unit->Current1DArray) {
curr = &unit->Current1DArray;
unit->CurrentRect = ctx->Shared->Default1DArray;
_mesa_reference_texobj(&unit->Current1DArray, ctx->Shared->Default1DArray);
}
else if (texObj == unit->Current2DArray) {
curr = &unit->Current1DArray;
unit->CurrentRect = ctx->Shared->Default2DArray;
}
if (curr) {
(*curr)->RefCount++;
texObj->RefCount--;
if (texObj == unit->_Current)
unit->_Current = *curr;
_mesa_reference_texobj(&unit->Current2DArray, ctx->Shared->Default2DArray);
}
}
}
@ -694,8 +775,6 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
= _mesa_lookup_texture(ctx, textures[i]);
if (delObj) {
GLboolean deleted;
_mesa_lock_texture(ctx, delObj);
/* Check if texture is bound to any framebuffer objects.
@ -705,10 +784,12 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
unbind_texobj_from_fbo(ctx, delObj);
/* 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);
_mesa_unlock_texture(ctx, delObj);
ctx->NewState |= _NEW_TEXTURE;
/* The texture _name_ is now free for re-use.
@ -718,23 +799,10 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
_mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
_glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
/* The actual texture object will not be freed until it's no
* longer bound in any context.
* XXX all RefCount accesses should be protected by a mutex.
/* Unreference the texobj. If refcount hits zero, the texture
* will be deleted.
*/
delObj->RefCount--;
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);
}
_mesa_reference_texobj(&delObj, NULL);
}
}
}
@ -762,7 +830,6 @@ _mesa_BindTexture( GLenum target, GLuint texName )
GET_CURRENT_CONTEXT(ctx);
const GLuint unit = ctx->Texture.CurrentUnit;
struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
struct gl_texture_object *oldTexObj;
struct gl_texture_object *newTexObj = NULL;
ASSERT_OUTSIDE_BEGIN_END(ctx);
@ -770,62 +837,6 @@ _mesa_BindTexture( GLenum target, GLuint texName )
_mesa_debug(ctx, "glBindTexture %s %d\n",
_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)
*/
@ -854,7 +865,8 @@ _mesa_BindTexture( GLenum target, GLuint texName )
newTexObj = ctx->Shared->Default2DArray;
break;
default:
; /* Bad targets are caught above */
_mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)");
return;
}
}
else {
@ -900,28 +912,30 @@ _mesa_BindTexture( GLenum target, GLuint texName )
newTexObj->Target = target;
}
/* XXX all RefCount accesses should be protected by a mutex. */
newTexObj->RefCount++;
assert(valid_texture_object(newTexObj));
/* do the actual binding, but first flush outstanding vertices:
*/
/* flush before changing binding */
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) {
case GL_TEXTURE_1D:
texUnit->Current1D = newTexObj;
_mesa_reference_texobj(&texUnit->Current1D, newTexObj);
break;
case GL_TEXTURE_2D:
texUnit->Current2D = newTexObj;
_mesa_reference_texobj(&texUnit->Current2D, newTexObj);
break;
case GL_TEXTURE_3D:
texUnit->Current3D = newTexObj;
_mesa_reference_texobj(&texUnit->Current3D, newTexObj);
break;
case GL_TEXTURE_CUBE_MAP_ARB:
texUnit->CurrentCubeMap = newTexObj;
_mesa_reference_texobj(&texUnit->CurrentCubeMap, newTexObj);
break;
case GL_TEXTURE_RECTANGLE_NV:
texUnit->CurrentRect = newTexObj;
_mesa_reference_texobj(&texUnit->CurrentRect, newTexObj);
break;
case GL_TEXTURE_1D_ARRAY_EXT:
texUnit->Current1DArray = newTexObj;
@ -930,6 +944,7 @@ _mesa_BindTexture( GLenum target, GLuint texName )
texUnit->Current2DArray = newTexObj;
break;
default:
/* Bad target should be caught above */
_mesa_problem(ctx, "bad target in BindTexture");
return;
}
@ -937,18 +952,6 @@ _mesa_BindTexture( GLenum target, GLuint texName )
/* Pass BindTexture call to device driver */
if (ctx->Driver.BindTexture)
(*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 );
}
}

View file

@ -57,6 +57,10 @@ extern void
_mesa_copy_texture_object( struct gl_texture_object *dest,
const struct gl_texture_object *src );
extern void
_mesa_reference_texobj(struct gl_texture_object **ptr,
struct gl_texture_object *tex);
extern void
_mesa_test_texobj_completeness( const GLcontext *ctx,
struct gl_texture_object *obj );

View file

@ -62,31 +62,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.
@ -143,20 +118,20 @@ _mesa_copy_texture_state( const GLcontext *src, GLcontext *dst )
/* copy texture object bindings, not contents of texture objects */
_mesa_lock_context_textures(dst);
copy_texture_binding(src, &dst->Texture.Unit[i].Current1D,
src->Texture.Unit[i].Current1D);
copy_texture_binding(src, &dst->Texture.Unit[i].Current2D,
src->Texture.Unit[i].Current2D);
copy_texture_binding(src, &dst->Texture.Unit[i].Current3D,
src->Texture.Unit[i].Current3D);
copy_texture_binding(src, &dst->Texture.Unit[i].CurrentCubeMap,
src->Texture.Unit[i].CurrentCubeMap);
copy_texture_binding(src, &dst->Texture.Unit[i].CurrentRect,
src->Texture.Unit[i].CurrentRect);
copy_texture_binding(src, &dst->Texture.Unit[i].Current1DArray,
src->Texture.Unit[i].Current1DArray);
copy_texture_binding(src, &dst->Texture.Unit[i].Current2DArray,
src->Texture.Unit[i].Current2DArray);
_mesa_reference_texobj(&dst->Texture.Unit[i].Current1D,
src->Texture.Unit[i].Current1D);
_mesa_reference_texobj(&dst->Texture.Unit[i].Current2D,
src->Texture.Unit[i].Current2D);
_mesa_reference_texobj(&dst->Texture.Unit[i].Current3D,
src->Texture.Unit[i].Current3D);
_mesa_reference_texobj(&dst->Texture.Unit[i].CurrentCubeMap,
src->Texture.Unit[i].CurrentCubeMap);
_mesa_reference_texobj(&dst->Texture.Unit[i].CurrentRect,
src->Texture.Unit[i].CurrentRect);
_mesa_reference_texobj(&dst->Texture.Unit[i].Current1DArray,
src->Texture.Unit[i].Current1DArray);
_mesa_reference_texobj(&dst->Texture.Unit[i].Current2DArray,
src->Texture.Unit[i].Current2DArray);
_mesa_unlock_context_textures(dst);
}
@ -727,6 +702,8 @@ alloc_proxy_textures( GLcontext *ctx )
if (!ctx->Texture.Proxy2DArray)
goto cleanup;
assert(ctx->Texture.Proxy1D->RefCount == 1);
return GL_TRUE;
cleanup:
@ -786,13 +763,14 @@ init_texture_unit( GLcontext *ctx, GLuint unit )
ASSIGN_4V( texUnit->EyePlaneR, 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;
texUnit->Current2D = ctx->Shared->Default2D;
texUnit->Current3D = ctx->Shared->Default3D;
texUnit->CurrentCubeMap = ctx->Shared->DefaultCubeMap;
texUnit->CurrentRect = ctx->Shared->DefaultRect;
texUnit->Current1DArray = ctx->Shared->Default1DArray;
texUnit->Current2DArray = ctx->Shared->Default2DArray;
/* initialize current texture object ptrs to the shared default objects */
_mesa_reference_texobj(&texUnit->Current1D, ctx->Shared->Default1D);
_mesa_reference_texobj(&texUnit->Current2D, ctx->Shared->Default2D);
_mesa_reference_texobj(&texUnit->Current3D, ctx->Shared->Default3D);
_mesa_reference_texobj(&texUnit->CurrentCubeMap, ctx->Shared->DefaultCubeMap);
_mesa_reference_texobj(&texUnit->CurrentRect, ctx->Shared->DefaultRect);
_mesa_reference_texobj(&texUnit->Current1DArray, ctx->Shared->Default1DArray);
_mesa_reference_texobj(&texUnit->Current2DArray, ctx->Shared->Default2DArray);
}
@ -807,25 +785,22 @@ _mesa_init_texture(GLcontext *ctx)
assert(MAX_TEXTURE_LEVELS >= MAX_3D_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 */
ctx->Texture.CurrentUnit = 0; /* multitexture */
ctx->Texture._EnabledUnits = 0;
for (i=0; i<MAX_TEXTURE_UNITS; i++)
init_texture_unit( ctx, i );
ctx->Texture.SharedPalette = GL_FALSE;
#if FEATURE_colortable
_mesa_init_colortable(&ctx->Texture.Palette);
#endif
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);
/* Allocate proxy textures */
if (!alloc_proxy_textures( ctx ))
return GL_FALSE;
@ -840,6 +815,20 @@ _mesa_init_texture(GLcontext *ctx)
void
_mesa_free_texture_data(GLcontext *ctx)
{
GLuint u;
/* unreference current textures */
for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) {
struct gl_texture_unit *unit = ctx->Texture.Unit + u;
_mesa_reference_texobj(&unit->Current1D, NULL);
_mesa_reference_texobj(&unit->Current2D, NULL);
_mesa_reference_texobj(&unit->Current3D, NULL);
_mesa_reference_texobj(&unit->CurrentCubeMap, NULL);
_mesa_reference_texobj(&unit->CurrentRect, NULL);
_mesa_reference_texobj(&unit->Current1DArray, NULL);
_mesa_reference_texobj(&unit->Current2DArray, NULL);
}
/* Free proxy texture objects */
(ctx->Driver.DeleteTexture)(ctx, ctx->Texture.Proxy1D );
(ctx->Driver.DeleteTexture)(ctx, ctx->Texture.Proxy2D );
@ -849,6 +838,7 @@ _mesa_free_texture_data(GLcontext *ctx)
(ctx->Driver.DeleteTexture)(ctx, ctx->Texture.Proxy1DArray );
(ctx->Driver.DeleteTexture)(ctx, ctx->Texture.Proxy2DArray );
#if FEATURE_colortable
{
GLuint i;