#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];
+ struct gl_texture_object Saved1DArray[MAX_TEXTURE_UNITS];
+ struct gl_texture_object Saved2DArray[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];
+ struct gl_texture_object *SavedRef1DArray[MAX_TEXTURE_UNITS];
+ struct gl_texture_object *SavedRef2DArray[MAX_TEXTURE_UNITS];
+};
+
+
/**
* Allocate a new attribute state node. These nodes have a
* "kind" value and a pointer to a struct of state data.
}
if (mask & GL_TEXTURE_BIT) {
- struct gl_texture_attrib *attr;
+ struct texture_state *texstate = CALLOC_STRUCT(texture_state);
GLuint u;
+ if (!texstate) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glPushAttrib(GL_TEXTURE_BIT)");
+ goto end;
+ }
+
_mesa_lock_context_textures(ctx);
- /* Bump the texture object reference counts so that they don't
- * inadvertantly get deleted.
+
+ /* 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++) {
- 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++;
- ctx->Texture.Unit[u].Current1DArray->RefCount++;
- ctx->Texture.Unit[u].Current2DArray->RefCount++;
+ _mesa_reference_texobj(&texstate->SavedRef1D[u], ctx->Texture.Unit[u].Current1D);
+ _mesa_reference_texobj(&texstate->SavedRef2D[u], ctx->Texture.Unit[u].Current2D);
+ _mesa_reference_texobj(&texstate->SavedRef3D[u], ctx->Texture.Unit[u].Current3D);
+ _mesa_reference_texobj(&texstate->SavedRefCube[u], ctx->Texture.Unit[u].CurrentCubeMap);
+ _mesa_reference_texobj(&texstate->SavedRefRect[u], ctx->Texture.Unit[u].CurrentRect);
+ _mesa_reference_texobj(&texstate->SavedRef1DArray[u], ctx->Texture.Unit[u].Current1DArray);
+ _mesa_reference_texobj(&texstate->SavedRef2DArray[u], ctx->Texture.Unit[u].Current2DArray);
}
- attr = MALLOC_STRUCT( gl_texture_attrib );
- MEMCPY( attr, &ctx->Texture, sizeof(struct gl_texture_attrib) );
- /* copy state of the currently bound texture objects */
+ /* copy state/contents of the currently bound texture objects */
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_copy_texture_object(&attr->Unit[u].Saved1DArray,
- attr->Unit[u].Current1DArray);
- _mesa_copy_texture_object(&attr->Unit[u].Saved2DArray,
- attr->Unit[u].Current2DArray);
+ _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_copy_texture_object(&texstate->Saved1DArray[u],
+ ctx->Texture.Unit[u].Current1DArray);
+ _mesa_copy_texture_object(&texstate->Saved2DArray[u],
+ ctx->Texture.Unit[u].Current2DArray);
}
_mesa_unlock_context_textures(ctx);
newnode = new_attrib_node( GL_TEXTURE_BIT );
- newnode->data = attr;
+ newnode->data = texstate;
newnode->next = head;
head = newnode;
}
head = newnode;
}
+end:
ctx->AttribStack[ctx->AttribStackDepth] = head;
ctx->AttribStackDepth++;
}
}
+/**
+ * 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;
+ _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,
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;
- case 5:
+ case TEXTURE_1D_ARRAY_INDEX:
if (!ctx->Extensions.MESA_texture_array)
continue;
- target = GL_TEXTURE_1D_ARRAY_EXT;
- obj = &unit->Saved1DArray;
+ obj = &texstate->Saved1DArray[u];
+ ASSERT(obj->Target == GL_TEXTURE_1D_ARRAY_EXT);
break;
- case 6:
+ case TEXTURE_2D_ARRAY_INDEX:
if (!ctx->Extensions.MESA_texture_array)
continue;
- target = GL_TEXTURE_2D_ARRAY_EXT;
- obj = &unit->Saved2DArray;
+ obj = &texstate->Saved2DArray[u];
+ ASSERT(obj->Target == GL_TEXTURE_2D_ARRAY_EXT);
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]);
bordColor[2] = CHAN_TO_FLOAT(obj->BorderColor[2]);
bordColor[3] = CHAN_TO_FLOAT(obj->BorderColor[3]);
- _mesa_TexParameterf(target, GL_TEXTURE_PRIORITY, obj->Priority);
_mesa_TexParameterfv(target, GL_TEXTURE_BORDER_COLOR, bordColor);
+ _mesa_TexParameterf(target, GL_TEXTURE_PRIORITY, obj->Priority);
_mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, obj->WrapS);
_mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, obj->WrapT);
_mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, obj->WrapR);
_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.
- */
- 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--;
- ctx->Texture.Unit[u].Current1DArray->RefCount--;
- ctx->Texture.Unit[u].Current2DArray->RefCount--;
+ /* remove saved references to the texture objects */
+ _mesa_reference_texobj(&texstate->SavedRef1D[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRef2D[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRef3D[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRefCube[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRefRect[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRef1DArray[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRef2DArray[u], NULL);
}
+
+ _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + texstate->Texture.CurrentUnit);
+
+ _mesa_unlock_context_textures(ctx);
}
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;
}
+/**
+ * Free any attribute state data that might be attached to the context.
+ */
+void
+_mesa_free_attrib_data(GLcontext *ctx)
+{
+ while (ctx->AttribStackDepth > 0) {
+ struct gl_attrib_node *attr, *next;
+
+ ctx->AttribStackDepth--;
+ attr = ctx->AttribStack[ctx->AttribStackDepth];
+
+ while (attr) {
+ 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_reference_texobj(&texstate->SavedRef1D[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRef2D[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRef3D[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRefCube[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRefRect[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRef1DArray[u], NULL);
+ _mesa_reference_texobj(&texstate->SavedRef2DArray[u], NULL);
+ }
+ }
+ else {
+ /* any other chunks of state that requires special handling? */
+ }
+
+ next = attr->next;
+ _mesa_free(attr->data);
+ _mesa_free(attr);
+ attr = next;
+ }
+ }
+}
+
+
void _mesa_init_attrib( GLcontext *ctx )
{
/* Renderer and client attribute stacks */
/* copy texture object bindings, not contents of texture objects */
_mesa_lock_context_textures(dst);
- _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_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);
}
void
_mesa_free_texture_data(GLcontext *ctx)
{
- GLuint i;
+ 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.Proxy1DArray );
(ctx->Driver.DeleteTexture)(ctx, ctx->Texture.Proxy2DArray );
- for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
- _mesa_free_colortable_data( &ctx->Texture.Unit[i].ColorTable );
+ for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++)
+ _mesa_free_colortable_data( &ctx->Texture.Unit[u].ColorTable );
_mesa_TexEnvProgramCacheDestroy( ctx );
}