Merge branch 'master' of git+ssh://keithw@git.freedesktop.org/git/mesa/mesa into...
authorKeith Whitwell <keith@tungstengraphics.com>
Tue, 16 Jan 2007 11:22:57 +0000 (11:22 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Tue, 16 Jan 2007 11:22:57 +0000 (11:22 +0000)
Conflicts:

src/mesa/array_cache/sources
src/mesa/drivers/dri/i965/brw_context.c
src/mesa/drivers/dri/i965/brw_draw.c
src/mesa/drivers/dri/i965/brw_fallback.c
src/mesa/drivers/dri/i965/brw_vs_emit.c
src/mesa/drivers/dri/i965/brw_vs_tnl.c
src/mesa/drivers/dri/mach64/mach64_context.c
src/mesa/main/extensions.c
src/mesa/main/getstring.c
src/mesa/tnl/sources
src/mesa/tnl/t_save_api.c
src/mesa/tnl/t_save_playback.c
src/mesa/tnl/t_vtx_api.c
src/mesa/tnl/t_vtx_exec.c
src/mesa/vbo/vbo_attrib.h
src/mesa/vbo/vbo_exec_api.c
src/mesa/vbo/vbo_save_api.c
src/mesa/vbo/vbo_save_draw.c

44 files changed:
1  2 
src/mesa/Makefile
src/mesa/drivers/directfb/idirectfbgl_mesa.c
src/mesa/drivers/dri/i915/intel_context.c
src/mesa/drivers/dri/i915tex/i915_context.c
src/mesa/drivers/dri/i915tex/intel_context.c
src/mesa/drivers/dri/i965/Makefile
src/mesa/drivers/dri/i965/brw_context.c
src/mesa/drivers/dri/i965/brw_context.h
src/mesa/drivers/dri/i965/brw_draw_upload.c
src/mesa/drivers/dri/i965/brw_metaops.c
src/mesa/drivers/dri/i965/brw_vs_tnl.c
src/mesa/drivers/dri/i965/brw_vtbl.c
src/mesa/drivers/dri/i965/intel_context.c
src/mesa/drivers/dri/mach64/mach64_context.c
src/mesa/drivers/dri/mga/mgastate.c
src/mesa/drivers/dri/nouveau/nouveau_context.c
src/mesa/drivers/dri/nouveau/nouveau_state.c
src/mesa/drivers/dri/r200/r200_context.c
src/mesa/drivers/dri/r200/r200_state.c
src/mesa/drivers/dri/r200/r200_tcl.c
src/mesa/drivers/dri/r300/r300_context.h
src/mesa/drivers/dri/r300/r300_state.c
src/mesa/drivers/dri/r300/radeon_state.c
src/mesa/drivers/dri/radeon/radeon_context.c
src/mesa/drivers/dri/savage/savage_xmesa.c
src/mesa/drivers/dri/savage/savagestate.c
src/mesa/drivers/dri/tdfx/tdfx_context.c
src/mesa/drivers/dri/trident/trident_context.c
src/mesa/drivers/dri/unichrome/via_context.c
src/mesa/drivers/dri/unichrome/via_state.c
src/mesa/main/context.c
src/mesa/main/enable.c
src/mesa/main/extensions.c
src/mesa/main/get.c
src/mesa/main/get_gen.py
src/mesa/main/mtypes.h
src/mesa/main/state.c
src/mesa/main/stencil.c
src/mesa/tnl/sources
src/mesa/tnl/t_context.c
src/mesa/vbo/vbo_attrib.h
src/mesa/vbo/vbo_save_api.c
src/mesa/vbo/vbo_save_draw.c
src/mesa/vbo/vbo_split_copy.c

Simple merge
index 4cbe29d79d6f5aae7af1f4fdbdf7887327ce6380,4cbe29d79d6f5aae7af1f4fdbdf7887327ce6380..9b4d72eab3ec5221aaa29f968382a2c8ed22998b
@@@ -36,7 -36,7 +36,6 @@@
  #include "swrast/swrast.h"
  #include "swrast_setup/swrast_setup.h"
  #include "tnl/tnl.h"
--#include "array_cache/acache.h"
  
  #include "utils.h"
  #include "i915_reg.h"
@@@ -67,7 -67,7 +66,7 @@@ i915InvalidateState(GLcontext * ctx, GL
  {
     _swrast_InvalidateState(ctx, new_state);
     _swsetup_InvalidateState(ctx, new_state);
--   _ac_InvalidateState(ctx, new_state);
++   _vbo_InvalidateState(ctx, new_state);
     _tnl_InvalidateState(ctx, new_state);
     _tnl_invalidate_vertex_state(ctx, new_state);
     intel_context(ctx)->NewGLState |= new_state;
index 3d51a6341c7e1153d1ff995c1fc36f34aab109b8,c77d365360d6bd47f5c79800bcb558b2defb89c9..946f9e804150e679937c8f6f0e552fe5cf32c512
@@@ -37,7 -37,7 +37,6 @@@
  #include "swrast/swrast.h"
  #include "swrast_setup/swrast_setup.h"
  #include "tnl/tnl.h"
--#include "array_cache/acache.h"
  
  #include "tnl/t_pipeline.h"
  #include "tnl/t_vertex.h"
@@@ -241,7 -241,7 +240,7 @@@ intelInvalidateState(GLcontext * ctx, G
  {
     _swrast_InvalidateState(ctx, new_state);
     _swsetup_InvalidateState(ctx, new_state);
--   _ac_InvalidateState(ctx, new_state);
++   _vbo_InvalidateState(ctx, new_state);
     _tnl_InvalidateState(ctx, new_state);
     _tnl_invalidate_vertex_state(ctx, new_state);
     intel_context(ctx)->NewGLState |= new_state;
@@@ -390,7 -390,7 +389,7 @@@ intelInitContext(struct intel_context *
  
     /* Initialize the software rasterizer and helper modules. */
     _swrast_CreateContext(ctx);
--   _ac_CreateContext(ctx);
++   _vbo_CreateContext(ctx);
     _tnl_CreateContext(ctx);
     _swsetup_CreateContext(ctx);
  
@@@ -500,7 -500,7 +499,7 @@@ intelDestroyContext(__DRIcontextPrivat
        release_texture_heaps = (intel->ctx.Shared->RefCount == 1);
        _swsetup_DestroyContext(&intel->ctx);
        _tnl_DestroyContext(&intel->ctx);
--      _ac_DestroyContext(&intel->ctx);
++      _vbo_DestroyContext(&intel->ctx);
  
        _swrast_DestroyContext(&intel->ctx);
        intel->Fallback = 0;      /* don't call _swrast_Flush later */
Simple merge
index 263110bf5e05ad9b2af97b1125a9cc8d21c05283,bc422c1a50bef20d274ffe7f240893ff68fa3636..6faee65542b683ad69cf235f953b119e70172d22
@@@ -154,7 -156,14 +154,8 @@@ GLboolean brwCreateContext( const __GLc
  
     brw_ProgramCacheInit( ctx );
  
+    brw_FrameBufferTexInit( brw );
  
 -   /* Hook our functions into exec and compile dispatch tables.  Only
 -    * fallback on out-of-memory situations.
 -    */
 -   brw_exec_init( ctx );
 -   brw_save_init( ctx );
 -
     {
        const char *filename = getenv("INTEL_REPLAY");
        if (filename) {
index dfb598acdf699acb11ee6412d9be6d219793c1b4,57ee294f0cf699b735cab9f2ace1be279f70165d..90637d16eae898a6aff59078b424c879c5620976
@@@ -411,10 -414,10 +411,10 @@@ GLboolean brw_upload_vertices( struct b
      */
     
     while (tmp) {
-       GLuint i = ffs(tmp)-1;
+       GLuint i = ffsll(tmp)-1;
        struct brw_vertex_element *input = &brw->vb.inputs[i];
  
 -      tmp &= ~((GLuint64EXT)1<<i);
 +      tmp &= ~(1<<i);
        enabled[nr_enabled++] = input;
  
        input->index = i;
index a5738e57747e89db662f63fe7300be31da833819,ac09754e3ae537b70b7d70b886b346ab18634522..786f30e641efb23f5182ab7aedd3f0d42cdeabdf
@@@ -66,7 -68,11 +66,8 @@@ static void brw_destroy_context( struc
     brw_destroy_state(brw);
     brw_draw_destroy( brw );
  
 -   brw_exec_destroy( ctx );
 -   brw_save_destroy( ctx );
 -
     brw_ProgramCacheDestroy( ctx );
+    brw_FrameBufferTexDestroy( brw );
  }
  
  /* called from intelDrawBuffer()
index c4c5488cbb189a38d045f2712998d08a1244ad96,459ed109ed575c24501e27ad3fc19afec64465fd..60fcf958926e43c1c905a94849fb556b4b4a6a1c
@@@ -320,9 -355,14 +355,14 @@@ GLboolean intelInitContext( struct inte
     ctx->Const.MaxPointSizeAA = 3.0;
     ctx->Const.PointSizeGranularity = 1.0;
  
+    /* reinitialize the context point state.
+     * It depend on constants in __GLcontextRec::Const
+     */
+    _mesa_init_point(ctx);
     /* Initialize the software rasterizer and helper modules. */
     _swrast_CreateContext( ctx );
 -   _ac_CreateContext( ctx );
 +   _vbo_CreateContext( ctx );
     _tnl_CreateContext( ctx );
     _swsetup_CreateContext( ctx );
  
index eeb4cbcf71ea764ff90a5b14422454f6a3d26a0f,2ab1cf2617e81a196e22f28af7b02a72d9eb231d..5a6c301da2d9359b168c892f1a623492a15c2fa2
@@@ -250,7 -272,16 +272,16 @@@ void mach64DestroyContext( __DRIcontext
  
     assert(mmesa);  /* should never be null */
     if ( mmesa ) {
-       if (mmesa->glCtx->Shared->RefCount == 1) {
+       GLboolean   release_texture_heaps;
+       release_texture_heaps = (mmesa->glCtx->Shared->RefCount == 1);
+       _swsetup_DestroyContext( mmesa->glCtx );
+       _tnl_DestroyContext( mmesa->glCtx );
 -      _ac_DestroyContext( mmesa->glCtx );
++      _vbo_DestroyContext( mmesa->glCtx );
+       _swrast_DestroyContext( mmesa->glCtx );
+       if (release_texture_heaps) {
           /* This share group is about to go away, free our private
            * texture object data.
            */
Simple merge
index 0000000000000000000000000000000000000000,79da46fc0b6aa7af770c3b3c4f0ecceca437f238..c86ff603f6fcc550bbcbf42ea9f0414d2bee91a8
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,367 +1,366 @@@
 -#include "array_cache/acache.h"
+ /**************************************************************************
+ Copyright 2006 Stephane Marchesin
+ 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"),
+ to deal in the Software without restriction, including without limitation
+ on the rights to use, copy, modify, merge, publish, distribute, sub
+ license, and/or sell copies of the Software, and to permit persons to whom
+ the Software is furnished to do so, subject to the following conditions:
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ ERIC ANHOLT OR SILICON INTEGRATED SYSTEMS CORP BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************/
+ #include "glheader.h"
+ #include "context.h"
+ #include "simple_list.h"
+ #include "imports.h"
+ #include "matrix.h"
+ #include "swrast/swrast.h"
+ #include "swrast_setup/swrast_setup.h"
 -      _ac_CreateContext( ctx );
+ #include "framebuffer.h"
+ #include "tnl/tnl.h"
+ #include "tnl/t_pipeline.h"
+ #include "tnl/t_vp_build.h"
+ #include "drivers/common/driverfuncs.h"
+ #include "nouveau_context.h"
+ #include "nouveau_driver.h"
+ //#include "nouveau_state.h"
+ #include "nouveau_span.h"
+ #include "nouveau_object.h"
+ #include "nouveau_fifo.h"
+ #include "nouveau_tex.h"
+ #include "nouveau_msg.h"
+ #include "nouveau_reg.h"
+ #include "nouveau_lock.h"
+ #include "nv10_swtcl.h"
+ #include "vblank.h"
+ #include "utils.h"
+ #include "texmem.h"
+ #include "xmlpool.h" /* for symbolic values of enum-type options */
+ #ifndef NOUVEAU_DEBUG
+ int NOUVEAU_DEBUG = 0;
+ #endif
+ static const struct dri_debug_control debug_control[] =
+ {
+       { "shaders"   , DEBUG_SHADERS    },
+       { "mem"       , DEBUG_MEM        },
+       { "bufferobj" , DEBUG_BUFFEROBJ  },
+       { NULL        , 0                }
+ };
+ #define need_GL_ARB_vertex_program
+ #include "extension_helper.h"
+ const struct dri_extension common_extensions[] =
+ {
+       { NULL,    0 }
+ };
+ const struct dri_extension nv10_extensions[] =
+ {
+       { NULL,    0 }
+ };
+ const struct dri_extension nv20_extensions[] =
+ {
+       { NULL,    0 }
+ };
+ const struct dri_extension nv30_extensions[] =
+ {
+       { "GL_ARB_fragment_program",    NULL                            },
+       { NULL,    0 }
+ };
+ const struct dri_extension nv40_extensions[] =
+ {
+    /* ARB_vp can be moved to nv20/30 once the shader backend has been
+     * written for those cards.
+     */
+       { "GL_ARB_vertex_program",      GL_ARB_vertex_program_functions },
+       { NULL, 0 }
+ };
+ const struct dri_extension nv50_extensions[] =
+ {
+       { NULL,    0 }
+ };
+ /* Create the device specific context.
+  */
+ GLboolean nouveauCreateContext( const __GLcontextModes *glVisual,
+               __DRIcontextPrivate *driContextPriv,
+               void *sharedContextPrivate )
+ {
+       GLcontext *ctx, *shareCtx;
+       __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv;
+       struct dd_function_table functions;
+       nouveauContextPtr nmesa;
+       nouveauScreenPtr screen;
+       /* Allocate the context */
+       nmesa = (nouveauContextPtr) CALLOC( sizeof(*nmesa) );
+       if ( !nmesa )
+               return GL_FALSE;
+       nmesa->driContext = driContextPriv;
+       nmesa->driScreen = sPriv;
+       nmesa->driDrawable = NULL;
+       nmesa->hHWContext = driContextPriv->hHWContext;
+       nmesa->driHwLock = &sPriv->pSAREA->lock;
+       nmesa->driFd = sPriv->fd;
+       nmesa->screen = (nouveauScreenPtr)(sPriv->private);
+       screen=nmesa->screen;
+       /* Create the hardware context */
+       if (!nouveauDRMGetParam(nmesa, NOUVEAU_GETPARAM_FB_PHYSICAL,
+                               &nmesa->vram_phys))
+          return GL_FALSE;
+       if (!nouveauDRMGetParam(nmesa, NOUVEAU_GETPARAM_AGP_PHYSICAL,
+                               &nmesa->agp_phys))
+          return GL_FALSE;
+       if (!nouveauFifoInit(nmesa))
+          return GL_FALSE;
+       nouveauObjectInit(nmesa);
+       /* Init default driver functions then plug in our nouveau-specific functions
+        * (the texture functions are especially important)
+        */
+       _mesa_init_driver_functions( &functions );
+       nouveauDriverInitFunctions( &functions );
+       nouveauTexInitFunctions( &functions );
+       /* Allocate the Mesa context */
+       if (sharedContextPrivate)
+               shareCtx = ((nouveauContextPtr) sharedContextPrivate)->glCtx;
+       else 
+               shareCtx = NULL;
+       nmesa->glCtx = _mesa_create_context(glVisual, shareCtx,
+                       &functions, (void *) nmesa);
+       if (!nmesa->glCtx) {
+               FREE(nmesa);
+               return GL_FALSE;
+       }
+       driContextPriv->driverPrivate = nmesa;
+       ctx = nmesa->glCtx;
+       /* Parse configuration files */
+       driParseConfigFiles (&nmesa->optionCache, &screen->optionCache,
+                       screen->driScreen->myNum, "nouveau");
+       nmesa->sarea = (drm_nouveau_sarea_t *)((char *)sPriv->pSAREA +
+                       screen->sarea_priv_offset);
+       /* Enable any supported extensions */
+       driInitExtensions(ctx, common_extensions, GL_TRUE);
+       if (nmesa->screen->card->type >= NV_10)
+               driInitExtensions(ctx, nv10_extensions, GL_FALSE);
+       if (nmesa->screen->card->type >= NV_20)
+               driInitExtensions(ctx, nv20_extensions, GL_FALSE);
+       if (nmesa->screen->card->type >= NV_30)
+               driInitExtensions(ctx, nv30_extensions, GL_FALSE);
+       if (nmesa->screen->card->type >= NV_40)
+               driInitExtensions(ctx, nv40_extensions, GL_FALSE);
+       if (nmesa->screen->card->type >= NV_50)
+               driInitExtensions(ctx, nv50_extensions, GL_FALSE);
+       nmesa->current_primitive = -1;
+       nouveauShaderInitFuncs(ctx);
+       /* Install Mesa's fixed-function texenv shader support */
+       if (nmesa->screen->card->type >= NV_40)
+               ctx->_MaintainTexEnvProgram = GL_TRUE;
+       /* Initialize the swrast */
+       _swrast_CreateContext( ctx );
++      _vbo_CreateContext( ctx );
+       _tnl_CreateContext( ctx );
+       _swsetup_CreateContext( ctx );
+       _math_matrix_ctr(&nmesa->viewport);
+       nouveauDDInitStateFuncs( ctx );
+       nouveauSpanInitFunctions( ctx );
+       nouveauDDInitState( nmesa );
+       switch(nmesa->screen->card->type)
+       {
+               case NV_03:
+                       //nv03TriInitFunctions( ctx );
+                       break;
+               case NV_04:
+               case NV_05:
+                       //nv04TriInitFunctions( ctx );
+                       break;
+               case NV_10:
+               case NV_20:
+               case NV_30:
+               case NV_40:
+               case NV_44:
+               case NV_50:
+               default:
+                       nv10TriInitFunctions( ctx );
+                       break;
+       }
+       nouveauInitBufferObjects(ctx);
+       if (!nouveauSyncInitFuncs(ctx))
+          return GL_FALSE;
+       nmesa->hw_func.InitCard(nmesa);
+         nouveauInitState(ctx);
+       driContextPriv->driverPrivate = (void *)nmesa;
+       NOUVEAU_DEBUG = driParseDebugString( getenv( "NOUVEAU_DEBUG" ),
+                       debug_control );
+       if (driQueryOptionb(&nmesa->optionCache, "no_rast")) {
+               fprintf(stderr, "disabling 3D acceleration\n");
+               FALLBACK(nmesa, NOUVEAU_FALLBACK_DISABLE, 1);
+       }
+       return GL_TRUE;
+ }
+ /* Destroy the device specific context. */
+ void nouveauDestroyContext( __DRIcontextPrivate *driContextPriv  )
+ {
+       nouveauContextPtr nmesa = (nouveauContextPtr) driContextPriv->driverPrivate;
+       assert(nmesa);
+       if ( nmesa ) {
+               /* free the option cache */
+               driDestroyOptionCache (&nmesa->optionCache);
+               FREE( nmesa );
+       }
+ }
+ /* Force the context `c' to be the current context and associate with it
+  * buffer `b'.
+  */
+ GLboolean nouveauMakeCurrent( __DRIcontextPrivate *driContextPriv,
+               __DRIdrawablePrivate *driDrawPriv,
+               __DRIdrawablePrivate *driReadPriv )
+ {
+       if ( driContextPriv ) {
+               nouveauContextPtr nmesa = (nouveauContextPtr) driContextPriv->driverPrivate;
+               struct gl_framebuffer *draw_fb =
+                       (struct gl_framebuffer*)driDrawPriv->driverPrivate;
+               struct gl_framebuffer *read_fb =
+                       (struct gl_framebuffer*)driReadPriv->driverPrivate;
+               driDrawableInitVBlank(driDrawPriv, nmesa->vblank_flags, &nmesa->vblank_seq );
+               nmesa->driDrawable = driDrawPriv;
+               _mesa_resize_framebuffer(nmesa->glCtx, draw_fb,
+                                        driDrawPriv->w, driDrawPriv->h);
+               if (draw_fb != read_fb) {
+                       _mesa_resize_framebuffer(nmesa->glCtx, draw_fb,
+                                                driReadPriv->w,
+                                                driReadPriv->h);
+               }
+               _mesa_make_current(nmesa->glCtx, draw_fb, read_fb);
+               nouveau_build_framebuffer(nmesa->glCtx,
+                                         driDrawPriv->driverPrivate);
+       } else {
+               _mesa_make_current( NULL, NULL, NULL );
+       }
+       return GL_TRUE;
+ }
+ /* Force the context `c' to be unbound from its buffer.
+  */
+ GLboolean nouveauUnbindContext( __DRIcontextPrivate *driContextPriv )
+ {
+       return GL_TRUE;
+ }
+ static void nouveauDoSwapBuffers(nouveauContextPtr nmesa,
+                                __DRIdrawablePrivate *dPriv)
+ {
+       struct gl_framebuffer *fb;
+       nouveau_renderbuffer *src, *dst;
+       drm_clip_rect_t *box;
+       int nbox, i;
+       fb = (struct gl_framebuffer *)dPriv->driverPrivate;
+       dst = (nouveau_renderbuffer*)
+               fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
+       src = (nouveau_renderbuffer*)
+               fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer;
+ #ifdef ALLOW_MULTI_SUBCHANNEL
+       LOCK_HARDWARE(nmesa);
+       nbox = dPriv->numClipRects;
+       box  = dPriv->pClipRects;
+       if (nbox) {
+               BEGIN_RING_SIZE(NvSubCtxSurf2D,
+                               NV10_CONTEXT_SURFACES_2D_FORMAT, 4);
+               if (src->mesa._ActualFormat == GL_RGBA8)
+                       OUT_RING       (6); /* X8R8G8B8 */
+               else
+                       OUT_RING       (4); /* R5G6B5 */
+               OUT_RING       ((dst->pitch << 16) | src->pitch);
+               OUT_RING       (src->offset);
+               OUT_RING       (dst->offset);
+       }
+       for (i=0; i<nbox; i++, box++) {
+               BEGIN_RING_SIZE(NvSubImageBlit, NV10_IMAGE_BLIT_SET_POINT, 3);
+               OUT_RING       (((box->y1 - dPriv->y) << 16) |
+                               (box->x1 - dPriv->x));
+               OUT_RING       ((box->y1 << 16) | box->x1);
+               OUT_RING       (((box->y2 - box->y1) << 16) |
+                               (box->x2 - box->x1));
+       }
+       UNLOCK_HARDWARE(nmesa);
+ #endif
+ }
+ void nouveauSwapBuffers(__DRIdrawablePrivate *dPriv)
+ {
+       if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
+               nouveauContextPtr nmesa = dPriv->driContextPriv->driverPrivate;
+               if (nmesa->glCtx->Visual.doubleBufferMode) {
+                       _mesa_notifySwapBuffers(nmesa->glCtx);
+                       nouveauDoSwapBuffers(nmesa, dPriv);
+               }
+       }
+ }
+ void nouveauCopySubBuffer(__DRIdrawablePrivate *dPriv,
+                         int x, int y, int w, int h)
+ {
+ }
index 0000000000000000000000000000000000000000,1ff881f0542cc930310f56b2fa0034059c92a98a..8d3c018dffaec12ed092832f27dfbee790e487de
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,342 +1,341 @@@
 -#include "array_cache/acache.h"
+ /**************************************************************************
+ Copyright 2006 Jeremy Kolb
+ 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"),
+ to deal in the Software without restriction, including without limitation
+ on the rights to use, copy, modify, merge, publish, distribute, sub
+ license, and/or sell copies of the Software, and to permit persons to whom
+ the Software is furnished to do so, subject to the following conditions:
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ ERIC ANHOLT OR SILICON INTEGRATED SYSTEMS CORP BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+ **************************************************************************/
+ #include "nouveau_context.h"
+ #include "nouveau_state.h"
+ #include "nouveau_swtcl.h"
+ #include "nouveau_fifo.h"
+ #include "swrast/swrast.h"
 -    _ac_InvalidateState( ctx, new_state );
+ #include "tnl/tnl.h"
+ #include "swrast_setup/swrast_setup.h"
+ #include "tnl/t_pipeline.h"
+ #include "mtypes.h"
+ #include "colormac.h"
+ static __inline__ GLuint nouveauPackColor(GLuint format,
+                                      GLubyte r, GLubyte g,
+                                      GLubyte b, GLubyte a)
+ {
+    switch (format) {
+    case 2:
+       return PACK_COLOR_565( r, g, b );
+    case 4:
+       return PACK_COLOR_8888( r, g, b, a);
+    default:
+       fprintf(stderr, "unknown format %d\n", (int)format);
+       return 0;
+    }
+ }
+ static void nouveauCalcViewport(GLcontext *ctx)
+ {
+     /* Calculate the Viewport Matrix */
+     
+     nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
+     const GLfloat *v = ctx->Viewport._WindowMap.m;
+     GLfloat *m = nmesa->viewport.m;
+     GLfloat xoffset = nmesa->drawX, yoffset = nmesa->drawY;
+   
+     nmesa->depth_scale = 1.0 / ctx->DrawBuffer->_DepthMaxF;
+     m[MAT_SX] =   v[MAT_SX];
+     m[MAT_TX] =   v[MAT_TX] + xoffset + SUBPIXEL_X;
+     m[MAT_SY] = - v[MAT_SY];
+     m[MAT_TY] =   v[MAT_TY] + yoffset + SUBPIXEL_Y;
+     m[MAT_SZ] =   v[MAT_SZ] * nmesa->depth_scale;
+     m[MAT_TZ] =   v[MAT_TZ] * nmesa->depth_scale;
+     nmesa->hw_func.WindowMoved(nmesa);
+ }
+ static void nouveauViewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
+ {
+     /* 
+      * Need to send (at least on an nv35 the following:
+      * cons = 4 (this may be bytes per pixel)
+      *
+      * The viewport:
+      * 445   0x0000bee0   {size: 0x0   channel: 0x1   cmd: 0x00009ee0} <-- VIEWPORT_SETUP/HEADER ?
+      * 446   0x00000000   {size: 0x0   channel: 0x0   cmd: 0x00000000} <-- x * cons
+      * 447   0x00000c80   {size: 0x0   channel: 0x0   cmd: 0x00000c80} <-- (height + x) * cons
+      * 448   0x00000000   {size: 0x0   channel: 0x0   cmd: 0x00000000} <-- y * cons
+      * 449   0x00000960   {size: 0x0   channel: 0x0   cmd: 0x00000960} <-- (width + y) * cons
+      * 44a   0x00082a00   {size: 0x2   channel: 0x1   cmd: 0x00000a00} <-- VIEWPORT_DIMS
+      * 44b   0x04000000  <-- (Width_from_glViewport << 16) | x
+      * 44c   0x03000000  <-- (Height_from_glViewport << 16) | (win_height - height - y)
+      *
+      */
+     
+     nouveauCalcViewport(ctx);
+ }
+ static void nouveauDepthRange(GLcontext *ctx, GLclampd near, GLclampd far)
+ {
+     nouveauCalcViewport(ctx);
+ }
+ static void nouveauDDUpdateHWState(GLcontext *ctx)
+ {
+     nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
+     int new_state = nmesa->new_state;
+     if ( new_state || nmesa->new_render_state & _NEW_TEXTURE )
+     {
+         nmesa->new_state = 0;
+         /* Update the various parts of the context's state.
+         */
+         /*
+         if ( new_state & NOUVEAU_NEW_ALPHA )
+             nouveauUpdateAlphaMode( ctx );
+         if ( new_state & NOUVEAU_NEW_DEPTH )
+             nouveauUpdateZMode( ctx );
+         if ( new_state & NOUVEAU_NEW_FOG )
+             nouveauUpdateFogAttrib( ctx );
+         if ( new_state & NOUVEAU_NEW_CLIP )
+             nouveauUpdateClipping( ctx );
+         if ( new_state & NOUVEAU_NEW_CULL )
+             nouveauUpdateCull( ctx );
+         if ( new_state & NOUVEAU_NEW_MASKS )
+             nouveauUpdateMasks( ctx );
+         if ( new_state & NOUVEAU_NEW_WINDOW )
+             nouveauUpdateWindow( ctx );
+         if ( nmesa->new_render_state & _NEW_TEXTURE ) {
+             nouveauUpdateTextureState( ctx );
+         }*/
+     }
+ }
+ static void nouveauDDInvalidateState(GLcontext *ctx, GLuint new_state)
+ {
+     _swrast_InvalidateState( ctx, new_state );
+     _swsetup_InvalidateState( ctx, new_state );
++    _vbo_InvalidateState( ctx, new_state );
+     _tnl_InvalidateState( ctx, new_state );
+     NOUVEAU_CONTEXT(ctx)->new_render_state |= new_state;
+ }
+ /* Initialize the context's hardware state. */
+ void nouveauDDInitState(nouveauContextPtr nmesa)
+ {
+     uint32_t type = nmesa->screen->card->type;
+     switch(type)
+     {
+         case NV_03:
+         case NV_04:
+         case NV_05:
+             /* No TCL engines for these ones */
+             break;
+         case NV_10:
+             nv10InitStateFuncs(nmesa->glCtx, &nmesa->glCtx->Driver);
+             break;
+         case NV_20:
+             nv20InitStateFuncs(nmesa->glCtx, &nmesa->glCtx->Driver);
+             break;
+         case NV_30:
+         case NV_40:
+         case NV_44:
+         case NV_50:
+             nv30InitStateFuncs(nmesa->glCtx, &nmesa->glCtx->Driver);
+             break;
+         default:
+             break;
+     }
+     nouveau_state_cache_init(nmesa);
+ }
+ /* Initialize the driver's state functions */
+ void nouveauDDInitStateFuncs(GLcontext *ctx)
+ {
+    ctx->Driver.UpdateState            = nouveauDDInvalidateState;
+    ctx->Driver.ClearIndex             = NULL;
+    ctx->Driver.ClearColor             = NULL; //nouveauDDClearColor;
+    ctx->Driver.ClearStencil           = NULL; //nouveauDDClearStencil;
+    ctx->Driver.DrawBuffer             = NULL; //nouveauDDDrawBuffer;
+    ctx->Driver.ReadBuffer             = NULL; //nouveauDDReadBuffer;
+    ctx->Driver.IndexMask              = NULL;
+    ctx->Driver.ColorMask              = NULL; //nouveauDDColorMask;
+    ctx->Driver.AlphaFunc              = NULL; //nouveauDDAlphaFunc;
+    ctx->Driver.BlendEquationSeparate  = NULL; //nouveauDDBlendEquationSeparate;
+    ctx->Driver.BlendFuncSeparate      = NULL; //nouveauDDBlendFuncSeparate;
+    ctx->Driver.ClearDepth             = NULL; //nouveauDDClearDepth;
+    ctx->Driver.CullFace                       = NULL; //nouveauDDCullFace;
+    ctx->Driver.FrontFace              = NULL; //nouveauDDFrontFace;
+    ctx->Driver.DepthFunc              = NULL; //nouveauDDDepthFunc;
+    ctx->Driver.DepthMask              = NULL; //nouveauDDDepthMask;
+    ctx->Driver.Enable                 = NULL; //nouveauDDEnable;
+    ctx->Driver.Fogfv                  = NULL; //nouveauDDFogfv;
+    ctx->Driver.Hint                   = NULL;
+    ctx->Driver.Lightfv                        = NULL;
+    ctx->Driver.LightModelfv           = NULL; //nouveauDDLightModelfv;
+    ctx->Driver.LogicOpcode            = NULL; //nouveauDDLogicOpCode;
+    ctx->Driver.PolygonMode            = NULL;
+    ctx->Driver.PolygonStipple         = NULL; //nouveauDDPolygonStipple;
+    ctx->Driver.RenderMode             = NULL; //nouveauDDRenderMode;
+    ctx->Driver.Scissor                        = NULL; //nouveauDDScissor;
+    ctx->Driver.ShadeModel             = NULL; //nouveauDDShadeModel;
+    ctx->Driver.StencilFuncSeparate    = NULL; //nouveauDDStencilFuncSeparate;
+    ctx->Driver.StencilMaskSeparate    = NULL; //nouveauDDStencilMaskSeparate;
+    ctx->Driver.StencilOpSeparate      = NULL; //nouveauDDStencilOpSeparate;
+    ctx->Driver.DepthRange               = nouveauDepthRange;
+    ctx->Driver.Viewport                 = nouveauViewport;
+    /* Pixel path fallbacks.
+     */
+    ctx->Driver.Accum = _swrast_Accum;
+    ctx->Driver.Bitmap = _swrast_Bitmap;
+    ctx->Driver.CopyPixels = _swrast_CopyPixels;
+    ctx->Driver.DrawPixels = _swrast_DrawPixels;
+    ctx->Driver.ReadPixels = _swrast_ReadPixels;
+    /* Swrast hooks for imaging extensions:
+     */
+    ctx->Driver.CopyColorTable = _swrast_CopyColorTable;
+    ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
+    ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
+    ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
+ }
+ #define STATE_INIT(a) if (ctx->Driver.a) ctx->Driver.a
+ void nouveauInitState(GLcontext *ctx)
+ {
+     /*
+      * Mesa should do this for us:
+      */
+     STATE_INIT(AlphaFunc)( ctx, 
+             ctx->Color.AlphaFunc,
+             ctx->Color.AlphaRef);
+     STATE_INIT(BlendColor)( ctx,
+             ctx->Color.BlendColor );
+     STATE_INIT(BlendEquationSeparate)( ctx, 
+             ctx->Color.BlendEquationRGB,
+             ctx->Color.BlendEquationA);
+     STATE_INIT(BlendFuncSeparate)( ctx,
+             ctx->Color.BlendSrcRGB,
+             ctx->Color.BlendDstRGB,
+             ctx->Color.BlendSrcA,
+             ctx->Color.BlendDstA);
+     STATE_INIT(ClearColor)( ctx, ctx->Color.ClearColor);
+     STATE_INIT(ClearDepth)( ctx, ctx->Depth.Clear);
+     STATE_INIT(ClearStencil)( ctx, ctx->Stencil.Clear);
+     STATE_INIT(ColorMask)( ctx, 
+             ctx->Color.ColorMask[RCOMP],
+             ctx->Color.ColorMask[GCOMP],
+             ctx->Color.ColorMask[BCOMP],
+             ctx->Color.ColorMask[ACOMP]);
+     STATE_INIT(CullFace)( ctx, ctx->Polygon.CullFaceMode );
+     STATE_INIT(DepthFunc)( ctx, ctx->Depth.Func );
+     STATE_INIT(DepthMask)( ctx, ctx->Depth.Mask );
+     STATE_INIT(Enable)( ctx, GL_ALPHA_TEST, ctx->Color.AlphaEnabled );
+     STATE_INIT(Enable)( ctx, GL_BLEND, ctx->Color.BlendEnabled );
+     STATE_INIT(Enable)( ctx, GL_COLOR_LOGIC_OP, ctx->Color.ColorLogicOpEnabled );
+     STATE_INIT(Enable)( ctx, GL_COLOR_SUM, ctx->Fog.ColorSumEnabled );
+     STATE_INIT(Enable)( ctx, GL_CULL_FACE, ctx->Polygon.CullFlag );
+     STATE_INIT(Enable)( ctx, GL_DEPTH_TEST, ctx->Depth.Test );
+     STATE_INIT(Enable)( ctx, GL_DITHER, ctx->Color.DitherFlag );
+     STATE_INIT(Enable)( ctx, GL_FOG, ctx->Fog.Enabled );
+     STATE_INIT(Enable)( ctx, GL_LIGHTING, ctx->Light.Enabled );
+     STATE_INIT(Enable)( ctx, GL_LINE_SMOOTH, ctx->Line.SmoothFlag );
+     STATE_INIT(Enable)( ctx, GL_LINE_STIPPLE, ctx->Line.StippleFlag );
+     STATE_INIT(Enable)( ctx, GL_POINT_SMOOTH, ctx->Point.SmoothFlag );
+     STATE_INIT(Enable)( ctx, GL_POLYGON_OFFSET_FILL, ctx->Polygon.OffsetFill);
+     STATE_INIT(Enable)( ctx, GL_POLYGON_OFFSET_LINE, ctx->Polygon.OffsetLine);
+     STATE_INIT(Enable)( ctx, GL_POLYGON_OFFSET_POINT, ctx->Polygon.OffsetPoint);
+     STATE_INIT(Enable)( ctx, GL_POLYGON_SMOOTH, ctx->Polygon.SmoothFlag );
+     STATE_INIT(Enable)( ctx, GL_POLYGON_STIPPLE, ctx->Polygon.StippleFlag );
+     STATE_INIT(Enable)( ctx, GL_SCISSOR_TEST, ctx->Scissor.Enabled );
+     STATE_INIT(Enable)( ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled );
+     STATE_INIT(Enable)( ctx, GL_TEXTURE_1D, GL_FALSE );
+     STATE_INIT(Enable)( ctx, GL_TEXTURE_2D, GL_FALSE );
+     STATE_INIT(Enable)( ctx, GL_TEXTURE_RECTANGLE_NV, GL_FALSE );
+     STATE_INIT(Enable)( ctx, GL_TEXTURE_3D, GL_FALSE );
+     STATE_INIT(Enable)( ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE );
+     STATE_INIT(Fogfv)( ctx, GL_FOG_COLOR, ctx->Fog.Color );
+     STATE_INIT(Fogfv)( ctx, GL_FOG_MODE, 0 );
+     STATE_INIT(Fogfv)( ctx, GL_FOG_DENSITY, &ctx->Fog.Density );
+     STATE_INIT(Fogfv)( ctx, GL_FOG_START, &ctx->Fog.Start );
+     STATE_INIT(Fogfv)( ctx, GL_FOG_END, &ctx->Fog.End );
+     STATE_INIT(FrontFace)( ctx, ctx->Polygon.FrontFace );
+     {
+         GLfloat f = (GLfloat)ctx->Light.Model.ColorControl;
+         STATE_INIT(LightModelfv)( ctx, GL_LIGHT_MODEL_COLOR_CONTROL, &f );
+     }
+     STATE_INIT(LineStipple)( ctx, ctx->Line.StippleFactor, ctx->Line.StipplePattern );
+     STATE_INIT(LineWidth)( ctx, ctx->Line.Width );
+     STATE_INIT(LogicOpcode)( ctx, ctx->Color.LogicOp );
+     STATE_INIT(PointSize)( ctx, ctx->Point.Size );
+     STATE_INIT(PolygonMode)( ctx, GL_FRONT, ctx->Polygon.FrontMode );
+     STATE_INIT(PolygonMode)( ctx, GL_BACK, ctx->Polygon.BackMode );
+     STATE_INIT(PolygonOffset)( ctx,
+           ctx->Polygon.OffsetFactor,
+           ctx->Polygon.OffsetUnits );
+     STATE_INIT(PolygonStipple)( ctx, (const GLubyte *)ctx->PolygonStipple );
+     STATE_INIT(ShadeModel)( ctx, ctx->Light.ShadeModel );
+     STATE_INIT(StencilFuncSeparate)( ctx, GL_FRONT,
+             ctx->Stencil.Function[0],
+             ctx->Stencil.Ref[0],
+             ctx->Stencil.ValueMask[0] );
+     STATE_INIT(StencilFuncSeparate)( ctx, GL_BACK,
+             ctx->Stencil.Function[1],
+             ctx->Stencil.Ref[1],
+             ctx->Stencil.ValueMask[1] );
+     STATE_INIT(StencilMaskSeparate)( ctx, GL_FRONT, ctx->Stencil.WriteMask[0] );
+     STATE_INIT(StencilMaskSeparate)( ctx, GL_BACK, ctx->Stencil.WriteMask[1] );
+     STATE_INIT(StencilOpSeparate)( ctx, GL_FRONT,
+             ctx->Stencil.FailFunc[0],
+             ctx->Stencil.ZFailFunc[0],
+             ctx->Stencil.ZPassFunc[0]);
+     STATE_INIT(StencilOpSeparate)( ctx, GL_BACK,
+             ctx->Stencil.FailFunc[1],
+             ctx->Stencil.ZFailFunc[1],
+             ctx->Stencil.ZPassFunc[1]);
+ }
index e68f1e30f3a6a8ff02a69b19a4496f8672241c1d,dc1fbef72ee386ebf38a5af14c4bfe3082fa2920..bab767838d807fa5fd7fe3e2d4818ec6a1bd0ee4
@@@ -40,9 -40,10 +40,10 @@@ WITH THE SOFTWARE OR THE USE OR OTHER D
  #include "enums.h"
  #include "colormac.h"
  #include "light.h"
+ #include "framebuffer.h"
  
  #include "swrast/swrast.h"
 -#include "array_cache/acache.h"
 +#include "vbo/vbo.h"
  #include "tnl/tnl.h"
  #include "tnl/t_pipeline.h"
  #include "swrast_setup/swrast_setup.h"
Simple merge
Simple merge
index bf86e6db7d2db5fa203f1aec819819c44cf2a6fb,076d8731f8fdf9da8414bfbdb7dfb2f86b6bed20..0d54c29949b855e932f88ed543a046a795ac40a9
     }
  
  
+ /**
+  * Helper to enable/disable client-side state.
+  */
  static void
- client_state( GLcontext *ctx, GLenum cap, GLboolean state )
+ client_state(GLcontext *ctx, GLenum cap, GLboolean state)
  {
     GLuint flag;
 -   GLuint *var;
 +   GLboolean *var;
  
     switch (cap) {
        case GL_VERTEX_ARRAY:
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 50f2f3a96d05b96d3d9571e6658b8592447cf75d,e01f55dbafb9d1b8e93dda9eba3d8c4620b03d7e..a0888be11d6a3cefc96bef4e1e54084a3a5f19f2
@@@ -1,7 -1,12 +1,7 @@@
- # List of ource files in this directory used for X.org xserver build
+ # List of source files in this directory used for X.org xserver build
  MESA_TNL_SOURCES = \
 -t_array_api.c \
 -t_array_import.c \
  t_context.c \
  t_pipeline.c \
 -t_save_api.c \
 -t_save_loopback.c \
 -t_save_playback.c \
  t_vb_arbprogram.c \
  t_vb_arbprogram_sse.c \
  t_vb_arbshader.c \
@@@ -18,4 -23,24 +18,17 @@@ t_vb_vertex.c 
  t_vertex.c \
  t_vertex_generic.c \
  t_vertex_sse.c \
 -t_vp_build.c \
 -t_vtx_api.c \
 -t_vtx_eval.c \
 -t_vtx_exec.c \
 -t_vtx_generic.c \
 -t_vtx_x86.c
 +t_vp_build.c 
+ MESA_TNL_HEADERS = \
+ t_array_api.h \
+ t_array_import.h \
+ t_context.h \
+ t_pipeline.h \
 -t_save_api.h \
+ t_vb_arbprogram.h \
+ t_vb_cliptmp.h \
+ t_vb_lighttmp.h \
+ t_vb_rendertmp.h \
+ t_vertex.h \
+ t_vp_build.h \
 -t_vtx_api.h \
+ tnl.h
index bd459a77479491e6d728e657f94162c638a95fbb,154780cc9753c574047487c5483538dae5d5347c..d9458b74ecafb747776fb6806f10b2388ba64a71
@@@ -182,12 -246,30 +182,9 @@@ voi
  _tnl_need_projected_coords( GLcontext *ctx, GLboolean mode )
  {
     TNLcontext *tnl = TNL_CONTEXT(ctx);
-    if (tnl->NeedNdcCoords != mode) {
-       tnl->NeedNdcCoords = mode;
-       _tnl_InvalidateState( ctx, _NEW_PROJECTION );
-    }
+    tnl->NeedNdcCoords = mode;
  }
  
 -void
 -_tnl_need_dlist_loopback( GLcontext *ctx, GLboolean mode )
 -{
 -   TNLcontext *tnl = TNL_CONTEXT(ctx);
 -   tnl->LoopbackDListCassettes = mode;
 -}
 -
 -void
 -_tnl_need_dlist_norm_lengths( GLcontext *ctx, GLboolean mode )
 -{
 -   TNLcontext *tnl = TNL_CONTEXT(ctx);
 -   tnl->CalcDListNormalLengths = mode;
 -}
 -
 -void
 -_tnl_isolate_materials( GLcontext *ctx, GLboolean mode )
 -{
 -   TNLcontext *tnl = TNL_CONTEXT(ctx);
 -   tnl->IsolateMaterials = mode;
 -}
 -
  void
  _tnl_allow_vertex_fog( GLcontext *ctx, GLboolean value )
  {
index 9de4fd06835c8a069e2d8ff670de1d4b88832774,0000000000000000000000000000000000000000..0ae928f2af4891f3e18ae95cffc1c05b3d496b22
mode 100644,000000..100644
--- /dev/null
@@@ -1,106 -1,0 +1,107 @@@
 +/*
 + Copyright (C) Intel Corp.  2006.  All Rights Reserved.
 + Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
 + develop this 3D driver.
 + 
 + Permission is hereby granted, free of charge, to any person obtaining
 + a copy of this software and associated documentation files (the
 + "Software"), to deal in the Software without restriction, including
 + without limitation the rights to use, copy, modify, merge, publish,
 + distribute, sublicense, and/or sell copies of the Software, and to
 + permit persons to whom the Software is furnished to do so, subject to
 + the following conditions:
 + 
 + The above copyright notice and this permission notice (including the
 + next paragraph) shall be included in all copies or substantial
 + portions of the Software.
 + 
 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 + IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
 + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 + 
 + **********************************************************************/
 + /*
 +  * Authors:
 +  *   Keith Whitwell <keith@tungstengraphics.com>
 +  */
 +
 +#ifndef VBO_ATTRIB_H
 +#define VBO_ATTRIB_H
 +
 +
 +/*
 + * Note: The first attributes match the VERT_ATTRIB_* definitions
 + * in mtypes.h.  However, the tnl module has additional attributes
 + * for materials, color indexes, edge flags, etc.
 + */
 +/* Although it's nice to use these as bit indexes in a DWORD flag, we
 + * could manage without if necessary.  Another limit currently is the
 + * number of bits allocated for these numbers in places like vertex
 + * program instruction formats and register layouts.
 + */
 +enum {
 +      VBO_ATTRIB_POS = 0,
 +      VBO_ATTRIB_WEIGHT = 1,
 +      VBO_ATTRIB_NORMAL = 2,
 +      VBO_ATTRIB_COLOR0 = 3,
 +      VBO_ATTRIB_COLOR1 = 4,
 +      VBO_ATTRIB_FOG = 5,
 +      VBO_ATTRIB_INDEX = 6,        
 +      VBO_ATTRIB_EDGEFLAG = 7,     
 +      VBO_ATTRIB_TEX0 = 8,
 +      VBO_ATTRIB_TEX1 = 9,
 +      VBO_ATTRIB_TEX2 = 10,
 +      VBO_ATTRIB_TEX3 = 11,
 +      VBO_ATTRIB_TEX4 = 12,
 +      VBO_ATTRIB_TEX5 = 13,
 +      VBO_ATTRIB_TEX6 = 14,
 +      VBO_ATTRIB_TEX7 = 15,
 +
 +      VBO_ATTRIB_GENERIC0 = 16, /* Not used? */
 +      VBO_ATTRIB_GENERIC1 = 17,
 +      VBO_ATTRIB_GENERIC2 = 18,
 +      VBO_ATTRIB_GENERIC3 = 19,
 +      VBO_ATTRIB_GENERIC4 = 20,
 +      VBO_ATTRIB_GENERIC5 = 21,
 +      VBO_ATTRIB_GENERIC6 = 22,
 +      VBO_ATTRIB_GENERIC7 = 23,
 +      VBO_ATTRIB_GENERIC8 = 24,
 +      VBO_ATTRIB_GENERIC9 = 25,
 +      VBO_ATTRIB_GENERIC10 = 26,
 +      VBO_ATTRIB_GENERIC11 = 27,
 +      VBO_ATTRIB_GENERIC12 = 28,
 +      VBO_ATTRIB_GENERIC13 = 29,
 +      VBO_ATTRIB_GENERIC14 = 30,
 +      VBO_ATTRIB_GENERIC15 = 31,
 +
 +      /* XXX: in the vertex program InputsRead flag, we alias
 +       * materials and generics and use knowledge about the program
 +       * (whether it is a fixed-function emulation) to
 +       * differentiate.  Here we must keep them apart instead.
 +       */
 +      VBO_ATTRIB_MAT_FRONT_AMBIENT = 32, 
 +      VBO_ATTRIB_MAT_BACK_AMBIENT = 33,
 +      VBO_ATTRIB_MAT_FRONT_DIFFUSE = 34,
 +      VBO_ATTRIB_MAT_BACK_DIFFUSE = 35,
 +      VBO_ATTRIB_MAT_FRONT_SPECULAR = 36,
 +      VBO_ATTRIB_MAT_BACK_SPECULAR = 37,
 +      VBO_ATTRIB_MAT_FRONT_EMISSION = 38,
 +      VBO_ATTRIB_MAT_BACK_EMISSION = 39,
 +      VBO_ATTRIB_MAT_FRONT_SHININESS = 40,
 +      VBO_ATTRIB_MAT_BACK_SHININESS = 41,
 +      VBO_ATTRIB_MAT_FRONT_INDEXES = 42,
 +      VBO_ATTRIB_MAT_BACK_INDEXES = 43, 
 +
 +      VBO_ATTRIB_MAX = 44
 +};
 +
 +#define VBO_ATTRIB_FIRST_MATERIAL VBO_ATTRIB_MAT_FRONT_AMBIENT
++#define VBO_ATTRIB_LAST_MATERIAL VBO_ATTRIB_MAT_BACK_INDEXES
 +
 +#define VBO_MAX_COPIED_VERTS 3
 +
 +#endif
index ade48d220e66a7ea3b577852212d95797a3df9db,0000000000000000000000000000000000000000..f718cdd91a73eb4aa584b243aff25eb72e6d7b6a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1138 -1,0 +1,1147 @@@
-    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_MAT_FRONT_AMBIENT; i++) {
 +/**************************************************************************
 +
 +Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
 +
 +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"),
 +to deal in the Software without restriction, including without limitation
 +on the rights to use, copy, modify, merge, publish, distribute, sub
 +license, and/or sell copies of the Software, and to permit persons to whom
 +the Software is furnished to do so, subject to the following conditions:
 +
 +The above copyright notice and this permission notice (including the next
 +paragraph) shall be included in all copies or substantial portions of the
 +Software.
 +
 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 +TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
 +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 +USE OR OTHER DEALINGS IN THE SOFTWARE.
 +
 +**************************************************************************/
 +
 +/*
 + * Authors:
 + *   Keith Whitwell <keith@tungstengraphics.com>
 + */
 +
 +
 +
 +/* Display list compiler attempts to store lists of vertices with the
 + * same vertex layout.  Additionally it attempts to minimize the need
 + * for execute-time fixup of these vertex lists, allowing them to be
 + * cached on hardware.
 + *
 + * There are still some circumstances where this can be thwarted, for
 + * example by building a list that consists of one very long primitive
 + * (eg Begin(Triangles), 1000 vertices, End), and calling that list
 + * from inside a different begin/end object (Begin(Lines), CallList,
 + * End).  
 + *
 + * In that case the code will have to replay the list as individual
 + * commands through the Exec dispatch table, or fix up the copied
 + * vertices at execute-time.
 + *
 + * The other case where fixup is required is when a vertex attribute
 + * is introduced in the middle of a primitive.  Eg:
 + *  Begin(Lines)
 + *  TexCoord1f()           Vertex2f()
 + *  TexCoord1f() Color3f() Vertex2f()
 + *  End()
 + *
 + *  If the current value of Color isn't known at compile-time, this
 + *  primitive will require fixup.
 + *
 + *
 + * The list compiler currently doesn't attempt to compile lists
 + * containing EvalCoord or EvalPoint commands.  On encountering one of
 + * these, compilation falls back to opcodes.  
 + *
 + * This could be improved to fallback only when a mix of EvalCoord and
 + * Vertex commands are issued within a single primitive.
 + */
 +
 +
 +#include "glheader.h"
 +#include "context.h"
 +#include "dlist.h"
 +#include "enums.h"
 +#include "macros.h"
 +#include "api_validate.h"
 +#include "api_arrayelt.h"
 +#include "vtxfmt.h"
 +#include "dispatch.h"
 +
 +#include "vbo_context.h"
 +
 +
 +
 +/*
 + * NOTE: Old 'parity' issue is gone, but copying can still be
 + * wrong-footed on replay.
 + */
 +static GLuint _save_copy_vertices( GLcontext *ctx, 
 +                                 const struct vbo_save_vertex_list *node,
 +                                 const GLfloat *src_buffer)
 +{
 +   struct vbo_save_context *save = &vbo_context( ctx )->save;
 +   const struct _mesa_prim *prim = &node->prim[node->prim_count-1];
 +   GLuint nr = prim->count;
 +   GLuint sz = save->vertex_size;
 +   const GLfloat *src = src_buffer + prim->start * sz;
 +   GLfloat *dst = save->copied.buffer;
 +   GLuint ovf, i;
 +
 +   if (prim->end)
 +      return 0;
 +       
 +   switch( prim->mode )
 +   {
 +   case GL_POINTS:
 +      return 0;
 +   case GL_LINES:
 +      ovf = nr&1;
 +      for (i = 0 ; i < ovf ; i++)
 +       _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
 +      return i;
 +   case GL_TRIANGLES:
 +      ovf = nr%3;
 +      for (i = 0 ; i < ovf ; i++)
 +       _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
 +      return i;
 +   case GL_QUADS:
 +      ovf = nr&3;
 +      for (i = 0 ; i < ovf ; i++)
 +       _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
 +      return i;
 +   case GL_LINE_STRIP:
 +      if (nr == 0) 
 +       return 0;
 +      else {
 +       _mesa_memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) );
 +       return 1;
 +      }
 +   case GL_LINE_LOOP:
 +   case GL_TRIANGLE_FAN:
 +   case GL_POLYGON:
 +      if (nr == 0) 
 +       return 0;
 +      else if (nr == 1) {
 +       _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
 +       return 1;
 +      } else {
 +       _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
 +       _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) );
 +       return 2;
 +      }
 +   case GL_TRIANGLE_STRIP:
 +   case GL_QUAD_STRIP:
 +      switch (nr) {
 +      case 0: ovf = 0; break;
 +      case 1: ovf = 1; break;
 +      default: ovf = 2 + (nr&1); break;
 +      }
 +      for (i = 0 ; i < ovf ; i++)
 +       _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
 +      return i;
 +   default:
 +      assert(0);
 +      return 0;
 +   }
 +}
 +
 +
 +static struct vbo_save_vertex_store *alloc_vertex_store( GLcontext *ctx )
 +{
 +   struct vbo_save_vertex_store *vertex_store = CALLOC_STRUCT(vbo_save_vertex_store);
 +
 +   /* obj->Name needs to be non-zero, but won't ever be examined more
 +    * closely than that.  In particular these buffers won't be entered
 +    * into the hash and can never be confused with ones visible to the
 +    * user.  Perhaps there could be a special number for internal
 +    * buffers:
 +    */
 +   vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, 1, GL_ARRAY_BUFFER_ARB);
 +
 +   ctx->Driver.BufferData( ctx, 
 +                         GL_ARRAY_BUFFER_ARB, 
 +                         VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
 +                         NULL,
 +                         GL_STATIC_DRAW_ARB,
 +                         vertex_store->bufferobj);
 +
 +   vertex_store->buffer = NULL;
 +   vertex_store->used = 0;
 +   vertex_store->refcount = 1;
 +
 +   return vertex_store;
 +}
 +
 +static void free_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store )
 +{
 +   assert(!vertex_store->buffer);
 +
 +   if (vertex_store->bufferobj)
 +      ctx->Driver.DeleteBuffer( ctx, vertex_store->bufferobj );
 +
 +   FREE( vertex_store );
 +}
 +
 +static GLfloat *map_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store )
 +{
 +   assert(vertex_store->bufferobj);
 +   assert(!vertex_store->buffer);
 +   vertex_store->buffer = (GLfloat *)ctx->Driver.MapBuffer(ctx, 
 +                                                         GL_ARRAY_BUFFER_ARB, /* not used */
 +                                                         GL_STATIC_DRAW_ARB, /* not used */
 +                                                         vertex_store->bufferobj); 
 +
 +   assert(vertex_store->buffer);
 +   return vertex_store->buffer + vertex_store->used;
 +}
 +
 +static void unmap_vertex_store( GLcontext *ctx, struct vbo_save_vertex_store *vertex_store )
 +{
 +   ctx->Driver.UnmapBuffer( ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj );
 +   vertex_store->buffer = NULL;
 +}
 +
 +
 +static struct vbo_save_primitive_store *alloc_prim_store( GLcontext *ctx )
 +{
 +   struct vbo_save_primitive_store *store = CALLOC_STRUCT(vbo_save_primitive_store);
 +   (void) ctx;
 +   store->used = 0;
 +   store->refcount = 1;
 +   return store;
 +}
 +
 +static void _save_reset_counters( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +
 +   save->prim = save->prim_store->buffer + save->prim_store->used;
 +   save->buffer = (save->vertex_store->buffer + 
 +                 save->vertex_store->used);
 +
 +   assert(save->buffer == save->vbptr);
 +
 +   if (save->vertex_size)
 +      save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / 
 +                       save->vertex_size);
 +   else
 +      save->max_vert = 0;
 +
 +   save->vert_count = 0;
 +   save->prim_count = 0;
 +   save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
 +   save->dangling_attr_ref = 0;
 +}
 +
 +
 +/* Insert the active immediate struct onto the display list currently
 + * being built.
 + */
 +static void _save_compile_vertex_list( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +   struct vbo_save_vertex_list *node;
 +
 +   /* Allocate space for this structure in the display list currently
 +    * being compiled.
 +    */
 +   node = (struct vbo_save_vertex_list *)
 +      _mesa_alloc_instruction(ctx, save->opcode_vertex_list, sizeof(*node));
 +
 +   if (!node)
 +      return;
 +
 +   /* Duplicate our template, increment refcounts to the storage structs:
 +    */
 +   _mesa_memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz)); 
 +   node->vertex_size = save->vertex_size;
 +   node->buffer_offset = (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat); 
 +   node->count = save->vert_count;
 +   node->wrap_count = save->copied.nr;
 +   node->dangling_attr_ref = save->dangling_attr_ref;
 +   node->prim = save->prim;
 +   node->prim_count = save->prim_count;
 +   node->vertex_store = save->vertex_store;
 +   node->prim_store = save->prim_store;
 +
 +   node->vertex_store->refcount++;
 +   node->prim_store->refcount++;
 +
 +   assert(node->attrsz[VBO_ATTRIB_POS] != 0 ||
 +        node->count == 0);
 +
 +   if (save->dangling_attr_ref)
 +      ctx->ListState.CurrentList->flags |= MESA_DLIST_DANGLING_REFS;
 +
 +   save->vertex_store->used += save->vertex_size * node->count;
 +   save->prim_store->used += node->prim_count;
 +
 +
 +   /* Copy duplicated vertices 
 +    */
 +   save->copied.nr = _save_copy_vertices( ctx, node, save->buffer );
 +
 +
 +   /* Deal with GL_COMPILE_AND_EXECUTE:
 +    */
 +   if (ctx->ExecuteFlag) {
 +      struct _glapi_table *dispatch = GET_DISPATCH();
 +
 +      _glapi_set_dispatch(ctx->Exec);
 +
 +      vbo_loopback_vertex_list( ctx,
 +                              (const GLfloat *)((const char *)save->vertex_store->buffer + 
 +                                                node->buffer_offset),
 +                              node->attrsz,
 +                              node->prim,
 +                              node->prim_count,
 +                              node->wrap_count,
 +                              node->vertex_size);
 +
 +      _glapi_set_dispatch(dispatch);
 +   }
 +
 +
 +   /* Decide whether the storage structs are full, or can be used for
 +    * the next vertex lists as well.
 +    */
 +   if (save->vertex_store->used > 
 +       VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
 +
 +      /* Unmap old store:
 +       */
 +      unmap_vertex_store( ctx, save->vertex_store );
 +
 +      /* Release old reference:
 +       */
 +      save->vertex_store->refcount--; 
 +      assert(save->vertex_store->refcount != 0);
 +      save->vertex_store = NULL;
 +
 +      /* Allocate and map new store:
 +       */
 +      save->vertex_store = alloc_vertex_store( ctx );
 +      save->vbptr = map_vertex_store( ctx, save->vertex_store );
 +   } 
 +
 +   if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
 +      save->prim_store->refcount--; 
 +      assert(save->prim_store->refcount != 0);
 +      save->prim_store = alloc_prim_store( ctx );
 +   } 
 +
 +   /* Reset our structures for the next run of vertices:
 +    */
 +   _save_reset_counters( ctx );
 +}
 +
 +
 +/* TODO -- If no new vertices have been stored, don't bother saving
 + * it.
 + */
 +static void _save_wrap_buffers( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +   GLint i = save->prim_count - 1;
 +   GLenum mode;
 +   GLboolean weak;
 +
 +   assert(i < (GLint) save->prim_max);
 +   assert(i >= 0);
 +
 +   /* Close off in-progress primitive.
 +    */
 +   save->prim[i].count = (save->vert_count - 
 +                        save->prim[i].start);
 +   mode = save->prim[i].mode;
 +   weak = save->prim[i].weak;
 +   
 +   /* store the copied vertices, and allocate a new list.
 +    */
 +   _save_compile_vertex_list( ctx );
 +
 +   /* Restart interrupted primitive
 +    */
 +   save->prim[0].mode = mode;
 +   save->prim[0].weak = weak;
 +   save->prim[0].begin = 0;
 +   save->prim[0].end = 0;
 +   save->prim[0].pad = 0;
 +   save->prim[0].start = 0;
 +   save->prim[0].count = 0;
 +   save->prim_count = 1;
 +}
 +
 +
 +
 +/* Called only when buffers are wrapped as the result of filling the
 + * vertex_store struct.  
 + */
 +static void _save_wrap_filled_vertex( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +   GLfloat *data = save->copied.buffer;
 +   GLuint i;
 +
 +   /* Emit a glEnd to close off the last vertex list.
 +    */
 +   _save_wrap_buffers( ctx );
 +   
 +    /* Copy stored stored vertices to start of new list.
 +    */
 +   assert(save->max_vert - save->vert_count > save->copied.nr);
 +
 +   for (i = 0 ; i < save->copied.nr ; i++) {
 +      _mesa_memcpy( save->vbptr, data, save->vertex_size * sizeof(GLfloat));
 +      data += save->vertex_size;
 +      save->vbptr += save->vertex_size;
 +      save->vert_count++;
 +   }
 +}
 +
 +
 +static void _save_copy_to_current( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save; 
 +   GLuint i;
 +
 +   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
 +      if (save->attrsz[i]) {
 +       save->currentsz[i][0] = save->attrsz[i];
 +       COPY_CLEAN_4V(save->current[i], 
 +                     save->attrsz[i], 
 +                     save->attrptr[i]);
 +      }
 +   }
 +}
 +
 +
 +static void _save_copy_from_current( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save; 
 +   GLint i;
 +
 +   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
 +      switch (save->attrsz[i]) {
 +      case 4: save->attrptr[i][3] = save->current[i][3];
 +      case 3: save->attrptr[i][2] = save->current[i][2];
 +      case 2: save->attrptr[i][1] = save->current[i][1];
 +      case 1: save->attrptr[i][0] = save->current[i][0];
 +      case 0: break;
 +      }
 +   }
 +}
 +
 +
 +
 +
 +/* Flush existing data, set new attrib size, replay copied vertices.
 + */ 
 +static void _save_upgrade_vertex( GLcontext *ctx, 
 +                               GLuint attr,
 +                               GLuint newsz )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +   GLuint oldsz;
 +   GLuint i;
 +   GLfloat *tmp;
 +
 +   /* Store the current run of vertices, and emit a GL_END.  Emit a
 +    * BEGIN in the new buffer.
 +    */
 +   if (save->vert_count) 
 +      _save_wrap_buffers( ctx );
 +   else
 +      assert( save->copied.nr == 0 );
 +
 +   /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
 +    * when the attribute already exists in the vertex and is having
 +    * its size increased.  
 +    */
 +   _save_copy_to_current( ctx );
 +
 +   /* Fix up sizes:
 +    */
 +   oldsz = save->attrsz[attr];
 +   save->attrsz[attr] = newsz;
 +
 +   save->vertex_size += newsz - oldsz;
 +   save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / 
 +                    save->vertex_size);
 +   save->vert_count = 0;
 +
 +   /* Recalculate all the attrptr[] values:
 +    */
 +   for (i = 0, tmp = save->vertex ; i < VBO_ATTRIB_MAX ; i++) {
 +      if (save->attrsz[i]) {
 +       save->attrptr[i] = tmp;
 +       tmp += save->attrsz[i];
 +      }
 +      else 
 +       save->attrptr[i] = NULL; /* will not be dereferenced. */
 +   }
 +
 +   /* Copy from current to repopulate the vertex with correct values.
 +    */
 +   _save_copy_from_current( ctx );
 +
 +   /* Replay stored vertices to translate them to new format here.
 +    *
 +    * If there are copied vertices and the new (upgraded) attribute
 +    * has not been defined before, this list is somewhat degenerate,
 +    * and will need fixup at runtime.
 +    */
 +   if (save->copied.nr)
 +   {
 +      GLfloat *data = save->copied.buffer;
 +      GLfloat *dest = save->buffer;
 +      GLuint j;
 +
 +      /* Need to note this and fix up at runtime (or loopback):
 +       */
 +      if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
 +       assert(oldsz == 0);
 +       save->dangling_attr_ref = GL_TRUE;
 +      }
 +
 +      for (i = 0 ; i < save->copied.nr ; i++) {
 +       for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
 +          if (save->attrsz[j]) {
 +             if (j == attr) {
 +                if (oldsz) {
 +                   COPY_CLEAN_4V( dest, oldsz, data );
 +                   data += oldsz;
 +                   dest += newsz;
 +                }
 +                else {
 +                   COPY_SZ_4V( dest, newsz, save->current[attr] );
 +                   dest += newsz;
 +                }
 +             }
 +             else {
 +                GLint sz = save->attrsz[j];
 +                COPY_SZ_4V( dest, sz, data );
 +                data += sz;
 +                dest += sz;
 +             }
 +          }
 +       }
 +      }
 +
 +      save->vbptr = dest;
 +      save->vert_count += save->copied.nr;
 +   }
 +}
 +
 +static void save_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save; 
 +
 +   if (sz > save->attrsz[attr]) {
 +      /* New size is larger.  Need to flush existing vertices and get
 +       * an enlarged vertex format.
 +       */
 +      _save_upgrade_vertex( ctx, attr, sz );
 +   }
 +   else if (sz < save->active_sz[attr]) {
 +      static GLfloat id[4] = { 0, 0, 0, 1 };
 +      GLuint i;
 +
 +      /* New size is equal or smaller - just need to fill in some
 +       * zeros.
 +       */
 +      for (i = sz ; i <= save->attrsz[attr] ; i++)
 +       save->attrptr[attr][i-1] = id[i-1];
 +   }
 +
 +   save->active_sz[attr] = sz;
 +}
 +
 +static void _save_reset_vertex( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +   GLuint i;
 +
 +   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
 +      save->attrsz[i] = 0;
 +      save->active_sz[i] = 0;
 +   }
 +      
 +   save->vertex_size = 0;
 +}
 +
 +
 +
 +#define ERROR()   _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
 +
 +
 +/* Only one size for each attribute may be active at once.  Eg. if
 + * Color3f is installed/active, then Color4f may not be, even if the
 + * vertex actually contains 4 color coordinates.  This is because the
 + * 3f version won't otherwise set color[3] to 1.0 -- this is the job
 + * of the chooser function when switching between Color4f and Color3f.
 + */
 +#define ATTR( A, N, V0, V1, V2, V3 )                          \
 +do {                                                          \
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;   \
 +                                                              \
 +   if (save->active_sz[A] != N)                               \
 +      save_fixup_vertex(ctx, A, N);                           \
 +                                                              \
 +   {                                                          \
 +      GLfloat *dest = save->attrptr[A];                       \
 +      if (N>0) dest[0] = V0;                                  \
 +      if (N>1) dest[1] = V1;                                  \
 +      if (N>2) dest[2] = V2;                                  \
 +      if (N>3) dest[3] = V3;                                  \
 +   }                                                          \
 +                                                              \
 +   if ((A) == 0) {                                            \
 +      GLuint i;                                                       \
 +                                                              \
 +      for (i = 0; i < save->vertex_size; i++)                 \
 +       save->vbptr[i] = save->vertex[i];                      \
 +                                                              \
 +      save->vbptr += save->vertex_size;                               \
 +                                                              \
 +      if (++save->vert_count >= save->max_vert)                       \
 +       _save_wrap_filled_vertex( ctx );                       \
 +   }                                                          \
 +} while (0)
 +
 +#define TAG(x) _save_##x
 +
 +#include "vbo_attrib_tmp.h"
 +
 +
 +
 +
 +/* Cope with EvalCoord/CallList called within a begin/end object:
 + *     -- Flush current buffer
 + *     -- Fallback to opcodes for the rest of the begin/end object.
 + */
 +#define DO_FALLBACK(ctx)                                                      \
 +do {                                                                  \
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;                                   \
 +                                                                      \
 +   if (save->vert_count || save->prim_count)                                          \
 +      _save_compile_vertex_list( ctx );                                       \
 +                                                                      \
 +   _save_copy_to_current( ctx );                                      \
 +   _save_reset_vertex( ctx );                                         \
 +   _save_reset_counters( ctx );  \
 +   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );      \
 +   ctx->Driver.SaveNeedFlush = 0;                                     \
 +} while (0)
 +
 +static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   DO_FALLBACK(ctx);
 +   ctx->Save->EvalCoord1f( u );
 +}
 +
 +static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   DO_FALLBACK(ctx);
 +   ctx->Save->EvalCoord1fv( v );
 +}
 +
 +static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   DO_FALLBACK(ctx);
 +   ctx->Save->EvalCoord2f( u, v );
 +}
 +
 +static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   DO_FALLBACK(ctx);
 +   ctx->Save->EvalCoord2fv( v );
 +}
 +
 +static void GLAPIENTRY _save_EvalPoint1( GLint i )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   DO_FALLBACK(ctx);
 +   ctx->Save->EvalPoint1( i );
 +}
 +
 +static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   DO_FALLBACK(ctx);
 +   ctx->Save->EvalPoint2( i, j );
 +}
 +
 +static void GLAPIENTRY _save_CallList( GLuint l )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   DO_FALLBACK(ctx);
 +   ctx->Save->CallList( l );
 +}
 +
 +static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   DO_FALLBACK(ctx);
 +   ctx->Save->CallLists( n, type, v );
 +}
 +
 +
 +
 +
 +/* This begin is hooked into ...  Updating of
 + * ctx->Driver.CurrentSavePrimitive is already taken care of.
 + */
 +GLboolean vbo_save_NotifyBegin( GLcontext *ctx, GLenum mode )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save; 
 +
 +   GLuint i = save->prim_count++;
 +
 +   assert(i < save->prim_max);
 +   save->prim[i].mode = mode & ~VBO_SAVE_PRIM_WEAK;
 +   save->prim[i].begin = 1;
 +   save->prim[i].end = 0;
 +   save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
 +   save->prim[i].pad = 0;
 +   save->prim[i].start = save->vert_count;
 +   save->prim[i].count = 0;   
 +
 +   _mesa_install_save_vtxfmt( ctx, &save->vtxfmt );      
 +   ctx->Driver.SaveNeedFlush = 1;
 +   return GL_TRUE;
 +}
 +
 +
 +
 +static void GLAPIENTRY _save_End( void )
 +{
 +   GET_CURRENT_CONTEXT( ctx ); 
 +   struct vbo_save_context *save = &vbo_context(ctx)->save; 
 +   GLint i = save->prim_count - 1;
 +
 +   ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
 +   save->prim[i].end = 1;
 +   save->prim[i].count = (save->vert_count - 
 +                        save->prim[i].start);
 +
 +   if (i == (GLint) save->prim_max - 1) {
 +      _save_compile_vertex_list( ctx );
 +      assert(save->copied.nr == 0);
 +   }
 +
 +   /* Swap out this vertex format while outside begin/end.  Any color,
 +    * etc. received between here and the next begin will be compiled
 +    * as opcodes.
 +    */   
 +   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
 +}
 +
 +
 +/* These are all errors as this vtxfmt is only installed inside
 + * begin/end pairs.
 + */
 +static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
 +                             const GLvoid *indices)
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   (void) mode; (void) count; (void) type; (void) indices;
 +   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
 +}
 +
 +
 +static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
 +                                  GLuint start, GLuint end,
 +                                  GLsizei count, GLenum type,
 +                                  const GLvoid *indices)
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices;
 +   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
 +}
 +
 +static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   (void) mode; (void) start; (void) count;
 +   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
 +}
 +
 +static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   (void) x1; (void) y1; (void) x2; (void) y2;
 +   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
 +}
 +
 +static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   (void) mode; (void) i1; (void) i2;
 +   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
 +}
 +
 +static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
 +                                GLint j1, GLint j2 )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   (void) mode; (void) i1; (void) i2; (void) j1; (void) j2;
 +   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
 +}
 +
 +static void GLAPIENTRY _save_Begin( GLenum mode )
 +{
 +   GET_CURRENT_CONTEXT( ctx );
 +   (void) mode;
 +   _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" );
 +}
 +
 +
 +/* Unlike the functions above, these are to be hooked into the vtxfmt
 + * maintained in ctx->ListState, active when the list is known or
 + * suspected to be outside any begin/end primitive.
 + */
 +static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   vbo_save_NotifyBegin( ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK );
 +   CALL_Vertex2f(GET_DISPATCH(), ( x1, y1 ));
 +   CALL_Vertex2f(GET_DISPATCH(), ( x2, y1 ));
 +   CALL_Vertex2f(GET_DISPATCH(), ( x2, y2 ));
 +   CALL_Vertex2f(GET_DISPATCH(), ( x1, y2 ));
 +   CALL_End(GET_DISPATCH(), ());
 +}
 +
 +
 +static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   GLint i;
 +
 +   if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
 +      return;
 +
++   _ae_map_vbos( ctx );
++
 +   vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK );
++
 +   for (i = 0; i < count; i++)
 +       CALL_ArrayElement(GET_DISPATCH(), (start + i));
 +   CALL_End(GET_DISPATCH(), ());
++
++   _ae_unmap_vbos( ctx );
 +}
 +
 +/* Could do better by copying the arrays and element list intact and
 + * then emitting an indexed prim at runtime.
 + */
 +static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
 +                                 const GLvoid *indices)
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   GLint i;
 +
 +   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
 +      return;
 +
++   _ae_map_vbos( ctx );
++
 +   vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK );
 +
 +   switch (type) {
 +   case GL_UNSIGNED_BYTE:
 +      for (i = 0 ; i < count ; i++)
 +        CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] ));
 +      break;
 +   case GL_UNSIGNED_SHORT:
 +      for (i = 0 ; i < count ; i++)
 +        CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] ));
 +      break;
 +   case GL_UNSIGNED_INT:
 +      for (i = 0 ; i < count ; i++)
 +        CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] ));
 +      break;
 +   default:
 +      _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
 +      break;
 +   }
 +
 +   CALL_End(GET_DISPATCH(), ());
++
++   _ae_unmap_vbos( ctx );
 +}
 +
 +static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
 +                                      GLuint start, GLuint end,
 +                                      GLsizei count, GLenum type,
 +                                      const GLvoid *indices)
 +{
 +   GET_CURRENT_CONTEXT(ctx);
 +   if (_mesa_validate_DrawRangeElements( ctx, mode,
 +                                       start, end,
 +                                       count, type, indices ))
 +      _save_OBE_DrawElements( mode, count, type, indices );
 +}
 +
 +
 +
 +
 +
 +static void _save_vtxfmt_init( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +   GLvertexformat *vfmt = &save->vtxfmt;
 +
 +   vfmt->ArrayElement = _ae_loopback_array_elt;               /* generic helper */
 +   vfmt->Begin = _save_Begin;
 +   vfmt->Color3f = _save_Color3f;
 +   vfmt->Color3fv = _save_Color3fv;
 +   vfmt->Color4f = _save_Color4f;
 +   vfmt->Color4fv = _save_Color4fv;
 +   vfmt->EdgeFlag = _save_EdgeFlag;
 +   vfmt->End = _save_End;
 +   vfmt->FogCoordfEXT = _save_FogCoordfEXT;
 +   vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
 +   vfmt->Indexf = _save_Indexf;
 +   vfmt->Indexfv = _save_Indexfv;
 +   vfmt->Materialfv = _save_Materialfv;
 +   vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
 +   vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
 +   vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
 +   vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
 +   vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
 +   vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
 +   vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
 +   vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
 +   vfmt->Normal3f = _save_Normal3f;
 +   vfmt->Normal3fv = _save_Normal3fv;
 +   vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
 +   vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
 +   vfmt->TexCoord1f = _save_TexCoord1f;
 +   vfmt->TexCoord1fv = _save_TexCoord1fv;
 +   vfmt->TexCoord2f = _save_TexCoord2f;
 +   vfmt->TexCoord2fv = _save_TexCoord2fv;
 +   vfmt->TexCoord3f = _save_TexCoord3f;
 +   vfmt->TexCoord3fv = _save_TexCoord3fv;
 +   vfmt->TexCoord4f = _save_TexCoord4f;
 +   vfmt->TexCoord4fv = _save_TexCoord4fv;
 +   vfmt->Vertex2f = _save_Vertex2f;
 +   vfmt->Vertex2fv = _save_Vertex2fv;
 +   vfmt->Vertex3f = _save_Vertex3f;
 +   vfmt->Vertex3fv = _save_Vertex3fv;
 +   vfmt->Vertex4f = _save_Vertex4f;
 +   vfmt->Vertex4fv = _save_Vertex4fv;
 +   vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
 +   vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
 +   vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
 +   vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
 +   vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
 +   vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
 +   vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
 +   vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
 +
 +   vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
 +   vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
 +   vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
 +   vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
 +   vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
 +   vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
 +   vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
 +   vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
 +   
 +   /* This will all require us to fallback to saving the list as opcodes:
 +    */ 
 +   vfmt->CallList = _save_CallList; /* inside begin/end */
 +   vfmt->CallLists = _save_CallLists; /* inside begin/end */
 +   vfmt->EvalCoord1f = _save_EvalCoord1f;
 +   vfmt->EvalCoord1fv = _save_EvalCoord1fv;
 +   vfmt->EvalCoord2f = _save_EvalCoord2f;
 +   vfmt->EvalCoord2fv = _save_EvalCoord2fv;
 +   vfmt->EvalPoint1 = _save_EvalPoint1;
 +   vfmt->EvalPoint2 = _save_EvalPoint2;
 +
 +   /* These are all errors as we at least know we are in some sort of
 +    * begin/end pair:
 +    */
 +   vfmt->EvalMesh1 = _save_EvalMesh1; 
 +   vfmt->EvalMesh2 = _save_EvalMesh2;
 +   vfmt->Begin = _save_Begin;
 +   vfmt->Rectf = _save_Rectf;
 +   vfmt->DrawArrays = _save_DrawArrays;
 +   vfmt->DrawElements = _save_DrawElements;
 +   vfmt->DrawRangeElements = _save_DrawRangeElements;
 +
 +}
 +
 +
 +void vbo_save_SaveFlushVertices( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +
 +   /* Noop when we are actually active:
 +    */
 +   if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
 +       ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
 +      return;
 +
 +   if (save->vert_count ||
 +       save->prim_count) 
 +      _save_compile_vertex_list( ctx );
 +   
 +   _save_copy_to_current( ctx );
 +   _save_reset_vertex( ctx );
 +   _save_reset_counters( ctx );  
 +   ctx->Driver.SaveNeedFlush = 0;
 +}
 +
 +void vbo_save_NewList( GLcontext *ctx, GLuint list, GLenum mode )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +
 +   (void) list; (void) mode;
 +
 +   if (!save->prim_store)
 +      save->prim_store = alloc_prim_store( ctx );
 +
 +   if (!save->vertex_store) 
 +      save->vertex_store = alloc_vertex_store( ctx );
 +      
 +   save->vbptr = map_vertex_store( ctx, save->vertex_store );
 +   
 +   _save_reset_vertex( ctx );
 +   _save_reset_counters( ctx );  
 +   ctx->Driver.SaveNeedFlush = 0;
 +}
 +
 +void vbo_save_EndList( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +   unmap_vertex_store( ctx, save->vertex_store );
 +
 +   assert(save->vertex_size == 0);
 +}
 + 
 +void vbo_save_BeginCallList( GLcontext *ctx, struct mesa_display_list *dlist )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +   save->replay_flags |= dlist->flags;
 +}
 +
 +void vbo_save_EndCallList( GLcontext *ctx )
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +   
 +   if (ctx->ListState.CallDepth == 1) {
 +      /* This is correct: want to keep only the VBO_SAVE_FALLBACK
 +       * flag, if it is set:
 +       */
 +      save->replay_flags &= VBO_SAVE_FALLBACK;
 +   }
 +}
 +
 +
 +static void vbo_destroy_vertex_list( GLcontext *ctx, void *data )
 +{
 +   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
 +   (void) ctx;
 +
 +   if ( --node->vertex_store->refcount == 0 ) 
 +      free_vertex_store( ctx, node->vertex_store );
 +
 +   if ( --node->prim_store->refcount == 0 )
 +      FREE( node->prim_store );
 +}
 +
 +
 +static void vbo_print_vertex_list( GLcontext *ctx, void *data )
 +{
 +   struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
 +   GLuint i;
 +   (void) ctx;
 +
 +   _mesa_debug(NULL, "VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
 +               node->count,
 +             node->prim_count,
 +             node->vertex_size);
 +
 +   for (i = 0 ; i < node->prim_count ; i++) {
 +      struct _mesa_prim *prim = &node->prim[i];
 +      _mesa_debug(NULL, "   prim %d: %s%s %d..%d %s %s\n",
 +                i, 
 +                _mesa_lookup_enum_by_nr(prim->mode),
 +                prim->weak ? " (weak)" : "",
 +                prim->start, 
 +                prim->start + prim->count,
 +                (prim->begin) ? "BEGIN" : "(wrap)",
 +                (prim->end) ? "END" : "(wrap)");
 +   }
 +}
 +
 +
 +static void _save_current_init( GLcontext *ctx ) 
 +{
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +   GLint i;
 +
 +   for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
 +      const GLuint j = i - VBO_ATTRIB_POS;
 +      ASSERT(j < VERT_ATTRIB_MAX);
 +      save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
 +      save->current[i] = ctx->ListState.CurrentAttrib[j];
 +   }
 +
++   for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
 +      const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
 +      ASSERT(j < MAT_ATTRIB_MAX);
 +      save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
 +      save->current[i] = ctx->ListState.CurrentMaterial[j];
 +   }
 +}
 +
 +/**
 + * Initialize the display list compiler
 + */
 +void vbo_save_api_init( struct vbo_save_context *save )
 +{
 +   GLcontext *ctx = save->ctx;
 +   GLuint i;
 +
 +   save->opcode_vertex_list =
 +      _mesa_alloc_opcode( ctx,
 +                        sizeof(struct vbo_save_vertex_list),
 +                        vbo_save_playback_vertex_list,
 +                        vbo_destroy_vertex_list,
 +                        vbo_print_vertex_list );
 +
 +   ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
 +
 +   _save_vtxfmt_init( ctx );
 +   _save_current_init( ctx );
 +
 +   for (i = 0; i < VBO_ATTRIB_MAX; i++)
 +      save->inputs[i] = &save->arrays[i];
 +
 +   /* Hook our array functions into the outside-begin-end vtxfmt in 
 +    * ctx->ListState.
 +    */
 +   ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
 +   ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
 +   ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
 +   ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
 +   _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
 +}
 +
index ab3275ec94ac156271fabb223a15ce8275891ab0,0000000000000000000000000000000000000000..daa686072ef8f977a570955affddb20c0b5767fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,222 -1,0 +1,227 @@@
 +/*
 + * Mesa 3-D graphics library
 + * Version:  6.1
 + *
 + * Copyright (C) 1999-2004  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"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
 + *
 + * The above copyright notice and this permission notice shall be included
 + * in all copies or substantial portions of the Software.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 + */
 +
 +/* Author:
 + *    Keith Whitwell <keith@tungstengraphics.com>
 + */
 +
 +#include "glheader.h"
 +#include "context.h"
 +#include "imports.h"
 +#include "mtypes.h"
 +#include "macros.h"
 +#include "light.h"
 +#include "state.h"
 +
 +#include "vbo_context.h"
 +
 +
-       offset = node->buffer_offset + (node->count-1) * node->vertex_size;
++/*
++ * After playback, copy everything but the position from the
++ * last vertex to the saved state
++ */
 +static void _playback_copy_to_current( GLcontext *ctx,
 +                                     const struct vbo_save_vertex_list *node )
 +{
 +   struct vbo_context *vbo = vbo_context(ctx);
 +   GLfloat vertex[VBO_ATTRIB_MAX * 4], *data = vertex;
 +   GLuint i, offset;
 +
 +   if (node->count)
-    ctx->Driver.GetBufferSubData( ctx, 0, offset, node->vertex_size, 
++      offset = (node->buffer_offset + 
++              (node->count-1) * node->vertex_size * sizeof(GLfloat));
 +   else
 +      offset = node->buffer_offset;
 +
-    for (i = VBO_ATTRIB_POS+1 ; i <= VBO_ATTRIB_INDEX ; i++) {
++   ctx->Driver.GetBufferSubData( ctx, 0, offset, 
++                               node->vertex_size * sizeof(GLfloat), 
 +                               data, node->vertex_store->bufferobj );
 +
-        if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
-            i <= VBO_ATTRIB_MAT_BACK_INDEXES)
++   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
 +      if (node->attrsz[i]) {
 +       GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
 +
 +       COPY_CLEAN_4V(current, 
 +                     node->attrsz[i], 
 +                     data);
 +
 +       vbo->currval[i].Size = node->attrsz[i];
 +
 +       data += node->attrsz[i];
 +
++       if (i >= VBO_ATTRIB_FIRST_MATERIAL &&
++           i <= VBO_ATTRIB_LAST_MATERIAL)
 +          ctx->NewState |= _NEW_LIGHT;
 +      }
 +   }
 +
 +   /* Colormaterial -- this kindof sucks.
 +    */
 +   if (ctx->Light.ColorMaterialEnabled) {
 +      _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
 +   }
 +
 +   /* CurrentExecPrimitive
 +    */
 +   if (node->prim_count) {
 +      const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
 +      if (prim->end)
 +       ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
 +      else
 +       ctx->Driver.CurrentExecPrimitive = prim->mode;
 +   }
 +}
 +
 +
 +
 +/* Treat the vertex storage as a VBO, define vertex arrays pointing
 + * into it:
 + */
 +static void vbo_bind_vertex_list( GLcontext *ctx,
 +                                   const struct vbo_save_vertex_list *node )
 +{
 +   struct vbo_context *vbo = vbo_context(ctx);
 +   struct vbo_save_context *save = &vbo->save;
 +   struct gl_client_array *arrays = save->arrays;
 +   GLuint data = node->buffer_offset;
 +   const GLuint *map;
 +   GLuint attr;
 +
 +   /* Install the default (ie Current) attributes first, then overlay
 +    * all active ones.
 +    */
 +   switch (get_program_mode(ctx)) {
 +   case VP_NONE:
 +      memcpy(arrays,      vbo->legacy_currval, 16 * sizeof(arrays[0]));
 +      memcpy(arrays + 16, vbo->mat_currval,    MAT_ATTRIB_MAX * sizeof(arrays[0]));
 +      map = vbo->map_vp_none;
 +      break;
 +   case VP_NV:
 +   case VP_ARB:
 +      /* The aliasing of attributes for NV vertex programs has already
 +       * occurred.  NV vertex programs cannot access material values,
 +       * nor attributes greater than VERT_ATTRIB_TEX7.  
 +       */
 +      memcpy(arrays,      vbo->legacy_currval,  16 * sizeof(arrays[0]));
 +      memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
 +      map = vbo->map_vp_arb;
 +      break;
 +   }
 +
 +   for (attr = 0; attr < VBO_ATTRIB_MAX; attr++) {
 +      if (node->attrsz[attr]) {
 +       arrays[attr].Ptr = (const GLubyte *)data;
 +       arrays[attr].Size = node->attrsz[attr];
 +       arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat);
 +       arrays[attr].Stride = node->vertex_size * sizeof(GLfloat);
 +       arrays[attr].Type = GL_FLOAT;
 +       arrays[attr].Enabled = 1;
 +       arrays[attr].BufferObj = node->vertex_store->bufferobj;
 +       arrays[attr]._MaxElement = node->count; /* ??? */
 +       
 +       assert(arrays[attr].BufferObj->Name);
 +
 +       data += node->attrsz[attr] * sizeof(GLfloat);
 +      }
 +   }
 +}
 +
 +static void vbo_save_loopback_vertex_list( GLcontext *ctx,
 +                                         const struct vbo_save_vertex_list *list )
 +{
 +   const char *buffer = ctx->Driver.MapBuffer(ctx, 
 +                                            GL_ARRAY_BUFFER_ARB, 
 +                                            GL_DYNAMIC_READ_ARB, /* ? */
 +                                             list->vertex_store->bufferobj);
 +
 +   vbo_loopback_vertex_list( ctx,
 +                           (const GLfloat *)(buffer + list->buffer_offset),
 +                           list->attrsz,
 +                           list->prim,
 +                           list->prim_count,
 +                           list->wrap_count,
 +                           list->vertex_size);
 +
 +   ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, 
 +                         list->vertex_store->bufferobj);
 +}
 +
 +
 +/**
 + * Execute the buffer and save copied verts.
 + */
 +void vbo_save_playback_vertex_list( GLcontext *ctx, void *data )
 +{
 +   const struct vbo_save_vertex_list *node = (const struct vbo_save_vertex_list *) data;
 +   struct vbo_save_context *save = &vbo_context(ctx)->save;
 +
 +   FLUSH_CURRENT(ctx, 0);
 +
 +   if (node->prim_count > 0 && node->count > 0) {
 +
 +      if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END &&
 +        node->prim[0].begin) {
 +
 +       /* Degenerate case: list is called inside begin/end pair and
 +        * includes operations such as glBegin or glDrawArrays.
 +        */
 +       if (0)
 +          _mesa_printf("displaylist recursive begin");
 +
 +       vbo_save_loopback_vertex_list( ctx, node );
 +       return;
 +      }
 +      else if (save->replay_flags) {
 +       /* Various degnerate cases: translate into immediate mode
 +        * calls rather than trying to execute in place.
 +        */
 +       vbo_save_loopback_vertex_list( ctx, node );
 +       return;
 +      }
 +      
 +      if (ctx->NewState)
 +       _mesa_update_state( ctx );
 +
 +      if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
 +          (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
 +         _mesa_error(ctx, GL_INVALID_OPERATION,
 +                     "glBegin (invalid vertex/fragment program)");
 +         return;
 +      }
 +
 +      vbo_bind_vertex_list( ctx, node );
 +
 +      vbo_context(ctx)->draw_prims( ctx, 
 +                                  save->inputs, 
 +                                  node->prim, 
 +                                  node->prim_count,
 +                                  NULL,
 +                                  0,  /* Node is a VBO, so this is ok */
 +                                  node->count );
 +   }
 +
 +   /* Copy to current?
 +    */
 +   _playback_copy_to_current( ctx, node );
 +}
index 0adad71732f98cb57be3ce54fef582d460cbd7fe,0000000000000000000000000000000000000000..08eae2db40f2d13f18bb9932fed0264297049a08
mode 100644,000000..100644
--- /dev/null
@@@ -1,549 -1,0 +1,550 @@@
-    _mesa_printf("begin %s (%d)\n", _mesa_lookup_enum_by_nr(mode), begin_flag);
 +
 +/*
 + * Mesa 3-D graphics library
 + * Version:  6.5
 + *
 + * Copyright (C) 1999-2006  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"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
 + *
 + * The above copyright notice and this permission notice shall be included
 + * in all copies or substantial portions of the Software.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 + *
 + * Authors:
 + *    Keith Whitwell <keith@tungstengraphics.com>
 + */
 +
 +/* Split indexed primitives with per-vertex copying.
 + */
 +
 +#include "glheader.h"
 +#include "imports.h"
 +#include "macros.h"
 +#include "enums.h"
 +#include "mtypes.h"
 +
 +#include "vbo_split.h"
 +#include "vbo.h"
 +
 +
 +#define ELT_TABLE_SIZE 16
 +
 +/* Used for vertex-level splitting of indexed buffers.  Note that
 + * non-indexed primitives may be converted to indexed in some cases
 + * (eg loops, fans) in order to use this splitting path.
 + */
 +struct copy_context {
 +
 +   GLcontext *ctx;
 +   const struct gl_client_array **array;
 +   const struct _mesa_prim *prim;
 +   GLuint nr_prims;
 +   const struct _mesa_index_buffer *ib;
 +   vbo_draw_func draw;
 +
 +   const struct split_limits *limits;
 +
 +   struct {
 +      GLuint attr;
 +      GLuint size;
 +      const struct gl_client_array *array;
 +      const GLubyte *src_ptr;
 +
 +      struct gl_client_array dstarray;
 +
 +   } varying[VERT_ATTRIB_MAX];
 +   GLuint nr_varying;
 +
 +   const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX];
 +   struct _mesa_index_buffer dstib;
 +
 +   GLuint *translated_elt_buf;
 +   const GLuint *srcelt;
 +
 +   /* A baby hash table to avoid re-emitting (some) duplicate
 +    * vertices when splitting indexed primitives.
 +    */
 +   struct { 
 +      GLuint in;
 +      GLuint out;
 +   } vert_cache[ELT_TABLE_SIZE];
 +      
 +
 +   GLuint vertex_size;
 +   GLubyte *dstbuf;
 +   GLubyte *dstptr;           /* dstptr == dstbuf + dstelt_max * vertsize */
 +   GLuint dstbuf_size;        /* in vertices */
 +   GLuint dstbuf_nr;          /* count of emitted vertices, also the
 +                               * largest value in dstelt.  Our
 +                               * MaxIndex.
 +                               */
 +
 +   GLuint *dstelt;
 +   GLuint dstelt_nr;
 +   GLuint dstelt_size;
 +
 +#define MAX_PRIM 32
 +   struct _mesa_prim dstprim[MAX_PRIM];
 +   GLuint dstprim_nr;
 +
 +};
 +
 +
 +static GLuint type_size( GLenum type )
 +{
 +   switch(type) {
 +   case GL_BYTE: return sizeof(GLbyte);
 +   case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
 +   case GL_SHORT: return sizeof(GLshort);
 +   case GL_UNSIGNED_SHORT: return sizeof(GLushort);
 +   case GL_INT: return sizeof(GLint);
 +   case GL_UNSIGNED_INT: return sizeof(GLuint);
 +   case GL_FLOAT: return sizeof(GLfloat);
 +   case GL_DOUBLE: return sizeof(GLdouble);
 +   default: return 0;
 +   }
 +}
 +
 +static GLuint attr_size( const struct gl_client_array *array )
 +{
 +   return array->Size * type_size(array->Type);
 +}
 +
 +
 +/* Starts returning true slightly before the buffer fills, to ensure
 + * that there is sufficient room for any remaining vertices to finish
 + * off the prim:
 + */
 +static GLboolean check_flush( struct copy_context *copy )
 +{
 +   if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
 +      return GL_TRUE;
 +
 +   if (copy->dstelt_nr + 4 > copy->dstelt_size)
 +      return GL_TRUE;
 +
 +   return GL_FALSE;
 +}
 +
 +static void flush( struct copy_context *copy )
 +{
 +   GLuint i;
 +
 +   /* Set some counters: 
 +    */
 +   copy->dstib.count = copy->dstelt_nr;
 +
 +   copy->draw( copy->ctx,
 +             copy->dstarray_ptr,
 +             copy->dstprim,
 +             copy->dstprim_nr,
 +             &copy->dstib,
 +             0,
 +             copy->dstbuf_nr );
 +
 +   /* Reset all pointers: 
 +    */
 +   copy->dstprim_nr = 0;
 +   copy->dstelt_nr = 0;
 +   copy->dstbuf_nr = 0;
 +   copy->dstptr = copy->dstbuf;
 +
 +   /* Clear the vertex cache:
 +    */
 +   for (i = 0; i < ELT_TABLE_SIZE; i++)
 +      copy->vert_cache[i].in = ~0;
 +}
 +
 +
 +
 +static void begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
 +{
 +   struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
 +
-    _mesa_printf("elt %d\n", elt);
++/*    _mesa_printf("begin %s (%d)\n", _mesa_lookup_enum_by_nr(mode), begin_flag); */
 +              
 +   prim->mode = mode;
 +   prim->begin = begin_flag;
 +}
 +
 +
 +/* Use a hashtable to attempt to identify recently-emitted vertices
 + * and avoid re-emitting them.
 + */
 +static GLuint elt(struct copy_context *copy, GLuint elt_idx)
 +{
 +   GLuint elt = copy->srcelt[elt_idx];
 +   GLuint slot = elt & (ELT_TABLE_SIZE-1);
 +
-       _mesa_printf("  --> emit to dstelt %d\n", copy->dstbuf_nr);
++/*    _mesa_printf("elt %d\n", elt); */
 +
 +   /* Look up the incoming element in the vertex cache.  Re-emit if
 +    * necessary.   
 +    */
 +   if (copy->vert_cache[slot].in != elt) {
 +      GLubyte *csr = copy->dstptr;
 +      GLuint i;
 +
-    else
-       _mesa_printf("  --> reuse vertex\n");
++/*       _mesa_printf("  --> emit to dstelt %d\n", copy->dstbuf_nr); */
 +
 +      for (i = 0; i < copy->nr_varying; i++) {
 +       const struct gl_client_array *srcarray = copy->varying[i].array;
 +       const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
 +
 +       memcpy(csr, srcptr, copy->varying[i].size);
 +       csr += copy->varying[i].size;
 +
++       if (0) 
 +       {
 +          const GLuint *f = (const GLuint *)srcptr;
 +          GLuint j;
 +          _mesa_printf("  varying %d: ", i);
 +          for(j = 0; j < copy->varying[i].size / 4; j++)
 +             _mesa_printf("%x ", f[j]);
 +          _mesa_printf("\n");
 +       }
 +             
 +      }
 +
 +      copy->vert_cache[slot].in = elt;
 +      copy->vert_cache[slot].out = copy->dstbuf_nr++;
 +      copy->dstptr += copy->vertex_size;
 +
 +      assert(csr == copy->dstptr);
 +      assert(copy->dstptr == (copy->dstbuf + 
 +                                  copy->dstbuf_nr * 
 +                                  copy->vertex_size));
 +   }
-    _mesa_printf("  --> emit %d\n", copy->vert_cache[slot].out);
++/*    else */
++/*       _mesa_printf("  --> reuse vertex\n"); */
 +   
-    _mesa_printf("end (%d)\n", end_flag);
++/*    _mesa_printf("  --> emit %d\n", copy->vert_cache[slot].out); */
 +   copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
 +   return check_flush(copy);
 +}
 +
 +static void end( struct copy_context *copy, GLboolean end_flag )
 +{
 +   struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
 +
++/*    _mesa_printf("end (%d)\n", end_flag); */
 +
 +   prim->end = end_flag;
 +   prim->count = copy->dstelt_nr - prim->start;
 +
 +   if (++copy->dstprim_nr == MAX_PRIM ||
 +       check_flush(copy)) 
 +      flush(copy);
 +}
 +
 +
 +
 +static void replay_elts( struct copy_context *copy )
 +{
 +   GLuint i, j, k;
 +   GLboolean split;
 +
 +   for (i = 0; i < copy->nr_prims; i++) {
 +      const struct _mesa_prim *prim = &copy->prim[i];
 +      const GLuint start = prim->start;
 +      GLuint first, incr;
 +
 +      switch (prim->mode) {
 +       
 +      case GL_LINE_LOOP:
 +       /* Convert to linestrip and emit the final vertex explicitly,
 +        * but only in the resultant strip that requires it.
 +        */
 +       j = 0;
 +       while (j != prim->count) {
 +          begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
 +
 +          for (split = GL_FALSE; j != prim->count && !split; j++)
 +             split = elt(copy, start + j);
 +
 +          if (j == prim->count) {
 +             /* Done, emit final line.  Split doesn't matter as
 +              * it is always raised a bit early so we can emit
 +              * the last verts if necessary!
 +              */
 +             if (prim->end) 
 +                (void)elt(copy, start + 0);
 +
 +             end(copy, prim->end);
 +          }
 +          else {
 +             /* Wrap
 +              */
 +             assert(split);
 +             end(copy, 0);
 +             j--;
 +          }
 +       }
 +       break;
 +
 +      case GL_TRIANGLE_FAN:
 +      case GL_POLYGON:
 +       j = 2;
 +       while (j != prim->count) {
 +          begin(copy, prim->mode, prim->begin && j == 0);
 +
 +          split = elt(copy, start+0); 
 +          assert(!split);
 +
 +          split = elt(copy, start+j-1); 
 +          assert(!split);
 +
 +          for (; j != prim->count && !split; j++)
 +             split = elt(copy, start+j);
 +
 +          end(copy, prim->end && j == prim->count);
 +
 +          if (j != prim->count) {
 +             /* Wrapped the primitive, need to repeat some vertices:
 +              */
 +             j -= 1;
 +          }
 +       }
 +       break;
 +
 +      default:
 +       (void)split_prim_inplace(prim->mode, &first, &incr);
 +       
 +       j = 0;
 +       while (j != prim->count) {
 +
 +          begin(copy, prim->mode, prim->begin && j == 0);
 +
 +          split = 0;
 +          for (k = 0; k < first; k++, j++)
 +             split |= elt(copy, start+j);
 +
 +          assert(!split);
 +
 +          for (; j != prim->count && !split; )
 +             for (k = 0; k < incr; k++, j++)
 +                split |= elt(copy, start+j);
 +
 +          end(copy, prim->end && j == prim->count);
 +
 +          if (j != prim->count) {
 +             /* Wrapped the primitive, need to repeat some vertices:
 +              */
 +             assert(j > first - incr);
 +             j -= (first - incr);
 +          }
 +       }
 +       break;
 +      }
 +   }
 +
 +   if (copy->dstprim_nr)
 +      flush(copy);
 +}
 +
 +
 +static void replay_init( struct copy_context *copy )
 +{
 +   GLcontext *ctx = copy->ctx;
 +   GLuint i;
 +   GLuint offset;
 +
 +   /* Make a list of varying attributes and their vbo's.  Also
 +    * calculate vertex size.
 +    */
 +   copy->vertex_size = 0;
 +   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
 +      struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
 +
 +      if (copy->array[i]->StrideB == 0) {
 +       copy->dstarray_ptr[i] = copy->array[i];
 +      }
 +      else {
 +       GLuint j = copy->nr_varying++;
 +       
 +       copy->varying[j].attr = i;
 +       copy->varying[j].array = copy->array[i];
 +       copy->varying[j].size = attr_size(copy->array[i]);
 +       copy->vertex_size += attr_size(copy->array[i]);
 +      
 +       if (vbo->Name && !vbo->Pointer) 
 +          ctx->Driver.MapBuffer(ctx,
 +                                GL_ARRAY_BUFFER_ARB, 
 +                                GL_DYNAMIC_DRAW_ARB, /* XXX */
 +                                vbo);
 +
 +       copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer,
 +                                               copy->array[i]->Ptr);
 +
 +       copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
 +      }
 +   }
 +
 +   /* There must always be an index buffer.  Currently require the
 +    * caller convert non-indexed prims to indexed.  Could alternately
 +    * do it internally.
 +    */
 +   if (copy->ib->obj->Name && !copy->ib->obj->Pointer) 
 +      ctx->Driver.MapBuffer(ctx, 
 +                          GL_ARRAY_BUFFER_ARB, /* XXX */
 +                          GL_DYNAMIC_DRAW_ARB, /* XXX */
 +                          copy->ib->obj);
 +
 +   switch (copy->ib->type) {
 +   case GL_UNSIGNED_BYTE:
 +      copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count);
 +      copy->srcelt = copy->translated_elt_buf;
 +      
 +      for (i = 0; i < copy->ib->count; i++)
 +       copy->translated_elt_buf[i] = ((const GLubyte *)copy->ib->ptr)[i];
 +      break;
 +
 +   case GL_UNSIGNED_SHORT:
 +      copy->translated_elt_buf = _mesa_malloc(sizeof(GLuint) * copy->ib->count);
 +      copy->srcelt = copy->translated_elt_buf;
 +
 +      for (i = 0; i < copy->ib->count; i++)
 +       copy->translated_elt_buf[i] = ((const GLushort *)copy->ib->ptr)[i];
 +      break;
 +
 +   case GL_UNSIGNED_INT:
 +      copy->translated_elt_buf = NULL;
 +      copy->srcelt = (const GLuint *)ADD_POINTERS(copy->ib->obj->Pointer, 
 +                                                copy->ib->ptr);
 +      break;
 +   }
 +   
 +
 +   /* Figure out the maximum allowed vertex buffer size:
 +    */
 +   if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
 +      copy->dstbuf_size = copy->limits->max_verts;
 +   }
 +   else {
 +      copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
 +   }
 +
 +   /* Allocate an output vertex buffer:
 +    *
 +    * XXX:  This should be a VBO!
 +    */
 +   copy->dstbuf = _mesa_malloc(copy->dstbuf_size * 
 +                             copy->vertex_size);   
 +   copy->dstptr = copy->dstbuf;
 +
 +   /* Setup new vertex arrays to point into the output buffer: 
 +    */
 +   for (offset = 0, i = 0; i < copy->nr_varying; i++) {
 +      const struct gl_client_array *src = copy->varying[i].array;
 +      struct gl_client_array *dst = &copy->varying[i].dstarray;
 +
 +      dst->Size = src->Size;
 +      dst->Type = src->Type;
 +      dst->Stride = copy->vertex_size;
 +      dst->StrideB = copy->vertex_size;
 +      dst->Ptr = copy->dstbuf + offset;
 +      dst->Enabled = GL_TRUE;
 +      dst->Normalized = GL_TRUE;
 +      dst->BufferObj = ctx->Array.NullBufferObj;
 +      dst->_MaxElement = copy->dstbuf_size; /* may be less! */
 +
 +      offset += copy->varying[i].size;
 +   }
 +
 +   /* Allocate an output element list:
 +    */
 +   copy->dstelt_size = MIN2(65536,
 +                          copy->ib->count * 2);
 +   copy->dstelt_size = MIN2(copy->dstelt_size,
 +                          copy->limits->max_indices);
 +   copy->dstelt = _mesa_malloc(copy->dstelt_size);
 +   copy->dstelt_nr = 0;
 +
 +   /* Setup the new index buffer to point to the allocated element
 +    * list:
 +    */
 +   copy->dstib.count = 0;     /* duplicates dstelt_nr */
 +   copy->dstib.type = GL_UNSIGNED_INT;
 +   copy->dstib.obj = ctx->Array.NullBufferObj;
 +   copy->dstib.ptr = copy->dstelt;
 +   copy->dstib.rebase = 0;    
 +}
 +
 +
 +static void replay_finish( struct copy_context *copy )
 +{
 +   GLcontext *ctx = copy->ctx;
 +   GLuint i;
 +
 +   /* Free our vertex and index buffers: 
 +    */
 +   _mesa_free(copy->translated_elt_buf);
 +   _mesa_free(copy->dstbuf);
 +   _mesa_free(copy->dstelt);
 +   
 +   /* Unmap VBO's 
 +    */
 +   for (i = 0; i < copy->nr_varying; i++) {
 +      struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
 +
 +      if (vbo->Name && vbo->Pointer) 
 +       ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, vbo);
 +   }
 +
 +   /* Unmap index buffer:
 +    */
 +   if (copy->ib->obj->Name && copy->ib->obj->Pointer) {
 +      ctx->Driver.UnmapBuffer(ctx, 
 +                            GL_ARRAY_BUFFER_ARB, /* XXX */
 +                            copy->ib->obj);
 +   }
 +}
 +
 +void vbo_split_copy( GLcontext *ctx,
 +                   const struct gl_client_array *arrays[],
 +                   const struct _mesa_prim *prim,
 +                   GLuint nr_prims,
 +                   const struct _mesa_index_buffer *ib,
 +                   vbo_draw_func draw,
 +                   const struct split_limits *limits )
 +{
 +   struct copy_context copy;
 +   GLuint i;
 +
 +   memset(&copy, 0, sizeof(copy));
 +
 +   /* Require indexed primitives:
 +    */
 +   assert(ib);
 +   
 +   copy.ctx = ctx;
 +   copy.array = arrays;
 +   copy.prim = prim;
 +   copy.nr_prims = nr_prims;
 +   copy.ib = ib;
 +   copy.draw = draw;
 +   copy.limits = limits;
 +
 +
 +   /* Clear the vertex cache:
 +    */
 +   for (i = 0; i < ELT_TABLE_SIZE; i++)
 +      copy.vert_cache[i].in = ~0;
 +
 +
 +   replay_init(&copy);
 +   replay_elts(&copy);
 +   replay_finish(&copy);
 +}