#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"
{
_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;
#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"
{
_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;
/* Initialize the software rasterizer and helper modules. */
_swrast_CreateContext(ctx);
-- _ac_CreateContext(ctx);
++ _vbo_CreateContext(ctx);
_tnl_CreateContext(ctx);
_swsetup_CreateContext(ctx);
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 */
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) {
*/
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;
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()
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 );
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.
*/
--- /dev/null
-#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)
+ {
+ }
+
--- /dev/null
-#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]);
+ }
#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"
}
+ /**
+ * 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:
- # 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 \
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
_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 )
{
--- /dev/null
+/*
+ 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
--- /dev/null
- 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 );
+}
+
--- /dev/null
-
+/*
+ * 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 );
+}
--- /dev/null
- _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,
+ ©->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 = ©->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 = ©->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 = ©->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] = ©->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 = ©->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(©, 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(©);
+ replay_elts(©);
+ replay_finish(©);
+}