Rewrite quite a bit of the code for glPush/PopAttrib() for texture state.

Remove the Saved1D/2D/etc fields from gl_texture_attrib in mtypes.h
Use a new texture_state struct in attrib.c that has the extra information
for restoring texture object state and saving references to the texture
objects (so they can't accidentally get deleted while referenced by the
attribute stack).  All the texobj refcounting is mutex-protected now.
This commit is contained in:
Brian 2007-08-15 11:21:06 +01:00
parent 21594921b1
commit 00ccff03a5
2 changed files with 137 additions and 132 deletions

View file

@ -1,6 +1,6 @@
/*
* Mesa 3-D graphics library
* Version: 6.5.3
* Version: 7.0.2
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
@ -51,6 +51,32 @@
#include "math/m_xform.h"
/**
* Special struct for saving/restoring texture state (GL_TEXTURE_BIT)
*/
struct texture_state
{
struct gl_texture_attrib Texture; /**< The usual context state */
/** to save per texture object state (wrap modes, filters, etc): */
struct gl_texture_object Saved1D[MAX_TEXTURE_UNITS];
struct gl_texture_object Saved2D[MAX_TEXTURE_UNITS];
struct gl_texture_object Saved3D[MAX_TEXTURE_UNITS];
struct gl_texture_object SavedCube[MAX_TEXTURE_UNITS];
struct gl_texture_object SavedRect[MAX_TEXTURE_UNITS];
/**
* To save references to texture objects (so they don't get accidentally
* deleted while saved in the attribute stack).
*/
struct gl_texture_object *SavedRef1D[MAX_TEXTURE_UNITS];
struct gl_texture_object *SavedRef2D[MAX_TEXTURE_UNITS];
struct gl_texture_object *SavedRef3D[MAX_TEXTURE_UNITS];
struct gl_texture_object *SavedRefCube[MAX_TEXTURE_UNITS];
struct gl_texture_object *SavedRefRect[MAX_TEXTURE_UNITS];
};
/**
* Allocate a new attribute state node. These nodes have a
* "kind" value and a pointer to a struct of state data.
@ -335,47 +361,57 @@ _mesa_PushAttrib(GLbitfield mask)
}
if (mask & GL_TEXTURE_BIT) {
struct gl_texture_attrib *attr;
struct texture_state *texstate = CALLOC_STRUCT( texture_state );
GLuint u;
_mesa_lock_context_textures(ctx);
/* Bump the texture object reference counts so that they don't
* inadvertantly get deleted.
*/
#ifdef DEBUG
printf("%lu: MESA PUSH TEX ATTRIB, INCR REF COUNT BY %d\n",
_glthread_GetID(),
ctx->Const.MaxTextureUnits);
#endif
for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
ctx->Texture.Unit[u].Current1D->RefCount++;
ctx->Texture.Unit[u].Current2D->RefCount++;
ctx->Texture.Unit[u].Current3D->RefCount++;
ctx->Texture.Unit[u].CurrentCubeMap->RefCount++;
ctx->Texture.Unit[u].CurrentRect->RefCount++;
if (!texstate) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glPushAttrib(GL_TEXTURE_BIT)");
goto end;
}
attr = MALLOC_STRUCT( gl_texture_attrib );
MEMCPY( attr, &ctx->Texture, sizeof(struct gl_texture_attrib) );
/* copy state of the currently bound texture objects */
#ifdef DEBUG
printf("%lu: MESA BEGIN PUSH TEX ATTRIB\n",
_glthread_GetID());
#endif
_mesa_lock_context_textures(ctx);
/* copy/save the bulk of texture state here */
_mesa_memcpy(&texstate->Texture, &ctx->Texture, sizeof(ctx->Texture));
/* Save references to the currently bound texture objects so they don't
* accidentally get deleted while referenced in the attribute stack.
*/
for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
_mesa_copy_texture_object(&attr->Unit[u].Saved1D,
attr->Unit[u].Current1D);
_mesa_copy_texture_object(&attr->Unit[u].Saved2D,
attr->Unit[u].Current2D);
_mesa_copy_texture_object(&attr->Unit[u].Saved3D,
attr->Unit[u].Current3D);
_mesa_copy_texture_object(&attr->Unit[u].SavedCubeMap,
attr->Unit[u].CurrentCubeMap);
_mesa_copy_texture_object(&attr->Unit[u].SavedRect,
attr->Unit[u].CurrentRect);
MESA_REF_TEXOBJ(&texstate->SavedRef1D[u], ctx->Texture.Unit[u].Current1D);
MESA_REF_TEXOBJ(&texstate->SavedRef2D[u], ctx->Texture.Unit[u].Current2D);
MESA_REF_TEXOBJ(&texstate->SavedRef3D[u], ctx->Texture.Unit[u].Current3D);
MESA_REF_TEXOBJ(&texstate->SavedRefCube[u], ctx->Texture.Unit[u].CurrentCubeMap);
MESA_REF_TEXOBJ(&texstate->SavedRefRect[u], ctx->Texture.Unit[u].CurrentRect);
}
/* copy state/contents of the currently bound texture objects */
for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
_mesa_copy_texture_object(&texstate->Saved1D[u],
ctx->Texture.Unit[u].Current1D);
_mesa_copy_texture_object(&texstate->Saved2D[u],
ctx->Texture.Unit[u].Current2D);
_mesa_copy_texture_object(&texstate->Saved3D[u],
ctx->Texture.Unit[u].Current3D);
_mesa_copy_texture_object(&texstate->SavedCube[u],
ctx->Texture.Unit[u].CurrentCubeMap);
_mesa_copy_texture_object(&texstate->SavedRect[u],
ctx->Texture.Unit[u].CurrentRect);
}
_mesa_unlock_context_textures(ctx);
#ifdef DEBUG
printf("%lu: MESA END PUSH TEX ATTRIB\n",
_glthread_GetID());
#endif
newnode = new_attrib_node( GL_TEXTURE_BIT );
newnode->data = attr;
newnode->data = texstate;
newnode->next = head;
head = newnode;
}
@ -411,6 +447,7 @@ _mesa_PushAttrib(GLbitfield mask)
head = newnode;
}
end:
ctx->AttribStack[ctx->AttribStackDepth] = head;
ctx->AttribStackDepth++;
}
@ -620,14 +657,24 @@ pop_enable_group(GLcontext *ctx, const struct gl_enable_attrib *enable)
}
/**
* Pop/restore texture attribute/group state.
*/
static void
pop_texture_group(GLcontext *ctx, const struct gl_texture_attrib *texAttrib)
pop_texture_group(GLcontext *ctx, struct texture_state *texstate)
{
GLuint u;
#ifdef DEBUG
printf("%lu: MESA BEGIN POP TEX ATTRIB\n",
_glthread_GetID());
#endif
_mesa_lock_context_textures(ctx);
for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
const struct gl_texture_unit *unit = &texAttrib->Unit[u];
GLuint i;
const struct gl_texture_unit *unit = &texstate->Texture.Unit[u];
GLuint tgt;
_mesa_ActiveTextureARB(GL_TEXTURE0_ARB + u);
_mesa_set_enable(ctx, GL_TEXTURE_1D,
@ -720,41 +767,44 @@ pop_texture_group(GLcontext *ctx, const struct gl_texture_attrib *texAttrib)
1 << unit->Combine.ScaleShiftA);
}
/* Restore texture object state */
for (i = 0; i < NUM_TEXTURE_TARGETS; i++) {
GLenum target = 0;
/* Restore texture object state for each target */
for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
const struct gl_texture_object *obj = NULL;
GLfloat bordColor[4];
GLenum target;
switch (i) {
case 0:
target = GL_TEXTURE_1D;
obj = &unit->Saved1D;
switch (tgt) {
case TEXTURE_1D_INDEX:
obj = &texstate->Saved1D[u];
ASSERT(obj->Target == GL_TEXTURE_1D);
break;
case 1:
target = GL_TEXTURE_2D;
obj = &unit->Saved2D;
case TEXTURE_2D_INDEX:
obj = &texstate->Saved2D[u];
ASSERT(obj->Target == GL_TEXTURE_2D);
break;
case 2:
target = GL_TEXTURE_3D;
obj = &unit->Saved3D;
case TEXTURE_3D_INDEX:
obj = &texstate->Saved3D[u];
ASSERT(obj->Target == GL_TEXTURE_3D);
break;
case 3:
case TEXTURE_CUBE_INDEX:
if (!ctx->Extensions.ARB_texture_cube_map)
continue;
target = GL_TEXTURE_CUBE_MAP_ARB;
obj = &unit->SavedCubeMap;
obj = &texstate->SavedCube[u];
ASSERT(obj->Target == GL_TEXTURE_CUBE_MAP_ARB);
break;
case 4:
case TEXTURE_RECT_INDEX:
if (!ctx->Extensions.NV_texture_rectangle)
continue;
target = GL_TEXTURE_RECTANGLE_NV;
obj = &unit->SavedRect;
obj = &texstate->SavedRect[u];
ASSERT(obj->Target == GL_TEXTURE_RECTANGLE_NV);
break;
default:
; /* silence warnings */
_mesa_problem(ctx, "bad texture index in pop_texture_group");
continue;
}
target = obj->Target;
_mesa_BindTexture(target, obj->Name);
bordColor[0] = CHAN_TO_FLOAT(obj->BorderColor[0]);
@ -789,28 +839,24 @@ pop_texture_group(GLcontext *ctx, const struct gl_texture_attrib *texAttrib)
_mesa_TexParameterf(target, GL_SHADOW_AMBIENT_SGIX,
obj->ShadowAmbient);
}
}
}
_mesa_ActiveTextureARB(GL_TEXTURE0_ARB
+ texAttrib->CurrentUnit);
/* "un-bump" the texture object reference counts. We did that so they
* wouldn't inadvertantly get deleted while they were still referenced
* inside the attribute state stack.
*/
#ifdef DEBUG
printf("%lu: MESA POP TEX ATTRIB, DECR REF COUNT BY %d\n",
_glthread_GetID(),
ctx->Const.MaxTextureUnits);
#endif
for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
ctx->Texture.Unit[u].Current1D->RefCount--;
ctx->Texture.Unit[u].Current2D->RefCount--;
ctx->Texture.Unit[u].Current3D->RefCount--;
ctx->Texture.Unit[u].CurrentCubeMap->RefCount--;
ctx->Texture.Unit[u].CurrentRect->RefCount--;
/* remove saved references to the texture objects */
MESA_REF_TEXOBJ(&texstate->SavedRef1D[u], NULL);
MESA_REF_TEXOBJ(&texstate->SavedRef2D[u], NULL);
MESA_REF_TEXOBJ(&texstate->SavedRef3D[u], NULL);
MESA_REF_TEXOBJ(&texstate->SavedRefCube[u], NULL);
MESA_REF_TEXOBJ(&texstate->SavedRefRect[u], NULL);
}
_mesa_ActiveTextureARB(GL_TEXTURE0_ARB + texstate->Texture.CurrentUnit);
_mesa_unlock_context_textures(ctx);
#ifdef DEBUG
printf("%lu: MESA END POP TEX ATTRIB\n",
_glthread_GetID());
#endif
}
@ -1189,9 +1235,9 @@ _mesa_PopAttrib(void)
case GL_TEXTURE_BIT:
/* Take care of texture object reference counters */
{
const struct gl_texture_attrib *texture;
texture = (const struct gl_texture_attrib *) attr->data;
pop_texture_group(ctx, texture);
struct texture_state *texstate
= (struct texture_state *) attr->data;
pop_texture_group(ctx, texstate);
ctx->NewState |= _NEW_TEXTURE;
}
break;
@ -1413,38 +1459,6 @@ _mesa_PopClientAttrib(void)
}
static struct gl_texture_object *
get_texobj(GLcontext *ctx, GLenum target, GLuint name)
{
struct gl_texture_object *texObj;
if (name) {
texObj = _mesa_lookup_texture(ctx, name);
}
else {
switch (target) {
case GL_TEXTURE_1D:
texObj = ctx->Shared->Default1D;
break;
case GL_TEXTURE_2D:
texObj = ctx->Shared->Default2D;
break;
case GL_TEXTURE_3D:
texObj = ctx->Shared->Default3D;
break;
case GL_TEXTURE_CUBE_MAP_ARB:
texObj = ctx->Shared->DefaultCubeMap;
break;
case GL_TEXTURE_RECTANGLE_NV:
texObj = ctx->Shared->DefaultRect;
break;
default:
abort();
}
}
return texObj;
}
void
_mesa_free_attrib_data(GLcontext *ctx)
{
@ -1459,23 +1473,20 @@ _mesa_free_attrib_data(GLcontext *ctx)
attr = ctx->AttribStack[ctx->AttribStackDepth];
while (attr) {
struct gl_texture_attrib *texAttrib
= (struct gl_texture_attrib *) attr->data;
GLuint u;
for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
struct gl_texture_unit *unit = &texAttrib->Unit[u];
struct gl_texture_object *texObj;
texObj = get_texobj(ctx, GL_TEXTURE_1D, unit->Saved1D.Name);
MESA_REF_TEXOBJ(&texObj, NULL);
texObj = get_texobj(ctx, GL_TEXTURE_2D, unit->Saved2D.Name);
MESA_REF_TEXOBJ(&texObj, NULL);
texObj = get_texobj(ctx, GL_TEXTURE_3D, unit->Saved3D.Name);
MESA_REF_TEXOBJ(&texObj, NULL);
texObj = get_texobj(ctx, GL_TEXTURE_CUBE_MAP, unit->SavedCubeMap.Name);
MESA_REF_TEXOBJ(&texObj, NULL);
texObj = get_texobj(ctx, GL_TEXTURE_RECTANGLE_NV, unit->SavedRect.Name);
MESA_REF_TEXOBJ(&texObj, NULL);
if (attr->kind == GL_TEXTURE_BIT) {
struct texture_state *texstate = (struct texture_state*)attr->data;
GLuint u;
/* clear references to the saved texture objects */
for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
MESA_REF_TEXOBJ(&texstate->SavedRef1D[u], NULL);
MESA_REF_TEXOBJ(&texstate->SavedRef2D[u], NULL);
MESA_REF_TEXOBJ(&texstate->SavedRef3D[u], NULL);
MESA_REF_TEXOBJ(&texstate->SavedRefCube[u], NULL);
MESA_REF_TEXOBJ(&texstate->SavedRefRect[u], NULL);
}
}
else {
/* any other chunks of state that requires special handling? */
}
next = attr->next;

View file

@ -1523,12 +1523,6 @@ struct gl_texture_unit
struct gl_texture_object *_Current; /**< Points to really enabled tex obj */
struct gl_texture_object Saved1D; /**< only used by glPush/PopAttrib */
struct gl_texture_object Saved2D;
struct gl_texture_object Saved3D;
struct gl_texture_object SavedCubeMap;
struct gl_texture_object SavedRect;
/* GL_SGI_texture_color_table */
struct gl_color_table ColorTable;
struct gl_color_table ProxyColorTable;