X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fattrib.c;h=59babeb47bf9f4f9a982ff2ce58a14a39a119f39;hb=32ef6e75839d6be283e034436e5dd34eabb67958;hp=a7448ee32a1895a8cdc9999ef218d20954c87eec;hpb=ba88dd0d92e818df20752ca5a4b1cd5fb0c49f76;p=mesa.git diff --git a/src/mesa/main/attrib.c b/src/mesa/main/attrib.c index a7448ee32a1..59babeb47bf 100644 --- a/src/mesa/main/attrib.c +++ b/src/mesa/main/attrib.c @@ -1,10 +1,8 @@ -/* $Id: attrib.c,v 1.70 2002/09/03 18:03:45 brianp Exp $ */ - /* * Mesa 3-D graphics library - * Version: 4.1 + * Version: 7.2 * - * Copyright (C) 1999-2002 Brian Paul All Rights Reserved. + * Copyright (C) 1999-2008 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"), @@ -24,16 +22,16 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - -#ifdef PC_HEADER -#include "all.h" -#else #include "glheader.h" +#include "imports.h" #include "accum.h" +#include "arrayobj.h" #include "attrib.h" #include "blend.h" #include "buffers.h" +#include "bufferobj.h" #include "colormac.h" +#include "colortab.h" #include "context.h" #include "depth.h" #include "enable.h" @@ -43,21 +41,35 @@ #include "light.h" #include "lines.h" #include "matrix.h" -#include "mem.h" #include "points.h" #include "polygon.h" #include "simple_list.h" #include "stencil.h" #include "texobj.h" #include "texstate.h" +#include "varray.h" #include "mtypes.h" #include "math/m_xform.h" -#endif +/** + * 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 SavedObj[MAX_TEXTURE_UNITS][NUM_TEXTURE_TARGETS]; + /** + * To save references to texture objects (so they don't get accidentally + * deleted while saved in the attribute stack). + */ + struct gl_texture_object *SavedTexRef[MAX_TEXTURE_UNITS][NUM_TEXTURE_TARGETS]; +}; -/* + +/** * Allocate a new attribute state node. These nodes have a * "kind" value and a pointer to a struct of state data. */ @@ -72,7 +84,7 @@ new_attrib_node( GLbitfield kind ) } -void +void GLAPIENTRY _mesa_PushAttrib(GLbitfield mask) { struct gl_attrib_node *newnode; @@ -104,9 +116,13 @@ _mesa_PushAttrib(GLbitfield mask) } if (mask & GL_COLOR_BUFFER_BIT) { + GLuint i; struct gl_colorbuffer_attrib *attr; attr = MALLOC_STRUCT( gl_colorbuffer_attrib ); MEMCPY( attr, &ctx->Color, sizeof(struct gl_colorbuffer_attrib) ); + /* push the Draw FBO's DrawBuffer[] state, not ctx->Color.DrawBuffer[] */ + for (i = 0; i < ctx->Const.MaxDrawBuffers; i ++) + attr->DrawBuffer[i] = ctx->DrawBuffer->ColorDrawBuffer[i]; newnode = new_attrib_node( GL_COLOR_BUFFER_BIT ); newnode->data = attr; newnode->next = head; @@ -144,6 +160,9 @@ _mesa_PushAttrib(GLbitfield mask) attr->Blend = ctx->Color.BlendEnabled; attr->ClipPlanes = ctx->Transform.ClipPlanesEnabled; attr->ColorMaterial = ctx->Light.ColorMaterialEnabled; + for (i = 0; i < COLORTABLE_MAX; i++) { + attr->ColorTable[i] = ctx->Pixel.ColorTableEnabled[i]; + } attr->Convolution1D = ctx->Pixel.Convolution1DEnabled; attr->Convolution2D = ctx->Pixel.Convolution2DEnabled; attr->Separable2D = ctx->Pixel.Separable2DEnabled; @@ -151,7 +170,7 @@ _mesa_PushAttrib(GLbitfield mask) attr->DepthTest = ctx->Depth.Test; attr->Dither = ctx->Color.DitherFlag; attr->Fog = ctx->Fog.Enabled; - for (i=0;iConst.MaxLights; i++) { attr->Light[i] = ctx->Light.Light[i].Enabled; } attr->Lighting = ctx->Light.Enabled; @@ -183,7 +202,6 @@ _mesa_PushAttrib(GLbitfield mask) MEMCPY(attr->Map2Attrib, ctx->Eval.Map2Attrib, sizeof(ctx->Eval.Map2Attrib)); attr->Normalize = ctx->Transform.Normalize; attr->RasterPositionUnclipped = ctx->Transform.RasterPositionUnclipped; - attr->PixelTexture = ctx->Pixel.PixelTextureEnabled; attr->PointSmooth = ctx->Point.SmoothFlag; attr->PointSprite = ctx->Point.PointSprite; attr->PolygonOffsetPoint = ctx->Polygon.OffsetPoint; @@ -194,6 +212,7 @@ _mesa_PushAttrib(GLbitfield mask) attr->RescaleNormals = ctx->Transform.RescaleNormals; attr->Scissor = ctx->Scissor.Enabled; attr->Stencil = ctx->Stencil.Enabled; + attr->StencilTwoSide = ctx->Stencil.TestTwoSide; attr->MultisampleEnabled = ctx->Multisample.Enabled; attr->SampleAlphaToCoverage = ctx->Multisample.SampleAlphaToCoverage; attr->SampleAlphaToOne = ctx->Multisample.SampleAlphaToOne; @@ -202,6 +221,7 @@ _mesa_PushAttrib(GLbitfield mask) for (i=0; iTexture[i] = ctx->Texture.Unit[i].Enabled; attr->TexGen[i] = ctx->Texture.Unit[i].TexGenEnabled; + attr->TextureColorTable[i] = ctx->Texture.Unit[i].ColorTableEnabled; } /* GL_NV_vertex_program */ attr->VertexProgram = ctx->VertexProgram.Enabled; @@ -278,6 +298,8 @@ _mesa_PushAttrib(GLbitfield mask) struct gl_pixel_attrib *attr; attr = MALLOC_STRUCT( gl_pixel_attrib ); MEMCPY( attr, &ctx->Pixel, sizeof(struct gl_pixel_attrib) ); + /* push the Read FBO's ReadBuffer state, not ctx->Pixel.ReadBuffer */ + attr->ReadBuffer = ctx->ReadBuffer->ColorReadBuffer; newnode = new_attrib_node( GL_PIXEL_MODE_BIT ); newnode->data = attr; newnode->next = head; @@ -335,35 +357,61 @@ _mesa_PushAttrib(GLbitfield mask) } if (mask & GL_TEXTURE_BIT) { - struct gl_texture_attrib *attr; + struct texture_state *texstate = CALLOC_STRUCT(texture_state); GLuint u; - /* Bump the texture object reference counts so that they don't - * inadvertantly get deleted. + + if (!texstate) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glPushAttrib(GL_TEXTURE_BIT)"); + goto end; + } + + _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++) { - 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++; + _mesa_reference_texobj(&texstate->SavedTexRef[u][TEXTURE_1D_INDEX], + ctx->Texture.Unit[u].Current1D); + _mesa_reference_texobj(&texstate->SavedTexRef[u][TEXTURE_2D_INDEX], + ctx->Texture.Unit[u].Current2D); + _mesa_reference_texobj(&texstate->SavedTexRef[u][TEXTURE_3D_INDEX], + ctx->Texture.Unit[u].Current3D); + _mesa_reference_texobj(&texstate->SavedTexRef[u][TEXTURE_CUBE_INDEX], + ctx->Texture.Unit[u].CurrentCubeMap); + _mesa_reference_texobj(&texstate->SavedTexRef[u][TEXTURE_RECT_INDEX], + ctx->Texture.Unit[u].CurrentRect); + _mesa_reference_texobj(&texstate->SavedTexRef[u][TEXTURE_1D_ARRAY_INDEX], + ctx->Texture.Unit[u].Current1DArray); + _mesa_reference_texobj(&texstate->SavedTexRef[u][TEXTURE_2D_ARRAY_INDEX], + 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(&texstate->SavedObj[u][TEXTURE_1D_INDEX], + ctx->Texture.Unit[u].Current1D); + _mesa_copy_texture_object(&texstate->SavedObj[u][TEXTURE_2D_INDEX], + ctx->Texture.Unit[u].Current2D); + _mesa_copy_texture_object(&texstate->SavedObj[u][TEXTURE_3D_INDEX], + ctx->Texture.Unit[u].Current3D); + _mesa_copy_texture_object(&texstate->SavedObj[u][TEXTURE_CUBE_INDEX], + ctx->Texture.Unit[u].CurrentCubeMap); + _mesa_copy_texture_object(&texstate->SavedObj[u][TEXTURE_RECT_INDEX], + ctx->Texture.Unit[u].CurrentRect); + _mesa_copy_texture_object(&texstate->SavedObj[u][TEXTURE_1D_ARRAY_INDEX], + ctx->Texture.Unit[u].Current1DArray); + _mesa_copy_texture_object(&texstate->SavedObj[u][TEXTURE_2D_ARRAY_INDEX], + 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; } @@ -399,6 +447,7 @@ _mesa_PushAttrib(GLbitfield mask) head = newnode; } +end: ctx->AttribStack[ctx->AttribStackDepth] = head; ctx->AttribStackDepth++; } @@ -421,12 +470,21 @@ pop_enable_group(GLcontext *ctx, const struct gl_enable_attrib *enable) for (i=0;iTransform.ClipPlanesEnabled & mask) != (enable->ClipPlanes & mask)) - _mesa_set_enable(ctx, (GLenum) (GL_CLIP_PLANE0 + i), - (enable->ClipPlanes & mask) ? GL_TRUE : GL_FALSE); + _mesa_set_enable(ctx, (GLenum) (GL_CLIP_PLANE0 + i), + (GLboolean) ((enable->ClipPlanes & mask) ? GL_TRUE : GL_FALSE)); } TEST_AND_UPDATE(ctx->Light.ColorMaterialEnabled, enable->ColorMaterial, GL_COLOR_MATERIAL); + TEST_AND_UPDATE(ctx->Pixel.ColorTableEnabled[COLORTABLE_PRECONVOLUTION], + enable->ColorTable[COLORTABLE_PRECONVOLUTION], + GL_COLOR_TABLE); + TEST_AND_UPDATE(ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCONVOLUTION], + enable->ColorTable[COLORTABLE_POSTCONVOLUTION], + GL_POST_CONVOLUTION_COLOR_TABLE); + TEST_AND_UPDATE(ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCOLORMATRIX], + enable->ColorTable[COLORTABLE_POSTCOLORMATRIX], + GL_POST_COLOR_MATRIX_COLOR_TABLE); TEST_AND_UPDATE(ctx->Polygon.CullFlag, enable->CullFace, GL_CULL_FACE); TEST_AND_UPDATE(ctx->Depth.Test, enable->DepthTest, GL_DEPTH_TEST); TEST_AND_UPDATE(ctx->Color.DitherFlag, enable->Dither, GL_DITHER); @@ -493,11 +551,9 @@ pop_enable_group(GLcontext *ctx, const struct gl_enable_attrib *enable) TEST_AND_UPDATE(ctx->Transform.RasterPositionUnclipped, enable->RasterPositionUnclipped, GL_RASTER_POSITION_UNCLIPPED_IBM); - TEST_AND_UPDATE(ctx->Pixel.PixelTextureEnabled, enable->PixelTexture, - GL_POINT_SMOOTH); TEST_AND_UPDATE(ctx->Point.SmoothFlag, enable->PointSmooth, GL_POINT_SMOOTH); - if (ctx->Extensions.NV_point_sprite) { + if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite) { TEST_AND_UPDATE(ctx->Point.PointSprite, enable->PointSprite, GL_POINT_SPRITE_NV); } @@ -513,6 +569,9 @@ pop_enable_group(GLcontext *ctx, const struct gl_enable_attrib *enable) GL_POLYGON_STIPPLE); TEST_AND_UPDATE(ctx->Scissor.Enabled, enable->Scissor, GL_SCISSOR_TEST); TEST_AND_UPDATE(ctx->Stencil.Enabled, enable->Stencil, GL_STENCIL_TEST); + if (ctx->Extensions.EXT_stencil_two_side) { + TEST_AND_UPDATE(ctx->Stencil.TestTwoSide, enable->StencilTwoSide, GL_STENCIL_TEST_TWO_SIDE_EXT); + } TEST_AND_UPDATE(ctx->Multisample.Enabled, enable->MultisampleEnabled, GL_MULTISAMPLE_ARB); TEST_AND_UPDATE(ctx->Multisample.SampleAlphaToCoverage, @@ -527,16 +586,16 @@ pop_enable_group(GLcontext *ctx, const struct gl_enable_attrib *enable) TEST_AND_UPDATE(ctx->Multisample.SampleCoverageInvert, enable->SampleCoverageInvert, GL_SAMPLE_COVERAGE_INVERT_ARB); - /* GL_NV_vertex_program */ + /* GL_ARB_vertex_program, GL_NV_vertex_program */ TEST_AND_UPDATE(ctx->VertexProgram.Enabled, enable->VertexProgram, - GL_VERTEX_PROGRAM_NV); + GL_VERTEX_PROGRAM_ARB); TEST_AND_UPDATE(ctx->VertexProgram.PointSizeEnabled, enable->VertexProgramPointSize, - GL_VERTEX_PROGRAM_POINT_SIZE_NV); + GL_VERTEX_PROGRAM_POINT_SIZE_ARB); TEST_AND_UPDATE(ctx->VertexProgram.TwoSideEnabled, enable->VertexProgramTwoSide, - GL_VERTEX_PROGRAM_TWO_SIDE_NV); + GL_VERTEX_PROGRAM_TWO_SIDE_ARB); #undef TEST_AND_UPDATE @@ -587,6 +646,9 @@ pop_enable_group(GLcontext *ctx, const struct gl_enable_attrib *enable) (*ctx->Driver.Enable)( ctx, GL_TEXTURE_GEN_Q, GL_FALSE); } } + + /* GL_SGI_texture_color_table */ + ctx->Texture.Unit[i].ColorTableEnabled = enable->TextureColorTable[i]; } if (ctx->Driver.ActiveTexture) { @@ -595,29 +657,38 @@ 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; + _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, - (GLboolean) (unit->Enabled & TEXTURE_1D_BIT ? GL_TRUE : GL_FALSE)); + (unit->Enabled & TEXTURE_1D_BIT) ? GL_TRUE : GL_FALSE); _mesa_set_enable(ctx, GL_TEXTURE_2D, - (GLboolean) (unit->Enabled & TEXTURE_2D_BIT ? GL_TRUE : GL_FALSE)); + (unit->Enabled & TEXTURE_2D_BIT) ? GL_TRUE : GL_FALSE); _mesa_set_enable(ctx, GL_TEXTURE_3D, - (GLboolean) (unit->Enabled & TEXTURE_3D_BIT ? GL_TRUE : GL_FALSE)); + (unit->Enabled & TEXTURE_3D_BIT) ? GL_TRUE : GL_FALSE); if (ctx->Extensions.ARB_texture_cube_map) { _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP_ARB, - (GLboolean) (unit->Enabled & TEXTURE_CUBE_BIT ? GL_TRUE : GL_FALSE)); + (unit->Enabled & TEXTURE_CUBE_BIT) ? GL_TRUE : GL_FALSE); } if (ctx->Extensions.NV_texture_rectangle) { _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE_NV, - (GLboolean) (unit->Enabled & TEXTURE_RECT_BIT ? GL_TRUE : GL_FALSE)); + (unit->Enabled & TEXTURE_RECT_BIT) ? GL_TRUE : GL_FALSE); + } + if (ctx->Extensions.SGI_texture_color_table) { + _mesa_set_enable(ctx, GL_TEXTURE_COLOR_TABLE_SGI, + unit->ColorTableEnabled); } _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, unit->EnvMode); _mesa_TexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, unit->EnvColor); @@ -629,84 +700,94 @@ pop_texture_group(GLcontext *ctx, const struct gl_texture_attrib *texAttrib) _mesa_TexGenfv(GL_T, GL_OBJECT_PLANE, unit->ObjectPlaneT); _mesa_TexGenfv(GL_R, GL_OBJECT_PLANE, unit->ObjectPlaneR); _mesa_TexGenfv(GL_Q, GL_OBJECT_PLANE, unit->ObjectPlaneQ); - _mesa_TexGenfv(GL_S, GL_EYE_PLANE, unit->EyePlaneS); - _mesa_TexGenfv(GL_T, GL_EYE_PLANE, unit->EyePlaneT); - _mesa_TexGenfv(GL_R, GL_EYE_PLANE, unit->EyePlaneR); - _mesa_TexGenfv(GL_Q, GL_EYE_PLANE, unit->EyePlaneQ); + /* Eye plane done differently to avoid re-transformation */ + { + struct gl_texture_unit *destUnit = &ctx->Texture.Unit[u]; + COPY_4FV(destUnit->EyePlaneS, unit->EyePlaneS); + COPY_4FV(destUnit->EyePlaneT, unit->EyePlaneT); + COPY_4FV(destUnit->EyePlaneR, unit->EyePlaneR); + COPY_4FV(destUnit->EyePlaneQ, unit->EyePlaneQ); + if (ctx->Driver.TexGen) { + ctx->Driver.TexGen(ctx, GL_S, GL_EYE_PLANE, unit->EyePlaneS); + ctx->Driver.TexGen(ctx, GL_T, GL_EYE_PLANE, unit->EyePlaneT); + ctx->Driver.TexGen(ctx, GL_R, GL_EYE_PLANE, unit->EyePlaneR); + ctx->Driver.TexGen(ctx, GL_Q, GL_EYE_PLANE, unit->EyePlaneQ); + } + } + _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, + ((unit->TexGenEnabled & S_BIT) ? GL_TRUE : GL_FALSE)); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, + ((unit->TexGenEnabled & T_BIT) ? GL_TRUE : GL_FALSE)); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, + ((unit->TexGenEnabled & R_BIT) ? GL_TRUE : GL_FALSE)); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, + ((unit->TexGenEnabled & Q_BIT) ? GL_TRUE : GL_FALSE)); if (ctx->Extensions.EXT_texture_lod_bias) { _mesa_TexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, unit->LodBias); } if (ctx->Extensions.EXT_texture_env_combine || ctx->Extensions.ARB_texture_env_combine) { - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, - unit->CombineModeRGB); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, - unit->CombineModeA); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, - unit->CombineSourceRGB[0]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, - unit->CombineSourceRGB[1]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, - unit->CombineSourceRGB[2]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, - unit->CombineSourceA[0]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, - unit->CombineSourceA[1]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, - unit->CombineSourceA[2]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, - unit->CombineOperandRGB[0]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, - unit->CombineOperandRGB[1]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, - unit->CombineOperandRGB[2]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, - unit->CombineOperandA[0]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_EXT, - unit->CombineOperandA[1]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, - unit->CombineOperandA[2]); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, - 1 << unit->CombineScaleShiftRGB); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, + unit->Combine.ModeRGB); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, + unit->Combine.ModeA); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, + unit->Combine.SourceRGB[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, + unit->Combine.SourceRGB[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, + unit->Combine.SourceRGB[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, + unit->Combine.SourceA[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, + unit->Combine.SourceA[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, + unit->Combine.SourceA[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, + unit->Combine.OperandRGB[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, + unit->Combine.OperandRGB[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, + unit->Combine.OperandRGB[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, + unit->Combine.OperandA[0]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, + unit->Combine.OperandA[1]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, + unit->Combine.OperandA[2]); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, + 1 << unit->Combine.ScaleShiftRGB); _mesa_TexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, - 1 << unit->CombineScaleShiftA); + 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; - break; - case 1: - target = GL_TEXTURE_2D; - obj = &unit->Saved2D; - break; - case 2: - target = GL_TEXTURE_3D; - obj = &unit->Saved3D; - break; - case 3: - if (!ctx->Extensions.ARB_texture_cube_map) - continue; - target = GL_TEXTURE_CUBE_MAP_ARB; - obj = &unit->SavedCubeMap; - break; - case 4: - if (!ctx->Extensions.NV_texture_rectangle) - continue; - target = GL_TEXTURE_RECTANGLE_NV; - obj = &unit->SavedRect; - break; - default: - ; /* silence warnings */ + obj = &texstate->SavedObj[u][tgt]; + + /* don't restore state for unsupported targets to prevent + * raising GL errors. + */ + if (obj->Target == GL_TEXTURE_CUBE_MAP_ARB && + !ctx->Extensions.ARB_texture_cube_map) { + continue; + } + else if (obj->Target == GL_TEXTURE_RECTANGLE_NV && + !ctx->Extensions.NV_texture_rectangle) { + continue; } + else if ((obj->Target == GL_TEXTURE_1D_ARRAY_EXT || + obj->Target == GL_TEXTURE_2D_ARRAY_EXT) && + !ctx->Extensions.MESA_texture_array) { + continue; + } + + target = obj->Target; _mesa_BindTexture(target, obj->Name); @@ -715,8 +796,8 @@ pop_texture_group(GLcontext *ctx, const struct gl_texture_attrib *texAttrib) 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); @@ -724,8 +805,10 @@ pop_texture_group(GLcontext *ctx, const struct gl_texture_attrib *texAttrib) _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, obj->MagFilter); _mesa_TexParameterf(target, GL_TEXTURE_MIN_LOD, obj->MinLod); _mesa_TexParameterf(target, GL_TEXTURE_MAX_LOD, obj->MaxLod); + _mesa_TexParameterf(target, GL_TEXTURE_LOD_BIAS, obj->LodBias); _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, obj->BaseLevel); - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, obj->MaxLevel); + if (target != GL_TEXTURE_RECTANGLE_ARB) + _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, obj->MaxLevel); if (ctx->Extensions.EXT_texture_filter_anisotropic) { _mesa_TexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, obj->MaxAnisotropy); @@ -738,25 +821,19 @@ pop_texture_group(GLcontext *ctx, const struct gl_texture_attrib *texAttrib) } if (ctx->Extensions.SGIX_shadow_ambient) { _mesa_TexParameterf(target, GL_SHADOW_AMBIENT_SGIX, - CHAN_TO_FLOAT(obj->ShadowAmbient)); + obj->ShadowAmbient); } + } + /* remove saved references to the texture objects */ + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + _mesa_reference_texobj(&texstate->SavedTexRef[u][tgt], NULL); } } - _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--; - } + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + texstate->Texture.CurrentUnit); + + _mesa_unlock_context_textures(ctx); } @@ -770,7 +847,7 @@ pop_texture_group(GLcontext *ctx, const struct gl_texture_attrib *texAttrib) * We could at least check if the value to restore equals the current value * and then skip the Mesa call. */ -void +void GLAPIENTRY _mesa_PopAttrib(void) { struct gl_attrib_node *attr, *next; @@ -808,25 +885,62 @@ _mesa_PopAttrib(void) const struct gl_colorbuffer_attrib *color; color = (const struct gl_colorbuffer_attrib *) attr->data; _mesa_ClearIndex((GLfloat) color->ClearIndex); - _mesa_ClearColor(CHAN_TO_FLOAT(color->ClearColor[0]), - CHAN_TO_FLOAT(color->ClearColor[1]), - CHAN_TO_FLOAT(color->ClearColor[2]), - CHAN_TO_FLOAT(color->ClearColor[3])); + _mesa_ClearColor(color->ClearColor[0], + color->ClearColor[1], + color->ClearColor[2], + color->ClearColor[3]); _mesa_IndexMask(color->IndexMask); _mesa_ColorMask((GLboolean) (color->ColorMask[0] != 0), (GLboolean) (color->ColorMask[1] != 0), (GLboolean) (color->ColorMask[2] != 0), (GLboolean) (color->ColorMask[3] != 0)); - _mesa_DrawBuffer(color->DrawBuffer); + { + /* Need to determine if more than one color output is + * specified. If so, call glDrawBuffersARB, else call + * glDrawBuffer(). This is a subtle, but essential point + * since GL_FRONT (for example) is illegal for the former + * function, but legal for the later. + */ + GLboolean multipleBuffers = GL_FALSE; + if (ctx->Extensions.ARB_draw_buffers) { + GLuint i; + for (i = 1; i < ctx->Const.MaxDrawBuffers; i++) { + if (color->DrawBuffer[i] != GL_NONE) { + multipleBuffers = GL_TRUE; + break; + } + } + } + /* Call the API_level functions, not _mesa_drawbuffers() + * since we need to do error checking on the pop'd + * GL_DRAW_BUFFER. + * Ex: if GL_FRONT were pushed, but we're popping with a + * user FBO bound, GL_FRONT will be illegal and we'll need + * to record that error. Per OpenGL ARB decision. + */ + if (multipleBuffers) + _mesa_DrawBuffersARB(ctx->Const.MaxDrawBuffers, + color->DrawBuffer); + else + _mesa_DrawBuffer(color->DrawBuffer[0]); + } _mesa_set_enable(ctx, GL_ALPHA_TEST, color->AlphaEnabled); - _mesa_AlphaFunc(color->AlphaFunc, - CHAN_TO_FLOAT(color->AlphaRef)); + _mesa_AlphaFunc(color->AlphaFunc, color->AlphaRef); _mesa_set_enable(ctx, GL_BLEND, color->BlendEnabled); _mesa_BlendFuncSeparateEXT(color->BlendSrcRGB, color->BlendDstRGB, color->BlendSrcA, color->BlendDstA); - _mesa_BlendEquation(color->BlendEquation); + /* This special case is because glBlendEquationSeparateEXT + * cannot take GL_LOGIC_OP as a parameter. + */ + if ( color->BlendEquationRGB == color->BlendEquationA ) { + _mesa_BlendEquation(color->BlendEquationRGB); + } + else { + _mesa_BlendEquationSeparateEXT(color->BlendEquationRGB, + color->BlendEquationA); + } _mesa_BlendColor(color->BlendColor[0], color->BlendColor[1], color->BlendColor[2], @@ -852,9 +966,6 @@ _mesa_PopAttrib(void) _mesa_ClearDepth(depth->Clear); _mesa_set_enable(ctx, GL_DEPTH_TEST, depth->Test); _mesa_DepthMask(depth->Mask); - if (ctx->Extensions.HP_occlusion_test) - _mesa_set_enable(ctx, GL_OCCLUSION_TEST_HP, - depth->OcclusionTest); } break; case GL_ENABLE_BIT: @@ -907,30 +1018,25 @@ _mesa_PopAttrib(void) /* lighting enable */ _mesa_set_enable(ctx, GL_LIGHTING, light->Enabled); /* per-light state */ - - if (ctx->ModelviewMatrixStack.Top->flags & MAT_DIRTY_INVERSE) - _math_matrix_analyse( ctx->ModelviewMatrixStack.Top ); + if (_math_matrix_is_dirty(ctx->ModelviewMatrixStack.Top)) + _math_matrix_analyse( ctx->ModelviewMatrixStack.Top ); - for (i = 0; i < MAX_LIGHTS; i++) { - GLenum lgt = (GLenum) (GL_LIGHT0 + i); + for (i = 0; i < ctx->Const.MaxLights; i++) { const struct gl_light *l = &light->Light[i]; - GLfloat tmp[4]; - _mesa_set_enable(ctx, lgt, l->Enabled); - _mesa_Lightfv( lgt, GL_AMBIENT, l->Ambient ); - _mesa_Lightfv( lgt, GL_DIFFUSE, l->Diffuse ); - _mesa_Lightfv( lgt, GL_SPECULAR, l->Specular ); - TRANSFORM_POINT( tmp, ctx->ModelviewMatrixStack.Top->inv, l->EyePosition ); - _mesa_Lightfv( lgt, GL_POSITION, tmp ); - TRANSFORM_POINT( tmp, ctx->ModelviewMatrixStack.Top->m, l->EyeDirection ); - _mesa_Lightfv( lgt, GL_SPOT_DIRECTION, tmp ); - _mesa_Lightfv( lgt, GL_SPOT_EXPONENT, &l->SpotExponent ); - _mesa_Lightfv( lgt, GL_SPOT_CUTOFF, &l->SpotCutoff ); - _mesa_Lightfv( lgt, GL_CONSTANT_ATTENUATION, - &l->ConstantAttenuation ); - _mesa_Lightfv( lgt, GL_LINEAR_ATTENUATION, - &l->LinearAttenuation ); - _mesa_Lightfv( lgt, GL_QUADRATIC_ATTENUATION, - &l->QuadraticAttenuation ); + _mesa_set_enable(ctx, GL_LIGHT0 + i, l->Enabled); + _mesa_light(ctx, i, GL_AMBIENT, l->Ambient); + _mesa_light(ctx, i, GL_DIFFUSE, l->Diffuse); + _mesa_light(ctx, i, GL_SPECULAR, l->Specular ); + _mesa_light(ctx, i, GL_POSITION, l->EyePosition); + _mesa_light(ctx, i, GL_SPOT_DIRECTION, l->EyeDirection); + _mesa_light(ctx, i, GL_SPOT_EXPONENT, &l->SpotExponent); + _mesa_light(ctx, i, GL_SPOT_CUTOFF, &l->SpotCutoff); + _mesa_light(ctx, i, GL_CONSTANT_ATTENUATION, + &l->ConstantAttenuation); + _mesa_light(ctx, i, GL_LINEAR_ATTENUATION, + &l->LinearAttenuation); + _mesa_light(ctx, i, GL_QUADRATIC_ATTENUATION, + &l->QuadraticAttenuation); } /* light model */ _mesa_LightModelfv(GL_LIGHT_MODEL_AMBIENT, @@ -941,9 +1047,6 @@ _mesa_PopAttrib(void) (GLfloat) light->Model.TwoSide); _mesa_LightModelf(GL_LIGHT_MODEL_COLOR_CONTROL, (GLfloat) light->Model.ColorControl); - /* materials */ - MEMCPY(ctx->Light.Material, light->Material, - 2 * sizeof(struct gl_material)); /* shade model */ _mesa_ShadeModel(light->ShadeModel); /* color material */ @@ -951,6 +1054,9 @@ _mesa_PopAttrib(void) light->ColorMaterialMode); _mesa_set_enable(ctx, GL_COLOR_MATERIAL, light->ColorMaterialEnabled); + /* materials */ + MEMCPY(&ctx->Light.Material, &light->Material, + sizeof(struct gl_material)); } break; case GL_LINE_BIT: @@ -968,6 +1074,8 @@ _mesa_PopAttrib(void) break; case GL_PIXEL_MODE_BIT: MEMCPY( &ctx->Pixel, attr->data, sizeof(struct gl_pixel_attrib) ); + /* XXX what other pixel state needs to be set by function calls? */ + _mesa_ReadBuffer(ctx->Pixel.ReadBuffer); ctx->NewState |= _NEW_PIXEL; break; case GL_POINT_BIT: @@ -976,21 +1084,29 @@ _mesa_PopAttrib(void) point = (const struct gl_point_attrib *) attr->data; _mesa_PointSize(point->Size); _mesa_set_enable(ctx, GL_POINT_SMOOTH, point->SmoothFlag); - _mesa_PointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, - point->Params); - _mesa_PointParameterfEXT(GL_POINT_SIZE_MIN_EXT, point->MinSize); - _mesa_PointParameterfEXT(GL_POINT_SIZE_MAX_EXT, point->MaxSize); - _mesa_PointParameterfEXT(GL_POINT_FADE_THRESHOLD_SIZE_EXT, - point->Threshold); - if (ctx->Extensions.NV_point_sprite) { + if (ctx->Extensions.EXT_point_parameters) { + _mesa_PointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, + point->Params); + _mesa_PointParameterfEXT(GL_POINT_SIZE_MIN_EXT, + point->MinSize); + _mesa_PointParameterfEXT(GL_POINT_SIZE_MAX_EXT, + point->MaxSize); + _mesa_PointParameterfEXT(GL_POINT_FADE_THRESHOLD_SIZE_EXT, + point->Threshold); + } + if (ctx->Extensions.NV_point_sprite + || ctx->Extensions.ARB_point_sprite) { GLuint u; for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { _mesa_TexEnvi(GL_POINT_SPRITE_NV, GL_COORD_REPLACE_NV, (GLint) point->CoordReplace[u]); } _mesa_set_enable(ctx, GL_POINT_SPRITE_NV,point->PointSprite); - _mesa_PointParameteriNV(GL_POINT_SPRITE_R_MODE_NV, + if (ctx->Extensions.NV_point_sprite) + _mesa_PointParameteriNV(GL_POINT_SPRITE_R_MODE_NV, ctx->Point.SpriteRMode); + _mesa_PointParameterfEXT(GL_POINT_SPRITE_COORD_ORIGIN, + (GLfloat)ctx->Point.SpriteOrigin); } } break; @@ -1036,11 +1152,30 @@ _mesa_PopAttrib(void) stencil = (const struct gl_stencil_attrib *) attr->data; _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); _mesa_ClearStencil(stencil->Clear); - _mesa_StencilFunc(stencil->Function, stencil->Ref, - stencil->ValueMask); - _mesa_StencilMask(stencil->WriteMask); - _mesa_StencilOp(stencil->FailFunc, stencil->ZFailFunc, - stencil->ZPassFunc); + if (ctx->Extensions.EXT_stencil_two_side) { + _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT, + stencil->TestTwoSide); + _mesa_ActiveStencilFaceEXT(stencil->ActiveFace + ? GL_BACK : GL_FRONT); + } + /* front state */ + _mesa_StencilFuncSeparate(GL_FRONT, + stencil->Function[0], + stencil->Ref[0], + stencil->ValueMask[0]); + _mesa_StencilMaskSeparate(GL_FRONT, stencil->WriteMask[0]); + _mesa_StencilOpSeparate(GL_FRONT, stencil->FailFunc[0], + stencil->ZFailFunc[0], + stencil->ZPassFunc[0]); + /* back state */ + _mesa_StencilFuncSeparate(GL_BACK, + stencil->Function[1], + stencil->Ref[1], + stencil->ValueMask[1]); + _mesa_StencilMaskSeparate(GL_BACK, stencil->WriteMask[1]); + _mesa_StencilOpSeparate(GL_BACK, stencil->FailFunc[1], + stencil->ZFailFunc[1], + stencil->ZPassFunc[1]); } break; case GL_TRANSFORM_BIT: @@ -1049,8 +1184,7 @@ _mesa_PopAttrib(void) const struct gl_transform_attrib *xform; xform = (const struct gl_transform_attrib *) attr->data; _mesa_MatrixMode(xform->MatrixMode); - - if (ctx->ProjectionMatrixStack.Top->flags & MAT_DIRTY) + if (_math_matrix_is_dirty(ctx->ProjectionMatrixStack.Top)) _math_matrix_analyse( ctx->ProjectionMatrixStack.Top ); /* restore clip planes */ @@ -1079,9 +1213,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; @@ -1115,11 +1249,59 @@ _mesa_PopAttrib(void) } +/** + * Helper for incrementing/decrementing vertex buffer object reference + * counts when pushing/popping the GL_CLIENT_VERTEX_ARRAY_BIT attribute group. + */ +static void +adjust_buffer_object_ref_counts(struct gl_array_attrib *array, GLint step) +{ + GLuint i; + array->ArrayObj->Vertex.BufferObj->RefCount += step; + array->ArrayObj->Normal.BufferObj->RefCount += step; + array->ArrayObj->Color.BufferObj->RefCount += step; + array->ArrayObj->SecondaryColor.BufferObj->RefCount += step; + array->ArrayObj->FogCoord.BufferObj->RefCount += step; + array->ArrayObj->Index.BufferObj->RefCount += step; + array->ArrayObj->EdgeFlag.BufferObj->RefCount += step; + for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) + array->ArrayObj->TexCoord[i].BufferObj->RefCount += step; + for (i = 0; i < VERT_ATTRIB_MAX; i++) + array->ArrayObj->VertexAttrib[i].BufferObj->RefCount += step; + + array->ArrayBufferObj->RefCount += step; + array->ElementArrayBufferObj->RefCount += step; +} + + +/** + * Copy gl_pixelstore_attrib from src to dst, updating buffer + * object refcounts. + */ +static void +copy_pixelstore(GLcontext *ctx, + struct gl_pixelstore_attrib *dst, + const struct gl_pixelstore_attrib *src) +{ + dst->Alignment = src->Alignment; + dst->RowLength = src->RowLength; + dst->SkipPixels = src->SkipPixels; + dst->SkipRows = src->SkipRows; + dst->ImageHeight = src->ImageHeight; + dst->SkipImages = src->SkipImages; + dst->SwapBytes = src->SwapBytes; + dst->LsbFirst = src->LsbFirst; + dst->ClientStorage = src->ClientStorage; + dst->Invert = src->Invert; + _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj); +} + + #define GL_CLIENT_PACK_BIT (1<<20) #define GL_CLIENT_UNPACK_BIT (1<<21) -void +void GLAPIENTRY _mesa_PushClientAttrib(GLbitfield mask) { struct gl_attrib_node *newnode; @@ -1133,35 +1315,53 @@ _mesa_PushClientAttrib(GLbitfield mask) return; } - /* Build linked list of attribute nodes which save all attribute */ - /* groups specified by the mask. */ + /* Build linked list of attribute nodes which save all attribute + * groups specified by the mask. + */ head = NULL; if (mask & GL_CLIENT_PIXEL_STORE_BIT) { struct gl_pixelstore_attrib *attr; /* packing attribs */ - attr = MALLOC_STRUCT( gl_pixelstore_attrib ); - MEMCPY( attr, &ctx->Pack, sizeof(struct gl_pixelstore_attrib) ); + attr = CALLOC_STRUCT( gl_pixelstore_attrib ); + copy_pixelstore(ctx, attr, &ctx->Pack); newnode = new_attrib_node( GL_CLIENT_PACK_BIT ); newnode->data = attr; newnode->next = head; head = newnode; /* unpacking attribs */ - attr = MALLOC_STRUCT( gl_pixelstore_attrib ); - MEMCPY( attr, &ctx->Unpack, sizeof(struct gl_pixelstore_attrib) ); + attr = CALLOC_STRUCT( gl_pixelstore_attrib ); + copy_pixelstore(ctx, attr, &ctx->Unpack); newnode = new_attrib_node( GL_CLIENT_UNPACK_BIT ); newnode->data = attr; newnode->next = head; head = newnode; } + if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) { struct gl_array_attrib *attr; + struct gl_array_object *obj; + attr = MALLOC_STRUCT( gl_array_attrib ); + obj = MALLOC_STRUCT( gl_array_object ); + +#if FEATURE_ARB_vertex_buffer_object + /* increment ref counts since we're copying pointers to these objects */ + ctx->Array.ArrayBufferObj->RefCount++; + ctx->Array.ElementArrayBufferObj->RefCount++; +#endif + MEMCPY( attr, &ctx->Array, sizeof(struct gl_array_attrib) ); + MEMCPY( obj, ctx->Array.ArrayObj, sizeof(struct gl_array_object) ); + + attr->ArrayObj = obj; + newnode = new_attrib_node( GL_CLIENT_VERTEX_ARRAY_BIT ); newnode->data = attr; newnode->next = head; head = newnode; + /* bump reference counts on buffer objects */ + adjust_buffer_object_ref_counts(&ctx->Array, 1); } ctx->ClientAttribStack[ctx->ClientAttribStackDepth] = head; @@ -1171,10 +1371,10 @@ _mesa_PushClientAttrib(GLbitfield mask) -void +void GLAPIENTRY _mesa_PopClientAttrib(void) { - struct gl_attrib_node *attr, *next; + struct gl_attrib_node *node, *next; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); @@ -1185,33 +1385,114 @@ _mesa_PopClientAttrib(void) } ctx->ClientAttribStackDepth--; - attr = ctx->ClientAttribStack[ctx->ClientAttribStackDepth]; + node = ctx->ClientAttribStack[ctx->ClientAttribStackDepth]; - while (attr) { - switch (attr->kind) { + while (node) { + switch (node->kind) { case GL_CLIENT_PACK_BIT: - MEMCPY( &ctx->Pack, attr->data, - sizeof(struct gl_pixelstore_attrib) ); + { + struct gl_pixelstore_attrib *store = + (struct gl_pixelstore_attrib *) node->data; + copy_pixelstore(ctx, &ctx->Pack, store); + _mesa_reference_buffer_object(ctx, &store->BufferObj, NULL); + } ctx->NewState |= _NEW_PACKUNPACK; break; case GL_CLIENT_UNPACK_BIT: - MEMCPY( &ctx->Unpack, attr->data, - sizeof(struct gl_pixelstore_attrib) ); + { + struct gl_pixelstore_attrib *store = + (struct gl_pixelstore_attrib *) node->data; + copy_pixelstore(ctx, &ctx->Unpack, store); + _mesa_reference_buffer_object(ctx, &store->BufferObj, NULL); + } ctx->NewState |= _NEW_PACKUNPACK; break; - case GL_CLIENT_VERTEX_ARRAY_BIT: - MEMCPY( &ctx->Array, attr->data, - sizeof(struct gl_array_attrib) ); + case GL_CLIENT_VERTEX_ARRAY_BIT: { + struct gl_array_attrib * data = + (struct gl_array_attrib *) node->data; + + adjust_buffer_object_ref_counts(&ctx->Array, -1); + + ctx->Array.ActiveTexture = data->ActiveTexture; + if (data->LockCount != 0) + _mesa_LockArraysEXT(data->LockFirst, data->LockCount); + else if (ctx->Array.LockCount) + _mesa_UnlockArraysEXT(); + + _mesa_BindVertexArrayAPPLE( data->ArrayObj->Name ); + +#if FEATURE_ARB_vertex_buffer_object + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, + data->ArrayBufferObj->Name); + _mesa_BindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, + data->ElementArrayBufferObj->Name); +#endif + + MEMCPY( ctx->Array.ArrayObj, data->ArrayObj, + sizeof( struct gl_array_object ) ); + + FREE( data->ArrayObj ); + + /* FIXME: Should some bits in ctx->Array->NewState also be set + * FIXME: here? It seems like it should be set to inclusive-or + * FIXME: of the old ArrayObj->_Enabled and the new _Enabled. + */ + ctx->NewState |= _NEW_ARRAY; break; + } default: _mesa_problem( ctx, "Bad attrib flag in PopClientAttrib"); break; } - next = attr->next; - FREE( attr->data ); - FREE( attr ); - attr = next; + next = node->next; + FREE( node->data ); + FREE( node ); + node = next; + } +} + + +/** + * 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, tgt; + /* clear references to the saved texture objects */ + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + _mesa_reference_texobj(&texstate->SavedTexRef[u][tgt], 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 */ + ctx->AttribStackDepth = 0; + ctx->ClientAttribStackDepth = 0; +}