summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Whitwell <keithw@vmware.com>2009-06-30 14:10:44 +0100
committerKeith Whitwell <keithw@vmware.com>2009-06-30 14:17:13 +0100
commitd9ef93f4da4ea6964ef908fd15ed52645e6fa82d (patch)
tree96e1f86319db2253464f35c5d1c7c00027db6006
parentf7cbaae13d67c55abe81ac230de37f564365099f (diff)
st/vbo: clone vbo module and rename structs to st_vbo
Want to acheive a couple of things here: 1) Build a better immediate vertex handler 2) Build gallium vertex buffer/element state directly from st_vbo module 3) Avoid breaking all the DRI drivers in the process The vbo code is pretty fragile and even small changes there seem to break DRI drivers left & right. In part that's due to the lack of a strong interface between the shared code and the drivers, and also to the fairly ill-defined interface between core mesa and the VBO module. Hopefully this branch will help figure out a better interface between mesa and the vertex code, and will be able to do so without breaking other drivers in the process. If this branch turns out well, it may be interesting to back-port some of the changes here to the original VBO module.
-rw-r--r--src/mesa/SConscript10
-rw-r--r--src/mesa/sources.mak14
-rw-r--r--src/mesa/state_tracker/st_cb_feedback.c8
-rw-r--r--src/mesa/state_tracker/st_cb_rasterpos.c4
-rw-r--r--src/mesa/state_tracker/st_context.c10
-rw-r--r--src/mesa/state_tracker/st_draw.c8
-rw-r--r--src/mesa/state_tracker/st_draw.h12
-rw-r--r--src/mesa/state_tracker/st_draw_feedback.c6
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo.h93
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_attrib.h107
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_attrib_tmp.h486
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_context.c269
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_context.h112
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_exec.c97
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_exec.h173
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_exec_api.c838
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_exec_array.c503
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_exec_draw.c385
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_exec_eval.c254
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_save.c110
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_save.h184
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_save_api.c1214
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_save_draw.c289
-rw-r--r--src/mesa/state_tracker/st_vbo/st_vbo_save_loopback.c191
24 files changed, 5351 insertions, 26 deletions
diff --git a/src/mesa/SConscript b/src/mesa/SConscript
index 9ffc15eeb7..447b888f63 100644
--- a/src/mesa/SConscript
+++ b/src/mesa/SConscript
@@ -180,6 +180,16 @@ if env['platform'] != 'winddk':
'state_tracker/st_mesa_to_tgsi.c',
'state_tracker/st_program.c',
'state_tracker/st_texture.c',
+ 'state_tracker/st_vbo/st_vbo_context.c',
+ 'state_tracker/st_vbo/st_vbo_exec.c',
+ 'state_tracker/st_vbo/st_vbo_exec_api.c',
+ 'state_tracker/st_vbo/st_vbo_exec_array.c',
+ 'state_tracker/st_vbo/st_vbo_exec_draw.c',
+ 'state_tracker/st_vbo/st_vbo_exec_eval.c',
+ 'state_tracker/st_vbo/st_vbo_save.c',
+ 'state_tracker/st_vbo/st_vbo_save_api.c',
+ 'state_tracker/st_vbo/st_vbo_save_draw.c',
+ 'state_tracker/st_vbo/st_vbo_save_loopback.c',
]
shader_sources = [
diff --git a/src/mesa/sources.mak b/src/mesa/sources.mak
index 78ca60f3ca..7cd3223b92 100644
--- a/src/mesa/sources.mak
+++ b/src/mesa/sources.mak
@@ -211,7 +211,18 @@ STATETRACKER_SOURCES = \
state_tracker/st_gen_mipmap.c \
state_tracker/st_mesa_to_tgsi.c \
state_tracker/st_program.c \
- state_tracker/st_texture.c
+ state_tracker/st_texture.c \
+ state_tracker/st_vbo/st_vbo_context.c \
+ state_tracker/st_vbo/st_vbo_exec.c \
+ state_tracker/st_vbo/st_vbo_exec_api.c \
+ state_tracker/st_vbo/st_vbo_exec_array.c \
+ state_tracker/st_vbo/st_vbo_exec_draw.c \
+ state_tracker/st_vbo/st_vbo_exec_eval.c \
+ state_tracker/st_vbo/st_vbo_save.c \
+ state_tracker/st_vbo/st_vbo_save_api.c \
+ state_tracker/st_vbo/st_vbo_save_draw.c \
+ state_tracker/st_vbo/st_vbo_save_loopback.c
+
SHADER_SOURCES = \
shader/arbprogparse.c \
@@ -324,7 +335,6 @@ MESA_SOURCES = \
MESA_GALLIUM_SOURCES = \
$(MAIN_SOURCES) \
$(MATH_SOURCES) \
- $(VBO_SOURCES) \
$(STATETRACKER_SOURCES) \
$(SHADER_SOURCES) \
x86/common_x86.c \
diff --git a/src/mesa/state_tracker/st_cb_feedback.c b/src/mesa/state_tracker/st_cb_feedback.c
index 93f7145219..687c1b58ea 100644
--- a/src/mesa/state_tracker/st_cb_feedback.c
+++ b/src/mesa/state_tracker/st_cb_feedback.c
@@ -42,7 +42,7 @@
#include "main/feedback.h"
#include "main/macros.h"
-#include "vbo/vbo.h"
+#include "st_vbo/st_vbo.h"
#include "st_context.h"
#include "st_atom.h"
@@ -281,21 +281,21 @@ st_RenderMode(GLcontext *ctx, GLenum newMode )
if (newMode == GL_RENDER) {
/* restore normal VBO draw function */
- vbo_set_draw_func(ctx, st_draw_vbo);
+ st_vbo_set_draw_func(ctx, st_draw_vbo);
}
else if (newMode == GL_SELECT) {
if (!st->selection_stage)
st->selection_stage = draw_glselect_stage(ctx, draw);
draw_set_rasterize_stage(draw, st->selection_stage);
/* Plug in new vbo draw function */
- vbo_set_draw_func(ctx, st_feedback_draw_vbo);
+ st_vbo_set_draw_func(ctx, st_feedback_draw_vbo);
}
else {
if (!st->feedback_stage)
st->feedback_stage = draw_glfeedback_stage(ctx, draw);
draw_set_rasterize_stage(draw, st->feedback_stage);
/* Plug in new vbo draw function */
- vbo_set_draw_func(ctx, st_feedback_draw_vbo);
+ st_vbo_set_draw_func(ctx, st_feedback_draw_vbo);
/* need to generate/use a vertex program that emits pos/color/tex */
st->dirty.st |= ST_NEW_VERTEX_PROGRAM;
}
diff --git a/src/mesa/state_tracker/st_cb_rasterpos.c b/src/mesa/state_tracker/st_cb_rasterpos.c
index 3bcccd0df4..00c1edf14f 100644
--- a/src/mesa/state_tracker/st_cb_rasterpos.c
+++ b/src/mesa/state_tracker/st_cb_rasterpos.c
@@ -48,7 +48,7 @@
#include "draw/draw_context.h"
#include "draw/draw_pipe.h"
#include "shader/prog_instruction.h"
-#include "vbo/vbo.h"
+#include "st_vbo/st_vbo.h"
@@ -63,7 +63,7 @@ struct rastpos_stage
/* vertex attrib info we can setup once and re-use */
struct gl_client_array array[VERT_ATTRIB_MAX];
const struct gl_client_array *arrays[VERT_ATTRIB_MAX];
- struct _mesa_prim prim;
+ struct st_mesa_prim prim;
};
diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
index 8514b6b375..619fd2fbee 100644
--- a/src/mesa/state_tracker/st_context.c
+++ b/src/mesa/state_tracker/st_context.c
@@ -32,7 +32,7 @@
#include "main/buffers.h"
#include "main/scissor.h"
#include "main/viewport.h"
-#include "vbo/vbo.h"
+#include "st_vbo/st_vbo.h"
#include "shader/shader_api.h"
#include "glapi/glapi.h"
#include "st_public.h"
@@ -85,7 +85,7 @@ void st_invalidate_state(GLcontext * ctx, GLuint new_state)
/* This is the only core Mesa module we depend upon.
* No longer use swrast, swsetup, tnl.
*/
- _vbo_InvalidateState(ctx, new_state);
+ _st_vbo_InvalidateState(ctx, new_state);
}
@@ -114,7 +114,7 @@ st_create_context_priv( GLcontext *ctx, struct pipe_context *pipe )
st->pipe = pipe;
/* state tracker needs the VBO module */
- _vbo_CreateContext(ctx);
+ _st_vbo_CreateContext(ctx);
#if FEATURE_feedback || FEATURE_drawpix
st->draw = draw_create(); /* for selection/feedback */
@@ -144,7 +144,7 @@ st_create_context_priv( GLcontext *ctx, struct pipe_context *pipe )
st->state.sampler_list[i] = &st->state.samplers[i];
/* we want all vertex data to be placed in buffer objects */
- vbo_use_buffer_objects(ctx);
+ st_vbo_use_buffer_objects(ctx);
/* Need these flags:
*/
@@ -249,7 +249,7 @@ void st_destroy_context( struct st_context *st )
_mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache);
- _vbo_DestroyContext(st->ctx);
+ _st_vbo_DestroyContext(st->ctx);
_mesa_free_context_data(ctx);
diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c
index 914a507bef..bcd39a7b74 100644
--- a/src/mesa/state_tracker/st_draw.c
+++ b/src/mesa/state_tracker/st_draw.c
@@ -35,7 +35,7 @@
#include "main/macros.h"
#include "shader/prog_uniform.h"
-#include "vbo/vbo.h"
+#include "st_vbo/st_vbo.h"
#include "st_context.h"
#include "st_atom.h"
@@ -530,9 +530,9 @@ check_uniforms(GLcontext *ctx)
void
st_draw_vbo(GLcontext *ctx,
const struct gl_client_array **arrays,
- const struct _mesa_prim *prims,
+ const struct st_mesa_prim *prims,
GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
+ const struct st_mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index)
{
@@ -703,7 +703,7 @@ void st_init_draw( struct st_context *st )
{
GLcontext *ctx = st->ctx;
- vbo_set_draw_func(ctx, st_draw_vbo);
+ st_vbo_set_draw_func(ctx, st_draw_vbo);
}
diff --git a/src/mesa/state_tracker/st_draw.h b/src/mesa/state_tracker/st_draw.h
index dcfe7e1536..46b257c98d 100644
--- a/src/mesa/state_tracker/st_draw.h
+++ b/src/mesa/state_tracker/st_draw.h
@@ -34,8 +34,8 @@
#ifndef ST_DRAW_H
#define ST_DRAW_H
-struct _mesa_prim;
-struct _mesa_index_buffer;
+struct st_mesa_prim;
+struct st_mesa_index_buffer;
void st_init_draw( struct st_context *st );
@@ -44,18 +44,18 @@ void st_destroy_draw( struct st_context *st );
extern void
st_draw_vbo(GLcontext *ctx,
const struct gl_client_array **arrays,
- const struct _mesa_prim *prims,
+ const struct st_mesa_prim *prims,
GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
+ const struct st_mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index);
extern void
st_feedback_draw_vbo(GLcontext *ctx,
const struct gl_client_array **arrays,
- const struct _mesa_prim *prims,
+ const struct st_mesa_prim *prims,
GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
+ const struct st_mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index);
diff --git a/src/mesa/state_tracker/st_draw_feedback.c b/src/mesa/state_tracker/st_draw_feedback.c
index 2712c131c0..48b462dbca 100644
--- a/src/mesa/state_tracker/st_draw_feedback.c
+++ b/src/mesa/state_tracker/st_draw_feedback.c
@@ -30,7 +30,7 @@
#include "main/macros.h"
#include "shader/prog_uniform.h"
-#include "vbo/vbo.h"
+#include "st_vbo/st_vbo.h"
#include "st_context.h"
#include "st_atom.h"
@@ -93,9 +93,9 @@ set_feedback_vertex_format(GLcontext *ctx)
void
st_feedback_draw_vbo(GLcontext *ctx,
const struct gl_client_array **arrays,
- const struct _mesa_prim *prims,
+ const struct st_mesa_prim *prims,
GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
+ const struct st_mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index)
{
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo.h b/src/mesa/state_tracker/st_vbo/st_vbo.h
new file mode 100644
index 0000000000..1d430f46a2
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+/**
+ * \file st_vbo_context.h
+ * \brief ST_VBO builder module datatypes and definitions.
+ * \author Keith Whitwell
+ */
+
+
+#ifndef _ST_VBO_H
+#define _ST_VBO_H
+
+#include "main/mtypes.h"
+
+struct st_mesa_prim {
+ GLuint mode:8;
+ GLuint indexed:1;
+ GLuint begin:1;
+ GLuint end:1;
+ GLuint weak:1;
+ GLuint pad:20;
+
+ GLuint start;
+ GLuint count;
+};
+
+/* Would like to call this a "st_vbo_index_buffer", but this would be
+ * confusing as the indices are not neccessarily yet in a non-null
+ * buffer object.
+ */
+struct st_mesa_index_buffer {
+ GLuint count;
+ GLenum type;
+ struct gl_buffer_object *obj;
+ const void *ptr;
+};
+
+
+
+GLboolean _st_vbo_CreateContext( GLcontext *ctx );
+void _st_vbo_DestroyContext( GLcontext *ctx );
+void _st_vbo_InvalidateState( GLcontext *ctx, GLuint new_state );
+
+typedef void (*st_vbo_draw_func)( GLcontext *ctx,
+ const struct gl_client_array **arrays,
+ const struct st_mesa_prim *prims,
+ GLuint nr_prims,
+ const struct st_mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index );
+
+void st_vbo_use_buffer_objects(GLcontext *ctx);
+
+void st_vbo_set_draw_func(GLcontext *ctx, st_vbo_draw_func func);
+
+void GLAPIENTRY
+_st_vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
+
+void GLAPIENTRY
+_st_vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z);
+
+void GLAPIENTRY
+_st_vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+
+void GLAPIENTRY
+_st_vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
+
+void GLAPIENTRY
+_st_vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+
+#endif
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_attrib.h b/src/mesa/state_tracker/st_vbo/st_vbo_attrib.h
new file mode 100644
index 0000000000..499b7a7726
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_attrib.h
@@ -0,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 ST_VBO_ATTRIB_H
+#define ST_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 {
+ ST_VBO_ATTRIB_POS = 0,
+ ST_VBO_ATTRIB_WEIGHT = 1,
+ ST_VBO_ATTRIB_NORMAL = 2,
+ ST_VBO_ATTRIB_COLOR0 = 3,
+ ST_VBO_ATTRIB_COLOR1 = 4,
+ ST_VBO_ATTRIB_FOG = 5,
+ ST_VBO_ATTRIB_INDEX = 6,
+ ST_VBO_ATTRIB_EDGEFLAG = 7,
+ ST_VBO_ATTRIB_TEX0 = 8,
+ ST_VBO_ATTRIB_TEX1 = 9,
+ ST_VBO_ATTRIB_TEX2 = 10,
+ ST_VBO_ATTRIB_TEX3 = 11,
+ ST_VBO_ATTRIB_TEX4 = 12,
+ ST_VBO_ATTRIB_TEX5 = 13,
+ ST_VBO_ATTRIB_TEX6 = 14,
+ ST_VBO_ATTRIB_TEX7 = 15,
+
+ ST_VBO_ATTRIB_GENERIC0 = 16, /* Not used? */
+ ST_VBO_ATTRIB_GENERIC1 = 17,
+ ST_VBO_ATTRIB_GENERIC2 = 18,
+ ST_VBO_ATTRIB_GENERIC3 = 19,
+ ST_VBO_ATTRIB_GENERIC4 = 20,
+ ST_VBO_ATTRIB_GENERIC5 = 21,
+ ST_VBO_ATTRIB_GENERIC6 = 22,
+ ST_VBO_ATTRIB_GENERIC7 = 23,
+ ST_VBO_ATTRIB_GENERIC8 = 24,
+ ST_VBO_ATTRIB_GENERIC9 = 25,
+ ST_VBO_ATTRIB_GENERIC10 = 26,
+ ST_VBO_ATTRIB_GENERIC11 = 27,
+ ST_VBO_ATTRIB_GENERIC12 = 28,
+ ST_VBO_ATTRIB_GENERIC13 = 29,
+ ST_VBO_ATTRIB_GENERIC14 = 30,
+ ST_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.
+ */
+ ST_VBO_ATTRIB_MAT_FRONT_AMBIENT = 32,
+ ST_VBO_ATTRIB_MAT_BACK_AMBIENT = 33,
+ ST_VBO_ATTRIB_MAT_FRONT_DIFFUSE = 34,
+ ST_VBO_ATTRIB_MAT_BACK_DIFFUSE = 35,
+ ST_VBO_ATTRIB_MAT_FRONT_SPECULAR = 36,
+ ST_VBO_ATTRIB_MAT_BACK_SPECULAR = 37,
+ ST_VBO_ATTRIB_MAT_FRONT_EMISSION = 38,
+ ST_VBO_ATTRIB_MAT_BACK_EMISSION = 39,
+ ST_VBO_ATTRIB_MAT_FRONT_SHININESS = 40,
+ ST_VBO_ATTRIB_MAT_BACK_SHININESS = 41,
+ ST_VBO_ATTRIB_MAT_FRONT_INDEXES = 42,
+ ST_VBO_ATTRIB_MAT_BACK_INDEXES = 43,
+
+ ST_VBO_ATTRIB_MAX = 44
+};
+
+#define ST_VBO_ATTRIB_FIRST_MATERIAL ST_VBO_ATTRIB_MAT_FRONT_AMBIENT
+#define ST_VBO_ATTRIB_LAST_MATERIAL ST_VBO_ATTRIB_MAT_BACK_INDEXES
+
+#define ST_VBO_MAX_COPIED_VERTS 3
+
+#endif
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_attrib_tmp.h b/src/mesa/state_tracker/st_vbo/st_vbo_attrib_tmp.h
new file mode 100644
index 0000000000..7a4db6dee0
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_attrib_tmp.h
@@ -0,0 +1,486 @@
+/**************************************************************************
+
+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.
+
+**************************************************************************/
+
+#define ATTR1FV( A, V ) ATTR( A, 1, (V)[0], 0, 0, 1 )
+#define ATTR2FV( A, V ) ATTR( A, 2, (V)[0], (V)[1], 0, 1 )
+#define ATTR3FV( A, V ) ATTR( A, 3, (V)[0], (V)[1], (V)[2], 1 )
+#define ATTR4FV( A, V ) ATTR( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] )
+
+#define ATTR1F( A, X ) ATTR( A, 1, X, 0, 0, 1 )
+#define ATTR2F( A, X, Y ) ATTR( A, 2, X, Y, 0, 1 )
+#define ATTR3F( A, X, Y, Z ) ATTR( A, 3, X, Y, Z, 1 )
+#define ATTR4F( A, X, Y, Z, W ) ATTR( A, 4, X, Y, Z, W )
+
+#define MAT_ATTR( A, N, V ) ATTR( A, N, (V)[0], (V)[1], (V)[2], (V)[3] )
+
+static void GLAPIENTRY TAG(Vertex2f)( GLfloat x, GLfloat y )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR2F( ST_VBO_ATTRIB_POS, x, y );
+}
+
+static void GLAPIENTRY TAG(Vertex2fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR2FV( ST_VBO_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY TAG(Vertex3f)( GLfloat x, GLfloat y, GLfloat z )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR3F( ST_VBO_ATTRIB_POS, x, y, z );
+}
+
+static void GLAPIENTRY TAG(Vertex3fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR3FV( ST_VBO_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY TAG(Vertex4f)( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR4F( ST_VBO_ATTRIB_POS, x, y, z, w );
+}
+
+static void GLAPIENTRY TAG(Vertex4fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR4FV( ST_VBO_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY TAG(TexCoord1f)( GLfloat x )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR1F( ST_VBO_ATTRIB_TEX0, x );
+}
+
+static void GLAPIENTRY TAG(TexCoord1fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR1FV( ST_VBO_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY TAG(TexCoord2f)( GLfloat x, GLfloat y )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR2F( ST_VBO_ATTRIB_TEX0, x, y );
+}
+
+static void GLAPIENTRY TAG(TexCoord2fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR2FV( ST_VBO_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY TAG(TexCoord3f)( GLfloat x, GLfloat y, GLfloat z )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR3F( ST_VBO_ATTRIB_TEX0, x, y, z );
+}
+
+static void GLAPIENTRY TAG(TexCoord3fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR3FV( ST_VBO_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY TAG(TexCoord4f)( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR4F( ST_VBO_ATTRIB_TEX0, x, y, z, w );
+}
+
+static void GLAPIENTRY TAG(TexCoord4fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR4FV( ST_VBO_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY TAG(Normal3f)( GLfloat x, GLfloat y, GLfloat z )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR3F( ST_VBO_ATTRIB_NORMAL, x, y, z );
+}
+
+static void GLAPIENTRY TAG(Normal3fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR3FV( ST_VBO_ATTRIB_NORMAL, v );
+}
+
+static void GLAPIENTRY TAG(FogCoordfEXT)( GLfloat x )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR1F( ST_VBO_ATTRIB_FOG, x );
+}
+
+static void GLAPIENTRY TAG(FogCoordfvEXT)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR1FV( ST_VBO_ATTRIB_FOG, v );
+}
+
+static void GLAPIENTRY TAG(Color3f)( GLfloat x, GLfloat y, GLfloat z )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR3F( ST_VBO_ATTRIB_COLOR0, x, y, z );
+}
+
+static void GLAPIENTRY TAG(Color3fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR3FV( ST_VBO_ATTRIB_COLOR0, v );
+}
+
+static void GLAPIENTRY TAG(Color4f)( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR4F( ST_VBO_ATTRIB_COLOR0, x, y, z, w );
+}
+
+static void GLAPIENTRY TAG(Color4fv)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR4FV( ST_VBO_ATTRIB_COLOR0, v );
+}
+
+static void GLAPIENTRY TAG(SecondaryColor3fEXT)( GLfloat x, GLfloat y, GLfloat z )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR3F( ST_VBO_ATTRIB_COLOR1, x, y, z );
+}
+
+static void GLAPIENTRY TAG(SecondaryColor3fvEXT)( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR3FV( ST_VBO_ATTRIB_COLOR1, v );
+}
+
+
+static void GLAPIENTRY TAG(EdgeFlag)( GLboolean b )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR1F( ST_VBO_ATTRIB_EDGEFLAG, (GLfloat)b );
+}
+
+static void GLAPIENTRY TAG(Indexf)( GLfloat f )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR1F( ST_VBO_ATTRIB_INDEX, f );
+}
+
+static void GLAPIENTRY TAG(Indexfv)( const GLfloat *f )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ ATTR1FV( ST_VBO_ATTRIB_INDEX, f );
+}
+
+
+static void GLAPIENTRY TAG(MultiTexCoord1f)( GLenum target, GLfloat x )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLuint attr = (target & 0x7) + ST_VBO_ATTRIB_TEX0;
+ ATTR1F( attr, x );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord1fv)( GLenum target, const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLuint attr = (target & 0x7) + ST_VBO_ATTRIB_TEX0;
+ ATTR1FV( attr, v );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord2f)( GLenum target, GLfloat x, GLfloat y )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLuint attr = (target & 0x7) + ST_VBO_ATTRIB_TEX0;
+ ATTR2F( attr, x, y );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord2fv)( GLenum target, const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLuint attr = (target & 0x7) + ST_VBO_ATTRIB_TEX0;
+ ATTR2FV( attr, v );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord3f)( GLenum target, GLfloat x, GLfloat y,
+ GLfloat z)
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLuint attr = (target & 0x7) + ST_VBO_ATTRIB_TEX0;
+ ATTR3F( attr, x, y, z );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord3fv)( GLenum target, const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLuint attr = (target & 0x7) + ST_VBO_ATTRIB_TEX0;
+ ATTR3FV( attr, v );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord4f)( GLenum target, GLfloat x, GLfloat y,
+ GLfloat z, GLfloat w )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLuint attr = (target & 0x7) + ST_VBO_ATTRIB_TEX0;
+ ATTR4F( attr, x, y, z, w );
+}
+
+static void GLAPIENTRY TAG(MultiTexCoord4fv)( GLenum target, const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLuint attr = (target & 0x7) + ST_VBO_ATTRIB_TEX0;
+ ATTR4FV( attr, v );
+}
+
+
+static void GLAPIENTRY TAG(VertexAttrib1fARB)( GLuint index, GLfloat x )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index == 0)
+ ATTR1F(0, x);
+ else if (index < MAX_VERTEX_ATTRIBS)
+ ATTR1F(ST_VBO_ATTRIB_GENERIC0 + index, x);
+ else
+ ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib1fvARB)( GLuint index,
+ const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index == 0)
+ ATTR1FV(0, v);
+ else if (index < MAX_VERTEX_ATTRIBS)
+ ATTR1FV(ST_VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib2fARB)( GLuint index, GLfloat x,
+ GLfloat y )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index == 0)
+ ATTR2F(0, x, y);
+ else if (index < MAX_VERTEX_ATTRIBS)
+ ATTR2F(ST_VBO_ATTRIB_GENERIC0 + index, x, y);
+ else
+ ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib2fvARB)( GLuint index,
+ const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index == 0)
+ ATTR2FV(0, v);
+ else if (index < MAX_VERTEX_ATTRIBS)
+ ATTR2FV(ST_VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib3fARB)( GLuint index, GLfloat x,
+ GLfloat y, GLfloat z )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index == 0)
+ ATTR3F(0, x, y, z);
+ else if (index < MAX_VERTEX_ATTRIBS)
+ ATTR3F(ST_VBO_ATTRIB_GENERIC0 + index, x, y, z);
+ else
+ ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib3fvARB)( GLuint index,
+ const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index == 0)
+ ATTR3FV(0, v);
+ else if (index < MAX_VERTEX_ATTRIBS)
+ ATTR3FV(ST_VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib4fARB)( GLuint index, GLfloat x,
+ GLfloat y, GLfloat z,
+ GLfloat w )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index == 0)
+ ATTR4F(0, x, y, z, w);
+ else if (index < MAX_VERTEX_ATTRIBS)
+ ATTR4F(ST_VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
+ else
+ ERROR();
+}
+
+static void GLAPIENTRY TAG(VertexAttrib4fvARB)( GLuint index,
+ const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index == 0)
+ ATTR4FV(0, v);
+ else if (index < MAX_VERTEX_ATTRIBS)
+ ATTR4FV(ST_VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR();
+}
+
+
+/* In addition to supporting NV_vertex_program, these entrypoints are
+ * used by the display list and other code specifically because of
+ * their property of aliasing with other attributes. (See
+ * st_vbo_save_loopback.c)
+ */
+static void GLAPIENTRY TAG(VertexAttrib1fNV)( GLuint index, GLfloat x )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index < ST_VBO_ATTRIB_MAX)
+ ATTR1F(index, x);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib1fvNV)( GLuint index,
+ const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index < ST_VBO_ATTRIB_MAX)
+ ATTR1FV(index, v);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib2fNV)( GLuint index, GLfloat x,
+ GLfloat y )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index < ST_VBO_ATTRIB_MAX)
+ ATTR2F(index, x, y);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib2fvNV)( GLuint index,
+ const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index < ST_VBO_ATTRIB_MAX)
+ ATTR2FV(index, v);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib3fNV)( GLuint index, GLfloat x,
+ GLfloat y, GLfloat z )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index < ST_VBO_ATTRIB_MAX)
+ ATTR3F(index, x, y, z);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib3fvNV)( GLuint index,
+ const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index < ST_VBO_ATTRIB_MAX)
+ ATTR3FV(index, v);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib4fNV)( GLuint index, GLfloat x,
+ GLfloat y, GLfloat z,
+ GLfloat w )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index < ST_VBO_ATTRIB_MAX)
+ ATTR4F(index, x, y, z, w);
+}
+
+static void GLAPIENTRY TAG(VertexAttrib4fvNV)( GLuint index,
+ const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ if (index < ST_VBO_ATTRIB_MAX)
+ ATTR4FV(index, v);
+}
+
+
+#define MAT( ATTR, N, face, params ) \
+do { \
+ if (face != GL_BACK) \
+ MAT_ATTR( ATTR, N, params ); /* front */ \
+ if (face != GL_FRONT) \
+ MAT_ATTR( ATTR + 1, N, params ); /* back */ \
+} while (0)
+
+
+/* Colormaterial conflicts are dealt with later.
+ */
+static void GLAPIENTRY TAG(Materialfv)( GLenum face, GLenum pname,
+ const GLfloat *params )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ switch (pname) {
+ case GL_EMISSION:
+ MAT( ST_VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
+ break;
+ case GL_AMBIENT:
+ MAT( ST_VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+ break;
+ case GL_DIFFUSE:
+ MAT( ST_VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+ break;
+ case GL_SPECULAR:
+ MAT( ST_VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
+ break;
+ case GL_SHININESS:
+ MAT( ST_VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
+ break;
+ case GL_COLOR_INDEXES:
+ MAT( ST_VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
+ break;
+ case GL_AMBIENT_AND_DIFFUSE:
+ MAT( ST_VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+ MAT( ST_VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+ break;
+ default:
+ ERROR();
+ return;
+ }
+}
+
+
+#undef ATTR1FV
+#undef ATTR2FV
+#undef ATTR3FV
+#undef ATTR4FV
+
+#undef ATTR1F
+#undef ATTR2F
+#undef ATTR3F
+#undef ATTR4F
+
+#undef MAT
+#undef MAT_ATTR
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_context.c b/src/mesa/state_tracker/st_vbo/st_vbo_context.c
new file mode 100644
index 0000000000..642064124b
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_context.c
@@ -0,0 +1,269 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.3
+ *
+ * Copyright (C) 1999-2005 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>
+ */
+
+#include "main/imports.h"
+#include "main/mtypes.h"
+#include "main/api_arrayelt.h"
+#include "math/m_eval.h"
+#include "st_vbo.h"
+#include "st_vbo_context.h"
+
+#if 0
+/* Reach out and grab this to use as the default:
+ */
+extern void _tnl_draw_prims( GLcontext *ctx,
+ const struct gl_client_array *arrays[],
+ const struct st_mesa_prim *prims,
+ GLuint nr_prims,
+ const struct st_mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index );
+#endif
+
+
+
+#define NR_LEGACY_ATTRIBS 16
+#define NR_GENERIC_ATTRIBS 16
+#define NR_MAT_ATTRIBS 12
+
+static GLuint check_size( const GLfloat *attr )
+{
+ if (attr[3] != 1.0) return 4;
+ if (attr[2] != 0.0) return 3;
+ if (attr[1] != 0.0) return 2;
+ return 1;
+}
+
+static void init_legacy_currval(GLcontext *ctx)
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct gl_client_array *arrays = st_vbo->legacy_currval;
+ GLuint i;
+
+ memset(arrays, 0, sizeof(*arrays) * NR_LEGACY_ATTRIBS);
+
+ /* Set up a constant (StrideB == 0) array for each current
+ * attribute:
+ */
+ for (i = 0; i < NR_LEGACY_ATTRIBS; i++) {
+ struct gl_client_array *cl = &arrays[i];
+
+ /* Size will have to be determined at runtime:
+ */
+ cl->Size = check_size(ctx->Current.Attrib[i]);
+ cl->Stride = 0;
+ cl->StrideB = 0;
+ cl->Enabled = 1;
+ cl->Type = GL_FLOAT;
+ cl->Format = GL_RGBA;
+ cl->Ptr = (const void *)ctx->Current.Attrib[i];
+ cl->BufferObj = ctx->Shared->NullBufferObj;
+ }
+}
+
+
+static void init_generic_currval(GLcontext *ctx)
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct gl_client_array *arrays = st_vbo->generic_currval;
+ GLuint i;
+
+ memset(arrays, 0, sizeof(*arrays) * NR_GENERIC_ATTRIBS);
+
+ for (i = 0; i < NR_GENERIC_ATTRIBS; i++) {
+ struct gl_client_array *cl = &arrays[i];
+
+ /* This will have to be determined at runtime:
+ */
+ cl->Size = 1;
+ cl->Type = GL_FLOAT;
+ cl->Format = GL_RGBA;
+ cl->Ptr = (const void *)ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + i];
+ cl->Stride = 0;
+ cl->StrideB = 0;
+ cl->Enabled = 1;
+ cl->BufferObj = ctx->Shared->NullBufferObj;
+ }
+}
+
+
+static void init_mat_currval(GLcontext *ctx)
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct gl_client_array *arrays = st_vbo->mat_currval;
+ GLuint i;
+
+ ASSERT(NR_MAT_ATTRIBS == MAT_ATTRIB_MAX);
+
+ memset(arrays, 0, sizeof(*arrays) * NR_MAT_ATTRIBS);
+
+ /* Set up a constant (StrideB == 0) array for each current
+ * attribute:
+ */
+ for (i = 0; i < NR_MAT_ATTRIBS; i++) {
+ struct gl_client_array *cl = &arrays[i];
+
+ /* Size is fixed for the material attributes, for others will
+ * be determined at runtime:
+ */
+ switch (i - VERT_ATTRIB_GENERIC0) {
+ case MAT_ATTRIB_FRONT_SHININESS:
+ case MAT_ATTRIB_BACK_SHININESS:
+ cl->Size = 1;
+ break;
+ case MAT_ATTRIB_FRONT_INDEXES:
+ case MAT_ATTRIB_BACK_INDEXES:
+ cl->Size = 3;
+ break;
+ default:
+ cl->Size = 4;
+ break;
+ }
+
+ cl->Ptr = (const void *)ctx->Light.Material.Attrib[i];
+ cl->Type = GL_FLOAT;
+ cl->Format = GL_RGBA;
+ cl->Stride = 0;
+ cl->StrideB = 0;
+ cl->Enabled = 1;
+ cl->BufferObj = ctx->Shared->NullBufferObj;
+ }
+}
+
+#if 0
+
+static void st_vbo_exec_current_init( struct st_vbo_exec_context *exec )
+{
+ GLcontext *ctx = exec->ctx;
+ GLint i;
+
+ /* setup the pointers for the typical 16 vertex attributes */
+ for (i = 0; i < ST_VBO_ATTRIB_FIRST_MATERIAL; i++)
+ exec->vtx.current[i] = ctx->Current.Attrib[i];
+
+ /* setup pointers for the 12 material attributes */
+ for (i = 0; i < MAT_ATTRIB_MAX; i++)
+ exec->vtx.current[ST_VBO_ATTRIB_FIRST_MATERIAL + i] =
+ ctx->Light.Material.Attrib[i];
+}
+#endif
+
+GLboolean _st_vbo_CreateContext( GLcontext *ctx )
+{
+ struct st_vbo_context *st_vbo = CALLOC_STRUCT(st_vbo_context);
+
+ ctx->swtnl_im = (void *)st_vbo;
+
+ /* Initialize the arrayelt helper
+ */
+ if (!ctx->aelt_context &&
+ !_ae_create_context( ctx )) {
+ return GL_FALSE;
+ }
+
+ /* TODO: remove these pointers.
+ */
+ st_vbo->legacy_currval = &st_vbo->currval[ST_VBO_ATTRIB_POS];
+ st_vbo->generic_currval = &st_vbo->currval[ST_VBO_ATTRIB_GENERIC0];
+ st_vbo->mat_currval = &st_vbo->currval[ST_VBO_ATTRIB_MAT_FRONT_AMBIENT];
+
+ init_legacy_currval( ctx );
+ init_generic_currval( ctx );
+ init_mat_currval( ctx );
+
+ /* Build mappings from VERT_ATTRIB -> ST_VBO_ATTRIB depending on type
+ * of vertex program active.
+ */
+ {
+ GLuint i;
+
+ /* When no vertex program, pull in the material attributes in
+ * the 16..32 generic range.
+ */
+ for (i = 0; i < 16; i++)
+ st_vbo->map_vp_none[i] = i;
+ for (i = 0; i < 12; i++)
+ st_vbo->map_vp_none[16+i] = ST_VBO_ATTRIB_MAT_FRONT_AMBIENT + i;
+ for (i = 0; i < 4; i++)
+ st_vbo->map_vp_none[28+i] = i;
+
+ for (i = 0; i < VERT_ATTRIB_MAX; i++)
+ st_vbo->map_vp_arb[i] = i;
+ }
+
+
+ /* By default:
+ */
+#if 0 /* dead - see st_vbo_set_draw_func() */
+ st_vbo->draw_prims = _tnl_draw_prims;
+#endif
+
+ /* Hook our functions into exec and compile dispatch tables. These
+ * will pretty much be permanently installed, which means that the
+ * vtxfmt mechanism can be removed now.
+ */
+ st_vbo_exec_init( ctx );
+#if FEATURE_dlist
+ st_vbo_save_init( ctx );
+#endif
+
+ _math_init_eval();
+
+ return GL_TRUE;
+}
+
+void _st_vbo_InvalidateState( GLcontext *ctx, GLuint new_state )
+{
+ _ae_invalidate_state(ctx, new_state);
+ st_vbo_exec_invalidate_state(ctx, new_state);
+}
+
+
+void _st_vbo_DestroyContext( GLcontext *ctx )
+{
+ if (ctx->aelt_context) {
+ _ae_destroy_context( ctx );
+ ctx->aelt_context = NULL;
+ }
+
+ if (st_vbo_context(ctx)) {
+ st_vbo_exec_destroy(ctx);
+#if FEATURE_dlist
+ st_vbo_save_destroy(ctx);
+#endif
+ FREE(st_vbo_context(ctx));
+ ctx->swtnl_im = NULL;
+ }
+}
+
+
+void st_vbo_set_draw_func(GLcontext *ctx, st_vbo_draw_func func)
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ st_vbo->draw_prims = func;
+}
+
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_context.h b/src/mesa/state_tracker/st_vbo/st_vbo_context.h
new file mode 100644
index 0000000000..fc68f10a82
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_context.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/**
+ * \file st_vbo_context.h
+ * \brief ST_VBO builder module datatypes and definitions.
+ * \author Keith Whitwell
+ */
+
+
+/**
+ * \mainpage The ST_VBO builder module
+ *
+ * This module hooks into the GL dispatch table and catches all vertex
+ * building and drawing commands, such as glVertex3f, glBegin and
+ * glDrawArrays. The module stores all incoming vertex data as arrays
+ * in GL vertex buffer objects (ST_VBOs), and translates all drawing
+ * commands into calls to a driver supplied DrawPrimitives() callback.
+ *
+ * The module captures both immediate mode and display list drawing,
+ * and manages the allocation, reference counting and deallocation of
+ * vertex buffer objects itself.
+ *
+ * The DrawPrimitives() callback can be either implemented by the
+ * driver itself or hooked to the tnl module's _tnl_draw_primitives()
+ * function for hardware without tnl capablilties or during fallbacks.
+ */
+
+
+#ifndef _ST_VBO_CONTEXT_H
+#define _ST_VBO_CONTEXT_H
+
+#include "st_vbo.h"
+#include "st_vbo_attrib.h"
+#include "st_vbo_exec.h"
+#if FEATURE_dlist
+#include "st_vbo_save.h"
+#endif
+
+
+struct st_vbo_context {
+ struct gl_client_array currval[ST_VBO_ATTRIB_MAX];
+
+ /* These point into the above. TODO: remove.
+ */
+ struct gl_client_array *legacy_currval;
+ struct gl_client_array *generic_currval;
+ struct gl_client_array *mat_currval;
+
+ GLuint map_vp_none[32];
+ GLuint map_vp_arb[32];
+
+ GLfloat *current[ST_VBO_ATTRIB_MAX]; /* points into ctx->Current, ctx->Light.Material */
+ GLfloat CurrentFloatEdgeFlag;
+
+
+ struct st_vbo_exec_context exec;
+#if FEATURE_dlist
+ struct st_vbo_save_context save;
+#endif
+
+ /* Callback into the driver. This must always succeed, the driver
+ * is responsible for initiating any fallback actions required:
+ */
+ st_vbo_draw_func draw_prims;
+};
+
+
+static INLINE struct st_vbo_context *st_vbo_context(GLcontext *ctx)
+{
+ return (struct st_vbo_context *)(ctx->swtnl_im);
+}
+
+enum {
+ VP_NONE = 1,
+ VP_NV,
+ VP_ARB
+};
+
+static INLINE GLuint get_program_mode( GLcontext *ctx )
+{
+ if (!ctx->VertexProgram._Current)
+ return VP_NONE;
+ else if (ctx->VertexProgram._Current->IsNVProgram)
+ return VP_NV;
+ else
+ return VP_ARB;
+}
+
+
+#endif
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_exec.c b/src/mesa/state_tracker/st_vbo/st_vbo_exec.c
new file mode 100644
index 0000000000..88dc7fb1a7
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_exec.c
@@ -0,0 +1,97 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.3
+ *
+ * Copyright (C) 1999-2005 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>
+ */
+
+
+#include "main/api_arrayelt.h"
+#include "main/glheader.h"
+#include "main/imports.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+#include "main/vtxfmt.h"
+
+#include "st_vbo_context.h"
+
+void st_vbo_exec_init( GLcontext *ctx )
+{
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+
+ exec->ctx = ctx;
+
+ /* Initialize the arrayelt helper
+ */
+ if (!ctx->aelt_context &&
+ !_ae_create_context( ctx ))
+ return;
+
+ st_vbo_exec_vtx_init( exec );
+ st_vbo_exec_array_init( exec );
+
+ /* Hook our functions into exec and compile dispatch tables.
+ */
+ _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt );
+
+ ctx->Driver.NeedFlush = 0;
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+ ctx->Driver.BeginVertices = st_vbo_exec_BeginVertices;
+ ctx->Driver.FlushVertices = st_vbo_exec_FlushVertices;
+
+ st_vbo_exec_invalidate_state( ctx, ~0 );
+}
+
+
+void st_vbo_exec_destroy( GLcontext *ctx )
+{
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+
+ if (ctx->aelt_context) {
+ _ae_destroy_context( ctx );
+ ctx->aelt_context = NULL;
+ }
+
+ st_vbo_exec_vtx_destroy( exec );
+ st_vbo_exec_array_destroy( exec );
+}
+
+/* Really want to install these callbacks to a central facility to be
+ * invoked according to the state flags. That will have to wait for a
+ * mesa rework:
+ */
+void st_vbo_exec_invalidate_state( GLcontext *ctx, GLuint new_state )
+{
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+
+ if (new_state & (_NEW_PROGRAM|_NEW_EVAL))
+ exec->eval.recalculate_maps = 1;
+
+ _ae_invalidate_state(ctx, new_state);
+}
+
+
+
+
+
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_exec.h b/src/mesa/state_tracker/st_vbo/st_vbo_exec.h
new file mode 100644
index 0000000000..53a7f47454
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_exec.h
@@ -0,0 +1,173 @@
+/**************************************************************************
+
+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>
+ *
+ */
+
+#ifndef __ST_VBO_EXEC_H__
+#define __ST_VBO_EXEC_H__
+
+#include "main/mtypes.h"
+#include "st_vbo.h"
+#include "st_vbo_attrib.h"
+
+
+#define ST_VBO_MAX_PRIM 64
+
+/* Wierd implementation stuff:
+ */
+#define ST_VBO_VERT_BUFFER_SIZE (1024*64) /* bytes */
+#define ST_VBO_MAX_ATTR_CODEGEN 16
+#define ERROR_ATTRIB 16
+
+
+
+
+struct st_vbo_exec_eval1_map {
+ struct gl_1d_map *map;
+ GLuint sz;
+};
+
+struct st_vbo_exec_eval2_map {
+ struct gl_2d_map *map;
+ GLuint sz;
+};
+
+
+
+struct st_vbo_exec_copied_vtx {
+ GLfloat buffer[ST_VBO_ATTRIB_MAX * 4 * ST_VBO_MAX_COPIED_VERTS];
+ GLuint nr;
+};
+
+
+typedef void (*st_vbo_attrfv_func)( const GLfloat * );
+
+
+struct st_vbo_exec_context
+{
+ GLcontext *ctx;
+ GLvertexformat vtxfmt;
+
+ struct {
+ struct gl_buffer_object *bufferobj;
+
+ GLuint vertex_size; /* in dwords */
+
+ struct st_mesa_prim prim[ST_VBO_MAX_PRIM];
+ GLuint prim_count;
+
+ GLfloat *buffer_map;
+ GLfloat *buffer_ptr; /* cursor, points into buffer */
+ GLuint buffer_used; /* in bytes */
+ GLfloat vertex[ST_VBO_ATTRIB_MAX*4]; /* current vertex */
+
+ GLuint vert_count;
+ GLuint max_vert;
+ struct st_vbo_exec_copied_vtx copied;
+
+ GLubyte attrsz[ST_VBO_ATTRIB_MAX];
+ GLubyte active_sz[ST_VBO_ATTRIB_MAX];
+
+ GLfloat *attrptr[ST_VBO_ATTRIB_MAX];
+ struct gl_client_array arrays[ST_VBO_ATTRIB_MAX];
+
+ /* According to program mode, the values above plus current
+ * values are squashed down to the 32 attributes passed to the
+ * vertex program below:
+ */
+ GLuint program_mode;
+ GLuint enabled_flags;
+ const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
+ } vtx;
+
+
+ struct {
+ GLboolean recalculate_maps;
+ struct st_vbo_exec_eval1_map map1[VERT_ATTRIB_MAX];
+ struct st_vbo_exec_eval2_map map2[VERT_ATTRIB_MAX];
+ } eval;
+
+ struct {
+ GLuint program_mode;
+ GLuint enabled_flags;
+ GLuint array_obj;
+
+ /* These just mirror the current arrayobj (todo: make arrayobj
+ * look like this and remove the mirror):
+ */
+ const struct gl_client_array *legacy_array[16];
+ const struct gl_client_array *generic_array[16];
+
+ /* Arrays and current values manipulated according to program
+ * mode, etc. These are the attributes as seen by vertex
+ * programs:
+ */
+ const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
+ } array;
+};
+
+
+
+/* External API:
+ */
+void st_vbo_exec_init( GLcontext *ctx );
+void st_vbo_exec_destroy( GLcontext *ctx );
+void st_vbo_exec_invalidate_state( GLcontext *ctx, GLuint new_state );
+void st_vbo_exec_FlushVertices_internal( GLcontext *ctx, GLboolean unmap );
+
+void st_vbo_exec_BeginVertices( GLcontext *ctx );
+void st_vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags );
+
+
+/* Internal functions:
+ */
+void st_vbo_exec_array_init( struct st_vbo_exec_context *exec );
+void st_vbo_exec_array_destroy( struct st_vbo_exec_context *exec );
+
+
+void st_vbo_exec_vtx_init( struct st_vbo_exec_context *exec );
+void st_vbo_exec_vtx_destroy( struct st_vbo_exec_context *exec );
+void st_vbo_exec_vtx_flush( struct st_vbo_exec_context *exec, GLboolean unmap );
+void st_vbo_exec_vtx_map( struct st_vbo_exec_context *exec );
+void st_vbo_exec_vtx_wrap( struct st_vbo_exec_context *exec );
+
+void st_vbo_exec_eval_update( struct st_vbo_exec_context *exec );
+
+void st_vbo_exec_do_EvalCoord2f( struct st_vbo_exec_context *exec,
+ GLfloat u, GLfloat v );
+
+void st_vbo_exec_do_EvalCoord1f( struct st_vbo_exec_context *exec,
+ GLfloat u);
+
+extern GLboolean
+st_vbo_validate_shaders(GLcontext *ctx);
+
+#endif
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_exec_api.c b/src/mesa/state_tracker/st_vbo/st_vbo_exec_api.c
new file mode 100644
index 0000000000..2973c34db7
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_exec_api.c
@@ -0,0 +1,838 @@
+/**************************************************************************
+
+Copyright 2002-2008 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>
+ */
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "main/vtxfmt.h"
+#if FEATURE_dlist
+#include "main/dlist.h"
+#endif
+#include "main/state.h"
+#include "main/light.h"
+#include "main/api_arrayelt.h"
+#include "main/api_noop.h"
+#include "glapi/dispatch.h"
+
+#include "st_vbo_context.h"
+
+#ifdef ERROR
+#undef ERROR
+#endif
+
+
+static void reset_attrfv( struct st_vbo_exec_context *exec );
+
+
+/* Close off the last primitive, execute the buffer, restart the
+ * primitive.
+ */
+static void st_vbo_exec_wrap_buffers( struct st_vbo_exec_context *exec )
+{
+ if (exec->vtx.prim_count == 0) {
+ exec->vtx.copied.nr = 0;
+ exec->vtx.vert_count = 0;
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ }
+ else {
+ GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
+ GLuint last_count;
+
+ if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ GLint i = exec->vtx.prim_count - 1;
+ assert(i >= 0);
+ exec->vtx.prim[i].count = (exec->vtx.vert_count -
+ exec->vtx.prim[i].start);
+ }
+
+ last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
+
+ /* Execute the buffer and save copied vertices.
+ */
+ if (exec->vtx.vert_count)
+ st_vbo_exec_vtx_flush( exec, GL_FALSE );
+ else {
+ exec->vtx.prim_count = 0;
+ exec->vtx.copied.nr = 0;
+ }
+
+ /* Emit a glBegin to start the new list.
+ */
+ assert(exec->vtx.prim_count == 0);
+
+ if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
+ exec->vtx.prim[0].start = 0;
+ exec->vtx.prim[0].count = 0;
+ exec->vtx.prim_count++;
+
+ if (exec->vtx.copied.nr == last_count)
+ exec->vtx.prim[0].begin = last_begin;
+ }
+ }
+}
+
+
+/* Deal with buffer wrapping where provoked by the vertex buffer
+ * filling up, as opposed to upgrade_vertex().
+ */
+void st_vbo_exec_vtx_wrap( struct st_vbo_exec_context *exec )
+{
+ GLfloat *data = exec->vtx.copied.buffer;
+ GLuint i;
+
+ /* Run pipeline on current vertices, copy wrapped vertices
+ * to exec->vtx.copied.
+ */
+ st_vbo_exec_wrap_buffers( exec );
+
+ /* Copy stored stored vertices to start of new list.
+ */
+ assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
+
+ for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
+ _mesa_memcpy( exec->vtx.buffer_ptr, data,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+ exec->vtx.buffer_ptr += exec->vtx.vertex_size;
+ data += exec->vtx.vertex_size;
+ exec->vtx.vert_count++;
+ }
+
+ exec->vtx.copied.nr = 0;
+}
+
+
+/*
+ * Copy the active vertex's values to the ctx->Current fields.
+ */
+static void st_vbo_exec_copy_to_current( struct st_vbo_exec_context *exec )
+{
+ GLcontext *ctx = exec->ctx;
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ GLuint i;
+
+ for (i = ST_VBO_ATTRIB_POS+1 ; i < ST_VBO_ATTRIB_MAX ; i++) {
+ if (exec->vtx.attrsz[i]) {
+ /* Note: the exec->vtx.current[i] pointers point into the
+ * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
+ */
+ GLfloat *current = (GLfloat *)st_vbo->currval[i].Ptr;
+ GLfloat tmp[4];
+
+ COPY_CLEAN_4V(tmp,
+ exec->vtx.attrsz[i],
+ exec->vtx.attrptr[i]);
+
+ if (memcmp(current, tmp, sizeof(tmp)) != 0)
+ {
+ memcpy(current, tmp, sizeof(tmp));
+
+ /* Given that we explicitly state size here, there is no need
+ * for the COPY_CLEAN above, could just copy 16 bytes and be
+ * done. The only problem is when Mesa accesses ctx->Current
+ * directly.
+ */
+ st_vbo->currval[i].Size = exec->vtx.attrsz[i];
+
+ /* This triggers rather too much recalculation of Mesa state
+ * that doesn't get used (eg light positions).
+ */
+ if (i >= ST_VBO_ATTRIB_MAT_FRONT_AMBIENT &&
+ i <= ST_VBO_ATTRIB_MAT_BACK_INDEXES)
+ ctx->NewState |= _NEW_LIGHT;
+
+ ctx->NewState |= _NEW_CURRENT_ATTRIB;
+ }
+ }
+ }
+
+ /* Colormaterial -- this kindof sucks.
+ */
+ if (ctx->Light.ColorMaterialEnabled &&
+ exec->vtx.attrsz[ST_VBO_ATTRIB_COLOR0]) {
+ _mesa_update_color_material(ctx,
+ ctx->Current.Attrib[ST_VBO_ATTRIB_COLOR0]);
+ }
+}
+
+
+static void st_vbo_exec_copy_from_current( struct st_vbo_exec_context *exec )
+{
+ GLcontext *ctx = exec->ctx;
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ GLint i;
+
+ for (i = ST_VBO_ATTRIB_POS+1 ; i < ST_VBO_ATTRIB_MAX ; i++) {
+ const GLfloat *current = (GLfloat *)st_vbo->currval[i].Ptr;
+ switch (exec->vtx.attrsz[i]) {
+ case 4: exec->vtx.attrptr[i][3] = current[3];
+ case 3: exec->vtx.attrptr[i][2] = current[2];
+ case 2: exec->vtx.attrptr[i][1] = current[1];
+ case 1: exec->vtx.attrptr[i][0] = current[0];
+ break;
+ }
+ }
+}
+
+
+/* Flush existing data, set new attrib size, replay copied vertices.
+ */
+static void st_vbo_exec_wrap_upgrade_vertex( struct st_vbo_exec_context *exec,
+ GLuint attr,
+ GLuint newsz )
+{
+ GLcontext *ctx = exec->ctx;
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ GLint lastcount = exec->vtx.vert_count;
+ GLfloat *tmp;
+ GLuint oldsz;
+ GLuint i;
+
+ /* Run pipeline on current vertices, copy wrapped vertices
+ * to exec->vtx.copied.
+ */
+ st_vbo_exec_wrap_buffers( exec );
+
+
+ /* 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.
+ */
+ st_vbo_exec_copy_to_current( exec );
+
+
+ /* Heuristic: Attempt to isolate attributes received outside
+ * begin/end so that they don't bloat the vertices.
+ */
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
+ exec->vtx.attrsz[attr] == 0 &&
+ lastcount > 8 &&
+ exec->vtx.vertex_size) {
+ reset_attrfv( exec );
+ }
+
+ /* Fix up sizes:
+ */
+ oldsz = exec->vtx.attrsz[attr];
+ exec->vtx.attrsz[attr] = newsz;
+
+ exec->vtx.vertex_size += newsz - oldsz;
+ exec->vtx.max_vert = ((ST_VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
+ (exec->vtx.vertex_size * sizeof(GLfloat)));
+ exec->vtx.vert_count = 0;
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+
+
+ /* Recalculate all the attrptr[] values
+ */
+ for (i = 0, tmp = exec->vtx.vertex ; i < ST_VBO_ATTRIB_MAX ; i++) {
+ if (exec->vtx.attrsz[i]) {
+ exec->vtx.attrptr[i] = tmp;
+ tmp += exec->vtx.attrsz[i];
+ }
+ else
+ exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
+ }
+
+ /* Copy from current to repopulate the vertex with correct values.
+ */
+ st_vbo_exec_copy_from_current( exec );
+
+ /* Replay stored vertices to translate them
+ * to new format here.
+ *
+ * -- No need to replay - just copy piecewise
+ */
+ if (exec->vtx.copied.nr)
+ {
+ GLfloat *data = exec->vtx.copied.buffer;
+ GLfloat *dest = exec->vtx.buffer_ptr;
+ GLuint j;
+
+ assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
+
+ for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
+ for (j = 0 ; j < ST_VBO_ATTRIB_MAX ; j++) {
+ if (exec->vtx.attrsz[j]) {
+ if (j == attr) {
+ if (oldsz) {
+ COPY_CLEAN_4V( dest, oldsz, data );
+ data += oldsz;
+ dest += newsz;
+ } else {
+ const GLfloat *current = (const GLfloat *)st_vbo->currval[j].Ptr;
+ COPY_SZ_4V( dest, newsz, current );
+ dest += newsz;
+ }
+ }
+ else {
+ GLuint sz = exec->vtx.attrsz[j];
+ COPY_SZ_4V( dest, sz, data );
+ dest += sz;
+ data += sz;
+ }
+ }
+ }
+ }
+
+ exec->vtx.buffer_ptr = dest;
+ exec->vtx.vert_count += exec->vtx.copied.nr;
+ exec->vtx.copied.nr = 0;
+ }
+}
+
+
+static void st_vbo_exec_fixup_vertex( struct st_vbo_exec_context *exec,
+ GLuint attr, GLuint sz )
+{
+ int i;
+
+ if (sz > exec->vtx.attrsz[attr]) {
+ /* New size is larger. Need to flush existing vertices and get
+ * an enlarged vertex format.
+ */
+ st_vbo_exec_wrap_upgrade_vertex( exec, attr, sz );
+ }
+ else if (sz < exec->vtx.active_sz[attr]) {
+ static const GLfloat id[4] = { 0, 0, 0, 1 };
+
+ /* New size is smaller - just need to fill in some
+ * zeros. Don't need to flush or wrap.
+ */
+ for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++)
+ exec->vtx.attrptr[attr][i-1] = id[i-1];
+ }
+
+ exec->vtx.active_sz[attr] = sz;
+
+ /* Does setting NeedFlush belong here? Necessitates resetting
+ * vtxfmt on each flush (otherwise flags won't get reset
+ * afterwards).
+ */
+ if (attr == 0)
+ exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+}
+
+
+
+
+/*
+ */
+#define ATTR( A, N, V0, V1, V2, V3 ) \
+do { \
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec; \
+ \
+ if (exec->vtx.active_sz[A] != N) \
+ st_vbo_exec_fixup_vertex(exec, A, N); \
+ \
+ { \
+ GLfloat *dest = exec->vtx.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 < exec->vtx.vertex_size; i++) \
+ exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
+ \
+ exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
+ exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
+ \
+ if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
+ st_vbo_exec_vtx_wrap( exec ); \
+ } \
+} while (0)
+
+
+#define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
+#define TAG(x) st_vbo_##x
+
+#include "st_vbo_attrib_tmp.h"
+
+
+
+
+
+/* Eval
+ */
+static void GLAPIENTRY st_vbo_exec_EvalCoord1f( GLfloat u )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+
+ {
+ GLint i;
+ if (exec->eval.recalculate_maps)
+ st_vbo_exec_eval_update( exec );
+
+ for (i = 0; i <= ST_VBO_ATTRIB_TEX7; i++) {
+ if (exec->eval.map1[i].map)
+ if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
+ st_vbo_exec_fixup_vertex( exec, i, exec->eval.map1[i].sz );
+ }
+ }
+
+
+ _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+
+ st_vbo_exec_do_EvalCoord1f( exec, u );
+
+ _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+}
+
+static void GLAPIENTRY st_vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+
+ {
+ GLint i;
+ if (exec->eval.recalculate_maps)
+ st_vbo_exec_eval_update( exec );
+
+ for (i = 0; i <= ST_VBO_ATTRIB_TEX7; i++) {
+ if (exec->eval.map2[i].map)
+ if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
+ st_vbo_exec_fixup_vertex( exec, i, exec->eval.map2[i].sz );
+ }
+
+ if (ctx->Eval.AutoNormal)
+ if (exec->vtx.active_sz[ST_VBO_ATTRIB_NORMAL] != 3)
+ st_vbo_exec_fixup_vertex( exec, ST_VBO_ATTRIB_NORMAL, 3 );
+ }
+
+ _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+
+ st_vbo_exec_do_EvalCoord2f( exec, u, v );
+
+ _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+}
+
+static void GLAPIENTRY st_vbo_exec_EvalCoord1fv( const GLfloat *u )
+{
+ st_vbo_exec_EvalCoord1f( u[0] );
+}
+
+static void GLAPIENTRY st_vbo_exec_EvalCoord2fv( const GLfloat *u )
+{
+ st_vbo_exec_EvalCoord2f( u[0], u[1] );
+}
+
+static void GLAPIENTRY st_vbo_exec_EvalPoint1( GLint i )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
+ (GLfloat) ctx->Eval.MapGrid1un);
+ GLfloat u = i * du + ctx->Eval.MapGrid1u1;
+
+ st_vbo_exec_EvalCoord1f( u );
+}
+
+
+static void GLAPIENTRY st_vbo_exec_EvalPoint2( GLint i, GLint j )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
+ (GLfloat) ctx->Eval.MapGrid2un);
+ GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
+ (GLfloat) ctx->Eval.MapGrid2vn);
+ GLfloat u = i * du + ctx->Eval.MapGrid2u1;
+ GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
+
+ st_vbo_exec_EvalCoord2f( u, v );
+}
+
+
+/**
+ * Check if programs/shaders are enabled and valid at glBegin time.
+ */
+GLboolean
+st_vbo_validate_shaders(GLcontext *ctx)
+{
+ if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
+ (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
+ return GL_FALSE;
+ }
+ if (ctx->Shader.CurrentProgram && !ctx->Shader.CurrentProgram->LinkStatus) {
+ return GL_FALSE;
+ }
+ return GL_TRUE;
+}
+
+
+/* Build a list of primitives on the fly. Keep
+ * ctx->Driver.CurrentExecPrimitive uptodate as well.
+ */
+static void GLAPIENTRY st_vbo_exec_Begin( GLenum mode )
+{
+ GET_CURRENT_CONTEXT( ctx );
+
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+ int i;
+
+ if (ctx->NewState) {
+ _mesa_update_state( ctx );
+
+ CALL_Begin(ctx->Exec, (mode));
+ return;
+ }
+
+ if (!st_vbo_validate_shaders(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBegin (invalid vertex/fragment program)");
+ return;
+ }
+
+ /* Heuristic: attempt to isolate attributes occuring outside
+ * begin/end pairs.
+ */
+ if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
+ st_vbo_exec_FlushVertices_internal( ctx, GL_FALSE );
+
+ i = exec->vtx.prim_count++;
+ exec->vtx.prim[i].mode = mode;
+ exec->vtx.prim[i].begin = 1;
+ exec->vtx.prim[i].end = 0;
+ exec->vtx.prim[i].indexed = 0;
+ exec->vtx.prim[i].weak = 0;
+ exec->vtx.prim[i].pad = 0;
+ exec->vtx.prim[i].start = exec->vtx.vert_count;
+ exec->vtx.prim[i].count = 0;
+
+ ctx->Driver.CurrentExecPrimitive = mode;
+ }
+ else
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+
+}
+
+static void GLAPIENTRY st_vbo_exec_End( void )
+{
+ GET_CURRENT_CONTEXT( ctx );
+
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+ int idx = exec->vtx.vert_count;
+ int i = exec->vtx.prim_count - 1;
+
+ exec->vtx.prim[i].end = 1;
+ exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
+
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+
+ if (exec->vtx.prim_count == ST_VBO_MAX_PRIM)
+ st_vbo_exec_vtx_flush( exec, GL_FALSE );
+ }
+ else
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
+}
+
+
+static void st_vbo_exec_vtxfmt_init( struct st_vbo_exec_context *exec )
+{
+ GLvertexformat *vfmt = &exec->vtxfmt;
+
+ vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
+ vfmt->Begin = st_vbo_exec_Begin;
+#if FEATURE_dlist
+ vfmt->CallList = _mesa_CallList;
+ vfmt->CallLists = _mesa_CallLists;
+#endif
+ vfmt->End = st_vbo_exec_End;
+ vfmt->EvalCoord1f = st_vbo_exec_EvalCoord1f;
+ vfmt->EvalCoord1fv = st_vbo_exec_EvalCoord1fv;
+ vfmt->EvalCoord2f = st_vbo_exec_EvalCoord2f;
+ vfmt->EvalCoord2fv = st_vbo_exec_EvalCoord2fv;
+ vfmt->EvalPoint1 = st_vbo_exec_EvalPoint1;
+ vfmt->EvalPoint2 = st_vbo_exec_EvalPoint2;
+
+ vfmt->Rectf = _mesa_noop_Rectf;
+ vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
+ vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
+
+
+ /* from attrib_tmp.h:
+ */
+ vfmt->Color3f = st_vbo_Color3f;
+ vfmt->Color3fv = st_vbo_Color3fv;
+ vfmt->Color4f = st_vbo_Color4f;
+ vfmt->Color4fv = st_vbo_Color4fv;
+ vfmt->FogCoordfEXT = st_vbo_FogCoordfEXT;
+ vfmt->FogCoordfvEXT = st_vbo_FogCoordfvEXT;
+ vfmt->MultiTexCoord1fARB = st_vbo_MultiTexCoord1f;
+ vfmt->MultiTexCoord1fvARB = st_vbo_MultiTexCoord1fv;
+ vfmt->MultiTexCoord2fARB = st_vbo_MultiTexCoord2f;
+ vfmt->MultiTexCoord2fvARB = st_vbo_MultiTexCoord2fv;
+ vfmt->MultiTexCoord3fARB = st_vbo_MultiTexCoord3f;
+ vfmt->MultiTexCoord3fvARB = st_vbo_MultiTexCoord3fv;
+ vfmt->MultiTexCoord4fARB = st_vbo_MultiTexCoord4f;
+ vfmt->MultiTexCoord4fvARB = st_vbo_MultiTexCoord4fv;
+ vfmt->Normal3f = st_vbo_Normal3f;
+ vfmt->Normal3fv = st_vbo_Normal3fv;
+ vfmt->SecondaryColor3fEXT = st_vbo_SecondaryColor3fEXT;
+ vfmt->SecondaryColor3fvEXT = st_vbo_SecondaryColor3fvEXT;
+ vfmt->TexCoord1f = st_vbo_TexCoord1f;
+ vfmt->TexCoord1fv = st_vbo_TexCoord1fv;
+ vfmt->TexCoord2f = st_vbo_TexCoord2f;
+ vfmt->TexCoord2fv = st_vbo_TexCoord2fv;
+ vfmt->TexCoord3f = st_vbo_TexCoord3f;
+ vfmt->TexCoord3fv = st_vbo_TexCoord3fv;
+ vfmt->TexCoord4f = st_vbo_TexCoord4f;
+ vfmt->TexCoord4fv = st_vbo_TexCoord4fv;
+ vfmt->Vertex2f = st_vbo_Vertex2f;
+ vfmt->Vertex2fv = st_vbo_Vertex2fv;
+ vfmt->Vertex3f = st_vbo_Vertex3f;
+ vfmt->Vertex3fv = st_vbo_Vertex3fv;
+ vfmt->Vertex4f = st_vbo_Vertex4f;
+ vfmt->Vertex4fv = st_vbo_Vertex4fv;
+
+ vfmt->VertexAttrib1fARB = st_vbo_VertexAttrib1fARB;
+ vfmt->VertexAttrib1fvARB = st_vbo_VertexAttrib1fvARB;
+ vfmt->VertexAttrib2fARB = st_vbo_VertexAttrib2fARB;
+ vfmt->VertexAttrib2fvARB = st_vbo_VertexAttrib2fvARB;
+ vfmt->VertexAttrib3fARB = st_vbo_VertexAttrib3fARB;
+ vfmt->VertexAttrib3fvARB = st_vbo_VertexAttrib3fvARB;
+ vfmt->VertexAttrib4fARB = st_vbo_VertexAttrib4fARB;
+ vfmt->VertexAttrib4fvARB = st_vbo_VertexAttrib4fvARB;
+
+ vfmt->VertexAttrib1fNV = st_vbo_VertexAttrib1fNV;
+ vfmt->VertexAttrib1fvNV = st_vbo_VertexAttrib1fvNV;
+ vfmt->VertexAttrib2fNV = st_vbo_VertexAttrib2fNV;
+ vfmt->VertexAttrib2fvNV = st_vbo_VertexAttrib2fvNV;
+ vfmt->VertexAttrib3fNV = st_vbo_VertexAttrib3fNV;
+ vfmt->VertexAttrib3fvNV = st_vbo_VertexAttrib3fvNV;
+ vfmt->VertexAttrib4fNV = st_vbo_VertexAttrib4fNV;
+ vfmt->VertexAttrib4fvNV = st_vbo_VertexAttrib4fvNV;
+
+ vfmt->Materialfv = st_vbo_Materialfv;
+
+ vfmt->EdgeFlag = st_vbo_EdgeFlag;
+ vfmt->Indexf = st_vbo_Indexf;
+ vfmt->Indexfv = st_vbo_Indexfv;
+
+}
+
+
+/**
+ * Tell the ST_VBO module to use a real OpenGL vertex buffer object to
+ * store accumulated immediate-mode vertex data.
+ * This replaces the malloced buffer which was created in
+ * vb_exec_vtx_init() below.
+ */
+void st_vbo_use_buffer_objects(GLcontext *ctx)
+{
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+ /* Any buffer name but 0 can be used here since this bufferobj won't
+ * go into the bufferobj hashtable.
+ */
+ GLuint bufName = 0xaabbccdd;
+ GLenum target = GL_ARRAY_BUFFER_ARB;
+ GLenum usage = GL_STREAM_DRAW_ARB;
+ GLsizei size = ST_VBO_VERT_BUFFER_SIZE;
+
+ /* Make sure this func is only used once */
+ assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
+ if (exec->vtx.buffer_map) {
+ _mesa_align_free(exec->vtx.buffer_map);
+ exec->vtx.buffer_map = NULL;
+ exec->vtx.buffer_ptr = NULL;
+ }
+
+ /* Allocate a real buffer object now */
+ exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
+ ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
+}
+
+
+
+void st_vbo_exec_vtx_init( struct st_vbo_exec_context *exec )
+{
+ GLcontext *ctx = exec->ctx;
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ GLuint i;
+
+ /* Allocate a buffer object. Will just reuse this object
+ * continuously, unless st_vbo_use_buffer_objects() is called to enable
+ * use of real ST_VBOs.
+ */
+ _mesa_reference_buffer_object(ctx,
+ &exec->vtx.bufferobj,
+ ctx->Shared->NullBufferObj);
+
+ ASSERT(!exec->vtx.buffer_map);
+ exec->vtx.buffer_map = (GLfloat *)ALIGN_MALLOC(ST_VBO_VERT_BUFFER_SIZE, 64);
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+
+ st_vbo_exec_vtxfmt_init( exec );
+
+ /* Hook our functions into the dispatch table.
+ */
+ _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
+
+ for (i = 0 ; i < ST_VBO_ATTRIB_MAX ; i++) {
+ exec->vtx.attrsz[i] = 0;
+ exec->vtx.active_sz[i] = 0;
+ exec->vtx.inputs[i] = &exec->vtx.arrays[i];
+ }
+
+ {
+ struct gl_client_array *arrays = exec->vtx.arrays;
+ memcpy(arrays, st_vbo->legacy_currval, 16 * sizeof(arrays[0]));
+ memcpy(arrays + 16, st_vbo->generic_currval, 16 * sizeof(arrays[0]));
+ }
+
+ exec->vtx.vertex_size = 0;
+}
+
+
+void st_vbo_exec_vtx_destroy( struct st_vbo_exec_context *exec )
+{
+ if (exec->vtx.bufferobj->Name) {
+ /* using a real ST_VBO for vertex data */
+ GLcontext *ctx = exec->ctx;
+ _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
+ }
+ else {
+ /* just using malloc'd space for vertex data */
+ if (exec->vtx.buffer_map) {
+ ALIGN_FREE(exec->vtx.buffer_map);
+ exec->vtx.buffer_map = NULL;
+ exec->vtx.buffer_ptr = NULL;
+ }
+ }
+}
+
+void st_vbo_exec_BeginVertices( GLcontext *ctx )
+{
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+ if (0) _mesa_printf("%s\n", __FUNCTION__);
+ st_vbo_exec_vtx_map( exec );
+
+ assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
+ exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+}
+
+void st_vbo_exec_FlushVertices_internal( GLcontext *ctx, GLboolean unmap )
+{
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+
+ if (exec->vtx.vert_count || unmap) {
+ st_vbo_exec_vtx_flush( exec, unmap );
+ }
+
+ if (exec->vtx.vertex_size) {
+ st_vbo_exec_copy_to_current( exec );
+ reset_attrfv( exec );
+ }
+}
+
+
+
+void st_vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags )
+{
+ struct st_vbo_exec_context *exec = &st_vbo_context(ctx)->exec;
+
+ if (0) _mesa_printf("%s\n", __FUNCTION__);
+
+ if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ if (0) _mesa_printf("%s - inside begin/end\n", __FUNCTION__);
+ return;
+ }
+
+ st_vbo_exec_FlushVertices_internal( ctx, GL_TRUE );
+
+ /* Need to do this to ensure BeginVertices gets called again:
+ */
+ if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) {
+ _mesa_restore_exec_vtxfmt( ctx );
+ exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
+ }
+
+ exec->ctx->Driver.NeedFlush &= ~flags;
+}
+
+
+static void reset_attrfv( struct st_vbo_exec_context *exec )
+{
+ GLuint i;
+
+ for (i = 0 ; i < ST_VBO_ATTRIB_MAX ; i++) {
+ exec->vtx.attrsz[i] = 0;
+ exec->vtx.active_sz[i] = 0;
+ }
+
+ exec->vtx.vertex_size = 0;
+}
+
+
+void GLAPIENTRY
+_st_vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+{
+ st_vbo_Color4f(r, g, b, a);
+}
+
+
+void GLAPIENTRY
+_st_vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z)
+{
+ st_vbo_Normal3f(x, y, z);
+}
+
+
+void GLAPIENTRY
+_st_vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+ st_vbo_MultiTexCoord4f(target, s, t, r, q);
+}
+
+void GLAPIENTRY
+_st_vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
+{
+ st_vbo_Materialfv(face, pname, params);
+}
+
+
+void GLAPIENTRY
+_st_vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ st_vbo_VertexAttrib4fARB(index, x, y, z, w);
+}
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_exec_array.c b/src/mesa/state_tracker/st_vbo/st_vbo_exec_array.c
new file mode 100644
index 0000000000..449b692ceb
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_exec_array.c
@@ -0,0 +1,503 @@
+/**************************************************************************
+ *
+ * Copyright 2003 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 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 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.
+ *
+ **************************************************************************/
+
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/state.h"
+#include "main/api_validate.h"
+#include "main/api_noop.h"
+#include "main/varray.h"
+#include "main/bufferobj.h"
+#include "glapi/dispatch.h"
+
+#include "st_vbo_context.h"
+
+/* Compute min and max elements for drawelements calls.
+ */
+static void get_minmax_index( GLuint count, GLuint type,
+ const GLvoid *indices,
+ GLuint *min_index,
+ GLuint *max_index)
+{
+ GLuint i;
+
+ switch(type) {
+ case GL_UNSIGNED_INT: {
+ const GLuint *ui_indices = (const GLuint *)indices;
+ GLuint max_ui = ui_indices[count-1];
+ GLuint min_ui = ui_indices[0];
+ for (i = 0; i < count; i++) {
+ if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
+ if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
+ }
+ *min_index = min_ui;
+ *max_index = max_ui;
+ break;
+ }
+ case GL_UNSIGNED_SHORT: {
+ const GLushort *us_indices = (const GLushort *)indices;
+ GLuint max_us = us_indices[count-1];
+ GLuint min_us = us_indices[0];
+ for (i = 0; i < count; i++) {
+ if (us_indices[i] > max_us) max_us = us_indices[i];
+ if (us_indices[i] < min_us) min_us = us_indices[i];
+ }
+ *min_index = min_us;
+ *max_index = max_us;
+ break;
+ }
+ case GL_UNSIGNED_BYTE: {
+ const GLubyte *ub_indices = (const GLubyte *)indices;
+ GLuint max_ub = ub_indices[count-1];
+ GLuint min_ub = ub_indices[0];
+ for (i = 0; i < count; i++) {
+ if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
+ if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
+ }
+ *min_index = min_ub;
+ *max_index = max_ub;
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+}
+
+
+/* Just translate the arrayobj into a sane layout.
+ */
+static void bind_array_obj( GLcontext *ctx )
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct st_vbo_exec_context *exec = &st_vbo->exec;
+ struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
+ GLuint i;
+
+ /* TODO: Fix the ArrayObj struct to keep legacy arrays in an array
+ * rather than as individual named arrays. Then this function can
+ * go away.
+ */
+ exec->array.legacy_array[VERT_ATTRIB_POS] = &arrayObj->Vertex;
+ exec->array.legacy_array[VERT_ATTRIB_WEIGHT] = &st_vbo->legacy_currval[VERT_ATTRIB_WEIGHT];
+ exec->array.legacy_array[VERT_ATTRIB_NORMAL] = &arrayObj->Normal;
+ exec->array.legacy_array[VERT_ATTRIB_COLOR0] = &arrayObj->Color;
+ exec->array.legacy_array[VERT_ATTRIB_COLOR1] = &arrayObj->SecondaryColor;
+ exec->array.legacy_array[VERT_ATTRIB_FOG] = &arrayObj->FogCoord;
+ exec->array.legacy_array[VERT_ATTRIB_COLOR_INDEX] = &arrayObj->Index;
+ if (arrayObj->PointSize.Enabled) {
+ /* this aliases COLOR_INDEX */
+ exec->array.legacy_array[VERT_ATTRIB_POINT_SIZE] = &arrayObj->PointSize;
+ }
+ exec->array.legacy_array[VERT_ATTRIB_EDGEFLAG] = &arrayObj->EdgeFlag;
+
+ for (i = 0; i < 8; i++)
+ exec->array.legacy_array[VERT_ATTRIB_TEX0 + i] = &arrayObj->TexCoord[i];
+
+ for (i = 0; i < VERT_ATTRIB_MAX; i++)
+ exec->array.generic_array[i] = &arrayObj->VertexAttrib[i];
+
+ exec->array.array_obj = arrayObj->Name;
+}
+
+static void recalculate_input_bindings( GLcontext *ctx )
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct st_vbo_exec_context *exec = &st_vbo->exec;
+ const struct gl_client_array **inputs = &exec->array.inputs[0];
+ GLbitfield const_inputs = 0x0;
+ GLuint i;
+
+ exec->array.program_mode = get_program_mode(ctx);
+ exec->array.enabled_flags = ctx->Array.ArrayObj->_Enabled;
+
+ switch (exec->array.program_mode) {
+ case VP_NONE:
+ /* When no vertex program is active, we put the material values
+ * into the generic slots. This is the only situation where
+ * material values are available as per-vertex attributes.
+ */
+ for (i = 0; i <= VERT_ATTRIB_TEX7; i++) {
+ if (exec->array.legacy_array[i]->Enabled)
+ inputs[i] = exec->array.legacy_array[i];
+ else {
+ inputs[i] = &st_vbo->legacy_currval[i];
+ const_inputs |= 1 << i;
+ }
+ }
+
+ for (i = 0; i < MAT_ATTRIB_MAX; i++) {
+ inputs[VERT_ATTRIB_GENERIC0 + i] = &st_vbo->mat_currval[i];
+ const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i);
+ }
+
+ /* Could use just about anything, just to fill in the empty
+ * slots:
+ */
+ for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_MAX - VERT_ATTRIB_GENERIC0; i++) {
+ inputs[VERT_ATTRIB_GENERIC0 + i] = &st_vbo->generic_currval[i];
+ const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i);
+ }
+
+ break;
+ case VP_NV:
+ /* NV_vertex_program - attribute arrays alias and override
+ * conventional, legacy arrays. No materials, and the generic
+ * slots are vacant.
+ */
+ for (i = 0; i <= VERT_ATTRIB_TEX7; i++) {
+ if (exec->array.generic_array[i]->Enabled)
+ inputs[i] = exec->array.generic_array[i];
+ else if (exec->array.legacy_array[i]->Enabled)
+ inputs[i] = exec->array.legacy_array[i];
+ else {
+ inputs[i] = &st_vbo->legacy_currval[i];
+ const_inputs |= 1 << i;
+ }
+ }
+
+ /* Could use just about anything, just to fill in the empty
+ * slots:
+ */
+ for (i = VERT_ATTRIB_GENERIC0; i < VERT_ATTRIB_MAX; i++) {
+ inputs[i] = &st_vbo->generic_currval[i - VERT_ATTRIB_GENERIC0];
+ const_inputs |= 1 << i;
+ }
+
+ break;
+ case VP_ARB:
+ /* ARB_vertex_program - Only the attribute zero (position) array
+ * aliases and overrides the legacy position array.
+ *
+ * Otherwise, legacy attributes available in the legacy slots,
+ * generic attributes in the generic slots and materials are not
+ * available as per-vertex attributes.
+ */
+ if (exec->array.generic_array[0]->Enabled)
+ inputs[0] = exec->array.generic_array[0];
+ else if (exec->array.legacy_array[0]->Enabled)
+ inputs[0] = exec->array.legacy_array[0];
+ else {
+ inputs[0] = &st_vbo->legacy_currval[0];
+ const_inputs |= 1 << 0;
+ }
+
+
+ for (i = 1; i <= VERT_ATTRIB_TEX7; i++) {
+ if (exec->array.legacy_array[i]->Enabled)
+ inputs[i] = exec->array.legacy_array[i];
+ else {
+ inputs[i] = &st_vbo->legacy_currval[i];
+ const_inputs |= 1 << i;
+ }
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (exec->array.generic_array[i]->Enabled)
+ inputs[VERT_ATTRIB_GENERIC0 + i] = exec->array.generic_array[i];
+ else {
+ inputs[VERT_ATTRIB_GENERIC0 + i] = &st_vbo->generic_currval[i];
+ const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i);
+ }
+
+ }
+ break;
+ }
+
+ _mesa_set_varying_vp_inputs( ctx, ~const_inputs );
+}
+
+static void bind_arrays( GLcontext *ctx )
+{
+#if 0
+ if (ctx->Array.ArrayObj.Name != exec->array.array_obj) {
+ bind_array_obj(ctx);
+ recalculate_input_bindings(ctx);
+ }
+ else if (exec->array.program_mode != get_program_mode(ctx) ||
+ exec->array.enabled_flags != ctx->Array.ArrayObj->_Enabled) {
+
+ recalculate_input_bindings(ctx);
+ }
+#else
+ bind_array_obj(ctx);
+ recalculate_input_bindings(ctx);
+#endif
+}
+
+
+
+/***********************************************************************
+ * API functions.
+ */
+
+static void GLAPIENTRY
+st_vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct st_vbo_exec_context *exec = &st_vbo->exec;
+ struct st_mesa_prim prim[1];
+
+ if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
+ return;
+
+ FLUSH_CURRENT( ctx, 0 );
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ if (!st_vbo_validate_shaders(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawArrays(bad shader)");
+ return;
+ }
+
+ bind_arrays( ctx );
+
+ /* Again...
+ */
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ prim[0].begin = 1;
+ prim[0].end = 1;
+ prim[0].weak = 0;
+ prim[0].pad = 0;
+ prim[0].mode = mode;
+ prim[0].start = start;
+ prim[0].count = count;
+ prim[0].indexed = 0;
+
+ st_vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL, start, start + count - 1 );
+
+#if 0
+ {
+ int i;
+
+ _mesa_printf("st_vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n",
+ mode, start, count);
+
+ for (i = 0; i < 32; i++) {
+ GLuint bufName = exec->array.inputs[i]->BufferObj->Name;
+ GLint stride = exec->array.inputs[i]->Stride;
+ _mesa_printf("attr %2d: size %d stride %d enabled %d "
+ "ptr %p Bufobj %u\n",
+ i,
+ exec->array.inputs[i]->Size,
+ stride,
+ /*exec->array.inputs[i]->Enabled,*/
+ exec->array.legacy_array[i]->Enabled,
+ exec->array.inputs[i]->Ptr,
+ bufName);
+
+ if (bufName) {
+ struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, bufName);
+ GLubyte *p = ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY_ARB, buf);
+ int offset = (int) exec->array.inputs[i]->Ptr;
+ float *f = (float *) (p + offset);
+ int *k = (int *) f;
+ int i;
+ int n = (count * stride) / 4;
+ if (n > 32)
+ n = 32;
+ _mesa_printf(" Data at offset %d:\n", offset);
+ for (i = 0; i < n; i++) {
+ _mesa_printf(" float[%d] = 0x%08x %f\n", i, k[i], f[i]);
+ }
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, buf);
+ }
+ }
+ }
+#endif
+}
+
+
+
+static void GLAPIENTRY
+st_vbo_exec_DrawRangeElements(GLenum mode,
+ GLuint start, GLuint end,
+ GLsizei count, GLenum type, const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct st_vbo_exec_context *exec = &st_vbo->exec;
+ struct st_mesa_index_buffer ib;
+ struct st_mesa_prim prim[1];
+
+ if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, type, indices ))
+ return;
+
+ FLUSH_CURRENT( ctx, 0 );
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ if (!st_vbo_validate_shaders(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawRangeElements(bad shader)");
+ return;
+ }
+
+ bind_arrays( ctx );
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ ib.count = count;
+ ib.type = type;
+ ib.obj = ctx->Array.ElementArrayBufferObj;
+ ib.ptr = indices;
+
+ prim[0].begin = 1;
+ prim[0].end = 1;
+ prim[0].weak = 0;
+ prim[0].pad = 0;
+ prim[0].mode = mode;
+ prim[0].start = 0;
+ prim[0].count = count;
+ prim[0].indexed = 1;
+
+ /* Need to give special consideration to rendering a range of
+ * indices starting somewhere above zero. Typically the
+ * application is issuing multiple DrawRangeElements() to draw
+ * successive primitives layed out linearly in the vertex arrays.
+ * Unless the vertex arrays are all in a ST_VBO (or locked as with
+ * CVA), the OpenGL semantics imply that we need to re-read or
+ * re-upload the vertex data on each draw call.
+ *
+ * In the case of hardware tnl, we want to avoid starting the
+ * upload at zero, as it will mean every draw call uploads an
+ * increasing amount of not-used vertex data. Worse - in the
+ * software tnl module, all those vertices might be transformed and
+ * lit but never rendered.
+ *
+ * If we just upload or transform the vertices in start..end,
+ * however, the indices will be incorrect.
+ *
+ * At this level, we don't know exactly what the requirements of
+ * the backend are going to be, though it will likely boil down to
+ * either:
+ *
+ * 1) Do nothing, everything is in a ST_VBO and is processed once
+ * only.
+ *
+ * 2) Adjust the indices and vertex arrays so that start becomes
+ * zero.
+ *
+ * Rather than doing anything here, I'll provide a helper function
+ * for the latter case elsewhere.
+ */
+
+ st_vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, start, end );
+}
+
+static void GLAPIENTRY
+st_vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint min_index = 0;
+ GLuint max_index = 0;
+
+ if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
+ return;
+
+ if (!st_vbo_validate_shaders(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawElements(bad shader)");
+ return;
+ }
+
+ if (ctx->Array.ElementArrayBufferObj->Name) {
+ const GLvoid *map = ctx->Driver.MapBuffer(ctx,
+ GL_ELEMENT_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY,
+ ctx->Array.ElementArrayBufferObj);
+
+ get_minmax_index(count, type, ADD_POINTERS(map, indices), &min_index, &max_index);
+
+ ctx->Driver.UnmapBuffer(ctx,
+ GL_ELEMENT_ARRAY_BUFFER_ARB,
+ ctx->Array.ElementArrayBufferObj);
+ }
+ else {
+ get_minmax_index(count, type, indices, &min_index, &max_index);
+ }
+
+ st_vbo_exec_DrawRangeElements(mode, min_index, max_index, count, type, indices);
+}
+
+
+/***********************************************************************
+ * Initialization
+ */
+
+
+
+
+void st_vbo_exec_array_init( struct st_vbo_exec_context *exec )
+{
+#if 1
+ exec->vtxfmt.DrawArrays = st_vbo_exec_DrawArrays;
+ exec->vtxfmt.DrawElements = st_vbo_exec_DrawElements;
+ exec->vtxfmt.DrawRangeElements = st_vbo_exec_DrawRangeElements;
+#else
+ exec->vtxfmt.DrawArrays = _mesa_noop_DrawArrays;
+ exec->vtxfmt.DrawElements = _mesa_noop_DrawElements;
+ exec->vtxfmt.DrawRangeElements = _mesa_noop_DrawRangeElements;
+#endif
+}
+
+
+void st_vbo_exec_array_destroy( struct st_vbo_exec_context *exec )
+{
+ /* nothing to do */
+}
+
+
+/* This API entrypoint is not ordinarily used */
+void GLAPIENTRY
+_mesa_DrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+ st_vbo_exec_DrawArrays(mode, first, count);
+}
+
+
+/* This API entrypoint is not ordinarily used */
+void GLAPIENTRY
+_mesa_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ st_vbo_exec_DrawElements(mode, count, type, indices);
+}
+
+
+/* This API entrypoint is not ordinarily used */
+void GLAPIENTRY
+_mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
+ GLenum type, const GLvoid *indices)
+{
+ st_vbo_exec_DrawRangeElements(mode, start, end, count, type, indices);
+}
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_exec_draw.c b/src/mesa/state_tracker/st_vbo/st_vbo_exec_draw.c
new file mode 100644
index 0000000000..810f7c1316
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_exec_draw.c
@@ -0,0 +1,385 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.2
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * 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>
+ */
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/context.h"
+#include "main/enums.h"
+#include "main/state.h"
+#include "main/macros.h"
+
+#include "st_vbo_context.h"
+
+
+static void st_vbo_exec_debug_verts( struct st_vbo_exec_context *exec )
+{
+ GLuint count = exec->vtx.vert_count;
+ GLuint i;
+
+ _mesa_printf("%s: %u vertices %d primitives, %d vertsize\n",
+ __FUNCTION__,
+ count,
+ exec->vtx.prim_count,
+ exec->vtx.vertex_size);
+
+ for (i = 0 ; i < exec->vtx.prim_count ; i++) {
+ struct st_mesa_prim *prim = &exec->vtx.prim[i];
+ _mesa_printf(" 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)");
+ }
+}
+
+
+/*
+ * NOTE: Need to have calculated primitives by this point -- do it on the fly.
+ * NOTE: Old 'parity' issue is gone.
+ */
+static GLuint st_vbo_copy_vertices( struct st_vbo_exec_context *exec )
+{
+ GLuint nr = exec->vtx.prim[exec->vtx.prim_count-1].count;
+ GLuint ovf, i;
+ GLuint sz = exec->vtx.vertex_size;
+ GLfloat *dst = exec->vtx.copied.buffer;
+ GLfloat *src = (exec->vtx.buffer_map +
+ exec->vtx.prim[exec->vtx.prim_count-1].start *
+ exec->vtx.vertex_size);
+
+
+ switch( exec->ctx->Driver.CurrentExecPrimitive )
+ {
+ 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:
+ /* no parity issue, but need to make sure the tri is not drawn twice */
+ if (nr & 1) {
+ exec->vtx.prim[exec->vtx.prim_count-1].count--;
+ }
+ /* fallthrough */
+ 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;
+ case PRIM_OUTSIDE_BEGIN_END:
+ return 0;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+
+
+/* TODO: populate these as the vertex is defined:
+ */
+static void st_vbo_exec_bind_arrays( GLcontext *ctx )
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct st_vbo_exec_context *exec = &st_vbo->exec;
+ struct gl_client_array *arrays = exec->vtx.arrays;
+ GLuint count = exec->vtx.vert_count;
+ GLubyte *data = (GLubyte *)exec->vtx.buffer_map;
+ const GLuint *map;
+ GLuint attr;
+ GLbitfield varying_inputs = 0x0;
+
+ /* Install the default (ie Current) attributes first, then overlay
+ * all active ones.
+ */
+ switch (get_program_mode(exec->ctx)) {
+ case VP_NONE:
+ for (attr = 0; attr < 16; attr++) {
+ exec->vtx.inputs[attr] = &st_vbo->legacy_currval[attr];
+ }
+ for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
+ exec->vtx.inputs[attr + 16] = &st_vbo->mat_currval[attr];
+ }
+ map = st_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.
+ */
+ for (attr = 0; attr < 16; attr++) {
+ exec->vtx.inputs[attr] = &st_vbo->legacy_currval[attr];
+ exec->vtx.inputs[attr + 16] = &st_vbo->generic_currval[attr];
+ }
+ map = st_vbo->map_vp_arb;
+
+ /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
+ * In that case we effectively need to route the data from
+ * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
+ */
+ if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
+ (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
+ exec->vtx.inputs[16] = exec->vtx.inputs[0];
+ exec->vtx.attrsz[16] = exec->vtx.attrsz[0];
+ exec->vtx.attrsz[0] = 0;
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ /* Make all active attributes (including edgeflag) available as
+ * arrays of floats.
+ */
+ for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) {
+ const GLuint src = map[attr];
+
+ if (exec->vtx.attrsz[src]) {
+ /* override the default array set above */
+ exec->vtx.inputs[attr] = &arrays[attr];
+
+ if (exec->vtx.bufferobj->Name) {
+ /* a real buffer obj: Ptr is an offset, not a pointer*/
+ GLsizeiptr offset;
+ assert(exec->vtx.bufferobj->Pointer); /* buf should be mapped */
+ offset = (GLbyte *) data - (GLbyte *) exec->vtx.bufferobj->Pointer;
+ assert(offset >= 0);
+ arrays[attr].Ptr = (void *) offset;
+ }
+ else {
+ /* Ptr into ordinary app memory */
+ arrays[attr].Ptr = (void *) data;
+ }
+ arrays[attr].Size = exec->vtx.attrsz[src];
+ arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat);
+ arrays[attr].Stride = exec->vtx.vertex_size * sizeof(GLfloat);
+ arrays[attr].Type = GL_FLOAT;
+ arrays[attr].Format = GL_RGBA;
+ arrays[attr].Enabled = 1;
+ _mesa_reference_buffer_object(ctx,
+ &arrays[attr].BufferObj,
+ exec->vtx.bufferobj);
+ arrays[attr]._MaxElement = count; /* ??? */
+
+ data += exec->vtx.attrsz[src] * sizeof(GLfloat);
+ varying_inputs |= 1<<attr;
+ }
+ }
+
+ _mesa_set_varying_vp_inputs( ctx, varying_inputs );
+}
+
+
+static void st_vbo_exec_vtx_unmap( struct st_vbo_exec_context *exec )
+{
+ GLenum target = GL_ARRAY_BUFFER_ARB;
+
+ if (exec->vtx.bufferobj->Name) {
+ GLcontext *ctx = exec->ctx;
+
+ if(ctx->Driver.FlushMappedBufferRange) {
+ GLintptr offset = exec->vtx.buffer_used - exec->vtx.bufferobj->Offset;
+ GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * sizeof(float);
+
+ if(length)
+ ctx->Driver.FlushMappedBufferRange(ctx, target,
+ offset, length,
+ exec->vtx.bufferobj);
+ }
+
+ exec->vtx.buffer_used += (exec->vtx.buffer_ptr -
+ exec->vtx.buffer_map) * sizeof(float);
+
+ assert(exec->vtx.buffer_used <= ST_VBO_VERT_BUFFER_SIZE);
+ assert(exec->vtx.buffer_ptr != NULL);
+
+ ctx->Driver.UnmapBuffer(ctx, target, exec->vtx.bufferobj);
+ exec->vtx.buffer_map = NULL;
+ exec->vtx.buffer_ptr = NULL;
+ exec->vtx.max_vert = 0;
+ }
+}
+
+void st_vbo_exec_vtx_map( struct st_vbo_exec_context *exec )
+{
+ GLcontext *ctx = exec->ctx;
+ GLenum target = GL_ARRAY_BUFFER_ARB;
+ GLenum access = GL_READ_WRITE_ARB;
+ GLenum usage = GL_STREAM_DRAW_ARB;
+
+ if (exec->vtx.bufferobj->Name == 0)
+ return;
+
+ if (exec->vtx.buffer_map != NULL) {
+ assert(0);
+ exec->vtx.buffer_map = NULL;
+ exec->vtx.buffer_ptr = NULL;
+ }
+
+ if (ST_VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024 &&
+ ctx->Driver.MapBufferRange)
+ {
+ exec->vtx.buffer_map =
+ (GLfloat *)ctx->Driver.MapBufferRange(ctx,
+ target,
+ exec->vtx.buffer_used,
+ (ST_VBO_VERT_BUFFER_SIZE -
+ exec->vtx.buffer_used),
+ (GL_MAP_WRITE_BIT |
+ GL_MAP_INVALIDATE_RANGE_BIT |
+ GL_MAP_UNSYNCHRONIZED_BIT |
+ MESA_MAP_NOWAIT_BIT),
+ exec->vtx.bufferobj);
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ }
+
+ if (!exec->vtx.buffer_map) {
+ exec->vtx.buffer_used = 0;
+
+ ctx->Driver.BufferData(ctx, target,
+ ST_VBO_VERT_BUFFER_SIZE,
+ NULL, usage, exec->vtx.bufferobj);
+
+ exec->vtx.buffer_map =
+ (GLfloat *)ctx->Driver.MapBuffer(ctx, target, access, exec->vtx.bufferobj);
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ }
+
+ if (0) _mesa_printf("map %d..\n", exec->vtx.buffer_used);
+}
+
+
+
+/**
+ * Execute the buffer and save copied verts.
+ */
+void st_vbo_exec_vtx_flush( struct st_vbo_exec_context *exec,
+ GLboolean unmap )
+{
+ if (0)
+ st_vbo_exec_debug_verts( exec );
+
+
+ if (exec->vtx.prim_count &&
+ exec->vtx.vert_count) {
+
+ exec->vtx.copied.nr = st_vbo_copy_vertices( exec );
+
+ if (exec->vtx.copied.nr != exec->vtx.vert_count) {
+ GLcontext *ctx = exec->ctx;
+
+ /* Before the update_state() as this may raise _NEW_ARRAY
+ * from _mesa_set_varying_vp_inputs().
+ */
+ st_vbo_exec_bind_arrays( ctx );
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ if (exec->vtx.bufferobj->Name) {
+ st_vbo_exec_vtx_unmap( exec );
+ }
+
+ if (0) _mesa_printf("%s %d %d\n", __FUNCTION__, exec->vtx.prim_count,
+ exec->vtx.vert_count);
+
+ st_vbo_context(ctx)->draw_prims( ctx,
+ exec->vtx.inputs,
+ exec->vtx.prim,
+ exec->vtx.prim_count,
+ NULL,
+ 0,
+ exec->vtx.vert_count - 1);
+
+ /* If using a real ST_VBO, get new storage -- unless asked not to.
+ */
+ if (exec->vtx.bufferobj->Name && !unmap) {
+ st_vbo_exec_vtx_map( exec );
+ }
+ }
+ }
+
+ /* May have to unmap explicitly if we didn't draw:
+ */
+ if (unmap &&
+ exec->vtx.bufferobj->Name &&
+ exec->vtx.buffer_map) {
+ st_vbo_exec_vtx_unmap( exec );
+ }
+
+
+ if (unmap)
+ exec->vtx.max_vert = 0;
+ else
+ exec->vtx.max_vert = ((ST_VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
+ (exec->vtx.vertex_size * sizeof(GLfloat)));
+
+
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ exec->vtx.prim_count = 0;
+ exec->vtx.vert_count = 0;
+}
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_exec_eval.c b/src/mesa/state_tracker/st_vbo/st_vbo_exec_eval.c
new file mode 100644
index 0000000000..5f7fc77185
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_exec_eval.c
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "math/m_eval.h"
+#include "glapi/dispatch.h"
+#include "st_vbo_exec.h"
+
+
+static void clear_active_eval1( struct st_vbo_exec_context *exec, GLuint attr )
+{
+ exec->eval.map1[attr].map = NULL;
+}
+
+static void clear_active_eval2( struct st_vbo_exec_context *exec, GLuint attr )
+{
+ exec->eval.map2[attr].map = NULL;
+}
+
+static void set_active_eval1( struct st_vbo_exec_context *exec, GLuint attr, GLuint dim,
+ struct gl_1d_map *map )
+{
+ if (!exec->eval.map1[attr].map) {
+ exec->eval.map1[attr].map = map;
+ exec->eval.map1[attr].sz = dim;
+ }
+}
+
+static void set_active_eval2( struct st_vbo_exec_context *exec, GLuint attr, GLuint dim,
+ struct gl_2d_map *map )
+{
+ if (!exec->eval.map2[attr].map) {
+ exec->eval.map2[attr].map = map;
+ exec->eval.map2[attr].sz = dim;
+ }
+}
+
+void st_vbo_exec_eval_update( struct st_vbo_exec_context *exec )
+{
+ GLcontext *ctx = exec->ctx;
+ GLuint attr;
+
+ /* Vertex program maps have priority over conventional attribs */
+
+ for (attr = 0; attr < ST_VBO_ATTRIB_FIRST_MATERIAL; attr++) {
+ clear_active_eval1( exec, attr );
+ clear_active_eval2( exec, attr );
+ }
+
+ /* _NEW_PROGRAM */
+ if (ctx->VertexProgram._Enabled) {
+ for (attr = 0; attr < ST_VBO_ATTRIB_FIRST_MATERIAL; attr++) {
+ /* _NEW_EVAL */
+ if (ctx->Eval.Map1Attrib[attr])
+ set_active_eval1( exec, attr, 4, &ctx->EvalMap.Map1Attrib[attr] );
+
+ if (ctx->Eval.Map2Attrib[attr])
+ set_active_eval2( exec, attr, 4, &ctx->EvalMap.Map2Attrib[attr] );
+ }
+ }
+
+ if (ctx->Eval.Map1Color4)
+ set_active_eval1( exec, ST_VBO_ATTRIB_COLOR0, 4, &ctx->EvalMap.Map1Color4 );
+
+ if (ctx->Eval.Map2Color4)
+ set_active_eval2( exec, ST_VBO_ATTRIB_COLOR0, 4, &ctx->EvalMap.Map2Color4 );
+
+ if (ctx->Eval.Map1TextureCoord4)
+ set_active_eval1( exec, ST_VBO_ATTRIB_TEX0, 4, &ctx->EvalMap.Map1Texture4 );
+ else if (ctx->Eval.Map1TextureCoord3)
+ set_active_eval1( exec, ST_VBO_ATTRIB_TEX0, 3, &ctx->EvalMap.Map1Texture3 );
+ else if (ctx->Eval.Map1TextureCoord2)
+ set_active_eval1( exec, ST_VBO_ATTRIB_TEX0, 2, &ctx->EvalMap.Map1Texture2 );
+ else if (ctx->Eval.Map1TextureCoord1)
+ set_active_eval1( exec, ST_VBO_ATTRIB_TEX0, 1, &ctx->EvalMap.Map1Texture1 );
+
+ if (ctx->Eval.Map2TextureCoord4)
+ set_active_eval2( exec, ST_VBO_ATTRIB_TEX0, 4, &ctx->EvalMap.Map2Texture4 );
+ else if (ctx->Eval.Map2TextureCoord3)
+ set_active_eval2( exec, ST_VBO_ATTRIB_TEX0, 3, &ctx->EvalMap.Map2Texture3 );
+ else if (ctx->Eval.Map2TextureCoord2)
+ set_active_eval2( exec, ST_VBO_ATTRIB_TEX0, 2, &ctx->EvalMap.Map2Texture2 );
+ else if (ctx->Eval.Map2TextureCoord1)
+ set_active_eval2( exec, ST_VBO_ATTRIB_TEX0, 1, &ctx->EvalMap.Map2Texture1 );
+
+ if (ctx->Eval.Map1Normal)
+ set_active_eval1( exec, ST_VBO_ATTRIB_NORMAL, 3, &ctx->EvalMap.Map1Normal );
+
+ if (ctx->Eval.Map2Normal)
+ set_active_eval2( exec, ST_VBO_ATTRIB_NORMAL, 3, &ctx->EvalMap.Map2Normal );
+
+ if (ctx->Eval.Map1Vertex4)
+ set_active_eval1( exec, ST_VBO_ATTRIB_POS, 4, &ctx->EvalMap.Map1Vertex4 );
+ else if (ctx->Eval.Map1Vertex3)
+ set_active_eval1( exec, ST_VBO_ATTRIB_POS, 3, &ctx->EvalMap.Map1Vertex3 );
+
+ if (ctx->Eval.Map2Vertex4)
+ set_active_eval2( exec, ST_VBO_ATTRIB_POS, 4, &ctx->EvalMap.Map2Vertex4 );
+ else if (ctx->Eval.Map2Vertex3)
+ set_active_eval2( exec, ST_VBO_ATTRIB_POS, 3, &ctx->EvalMap.Map2Vertex3 );
+
+ exec->eval.recalculate_maps = 0;
+}
+
+
+
+void st_vbo_exec_do_EvalCoord1f(struct st_vbo_exec_context *exec, GLfloat u)
+{
+ GLuint attr;
+
+ for (attr = 1; attr <= ST_VBO_ATTRIB_TEX7; attr++) {
+ struct gl_1d_map *map = exec->eval.map1[attr].map;
+ if (map) {
+ GLfloat uu = (u - map->u1) * map->du;
+ GLfloat data[4];
+
+ ASSIGN_4V(data, 0, 0, 0, 1);
+
+ _math_horner_bezier_curve(map->Points, data, uu,
+ exec->eval.map1[attr].sz,
+ map->Order);
+
+ COPY_SZ_4V( exec->vtx.attrptr[attr],
+ exec->vtx.attrsz[attr],
+ data );
+ }
+ }
+
+ /** Vertex -- EvalCoord1f is a noop if this map not enabled:
+ **/
+ if (exec->eval.map1[0].map) {
+ struct gl_1d_map *map = exec->eval.map1[0].map;
+ GLfloat uu = (u - map->u1) * map->du;
+ GLfloat vertex[4];
+
+ ASSIGN_4V(vertex, 0, 0, 0, 1);
+
+ _math_horner_bezier_curve(map->Points, vertex, uu,
+ exec->eval.map1[0].sz,
+ map->Order);
+
+ if (exec->eval.map1[0].sz == 4)
+ CALL_Vertex4fv(GET_DISPATCH(), ( vertex ));
+ else
+ CALL_Vertex3fv(GET_DISPATCH(), ( vertex ));
+ }
+}
+
+
+
+void st_vbo_exec_do_EvalCoord2f( struct st_vbo_exec_context *exec,
+ GLfloat u, GLfloat v )
+{
+ GLuint attr;
+
+ for (attr = 1; attr <= ST_VBO_ATTRIB_TEX7; attr++) {
+ struct gl_2d_map *map = exec->eval.map2[attr].map;
+ if (map) {
+ GLfloat uu = (u - map->u1) * map->du;
+ GLfloat vv = (v - map->v1) * map->dv;
+ GLfloat data[4];
+
+ ASSIGN_4V(data, 0, 0, 0, 1);
+
+ _math_horner_bezier_surf(map->Points,
+ data,
+ uu, vv,
+ exec->eval.map2[attr].sz,
+ map->Uorder, map->Vorder);
+
+ COPY_SZ_4V( exec->vtx.attrptr[attr],
+ exec->vtx.attrsz[attr],
+ data );
+ }
+ }
+
+ /** Vertex -- EvalCoord2f is a noop if this map not enabled:
+ **/
+ if (exec->eval.map2[0].map) {
+ struct gl_2d_map *map = exec->eval.map2[0].map;
+ GLfloat uu = (u - map->u1) * map->du;
+ GLfloat vv = (v - map->v1) * map->dv;
+ GLfloat vertex[4];
+
+ ASSIGN_4V(vertex, 0, 0, 0, 1);
+
+ if (exec->ctx->Eval.AutoNormal) {
+ GLfloat normal[4];
+ GLfloat du[4], dv[4];
+
+ _math_de_casteljau_surf(map->Points, vertex, du, dv, uu, vv,
+ exec->eval.map2[0].sz,
+ map->Uorder, map->Vorder);
+
+ if (exec->eval.map2[0].sz == 4) {
+ du[0] = du[0]*vertex[3] - du[3]*vertex[0];
+ du[1] = du[1]*vertex[3] - du[3]*vertex[1];
+ du[2] = du[2]*vertex[3] - du[3]*vertex[2];
+
+ dv[0] = dv[0]*vertex[3] - dv[3]*vertex[0];
+ dv[1] = dv[1]*vertex[3] - dv[3]*vertex[1];
+ dv[2] = dv[2]*vertex[3] - dv[3]*vertex[2];
+ }
+
+
+ CROSS3(normal, du, dv);
+ NORMALIZE_3FV(normal);
+ normal[3] = 1.0;
+
+ COPY_SZ_4V( exec->vtx.attrptr[ST_VBO_ATTRIB_NORMAL],
+ exec->vtx.attrsz[ST_VBO_ATTRIB_NORMAL],
+ normal );
+
+ }
+ else {
+ _math_horner_bezier_surf(map->Points, vertex, uu, vv,
+ exec->eval.map2[0].sz,
+ map->Uorder, map->Vorder);
+ }
+
+ if (exec->vtx.attrsz[0] == 4)
+ CALL_Vertex4fv(GET_DISPATCH(), ( vertex ));
+ else
+ CALL_Vertex3fv(GET_DISPATCH(), ( vertex ));
+ }
+}
+
+
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_save.c b/src/mesa/state_tracker/st_vbo/st_vbo_save.c
new file mode 100644
index 0000000000..92919958ea
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_save.c
@@ -0,0 +1,110 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.2
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * 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>
+ */
+
+
+#include "main/mtypes.h"
+#include "main/bufferobj.h"
+#include "main/dlist.h"
+#include "main/vtxfmt.h"
+#include "main/imports.h"
+
+#include "st_vbo_context.h"
+
+
+
+static void st_vbo_save_callback_init( GLcontext *ctx )
+{
+ ctx->Driver.NewList = st_vbo_save_NewList;
+ ctx->Driver.EndList = st_vbo_save_EndList;
+ ctx->Driver.SaveFlushVertices = st_vbo_save_SaveFlushVertices;
+ ctx->Driver.BeginCallList = st_vbo_save_BeginCallList;
+ ctx->Driver.EndCallList = st_vbo_save_EndCallList;
+ ctx->Driver.NotifySaveBegin = st_vbo_save_NotifyBegin;
+}
+
+
+
+void st_vbo_save_init( GLcontext *ctx )
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct st_vbo_save_context *save = &st_vbo->save;
+
+ save->ctx = ctx;
+
+ st_vbo_save_api_init( save );
+ st_vbo_save_callback_init(ctx);
+
+ {
+ struct gl_client_array *arrays = save->arrays;
+ memcpy(arrays, st_vbo->legacy_currval, 16 * sizeof(arrays[0]));
+ memcpy(arrays + 16, st_vbo->generic_currval, 16 * sizeof(arrays[0]));
+ }
+
+ ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
+}
+
+
+void st_vbo_save_destroy( GLcontext *ctx )
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct st_vbo_save_context *save = &st_vbo->save;
+ GLuint i;
+
+ if (save->prim_store) {
+ if ( --save->prim_store->refcount == 0 ) {
+ FREE( save->prim_store );
+ save->prim_store = NULL;
+ }
+ if ( --save->vertex_store->refcount == 0 ) {
+ _mesa_reference_buffer_object(ctx,
+ &save->vertex_store->bufferobj, NULL);
+ FREE( save->vertex_store );
+ save->vertex_store = NULL;
+ }
+ }
+
+ for (i = 0; i < ST_VBO_ATTRIB_MAX; i++) {
+ _mesa_reference_buffer_object(ctx, &save->arrays[i].BufferObj, NULL);
+ }
+}
+
+
+
+
+/* Note that this can occur during the playback of a display list:
+ */
+void st_vbo_save_fallback( GLcontext *ctx, GLboolean fallback )
+{
+ struct st_vbo_save_context *save = &st_vbo_context(ctx)->save;
+
+ if (fallback)
+ save->replay_flags |= ST_VBO_SAVE_FALLBACK;
+ else
+ save->replay_flags &= ~ST_VBO_SAVE_FALLBACK;
+}
+
+
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_save.h b/src/mesa/state_tracker/st_vbo/st_vbo_save.h
new file mode 100644
index 0000000000..8bd9008641
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_save.h
@@ -0,0 +1,184 @@
+/**************************************************************************
+
+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>
+ *
+ */
+
+#ifndef ST_VBO_SAVE_H
+#define ST_VBO_SAVE_H
+
+#include "main/mtypes.h"
+#include "st_vbo.h"
+#include "st_vbo_attrib.h"
+
+
+struct st_vbo_save_copied_vtx {
+ GLfloat buffer[ST_VBO_ATTRIB_MAX * 4 * ST_VBO_MAX_COPIED_VERTS];
+ GLuint nr;
+};
+
+
+/* For display lists, this structure holds a run of vertices of the
+ * same format, and a strictly well-formed set of begin/end pairs,
+ * starting on the first vertex and ending at the last. Vertex
+ * copying on buffer breaks is precomputed according to these
+ * primitives, though there are situations where the copying will need
+ * correction at execute-time, perhaps by replaying the list as
+ * immediate mode commands.
+ *
+ * On executing this list, the 'current' values may be updated with
+ * the values of the final vertex, and often no fixup of the start of
+ * the vertex list is required.
+ *
+ * Eval and other commands that don't fit into these vertex lists are
+ * compiled using the fallback opcode mechanism provided by dlist.c.
+ */
+struct st_vbo_save_vertex_list {
+ GLubyte attrsz[ST_VBO_ATTRIB_MAX];
+ GLuint vertex_size;
+
+ /* Copy of the final vertex from node->vertex_store->bufferobj.
+ * Keep this in regular (non-ST_VBO) memory to avoid repeated
+ * map/unmap of the ST_VBO when updating GL current data.
+ */
+ GLfloat *current_data;
+ GLuint current_size;
+
+ GLuint buffer_offset;
+ GLuint count;
+ GLuint wrap_count; /* number of copied vertices at start */
+ GLboolean dangling_attr_ref; /* current attr implicitly referenced
+ outside the list */
+
+ struct st_mesa_prim *prim;
+ GLuint prim_count;
+
+ struct st_vbo_save_vertex_store *vertex_store;
+ struct st_vbo_save_primitive_store *prim_store;
+};
+
+/* These buffers should be a reasonable size to support upload to
+ * hardware. Current st_vbo implementation will re-upload on any
+ * changes, so don't make too big or apps which dynamically create
+ * dlists and use only a few times will suffer.
+ *
+ * Consider stategy of uploading regions from the ST_VBO on demand in the
+ * case of dynamic st_vbos. Then make the dlist code signal that
+ * likelyhood as it occurs. No reason we couldn't change usage
+ * internally even though this probably isn't allowed for client ST_VBOs?
+ */
+#define ST_VBO_SAVE_BUFFER_SIZE (8*1024) /* dwords */
+#define ST_VBO_SAVE_PRIM_SIZE 128
+#define ST_VBO_SAVE_PRIM_WEAK 0x40
+
+#define ST_VBO_SAVE_FALLBACK 0x10000000
+
+/* Storage to be shared among several vertex_lists.
+ */
+struct st_vbo_save_vertex_store {
+ struct gl_buffer_object *bufferobj;
+ GLfloat *buffer;
+ GLuint used;
+ GLuint refcount;
+};
+
+struct st_vbo_save_primitive_store {
+ struct st_mesa_prim buffer[ST_VBO_SAVE_PRIM_SIZE];
+ GLuint used;
+ GLuint refcount;
+};
+
+
+struct st_vbo_save_context {
+ GLcontext *ctx;
+ GLvertexformat vtxfmt;
+ struct gl_client_array arrays[ST_VBO_ATTRIB_MAX];
+ const struct gl_client_array *inputs[ST_VBO_ATTRIB_MAX];
+
+ GLubyte attrsz[ST_VBO_ATTRIB_MAX];
+ GLubyte active_sz[ST_VBO_ATTRIB_MAX];
+ GLuint vertex_size;
+
+ GLfloat *buffer;
+ GLuint count;
+ GLuint wrap_count;
+ GLuint replay_flags;
+
+ struct st_mesa_prim *prim;
+ GLuint prim_count, prim_max;
+
+ struct st_vbo_save_vertex_store *vertex_store;
+ struct st_vbo_save_primitive_store *prim_store;
+
+ GLfloat *buffer_ptr; /* cursor, points into buffer */
+ GLfloat vertex[ST_VBO_ATTRIB_MAX*4]; /* current values */
+ GLfloat *attrptr[ST_VBO_ATTRIB_MAX];
+ GLuint vert_count;
+ GLuint max_vert;
+ GLboolean dangling_attr_ref;
+ GLboolean have_materials;
+
+ GLuint opcode_vertex_list;
+
+ struct st_vbo_save_copied_vtx copied;
+
+ GLfloat *current[ST_VBO_ATTRIB_MAX]; /* points into ctx->ListState */
+ GLubyte *currentsz[ST_VBO_ATTRIB_MAX];
+};
+
+
+void st_vbo_save_init( GLcontext *ctx );
+void st_vbo_save_destroy( GLcontext *ctx );
+void st_vbo_save_fallback( GLcontext *ctx, GLboolean fallback );
+
+/* save_loopback.c:
+ */
+void st_vbo_loopback_vertex_list( GLcontext *ctx,
+ const GLfloat *buffer,
+ const GLubyte *attrsz,
+ const struct st_mesa_prim *prim,
+ GLuint prim_count,
+ GLuint wrap_count,
+ GLuint vertex_size);
+
+/* Callbacks:
+ */
+void st_vbo_save_EndList( GLcontext *ctx );
+void st_vbo_save_NewList( GLcontext *ctx, GLuint list, GLenum mode );
+void st_vbo_save_EndCallList( GLcontext *ctx );
+void st_vbo_save_BeginCallList( GLcontext *ctx, struct gl_display_list *list );
+void st_vbo_save_SaveFlushVertices( GLcontext *ctx );
+GLboolean st_vbo_save_NotifyBegin( GLcontext *ctx, GLenum mode );
+
+void st_vbo_save_playback_vertex_list( GLcontext *ctx, void *data );
+
+void st_vbo_save_api_init( struct st_vbo_save_context *save );
+
+#endif
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_save_api.c b/src/mesa/state_tracker/st_vbo/st_vbo_save_api.c
new file mode 100644
index 0000000000..4ea24e8d16
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_save_api.c
@@ -0,0 +1,1214 @@
+/**************************************************************************
+
+Copyright 2002-2008 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 "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/context.h"
+#include "main/dlist.h"
+#include "main/enums.h"
+#include "main/macros.h"
+#include "main/api_validate.h"
+#include "main/api_arrayelt.h"
+#include "main/vtxfmt.h"
+#include "glapi/dispatch.h"
+
+#include "st_vbo_context.h"
+
+
+#ifdef ERROR
+#undef ERROR
+#endif
+
+
+/* An interesting ST_VBO number/name to help with debugging */
+#define ST_VBO_BUF_ID 12345
+
+
+/*
+ * NOTE: Old 'parity' issue is gone, but copying can still be
+ * wrong-footed on replay.
+ */
+static GLuint _save_copy_vertices( GLcontext *ctx,
+ const struct st_vbo_save_vertex_list *node,
+ const GLfloat *src_buffer)
+{
+ struct st_vbo_save_context *save = &st_vbo_context( ctx )->save;
+ const struct st_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 st_vbo_save_vertex_store *alloc_vertex_store( GLcontext *ctx )
+{
+ struct st_vbo_save_vertex_store *vertex_store = CALLOC_STRUCT(st_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,
+ ST_VBO_BUF_ID,
+ GL_ARRAY_BUFFER_ARB);
+
+ ctx->Driver.BufferData( ctx,
+ GL_ARRAY_BUFFER_ARB,
+ ST_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 st_vbo_save_vertex_store *vertex_store )
+{
+ assert(!vertex_store->buffer);
+
+ if (vertex_store->bufferobj) {
+ _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
+ }
+
+ FREE( vertex_store );
+}
+
+static GLfloat *map_vertex_store( GLcontext *ctx, struct st_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_WRITE_ONLY, /* not used */
+ vertex_store->bufferobj);
+
+ assert(vertex_store->buffer);
+ return vertex_store->buffer + vertex_store->used;
+}
+
+static void unmap_vertex_store( GLcontext *ctx, struct st_vbo_save_vertex_store *vertex_store )
+{
+ ctx->Driver.UnmapBuffer( ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj );
+ vertex_store->buffer = NULL;
+}
+
+
+static struct st_vbo_save_primitive_store *alloc_prim_store( GLcontext *ctx )
+{
+ struct st_vbo_save_primitive_store *store = CALLOC_STRUCT(st_vbo_save_primitive_store);
+ (void) ctx;
+ store->used = 0;
+ store->refcount = 1;
+ return store;
+}
+
+static void _save_reset_counters( GLcontext *ctx )
+{
+ struct st_vbo_save_context *save = &st_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->buffer_ptr);
+
+ if (save->vertex_size)
+ save->max_vert = ((ST_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 = ST_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 st_vbo_save_context *save = &st_vbo_context(ctx)->save;
+ struct st_vbo_save_vertex_list *node;
+
+ /* Allocate space for this structure in the display list currently
+ * being compiled.
+ */
+ node = (struct st_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++;
+
+
+ node->current_size = node->vertex_size - node->attrsz[0];
+ node->current_data = NULL;
+
+ if (node->current_size) {
+ /* If the malloc fails, we just pull the data out of the ST_VBO
+ * later instead.
+ */
+ node->current_data = MALLOC( node->current_size * sizeof(GLfloat) );
+ if (node->current_data) {
+ const char *buffer = (const char *)save->vertex_store->buffer;
+ unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
+ unsigned vertex_offset = 0;
+
+ if (node->count)
+ vertex_offset = (node->count-1) * node->vertex_size * sizeof(GLfloat);
+
+ memcpy( node->current_data,
+ buffer + node->buffer_offset + vertex_offset + attr_offset,
+ node->current_size * sizeof(GLfloat) );
+ }
+ }
+
+
+
+ assert(node->attrsz[ST_VBO_ATTRIB_POS] != 0 ||
+ node->count == 0);
+
+ if (save->dangling_attr_ref)
+ ctx->ListState.CurrentList->Flags |= 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);
+
+ st_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 >
+ ST_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->buffer_ptr = map_vertex_store( ctx, save->vertex_store );
+ }
+
+ if (save->prim_store->used > ST_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 st_vbo_save_context *save = &st_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 st_vbo_save_context *save = &st_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->buffer_ptr, data, save->vertex_size * sizeof(GLfloat));
+ data += save->vertex_size;
+ save->buffer_ptr += save->vertex_size;
+ save->vert_count++;
+ }
+}
+
+
+static void _save_copy_to_current( GLcontext *ctx )
+{
+ struct st_vbo_save_context *save = &st_vbo_context(ctx)->save;
+ GLuint i;
+
+ for (i = ST_VBO_ATTRIB_POS+1 ; i < ST_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 st_vbo_save_context *save = &st_vbo_context(ctx)->save;
+ GLint i;
+
+ for (i = ST_VBO_ATTRIB_POS+1 ; i < ST_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 st_vbo_save_context *save = &st_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 = ((ST_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 < ST_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 != ST_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 < ST_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->buffer_ptr = dest;
+ save->vert_count += save->copied.nr;
+ }
+}
+
+static void save_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
+{
+ struct st_vbo_save_context *save = &st_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 st_vbo_save_context *save = &st_vbo_context(ctx)->save;
+ GLuint i;
+
+ for (i = 0 ; i < ST_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 st_vbo_save_context *save = &st_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->buffer_ptr[i] = save->vertex[i]; \
+ \
+ save->buffer_ptr += save->vertex_size; \
+ \
+ if (++save->vert_count >= save->max_vert) \
+ _save_wrap_filled_vertex( ctx ); \
+ } \
+} while (0)
+
+#define TAG(x) _save_##x
+
+#include "st_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 st_vbo_save_context *save = &st_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 st_vbo_save_NotifyBegin( GLcontext *ctx, GLenum mode )
+{
+ struct st_vbo_save_context *save = &st_vbo_context(ctx)->save;
+
+ GLuint i = save->prim_count++;
+
+ assert(i < save->prim_max);
+ save->prim[i].mode = mode & ~ST_VBO_SAVE_PRIM_WEAK;
+ save->prim[i].begin = 1;
+ save->prim[i].end = 0;
+ save->prim[i].weak = (mode & ST_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 st_vbo_save_context *save = &st_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);
+ st_vbo_save_NotifyBegin( ctx, GL_QUADS | ST_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_st_vbos( ctx );
+
+ st_vbo_save_NotifyBegin( ctx, mode | ST_VBO_SAVE_PRIM_WEAK );
+
+ for (i = 0; i < count; i++)
+ CALL_ArrayElement(GET_DISPATCH(), (start + i));
+ CALL_End(GET_DISPATCH(), ());
+
+ _ae_unmap_st_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_st_vbos( ctx );
+
+ if (ctx->Array.ElementArrayBufferObj->Name)
+ indices = ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Pointer, indices);
+
+ st_vbo_save_NotifyBegin( ctx, mode | ST_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_st_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 st_vbo_save_context *save = &st_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 st_vbo_save_SaveFlushVertices( GLcontext *ctx )
+{
+ struct st_vbo_save_context *save = &st_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 st_vbo_save_NewList( GLcontext *ctx, GLuint list, GLenum mode )
+{
+ struct st_vbo_save_context *save = &st_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->buffer_ptr = map_vertex_store( ctx, save->vertex_store );
+
+ _save_reset_vertex( ctx );
+ _save_reset_counters( ctx );
+ ctx->Driver.SaveNeedFlush = 0;
+}
+
+void st_vbo_save_EndList( GLcontext *ctx )
+{
+ struct st_vbo_save_context *save = &st_vbo_context(ctx)->save;
+
+ /* EndList called inside a (saved) Begin/End pair?
+ */
+ if (ctx->Driver.CurrentSavePrimitive != PRIM_OUTSIDE_BEGIN_END) {
+
+ if (save->prim_count > 0) {
+ GLint i = save->prim_count - 1;
+ ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
+ save->prim[i].end = 0;
+ save->prim[i].count = (save->vert_count -
+ save->prim[i].start);
+ }
+
+ /* Make sure this vertex list gets replayed by the "loopback"
+ * mechanism:
+ */
+ save->dangling_attr_ref = 1;
+ st_vbo_save_SaveFlushVertices( ctx );
+
+ /* 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 );
+ }
+
+ unmap_vertex_store( ctx, save->vertex_store );
+
+ assert(save->vertex_size == 0);
+}
+
+void st_vbo_save_BeginCallList( GLcontext *ctx, struct gl_display_list *dlist )
+{
+ struct st_vbo_save_context *save = &st_vbo_context(ctx)->save;
+ save->replay_flags |= dlist->Flags;
+}
+
+void st_vbo_save_EndCallList( GLcontext *ctx )
+{
+ struct st_vbo_save_context *save = &st_vbo_context(ctx)->save;
+
+ if (ctx->ListState.CallDepth == 1) {
+ /* This is correct: want to keep only the ST_VBO_SAVE_FALLBACK
+ * flag, if it is set:
+ */
+ save->replay_flags &= ST_VBO_SAVE_FALLBACK;
+ }
+}
+
+
+static void st_vbo_destroy_vertex_list( GLcontext *ctx, void *data )
+{
+ struct st_vbo_save_vertex_list *node = (struct st_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 st_vbo_print_vertex_list( GLcontext *ctx, void *data )
+{
+ struct st_vbo_save_vertex_list *node = (struct st_vbo_save_vertex_list *)data;
+ GLuint i;
+ (void) ctx;
+
+ _mesa_debug(NULL, "ST_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 st_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 st_vbo_save_context *save = &st_vbo_context(ctx)->save;
+ GLint i;
+
+ for (i = ST_VBO_ATTRIB_POS; i <= ST_VBO_ATTRIB_GENERIC15; i++) {
+ const GLuint j = i - ST_VBO_ATTRIB_POS;
+ ASSERT(j < VERT_ATTRIB_MAX);
+ save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
+ save->current[i] = ctx->ListState.CurrentAttrib[j];
+ }
+
+ for (i = ST_VBO_ATTRIB_FIRST_MATERIAL; i <= ST_VBO_ATTRIB_LAST_MATERIAL; i++) {
+ const GLuint j = i - ST_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 st_vbo_save_api_init( struct st_vbo_save_context *save )
+{
+ GLcontext *ctx = save->ctx;
+ GLuint i;
+
+ save->opcode_vertex_list =
+ _mesa_alloc_opcode( ctx,
+ sizeof(struct st_vbo_save_vertex_list),
+ st_vbo_save_playback_vertex_list,
+ st_vbo_destroy_vertex_list,
+ st_vbo_print_vertex_list );
+
+ ctx->Driver.NotifySaveBegin = st_vbo_save_NotifyBegin;
+
+ _save_vtxfmt_init( ctx );
+ _save_current_init( ctx );
+
+ /* These will actually get set again when binding/drawing */
+ for (i = 0; i < ST_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 );
+}
+
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_save_draw.c b/src/mesa/state_tracker/st_vbo/st_vbo_save_draw.c
new file mode 100644
index 0000000000..77d595e6f0
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_save_draw.c
@@ -0,0 +1,289 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.2
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * 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 "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/context.h"
+#include "main/imports.h"
+#include "main/mtypes.h"
+#include "main/macros.h"
+#include "main/light.h"
+#include "main/state.h"
+
+#include "st_vbo_context.h"
+
+
+/*
+ * 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 st_vbo_save_vertex_list *node )
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ GLfloat vertex[ST_VBO_ATTRIB_MAX * 4];
+ GLfloat *data;
+ GLuint i, offset;
+
+ if (node->current_size == 0)
+ return;
+
+ if (node->current_data) {
+ data = node->current_data;
+ }
+ else {
+ data = vertex;
+
+ if (node->count)
+ offset = (node->buffer_offset +
+ (node->count-1) * node->vertex_size * sizeof(GLfloat));
+ else
+ offset = node->buffer_offset;
+
+ ctx->Driver.GetBufferSubData( ctx, 0, offset,
+ node->vertex_size * sizeof(GLfloat),
+ data, node->vertex_store->bufferobj );
+
+ data += node->attrsz[0]; /* skip vertex position */
+ }
+
+ for (i = ST_VBO_ATTRIB_POS+1 ; i < ST_VBO_ATTRIB_MAX ; i++) {
+ if (node->attrsz[i]) {
+ GLfloat *current = (GLfloat *)st_vbo->currval[i].Ptr;
+ GLfloat tmp[4];
+
+ COPY_CLEAN_4V(tmp,
+ node->attrsz[i],
+ data);
+
+ if (memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0)
+ {
+ memcpy(current, tmp, 4 * sizeof(GLfloat));
+
+ st_vbo->currval[i].Size = node->attrsz[i];
+
+ if (i >= ST_VBO_ATTRIB_FIRST_MATERIAL &&
+ i <= ST_VBO_ATTRIB_LAST_MATERIAL)
+ ctx->NewState |= _NEW_LIGHT;
+
+ ctx->NewState |= _NEW_CURRENT_ATTRIB;
+ }
+
+ data += node->attrsz[i];
+ }
+ }
+
+ /* Colormaterial -- this kindof sucks.
+ */
+ if (ctx->Light.ColorMaterialEnabled) {
+ _mesa_update_color_material(ctx, ctx->Current.Attrib[ST_VBO_ATTRIB_COLOR0]);
+ }
+
+ /* CurrentExecPrimitive
+ */
+ if (node->prim_count) {
+ const struct st_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 ST_VBO, define vertex arrays pointing
+ * into it:
+ */
+static void st_vbo_bind_vertex_list( GLcontext *ctx,
+ const struct st_vbo_save_vertex_list *node )
+{
+ struct st_vbo_context *st_vbo = st_vbo_context(ctx);
+ struct st_vbo_save_context *save = &st_vbo->save;
+ struct gl_client_array *arrays = save->arrays;
+ GLuint buffer_offset = node->buffer_offset;
+ const GLuint *map;
+ GLuint attr;
+ GLubyte node_attrsz[ST_VBO_ATTRIB_MAX]; /* copy of node->attrsz[] */
+ GLbitfield varying_inputs = 0x0;
+
+ memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz));
+
+ /* Install the default (ie Current) attributes first, then overlay
+ * all active ones.
+ */
+ switch (get_program_mode(ctx)) {
+ case VP_NONE:
+ for (attr = 0; attr < 16; attr++) {
+ save->inputs[attr] = &st_vbo->legacy_currval[attr];
+ }
+ for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
+ save->inputs[attr + 16] = &st_vbo->mat_currval[attr];
+ }
+ map = st_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.
+ */
+ for (attr = 0; attr < 16; attr++) {
+ save->inputs[attr] = &st_vbo->legacy_currval[attr];
+ save->inputs[attr + 16] = &st_vbo->generic_currval[attr];
+ }
+ map = st_vbo->map_vp_arb;
+
+ /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
+ * In that case we effectively need to route the data from
+ * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
+ */
+ if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
+ (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
+ save->inputs[16] = save->inputs[0];
+ node_attrsz[16] = node_attrsz[0];
+ node_attrsz[0] = 0;
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
+ GLuint src = map[attr];
+
+ if (node_attrsz[src]) {
+ /* override the default array set above */
+ save->inputs[attr] = &arrays[attr];
+
+ arrays[attr].Ptr = (const GLubyte *) NULL + buffer_offset;
+ arrays[attr].Size = node->attrsz[src];
+ arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat);
+ arrays[attr].Stride = node->vertex_size * sizeof(GLfloat);
+ arrays[attr].Type = GL_FLOAT;
+ arrays[attr].Format = GL_RGBA;
+ arrays[attr].Enabled = 1;
+ _mesa_reference_buffer_object(ctx,
+ &arrays[attr].BufferObj,
+ node->vertex_store->bufferobj);
+ arrays[attr]._MaxElement = node->count; /* ??? */
+
+ assert(arrays[attr].BufferObj->Name);
+
+ buffer_offset += node->attrsz[src] * sizeof(GLfloat);
+ varying_inputs |= 1<<attr;
+ }
+ }
+
+ _mesa_set_varying_vp_inputs( ctx, varying_inputs );
+}
+
+static void st_vbo_save_loopback_vertex_list( GLcontext *ctx,
+ const struct st_vbo_save_vertex_list *list )
+{
+ const char *buffer = ctx->Driver.MapBuffer(ctx,
+ GL_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY, /* ? */
+ list->vertex_store->bufferobj);
+
+ st_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 st_vbo_save_playback_vertex_list( GLcontext *ctx, void *data )
+{
+ const struct st_vbo_save_vertex_list *node = (const struct st_vbo_save_vertex_list *) data;
+ struct st_vbo_save_context *save = &st_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");
+
+ st_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.
+ */
+ st_vbo_save_loopback_vertex_list( ctx, node );
+ return;
+ }
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ /* XXX also need to check if shader enabled, but invalid */
+ 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;
+ }
+
+ st_vbo_bind_vertex_list( ctx, node );
+
+ /* Again...
+ */
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ st_vbo_context(ctx)->draw_prims( ctx,
+ save->inputs,
+ node->prim,
+ node->prim_count,
+ NULL,
+ 0, /* Node is a ST_VBO, so this is ok */
+ node->count - 1);
+ }
+
+ /* Copy to current?
+ */
+ _playback_copy_to_current( ctx, node );
+}
diff --git a/src/mesa/state_tracker/st_vbo/st_vbo_save_loopback.c b/src/mesa/state_tracker/st_vbo/st_vbo_save_loopback.c
new file mode 100644
index 0000000000..fa18dcae11
--- /dev/null
+++ b/src/mesa/state_tracker/st_vbo/st_vbo_save_loopback.c
@@ -0,0 +1,191 @@
+/**************************************************************************
+ *
+ * Copyright 2005 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 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 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.
+ *
+ **************************************************************************/
+
+#include "main/context.h"
+#include "main/glheader.h"
+#include "main/enums.h"
+#include "main/imports.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+#include "glapi/dispatch.h"
+#include "glapi/glapi.h"
+
+#include "st_vbo_context.h"
+
+
+
+typedef void (*attr_func)( GLcontext *ctx, GLint target, const GLfloat * );
+
+
+/* This file makes heavy use of the aliasing of NV vertex attributes
+ * with the legacy attributes, and also with ARB and Material
+ * attributes as currently implemented.
+ */
+static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+ CALL_VertexAttrib1fvNV(ctx->Exec, (target, v));
+}
+
+static void VertexAttrib2fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+ CALL_VertexAttrib2fvNV(ctx->Exec, (target, v));
+}
+
+static void VertexAttrib3fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+ CALL_VertexAttrib3fvNV(ctx->Exec, (target, v));
+}
+
+static void VertexAttrib4fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+ CALL_VertexAttrib4fvNV(ctx->Exec, (target, v));
+}
+
+static attr_func vert_attrfunc[4] = {
+ VertexAttrib1fvNV,
+ VertexAttrib2fvNV,
+ VertexAttrib3fvNV,
+ VertexAttrib4fvNV
+};
+
+struct loopback_attr {
+ GLint target;
+ GLint sz;
+ attr_func func;
+};
+
+/* Don't emit ends and begins on wrapped primitives. Don't replay
+ * wrapped vertices. If we get here, it's probably because the the
+ * precalculated wrapping is wrong.
+ */
+static void loopback_prim( GLcontext *ctx,
+ const GLfloat *buffer,
+ const struct st_mesa_prim *prim,
+ GLuint wrap_count,
+ GLuint vertex_size,
+ const struct loopback_attr *la, GLuint nr )
+{
+ GLint start = prim->start;
+ GLint end = start + prim->count;
+ const GLfloat *data;
+ GLint j;
+ GLuint k;
+
+ if (0)
+ _mesa_printf("loopback prim %s(%s,%s) verts %d..%d\n",
+ _mesa_lookup_enum_by_nr(prim->mode),
+ prim->begin ? "begin" : "..",
+ prim->end ? "end" : "..",
+ start,
+ end);
+
+ if (prim->begin) {
+ CALL_Begin(GET_DISPATCH(), ( prim->mode ));
+ }
+ else {
+ assert(start == 0);
+ start += wrap_count;
+ }
+
+ data = buffer + start * vertex_size;
+
+ for (j = start ; j < end ; j++) {
+ const GLfloat *tmp = data + la[0].sz;
+
+ for (k = 1 ; k < nr ; k++) {
+ la[k].func( ctx, la[k].target, tmp );
+ tmp += la[k].sz;
+ }
+
+ /* Fire the vertex
+ */
+ la[0].func( ctx, ST_VBO_ATTRIB_POS, data );
+ data = tmp;
+ }
+
+ if (prim->end) {
+ CALL_End(GET_DISPATCH(), ());
+ }
+}
+
+/* Primitives generated by DrawArrays/DrawElements/Rectf may be
+ * caught here. If there is no primitive in progress, execute them
+ * normally, otherwise need to track and discard the generated
+ * primitives.
+ */
+static void loopback_weak_prim( GLcontext *ctx,
+ const struct st_mesa_prim *prim )
+{
+ /* Use the prim_weak flag to ensure that if this primitive
+ * wraps, we don't mistake future vertex_lists for part of the
+ * surrounding primitive.
+ *
+ * While this flag is set, we are simply disposing of data
+ * generated by an operation now known to be a noop.
+ */
+ if (prim->begin)
+ ctx->Driver.CurrentExecPrimitive |= ST_VBO_SAVE_PRIM_WEAK;
+ if (prim->end)
+ ctx->Driver.CurrentExecPrimitive &= ~ST_VBO_SAVE_PRIM_WEAK;
+}
+
+
+void st_vbo_loopback_vertex_list( GLcontext *ctx,
+ const GLfloat *buffer,
+ const GLubyte *attrsz,
+ const struct st_mesa_prim *prim,
+ GLuint prim_count,
+ GLuint wrap_count,
+ GLuint vertex_size)
+{
+ struct loopback_attr la[ST_VBO_ATTRIB_MAX];
+ GLuint i, nr = 0;
+
+ /* All Legacy, NV, ARB and Material attributes are routed through
+ * the NV attributes entrypoints:
+ */
+ for (i = 0 ; i < ST_VBO_ATTRIB_MAX ; i++) {
+ if (attrsz[i]) {
+ la[nr].target = i;
+ la[nr].sz = attrsz[i];
+ la[nr].func = vert_attrfunc[attrsz[i]-1];
+ nr++;
+ }
+ }
+
+ for (i = 0 ; i < prim_count ; i++) {
+ if ((prim[i].mode & ST_VBO_SAVE_PRIM_WEAK) &&
+ (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END))
+ {
+ loopback_weak_prim( ctx, &prim[i] );
+ }
+ else
+ {
+ loopback_prim( ctx, buffer, &prim[i], wrap_count, vertex_size, la, nr );
+ }
+ }
+}