diff options
Diffstat (limited to 'mesalib/src/mesa/vbo')
-rw-r--r-- | mesalib/src/mesa/vbo/vbo.h | 352 | ||||
-rw-r--r-- | mesalib/src/mesa/vbo/vbo_attrib_tmp.h | 1480 | ||||
-rw-r--r-- | mesalib/src/mesa/vbo/vbo_exec.h | 408 | ||||
-rw-r--r-- | mesalib/src/mesa/vbo/vbo_exec_array.c | 2720 | ||||
-rw-r--r-- | mesalib/src/mesa/vbo/vbo_save_api.c | 2806 |
5 files changed, 3883 insertions, 3883 deletions
diff --git a/mesalib/src/mesa/vbo/vbo.h b/mesalib/src/mesa/vbo/vbo.h index 26c3d4e0a..37bdde9a8 100644 --- a/mesalib/src/mesa/vbo/vbo.h +++ b/mesalib/src/mesa/vbo/vbo.h @@ -1,176 +1,176 @@ -/* - * 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 vbo_context.h - * \brief VBO builder module datatypes and definitions. - * \author Keith Whitwell - */ - - -#ifndef _VBO_H -#define _VBO_H - -#include "main/glheader.h" - -struct gl_client_array; -struct gl_context; - -struct _mesa_prim { - GLuint mode:8; /**< GL_POINTS, GL_LINES, GL_QUAD_STRIP, etc */ - GLuint indexed:1; - GLuint begin:1; - GLuint end:1; - GLuint weak:1; - GLuint no_current_update:1; - GLuint pad:19; - - GLuint start; - GLuint count; - GLint basevertex; - GLsizei num_instances; -}; - -/* Would like to call this a "vbo_index_buffer", but this would be - * confusing as the indices are not neccessarily yet in a non-null - * buffer object. - */ -struct _mesa_index_buffer { - GLuint count; - GLenum type; - struct gl_buffer_object *obj; - const void *ptr; -}; - - - -GLboolean _vbo_CreateContext( struct gl_context *ctx ); -void _vbo_DestroyContext( struct gl_context *ctx ); -void _vbo_InvalidateState( struct gl_context *ctx, GLuint new_state ); - - -typedef void (*vbo_draw_func)( struct gl_context *ctx, - const struct gl_client_array **arrays, - const struct _mesa_prim *prims, - GLuint nr_prims, - const struct _mesa_index_buffer *ib, - GLboolean index_bounds_valid, - GLuint min_index, - GLuint max_index ); - - - - -/* Utility function to cope with various constraints on tnl modules or - * hardware. This can be used to split an incoming set of arrays and - * primitives against the following constraints: - * - Maximum number of indices in index buffer. - * - Maximum number of vertices referenced by index buffer. - * - Maximum hardware vertex buffer size. - */ -struct split_limits { - GLuint max_verts; - GLuint max_indices; - GLuint max_vb_size; /* bytes */ -}; - - -void vbo_split_prims( struct gl_context *ctx, - const struct gl_client_array *arrays[], - const struct _mesa_prim *prim, - GLuint nr_prims, - const struct _mesa_index_buffer *ib, - GLuint min_index, - GLuint max_index, - vbo_draw_func draw, - const struct split_limits *limits ); - - -/* Helpers for dealing translating away non-zero min_index. - */ -GLboolean vbo_all_varyings_in_vbos( const struct gl_client_array *arrays[] ); -GLboolean vbo_any_varyings_in_vbos( const struct gl_client_array *arrays[] ); - -void vbo_rebase_prims( struct gl_context *ctx, - const struct gl_client_array *arrays[], - const struct _mesa_prim *prim, - GLuint nr_prims, - const struct _mesa_index_buffer *ib, - GLuint min_index, - GLuint max_index, - vbo_draw_func draw ); -void -vbo_get_minmax_index(struct gl_context *ctx, const struct _mesa_prim *prim, - const struct _mesa_index_buffer *ib, - GLuint *min_index, GLuint *max_index); - -void vbo_use_buffer_objects(struct gl_context *ctx); - -void vbo_always_unmap_buffers(struct gl_context *ctx); - -void vbo_set_draw_func(struct gl_context *ctx, vbo_draw_func func); - -void vbo_check_buffers_are_unmapped(struct gl_context *ctx); - - -void GLAPIENTRY -_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a); - -void GLAPIENTRY -_es_Normal3f(GLfloat x, GLfloat y, GLfloat z); - -void GLAPIENTRY -_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); - -void GLAPIENTRY -_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params); - -void GLAPIENTRY -_es_Materialf(GLenum face, GLenum pname, GLfloat param); - -void GLAPIENTRY -_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - -void GLAPIENTRY -_es_VertexAttrib1f(GLuint indx, GLfloat x); - -void GLAPIENTRY -_es_VertexAttrib1fv(GLuint indx, const GLfloat* values); - -void GLAPIENTRY -_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y); - -void GLAPIENTRY -_es_VertexAttrib2fv(GLuint indx, const GLfloat* values); - -void GLAPIENTRY -_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z); - -void GLAPIENTRY -_es_VertexAttrib3fv(GLuint indx, const GLfloat* values); - -void GLAPIENTRY -_es_VertexAttrib4fv(GLuint indx, const GLfloat* values); - -#endif +/*
+ * 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 vbo_context.h
+ * \brief VBO builder module datatypes and definitions.
+ * \author Keith Whitwell
+ */
+
+
+#ifndef _VBO_H
+#define _VBO_H
+
+#include "main/glheader.h"
+
+struct gl_client_array;
+struct gl_context;
+
+struct _mesa_prim {
+ GLuint mode:8; /**< GL_POINTS, GL_LINES, GL_QUAD_STRIP, etc */
+ GLuint indexed:1;
+ GLuint begin:1;
+ GLuint end:1;
+ GLuint weak:1;
+ GLuint no_current_update:1;
+ GLuint pad:19;
+
+ GLuint start;
+ GLuint count;
+ GLint basevertex;
+ GLsizei num_instances;
+};
+
+/* Would like to call this a "vbo_index_buffer", but this would be
+ * confusing as the indices are not neccessarily yet in a non-null
+ * buffer object.
+ */
+struct _mesa_index_buffer {
+ GLuint count;
+ GLenum type;
+ struct gl_buffer_object *obj;
+ const void *ptr;
+};
+
+
+
+GLboolean _vbo_CreateContext( struct gl_context *ctx );
+void _vbo_DestroyContext( struct gl_context *ctx );
+void _vbo_InvalidateState( struct gl_context *ctx, GLuint new_state );
+
+
+typedef void (*vbo_draw_func)( struct gl_context *ctx,
+ const struct gl_client_array **arrays,
+ const struct _mesa_prim *prims,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLboolean index_bounds_valid,
+ GLuint min_index,
+ GLuint max_index );
+
+
+
+
+/* Utility function to cope with various constraints on tnl modules or
+ * hardware. This can be used to split an incoming set of arrays and
+ * primitives against the following constraints:
+ * - Maximum number of indices in index buffer.
+ * - Maximum number of vertices referenced by index buffer.
+ * - Maximum hardware vertex buffer size.
+ */
+struct split_limits {
+ GLuint max_verts;
+ GLuint max_indices;
+ GLuint max_vb_size; /* bytes */
+};
+
+
+void vbo_split_prims( struct gl_context *ctx,
+ const struct gl_client_array *arrays[],
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index,
+ vbo_draw_func draw,
+ const struct split_limits *limits );
+
+
+/* Helpers for dealing translating away non-zero min_index.
+ */
+GLboolean vbo_all_varyings_in_vbos( const struct gl_client_array *arrays[] );
+GLboolean vbo_any_varyings_in_vbos( const struct gl_client_array *arrays[] );
+
+void vbo_rebase_prims( struct gl_context *ctx,
+ const struct gl_client_array *arrays[],
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index,
+ vbo_draw_func draw );
+void
+vbo_get_minmax_index(struct gl_context *ctx, const struct _mesa_prim *prim,
+ const struct _mesa_index_buffer *ib,
+ GLuint *min_index, GLuint *max_index);
+
+void vbo_use_buffer_objects(struct gl_context *ctx);
+
+void vbo_always_unmap_buffers(struct gl_context *ctx);
+
+void vbo_set_draw_func(struct gl_context *ctx, vbo_draw_func func);
+
+void vbo_check_buffers_are_unmapped(struct gl_context *ctx);
+
+
+void GLAPIENTRY
+_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
+
+void GLAPIENTRY
+_es_Normal3f(GLfloat x, GLfloat y, GLfloat z);
+
+void GLAPIENTRY
+_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+
+void GLAPIENTRY
+_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
+
+void GLAPIENTRY
+_es_Materialf(GLenum face, GLenum pname, GLfloat param);
+
+void GLAPIENTRY
+_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+
+void GLAPIENTRY
+_es_VertexAttrib1f(GLuint indx, GLfloat x);
+
+void GLAPIENTRY
+_es_VertexAttrib1fv(GLuint indx, const GLfloat* values);
+
+void GLAPIENTRY
+_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y);
+
+void GLAPIENTRY
+_es_VertexAttrib2fv(GLuint indx, const GLfloat* values);
+
+void GLAPIENTRY
+_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+
+void GLAPIENTRY
+_es_VertexAttrib3fv(GLuint indx, const GLfloat* values);
+
+void GLAPIENTRY
+_es_VertexAttrib4fv(GLuint indx, const GLfloat* values);
+
+#endif
diff --git a/mesalib/src/mesa/vbo/vbo_attrib_tmp.h b/mesalib/src/mesa/vbo/vbo_attrib_tmp.h index c793ce0dc..198b2d85f 100644 --- a/mesalib/src/mesa/vbo/vbo_attrib_tmp.h +++ b/mesalib/src/mesa/vbo/vbo_attrib_tmp.h @@ -1,740 +1,740 @@ -/************************************************************************** - -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. - -**************************************************************************/ - -/* float */ -#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 ) - -/* int */ -#define ATTR2IV( A, V ) ATTR( A, 2, (V)[0], (V)[1], 0, 1 ) -#define ATTR3IV( A, V ) ATTR( A, 3, (V)[0], (V)[1], (V)[2], 1 ) -#define ATTR4IV( A, V ) ATTR( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] ) - -#define ATTR1I( A, X ) ATTR( A, 1, X, 0, 0, 1 ) -#define ATTR2I( A, X, Y ) ATTR( A, 2, X, Y, 0, 1 ) -#define ATTR3I( A, X, Y, Z ) ATTR( A, 3, X, Y, Z, 1 ) -#define ATTR4I( A, X, Y, Z, W ) ATTR( A, 4, X, Y, Z, W ) - - -/* uint */ -#define ATTR2UIV( A, V ) ATTR( A, 2, (V)[0], (V)[1], 0, 1 ) -#define ATTR3UIV( A, V ) ATTR( A, 3, (V)[0], (V)[1], (V)[2], 1 ) -#define ATTR4UIV( A, V ) ATTR( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] ) - -#define ATTR1UI( A, X ) ATTR( A, 1, X, 0, 0, 1 ) -#define ATTR2UI( A, X, Y ) ATTR( A, 2, X, Y, 0, 1 ) -#define ATTR3UI( A, X, Y, Z ) ATTR( A, 3, X, Y, Z, 1 ) -#define ATTR4UI( 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(VBO_ATTRIB_POS, x, y); -} - -static void GLAPIENTRY -TAG(Vertex2fv)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR2FV(VBO_ATTRIB_POS, v); -} - -static void GLAPIENTRY -TAG(Vertex3f)(GLfloat x, GLfloat y, GLfloat z) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR3F(VBO_ATTRIB_POS, x, y, z); -} - -static void GLAPIENTRY -TAG(Vertex3fv)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR3FV(VBO_ATTRIB_POS, v); -} - -static void GLAPIENTRY -TAG(Vertex4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR4F(VBO_ATTRIB_POS, x, y, z, w); -} - -static void GLAPIENTRY -TAG(Vertex4fv)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR4FV(VBO_ATTRIB_POS, v); -} - - - -static void GLAPIENTRY -TAG(TexCoord1f)(GLfloat x) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR1F(VBO_ATTRIB_TEX0, x); -} - -static void GLAPIENTRY -TAG(TexCoord1fv)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR1FV(VBO_ATTRIB_TEX0, v); -} - -static void GLAPIENTRY -TAG(TexCoord2f)(GLfloat x, GLfloat y) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR2F(VBO_ATTRIB_TEX0, x, y); -} - -static void GLAPIENTRY -TAG(TexCoord2fv)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR2FV(VBO_ATTRIB_TEX0, v); -} - -static void GLAPIENTRY -TAG(TexCoord3f)(GLfloat x, GLfloat y, GLfloat z) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR3F(VBO_ATTRIB_TEX0, x, y, z); -} - -static void GLAPIENTRY -TAG(TexCoord3fv)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR3FV(VBO_ATTRIB_TEX0, v); -} - -static void GLAPIENTRY -TAG(TexCoord4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR4F(VBO_ATTRIB_TEX0, x, y, z, w); -} - -static void GLAPIENTRY -TAG(TexCoord4fv)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR4FV(VBO_ATTRIB_TEX0, v); -} - - - -static void GLAPIENTRY -TAG(Normal3f)(GLfloat x, GLfloat y, GLfloat z) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR3F(VBO_ATTRIB_NORMAL, x, y, z); -} - -static void GLAPIENTRY -TAG(Normal3fv)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR3FV(VBO_ATTRIB_NORMAL, v); -} - - - -static void GLAPIENTRY -TAG(FogCoordfEXT)(GLfloat x) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR1F(VBO_ATTRIB_FOG, x); -} - - - -static void GLAPIENTRY -TAG(FogCoordfvEXT)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR1FV(VBO_ATTRIB_FOG, v); -} - -static void GLAPIENTRY -TAG(Color3f)(GLfloat x, GLfloat y, GLfloat z) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR3F(VBO_ATTRIB_COLOR0, x, y, z); -} - -static void GLAPIENTRY -TAG(Color3fv)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR3FV(VBO_ATTRIB_COLOR0, v); -} - -static void GLAPIENTRY -TAG(Color4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR4F(VBO_ATTRIB_COLOR0, x, y, z, w); -} - -static void GLAPIENTRY -TAG(Color4fv)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR4FV(VBO_ATTRIB_COLOR0, v); -} - - - -static void GLAPIENTRY -TAG(SecondaryColor3fEXT)(GLfloat x, GLfloat y, GLfloat z) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR3F(VBO_ATTRIB_COLOR1, x, y, z); -} - -static void GLAPIENTRY -TAG(SecondaryColor3fvEXT)(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR3FV(VBO_ATTRIB_COLOR1, v); -} - - - -static void GLAPIENTRY -TAG(EdgeFlag)(GLboolean b) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR1F(VBO_ATTRIB_EDGEFLAG, (GLfloat) b); -} - - - -static void GLAPIENTRY -TAG(Indexf)(GLfloat f) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR1F(VBO_ATTRIB_INDEX, f); -} - -static void GLAPIENTRY -TAG(Indexfv)(const GLfloat * f) -{ - GET_CURRENT_CONTEXT(ctx); - ATTR1FV(VBO_ATTRIB_INDEX, f); -} - - - -static void GLAPIENTRY -TAG(MultiTexCoord1f)(GLenum target, GLfloat x) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0; - ATTR1F(attr, x); -} - -static void GLAPIENTRY -TAG(MultiTexCoord1fv)(GLenum target, const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - GLuint attr = (target & 0x7) + 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) + 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) + 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) + 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) + 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) + 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) + 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_GENERIC_ATTRIBS) - ATTR1F(VBO_ATTRIB_GENERIC0 + index, x); - else - ERROR(GL_INVALID_VALUE); -} - -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_GENERIC_ATTRIBS) - ATTR1FV(VBO_ATTRIB_GENERIC0 + index, v); - else - ERROR(GL_INVALID_VALUE); -} - -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_GENERIC_ATTRIBS) - ATTR2F(VBO_ATTRIB_GENERIC0 + index, x, y); - else - ERROR(GL_INVALID_VALUE); -} - -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_GENERIC_ATTRIBS) - ATTR2FV(VBO_ATTRIB_GENERIC0 + index, v); - else - ERROR(GL_INVALID_VALUE); -} - -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_GENERIC_ATTRIBS) - ATTR3F(VBO_ATTRIB_GENERIC0 + index, x, y, z); - else - ERROR(GL_INVALID_VALUE); -} - -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_GENERIC_ATTRIBS) - ATTR3FV(VBO_ATTRIB_GENERIC0 + index, v); - else - ERROR(GL_INVALID_VALUE); -} - -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_GENERIC_ATTRIBS) - ATTR4F(VBO_ATTRIB_GENERIC0 + index, x, y, z, w); - else - ERROR(GL_INVALID_VALUE); -} - -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_GENERIC_ATTRIBS) - ATTR4FV(VBO_ATTRIB_GENERIC0 + index, v); - else - ERROR(GL_INVALID_VALUE); -} - - - -/* Integer-valued generic attributes. - * XXX: the integers just get converted to floats at this time - */ -static void GLAPIENTRY -TAG(VertexAttribI1i)(GLuint index, GLint x) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR1I(0, x); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR1I(VBO_ATTRIB_GENERIC0 + index, x); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI2i)(GLuint index, GLint x, GLint y) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR2I(0, x, y); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR2I(VBO_ATTRIB_GENERIC0 + index, x, y); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI3i)(GLuint index, GLint x, GLint y, GLint z) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR3I(0, x, y, z); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR3I(VBO_ATTRIB_GENERIC0 + index, x, y, z); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI4i)(GLuint index, GLint x, GLint y, GLint z, GLint w) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR4I(0, x, y, z, w); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR4I(VBO_ATTRIB_GENERIC0 + index, x, y, z, w); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI2iv)(GLuint index, const GLint *v) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR2IV(0, v); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR2IV(VBO_ATTRIB_GENERIC0 + index, v); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI3iv)(GLuint index, const GLint *v) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR3IV(0, v); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR3IV(VBO_ATTRIB_GENERIC0 + index, v); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI4iv)(GLuint index, const GLint *v) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR4IV(0, v); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR4IV(VBO_ATTRIB_GENERIC0 + index, v); - else - ERROR(GL_INVALID_VALUE); -} - - - -/* Unsigned integer-valued generic attributes. - * XXX: the integers just get converted to floats at this time - */ -static void GLAPIENTRY -TAG(VertexAttribI1ui)(GLuint index, GLuint x) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR1UI(0, x); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR1UI(VBO_ATTRIB_GENERIC0 + index, x); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI2ui)(GLuint index, GLuint x, GLuint y) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR2UI(0, x, y); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR2UI(VBO_ATTRIB_GENERIC0 + index, x, y); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI3ui)(GLuint index, GLuint x, GLuint y, GLuint z) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR3UI(0, x, y, z); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR3UI(VBO_ATTRIB_GENERIC0 + index, x, y, z); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI4ui)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR4UI(0, x, y, z, w); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR4UI(VBO_ATTRIB_GENERIC0 + index, x, y, z, w); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI2uiv)(GLuint index, const GLuint *v) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR2UIV(0, v); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR2UIV(VBO_ATTRIB_GENERIC0 + index, v); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI3uiv)(GLuint index, const GLuint *v) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR3UIV(0, v); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR3UIV(VBO_ATTRIB_GENERIC0 + index, v); - else - ERROR(GL_INVALID_VALUE); -} - -static void GLAPIENTRY -TAG(VertexAttribI4uiv)(GLuint index, const GLuint *v) -{ - GET_CURRENT_CONTEXT(ctx); - if (index == 0) - ATTR4UIV(0, v); - else if (index < MAX_VERTEX_GENERIC_ATTRIBS) - ATTR4UIV(VBO_ATTRIB_GENERIC0 + index, v); - else - ERROR(GL_INVALID_VALUE); -} - - - -/* 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 - * vbo_save_loopback.c) - */ -static void GLAPIENTRY -TAG(VertexAttrib1fNV)(GLuint index, GLfloat x) -{ - GET_CURRENT_CONTEXT(ctx); - if (index < VBO_ATTRIB_MAX) - ATTR1F(index, x); -} - -static void GLAPIENTRY -TAG(VertexAttrib1fvNV)(GLuint index, const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - if (index < VBO_ATTRIB_MAX) - ATTR1FV(index, v); -} - -static void GLAPIENTRY -TAG(VertexAttrib2fNV)(GLuint index, GLfloat x, GLfloat y) -{ - GET_CURRENT_CONTEXT(ctx); - if (index < VBO_ATTRIB_MAX) - ATTR2F(index, x, y); -} - -static void GLAPIENTRY -TAG(VertexAttrib2fvNV)(GLuint index, const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - if (index < 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 < VBO_ATTRIB_MAX) - ATTR3F(index, x, y, z); -} - -static void GLAPIENTRY -TAG(VertexAttrib3fvNV)(GLuint index, - const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - if (index < 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 < 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 < 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(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params); - break; - case GL_AMBIENT: - MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params); - break; - case GL_DIFFUSE: - MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params); - break; - case GL_SPECULAR: - MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params); - break; - case GL_SHININESS: - MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params); - break; - case GL_COLOR_INDEXES: - MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params); - break; - case GL_AMBIENT_AND_DIFFUSE: - MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params); - MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params); - break; - default: - ERROR(GL_INVALID_ENUM); - return; - } -} - - -#undef ATTR1FV -#undef ATTR2FV -#undef ATTR3FV -#undef ATTR4FV - -#undef ATTR1F -#undef ATTR2F -#undef ATTR3F -#undef ATTR4F - -#undef MAT -#undef MAT_ATTR +/**************************************************************************
+
+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.
+
+**************************************************************************/
+
+/* float */
+#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 )
+
+/* int */
+#define ATTR2IV( A, V ) ATTR( A, 2, (V)[0], (V)[1], 0, 1 )
+#define ATTR3IV( A, V ) ATTR( A, 3, (V)[0], (V)[1], (V)[2], 1 )
+#define ATTR4IV( A, V ) ATTR( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] )
+
+#define ATTR1I( A, X ) ATTR( A, 1, X, 0, 0, 1 )
+#define ATTR2I( A, X, Y ) ATTR( A, 2, X, Y, 0, 1 )
+#define ATTR3I( A, X, Y, Z ) ATTR( A, 3, X, Y, Z, 1 )
+#define ATTR4I( A, X, Y, Z, W ) ATTR( A, 4, X, Y, Z, W )
+
+
+/* uint */
+#define ATTR2UIV( A, V ) ATTR( A, 2, (V)[0], (V)[1], 0, 1 )
+#define ATTR3UIV( A, V ) ATTR( A, 3, (V)[0], (V)[1], (V)[2], 1 )
+#define ATTR4UIV( A, V ) ATTR( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] )
+
+#define ATTR1UI( A, X ) ATTR( A, 1, X, 0, 0, 1 )
+#define ATTR2UI( A, X, Y ) ATTR( A, 2, X, Y, 0, 1 )
+#define ATTR3UI( A, X, Y, Z ) ATTR( A, 3, X, Y, Z, 1 )
+#define ATTR4UI( 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(VBO_ATTRIB_POS, x, y);
+}
+
+static void GLAPIENTRY
+TAG(Vertex2fv)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR2FV(VBO_ATTRIB_POS, v);
+}
+
+static void GLAPIENTRY
+TAG(Vertex3f)(GLfloat x, GLfloat y, GLfloat z)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR3F(VBO_ATTRIB_POS, x, y, z);
+}
+
+static void GLAPIENTRY
+TAG(Vertex3fv)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR3FV(VBO_ATTRIB_POS, v);
+}
+
+static void GLAPIENTRY
+TAG(Vertex4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR4F(VBO_ATTRIB_POS, x, y, z, w);
+}
+
+static void GLAPIENTRY
+TAG(Vertex4fv)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR4FV(VBO_ATTRIB_POS, v);
+}
+
+
+
+static void GLAPIENTRY
+TAG(TexCoord1f)(GLfloat x)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR1F(VBO_ATTRIB_TEX0, x);
+}
+
+static void GLAPIENTRY
+TAG(TexCoord1fv)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR1FV(VBO_ATTRIB_TEX0, v);
+}
+
+static void GLAPIENTRY
+TAG(TexCoord2f)(GLfloat x, GLfloat y)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR2F(VBO_ATTRIB_TEX0, x, y);
+}
+
+static void GLAPIENTRY
+TAG(TexCoord2fv)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR2FV(VBO_ATTRIB_TEX0, v);
+}
+
+static void GLAPIENTRY
+TAG(TexCoord3f)(GLfloat x, GLfloat y, GLfloat z)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR3F(VBO_ATTRIB_TEX0, x, y, z);
+}
+
+static void GLAPIENTRY
+TAG(TexCoord3fv)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR3FV(VBO_ATTRIB_TEX0, v);
+}
+
+static void GLAPIENTRY
+TAG(TexCoord4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR4F(VBO_ATTRIB_TEX0, x, y, z, w);
+}
+
+static void GLAPIENTRY
+TAG(TexCoord4fv)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR4FV(VBO_ATTRIB_TEX0, v);
+}
+
+
+
+static void GLAPIENTRY
+TAG(Normal3f)(GLfloat x, GLfloat y, GLfloat z)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR3F(VBO_ATTRIB_NORMAL, x, y, z);
+}
+
+static void GLAPIENTRY
+TAG(Normal3fv)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR3FV(VBO_ATTRIB_NORMAL, v);
+}
+
+
+
+static void GLAPIENTRY
+TAG(FogCoordfEXT)(GLfloat x)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR1F(VBO_ATTRIB_FOG, x);
+}
+
+
+
+static void GLAPIENTRY
+TAG(FogCoordfvEXT)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR1FV(VBO_ATTRIB_FOG, v);
+}
+
+static void GLAPIENTRY
+TAG(Color3f)(GLfloat x, GLfloat y, GLfloat z)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR3F(VBO_ATTRIB_COLOR0, x, y, z);
+}
+
+static void GLAPIENTRY
+TAG(Color3fv)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR3FV(VBO_ATTRIB_COLOR0, v);
+}
+
+static void GLAPIENTRY
+TAG(Color4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR4F(VBO_ATTRIB_COLOR0, x, y, z, w);
+}
+
+static void GLAPIENTRY
+TAG(Color4fv)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR4FV(VBO_ATTRIB_COLOR0, v);
+}
+
+
+
+static void GLAPIENTRY
+TAG(SecondaryColor3fEXT)(GLfloat x, GLfloat y, GLfloat z)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR3F(VBO_ATTRIB_COLOR1, x, y, z);
+}
+
+static void GLAPIENTRY
+TAG(SecondaryColor3fvEXT)(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR3FV(VBO_ATTRIB_COLOR1, v);
+}
+
+
+
+static void GLAPIENTRY
+TAG(EdgeFlag)(GLboolean b)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR1F(VBO_ATTRIB_EDGEFLAG, (GLfloat) b);
+}
+
+
+
+static void GLAPIENTRY
+TAG(Indexf)(GLfloat f)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR1F(VBO_ATTRIB_INDEX, f);
+}
+
+static void GLAPIENTRY
+TAG(Indexfv)(const GLfloat * f)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ATTR1FV(VBO_ATTRIB_INDEX, f);
+}
+
+
+
+static void GLAPIENTRY
+TAG(MultiTexCoord1f)(GLenum target, GLfloat x)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
+ ATTR1F(attr, x);
+}
+
+static void GLAPIENTRY
+TAG(MultiTexCoord1fv)(GLenum target, const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint attr = (target & 0x7) + 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) + 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) + 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) + 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) + 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) + 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) + 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_GENERIC_ATTRIBS)
+ ATTR1F(VBO_ATTRIB_GENERIC0 + index, x);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+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_GENERIC_ATTRIBS)
+ ATTR1FV(VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+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_GENERIC_ATTRIBS)
+ ATTR2F(VBO_ATTRIB_GENERIC0 + index, x, y);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+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_GENERIC_ATTRIBS)
+ ATTR2FV(VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+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_GENERIC_ATTRIBS)
+ ATTR3F(VBO_ATTRIB_GENERIC0 + index, x, y, z);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+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_GENERIC_ATTRIBS)
+ ATTR3FV(VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+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_GENERIC_ATTRIBS)
+ ATTR4F(VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+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_GENERIC_ATTRIBS)
+ ATTR4FV(VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+
+
+/* Integer-valued generic attributes.
+ * XXX: the integers just get converted to floats at this time
+ */
+static void GLAPIENTRY
+TAG(VertexAttribI1i)(GLuint index, GLint x)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR1I(0, x);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR1I(VBO_ATTRIB_GENERIC0 + index, x);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI2i)(GLuint index, GLint x, GLint y)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR2I(0, x, y);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR2I(VBO_ATTRIB_GENERIC0 + index, x, y);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI3i)(GLuint index, GLint x, GLint y, GLint z)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR3I(0, x, y, z);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR3I(VBO_ATTRIB_GENERIC0 + index, x, y, z);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI4i)(GLuint index, GLint x, GLint y, GLint z, GLint w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR4I(0, x, y, z, w);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR4I(VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI2iv)(GLuint index, const GLint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR2IV(0, v);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR2IV(VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI3iv)(GLuint index, const GLint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR3IV(0, v);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR3IV(VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI4iv)(GLuint index, const GLint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR4IV(0, v);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR4IV(VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+
+
+/* Unsigned integer-valued generic attributes.
+ * XXX: the integers just get converted to floats at this time
+ */
+static void GLAPIENTRY
+TAG(VertexAttribI1ui)(GLuint index, GLuint x)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR1UI(0, x);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR1UI(VBO_ATTRIB_GENERIC0 + index, x);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI2ui)(GLuint index, GLuint x, GLuint y)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR2UI(0, x, y);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR2UI(VBO_ATTRIB_GENERIC0 + index, x, y);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI3ui)(GLuint index, GLuint x, GLuint y, GLuint z)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR3UI(0, x, y, z);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR3UI(VBO_ATTRIB_GENERIC0 + index, x, y, z);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI4ui)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR4UI(0, x, y, z, w);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR4UI(VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI2uiv)(GLuint index, const GLuint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR2UIV(0, v);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR2UIV(VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI3uiv)(GLuint index, const GLuint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR3UIV(0, v);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR3UIV(VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttribI4uiv)(GLuint index, const GLuint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index == 0)
+ ATTR4UIV(0, v);
+ else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR4UIV(VBO_ATTRIB_GENERIC0 + index, v);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+
+
+/* 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
+ * vbo_save_loopback.c)
+ */
+static void GLAPIENTRY
+TAG(VertexAttrib1fNV)(GLuint index, GLfloat x)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index < VBO_ATTRIB_MAX)
+ ATTR1F(index, x);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttrib1fvNV)(GLuint index, const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index < VBO_ATTRIB_MAX)
+ ATTR1FV(index, v);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttrib2fNV)(GLuint index, GLfloat x, GLfloat y)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index < VBO_ATTRIB_MAX)
+ ATTR2F(index, x, y);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttrib2fvNV)(GLuint index, const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index < 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 < VBO_ATTRIB_MAX)
+ ATTR3F(index, x, y, z);
+}
+
+static void GLAPIENTRY
+TAG(VertexAttrib3fvNV)(GLuint index,
+ const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index < 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 < 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 < 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(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
+ break;
+ case GL_AMBIENT:
+ MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
+ break;
+ case GL_DIFFUSE:
+ MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
+ break;
+ case GL_SPECULAR:
+ MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
+ break;
+ case GL_SHININESS:
+ MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
+ break;
+ case GL_COLOR_INDEXES:
+ MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
+ break;
+ case GL_AMBIENT_AND_DIFFUSE:
+ MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
+ MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
+ break;
+ default:
+ ERROR(GL_INVALID_ENUM);
+ 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/mesalib/src/mesa/vbo/vbo_exec.h b/mesalib/src/mesa/vbo/vbo_exec.h index d52a557e0..c8e509285 100644 --- a/mesalib/src/mesa/vbo/vbo_exec.h +++ b/mesalib/src/mesa/vbo/vbo_exec.h @@ -1,204 +1,204 @@ -/************************************************************************** - -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 __VBO_EXEC_H__ -#define __VBO_EXEC_H__ - -#include "main/mfeatures.h" -#include "main/mtypes.h" -#include "vbo.h" -#include "vbo_attrib.h" - - -/** - * Max number of primitives (number of glBegin/End pairs) per VBO. - */ -#define VBO_MAX_PRIM 64 - - -/** - * Size of the VBO to use for glBegin/glVertex/glEnd-style rendering. - */ -#define VBO_VERT_BUFFER_SIZE (1024*64) /* bytes */ - - -/** Current vertex program mode */ -enum vp_mode { - VP_NONE, /**< fixed function */ - VP_NV, /**< NV vertex program */ - VP_ARB /**< ARB vertex program or GLSL vertex shader */ -}; - - -struct vbo_exec_eval1_map { - struct gl_1d_map *map; - GLuint sz; -}; - -struct vbo_exec_eval2_map { - struct gl_2d_map *map; - GLuint sz; -}; - - - -struct vbo_exec_copied_vtx { - GLfloat buffer[VBO_ATTRIB_MAX * 4 * VBO_MAX_COPIED_VERTS]; - GLuint nr; -}; - - -typedef void (*vbo_attrfv_func)( const GLfloat * ); - - -struct vbo_exec_context -{ - struct gl_context *ctx; - GLvertexformat vtxfmt; - - struct { - struct gl_buffer_object *bufferobj; - - GLuint vertex_size; /* in dwords */ - - struct _mesa_prim prim[VBO_MAX_PRIM]; - GLuint prim_count; - - GLfloat *buffer_map; - GLfloat *buffer_ptr; /* cursor, points into buffer */ - GLuint buffer_used; /* in bytes */ - GLfloat vertex[VBO_ATTRIB_MAX*4]; /* current vertex */ - - GLuint vert_count; - GLuint max_vert; - struct vbo_exec_copied_vtx copied; - - GLubyte attrsz[VBO_ATTRIB_MAX]; - GLubyte active_sz[VBO_ATTRIB_MAX]; - - GLfloat *attrptr[VBO_ATTRIB_MAX]; - struct gl_client_array arrays[VERT_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: - */ - enum vp_mode program_mode; - GLuint enabled_flags; - const struct gl_client_array *inputs[VERT_ATTRIB_MAX]; - } vtx; - - - struct { - GLboolean recalculate_maps; - struct vbo_exec_eval1_map map1[VERT_ATTRIB_MAX]; - struct vbo_exec_eval2_map map2[VERT_ATTRIB_MAX]; - } eval; - - struct { - enum vp_mode 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; - - /* Which flags to set in vbo_exec_BeginVertices() */ - GLbitfield begin_vertices_flags; - -#ifdef DEBUG - GLint flush_call_depth; -#endif -}; - - - -/* External API: - */ -void vbo_exec_init( struct gl_context *ctx ); -void vbo_exec_destroy( struct gl_context *ctx ); -void vbo_exec_invalidate_state( struct gl_context *ctx, GLuint new_state ); - -void vbo_exec_BeginVertices( struct gl_context *ctx ); -void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags ); - - -/* Internal functions: - */ -void vbo_exec_array_init( struct vbo_exec_context *exec ); -void vbo_exec_array_destroy( struct vbo_exec_context *exec ); - - -void vbo_exec_vtx_init( struct vbo_exec_context *exec ); -void vbo_exec_vtx_destroy( struct vbo_exec_context *exec ); - -#if FEATURE_beginend - -void vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap ); -void vbo_exec_vtx_map( struct vbo_exec_context *exec ); - -#else /* FEATURE_beginend */ - -static INLINE void -vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap ) -{ -} - -static INLINE void -vbo_exec_vtx_map( struct vbo_exec_context *exec ) -{ -} - -#endif /* FEATURE_beginend */ - -void vbo_exec_vtx_wrap( struct vbo_exec_context *exec ); - -void vbo_exec_eval_update( struct vbo_exec_context *exec ); - -void vbo_exec_do_EvalCoord2f( struct vbo_exec_context *exec, - GLfloat u, GLfloat v ); - -void vbo_exec_do_EvalCoord1f( struct vbo_exec_context *exec, - GLfloat u); - -#endif +/**************************************************************************
+
+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 __VBO_EXEC_H__
+#define __VBO_EXEC_H__
+
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
+#include "vbo.h"
+#include "vbo_attrib.h"
+
+
+/**
+ * Max number of primitives (number of glBegin/End pairs) per VBO.
+ */
+#define VBO_MAX_PRIM 64
+
+
+/**
+ * Size of the VBO to use for glBegin/glVertex/glEnd-style rendering.
+ */
+#define VBO_VERT_BUFFER_SIZE (1024*64) /* bytes */
+
+
+/** Current vertex program mode */
+enum vp_mode {
+ VP_NONE, /**< fixed function */
+ VP_NV, /**< NV vertex program */
+ VP_ARB /**< ARB vertex program or GLSL vertex shader */
+};
+
+
+struct vbo_exec_eval1_map {
+ struct gl_1d_map *map;
+ GLuint sz;
+};
+
+struct vbo_exec_eval2_map {
+ struct gl_2d_map *map;
+ GLuint sz;
+};
+
+
+
+struct vbo_exec_copied_vtx {
+ GLfloat buffer[VBO_ATTRIB_MAX * 4 * VBO_MAX_COPIED_VERTS];
+ GLuint nr;
+};
+
+
+typedef void (*vbo_attrfv_func)( const GLfloat * );
+
+
+struct vbo_exec_context
+{
+ struct gl_context *ctx;
+ GLvertexformat vtxfmt;
+
+ struct {
+ struct gl_buffer_object *bufferobj;
+
+ GLuint vertex_size; /* in dwords */
+
+ struct _mesa_prim prim[VBO_MAX_PRIM];
+ GLuint prim_count;
+
+ GLfloat *buffer_map;
+ GLfloat *buffer_ptr; /* cursor, points into buffer */
+ GLuint buffer_used; /* in bytes */
+ GLfloat vertex[VBO_ATTRIB_MAX*4]; /* current vertex */
+
+ GLuint vert_count;
+ GLuint max_vert;
+ struct vbo_exec_copied_vtx copied;
+
+ GLubyte attrsz[VBO_ATTRIB_MAX];
+ GLubyte active_sz[VBO_ATTRIB_MAX];
+
+ GLfloat *attrptr[VBO_ATTRIB_MAX];
+ struct gl_client_array arrays[VERT_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:
+ */
+ enum vp_mode program_mode;
+ GLuint enabled_flags;
+ const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
+ } vtx;
+
+
+ struct {
+ GLboolean recalculate_maps;
+ struct vbo_exec_eval1_map map1[VERT_ATTRIB_MAX];
+ struct vbo_exec_eval2_map map2[VERT_ATTRIB_MAX];
+ } eval;
+
+ struct {
+ enum vp_mode 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;
+
+ /* Which flags to set in vbo_exec_BeginVertices() */
+ GLbitfield begin_vertices_flags;
+
+#ifdef DEBUG
+ GLint flush_call_depth;
+#endif
+};
+
+
+
+/* External API:
+ */
+void vbo_exec_init( struct gl_context *ctx );
+void vbo_exec_destroy( struct gl_context *ctx );
+void vbo_exec_invalidate_state( struct gl_context *ctx, GLuint new_state );
+
+void vbo_exec_BeginVertices( struct gl_context *ctx );
+void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags );
+
+
+/* Internal functions:
+ */
+void vbo_exec_array_init( struct vbo_exec_context *exec );
+void vbo_exec_array_destroy( struct vbo_exec_context *exec );
+
+
+void vbo_exec_vtx_init( struct vbo_exec_context *exec );
+void vbo_exec_vtx_destroy( struct vbo_exec_context *exec );
+
+#if FEATURE_beginend
+
+void vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap );
+void vbo_exec_vtx_map( struct vbo_exec_context *exec );
+
+#else /* FEATURE_beginend */
+
+static INLINE void
+vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap )
+{
+}
+
+static INLINE void
+vbo_exec_vtx_map( struct vbo_exec_context *exec )
+{
+}
+
+#endif /* FEATURE_beginend */
+
+void vbo_exec_vtx_wrap( struct vbo_exec_context *exec );
+
+void vbo_exec_eval_update( struct vbo_exec_context *exec );
+
+void vbo_exec_do_EvalCoord2f( struct vbo_exec_context *exec,
+ GLfloat u, GLfloat v );
+
+void vbo_exec_do_EvalCoord1f( struct vbo_exec_context *exec,
+ GLfloat u);
+
+#endif
diff --git a/mesalib/src/mesa/vbo/vbo_exec_array.c b/mesalib/src/mesa/vbo/vbo_exec_array.c index 32ce0e4a8..ea96761e7 100644 --- a/mesalib/src/mesa/vbo/vbo_exec_array.c +++ b/mesalib/src/mesa/vbo/vbo_exec_array.c @@ -1,1360 +1,1360 @@ -/************************************************************************** - * - * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. - * Copyright 2009 VMware, Inc. - * 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/varray.h" -#include "main/bufferobj.h" -#include "main/enums.h" -#include "main/macros.h" - -#include "vbo_context.h" - - -/** - * All vertex buffers should be in an unmapped state when we're about - * to draw. This debug function checks that. - */ -static void -check_buffers_are_unmapped(const struct gl_client_array **inputs) -{ -#ifdef DEBUG - GLuint i; - - for (i = 0; i < VERT_ATTRIB_MAX; i++) { - if (inputs[i]) { - struct gl_buffer_object *obj = inputs[i]->BufferObj; - assert(!_mesa_bufferobj_mapped(obj)); - (void) obj; - } - } -#endif -} - - -/** - * A debug function that may be called from other parts of Mesa as - * needed during debugging. - */ -void -vbo_check_buffers_are_unmapped(struct gl_context *ctx) -{ - struct vbo_context *vbo = vbo_context(ctx); - struct vbo_exec_context *exec = &vbo->exec; - /* check the current vertex arrays */ - check_buffers_are_unmapped(exec->array.inputs); - /* check the current glBegin/glVertex/glEnd-style VBO */ - assert(!_mesa_bufferobj_mapped(exec->vtx.bufferobj)); -} - - - -/** - * Compute min and max elements by scanning the index buffer for - * glDraw[Range]Elements() calls. - * If primitive restart is enabled, we need to ignore restart - * indexes when computing min/max. - */ -void -vbo_get_minmax_index(struct gl_context *ctx, - const struct _mesa_prim *prim, - const struct _mesa_index_buffer *ib, - GLuint *min_index, GLuint *max_index) -{ - const GLboolean restart = ctx->Array.PrimitiveRestart; - const GLuint restartIndex = ctx->Array.RestartIndex; - const GLuint count = prim->count; - const void *indices; - GLuint i; - - if (_mesa_is_bufferobj(ib->obj)) { - const GLvoid *map = - ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, - GL_READ_ONLY, ib->obj); - indices = ADD_POINTERS(map, ib->ptr); - } else { - indices = ib->ptr; - } - - switch (ib->type) { - case GL_UNSIGNED_INT: { - const GLuint *ui_indices = (const GLuint *)indices; - GLuint max_ui = 0; - GLuint min_ui = ~0U; - if (restart) { - for (i = 0; i < count; i++) { - if (ui_indices[i] != restartIndex) { - if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; - if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; - } - } - } - else { - 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 = 0; - GLuint min_us = ~0U; - if (restart) { - for (i = 0; i < count; i++) { - if (us_indices[i] != restartIndex) { - if (us_indices[i] > max_us) max_us = us_indices[i]; - if (us_indices[i] < min_us) min_us = us_indices[i]; - } - } - } - else { - 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 = 0; - GLuint min_ub = ~0U; - if (restart) { - for (i = 0; i < count; i++) { - if (ub_indices[i] != restartIndex) { - if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; - if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; - } - } - } - else { - 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; - } - - if (_mesa_is_bufferobj(ib->obj)) { - ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, ib->obj); - } -} - - -/** - * Check that element 'j' of the array has reasonable data. - * Map VBO if needed. - * For debugging purposes; not normally used. - */ -static void -check_array_data(struct gl_context *ctx, struct gl_client_array *array, - GLuint attrib, GLuint j) -{ - if (array->Enabled) { - const void *data = array->Ptr; - if (_mesa_is_bufferobj(array->BufferObj)) { - if (!array->BufferObj->Pointer) { - /* need to map now */ - array->BufferObj->Pointer = - ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB, - GL_READ_ONLY, array->BufferObj); - } - data = ADD_POINTERS(data, array->BufferObj->Pointer); - } - switch (array->Type) { - case GL_FLOAT: - { - GLfloat *f = (GLfloat *) ((GLubyte *) data + array->StrideB * j); - GLint k; - for (k = 0; k < array->Size; k++) { - if (IS_INF_OR_NAN(f[k]) || - f[k] >= 1.0e20 || f[k] <= -1.0e10) { - printf("Bad array data:\n"); - printf(" Element[%u].%u = %f\n", j, k, f[k]); - printf(" Array %u at %p\n", attrib, (void* ) array); - printf(" Type 0x%x, Size %d, Stride %d\n", - array->Type, array->Size, array->Stride); - printf(" Address/offset %p in Buffer Object %u\n", - array->Ptr, array->BufferObj->Name); - f[k] = 1.0; /* XXX replace the bad value! */ - } - /*assert(!IS_INF_OR_NAN(f[k]));*/ - } - } - break; - default: - ; - } - } -} - - -/** - * Unmap the buffer object referenced by given array, if mapped. - */ -static void -unmap_array_buffer(struct gl_context *ctx, struct gl_client_array *array) -{ - if (array->Enabled && - _mesa_is_bufferobj(array->BufferObj) && - _mesa_bufferobj_mapped(array->BufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, array->BufferObj); - } -} - - -/** - * Examine the array's data for NaNs, etc. - * For debug purposes; not normally used. - */ -static void -check_draw_elements_data(struct gl_context *ctx, GLsizei count, GLenum elemType, - const void *elements, GLint basevertex) -{ - struct gl_array_object *arrayObj = ctx->Array.ArrayObj; - const void *elemMap; - GLint i, k; - - if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { - elemMap = ctx->Driver.MapBuffer(ctx, - GL_ELEMENT_ARRAY_BUFFER_ARB, - GL_READ_ONLY, - ctx->Array.ElementArrayBufferObj); - elements = ADD_POINTERS(elements, elemMap); - } - - for (i = 0; i < count; i++) { - GLuint j; - - /* j = element[i] */ - switch (elemType) { - case GL_UNSIGNED_BYTE: - j = ((const GLubyte *) elements)[i]; - break; - case GL_UNSIGNED_SHORT: - j = ((const GLushort *) elements)[i]; - break; - case GL_UNSIGNED_INT: - j = ((const GLuint *) elements)[i]; - break; - default: - assert(0); - } - - /* check element j of each enabled array */ - check_array_data(ctx, &arrayObj->Vertex, VERT_ATTRIB_POS, j); - check_array_data(ctx, &arrayObj->Normal, VERT_ATTRIB_NORMAL, j); - check_array_data(ctx, &arrayObj->Color, VERT_ATTRIB_COLOR0, j); - check_array_data(ctx, &arrayObj->SecondaryColor, VERT_ATTRIB_COLOR1, j); - for (k = 0; k < Elements(arrayObj->TexCoord); k++) { - check_array_data(ctx, &arrayObj->TexCoord[k], VERT_ATTRIB_TEX0 + k, j); - } - for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { - check_array_data(ctx, &arrayObj->VertexAttrib[k], - VERT_ATTRIB_GENERIC0 + k, j); - } - } - - if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { - ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, - ctx->Array.ElementArrayBufferObj); - } - - unmap_array_buffer(ctx, &arrayObj->Vertex); - unmap_array_buffer(ctx, &arrayObj->Normal); - unmap_array_buffer(ctx, &arrayObj->Color); - for (k = 0; k < Elements(arrayObj->TexCoord); k++) { - unmap_array_buffer(ctx, &arrayObj->TexCoord[k]); - } - for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { - unmap_array_buffer(ctx, &arrayObj->VertexAttrib[k]); - } -} - - -/** - * Check array data, looking for NaNs, etc. - */ -static void -check_draw_arrays_data(struct gl_context *ctx, GLint start, GLsizei count) -{ - /* TO DO */ -} - - -/** - * Print info/data for glDrawArrays(), for debugging. - */ -static void -print_draw_arrays(struct gl_context *ctx, - GLenum mode, GLint start, GLsizei count) -{ - struct vbo_context *vbo = vbo_context(ctx); - struct vbo_exec_context *exec = &vbo->exec; - int i; - - printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n", - mode, start, count); - - for (i = 0; i < 32; i++) { - struct gl_buffer_object *bufObj = exec->array.inputs[i]->BufferObj; - GLuint bufName = bufObj->Name; - GLint stride = exec->array.inputs[i]->Stride; - 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) { - GLubyte *p = ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB, - GL_READ_ONLY_ARB, bufObj); - int offset = (int) (GLintptr) 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; - printf(" Data at offset %d:\n", offset); - for (i = 0; i < n; i++) { - printf(" float[%d] = 0x%08x %f\n", i, k[i], f[i]); - } - ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, bufObj); - } - } -} - - -/** - * Bind the VBO executor to the current vertex array object prior - * to drawing. - * - * Just translate the arrayobj into a sane layout. - */ -static void -bind_array_obj(struct gl_context *ctx) -{ - struct vbo_context *vbo = vbo_context(ctx); - struct vbo_exec_context *exec = &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] = &arrayObj->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 < Elements(arrayObj->TexCoord); i++) - exec->array.legacy_array[VERT_ATTRIB_TEX0 + i] = &arrayObj->TexCoord[i]; - - for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) { - assert(i < Elements(exec->array.generic_array)); - exec->array.generic_array[i] = &arrayObj->VertexAttrib[i]; - } - - exec->array.array_obj = arrayObj->Name; -} - - -/** - * Set the vbo->exec->inputs[] pointers to point to the enabled - * vertex arrays. This depends on the current vertex program/shader - * being executed because of whether or not generic vertex arrays - * alias the conventional vertex arrays. - * For arrays that aren't enabled, we set the input[attrib] pointer - * to point at a zero-stride current value "array". - */ -static void -recalculate_input_bindings(struct gl_context *ctx) -{ - struct vbo_context *vbo = vbo_context(ctx); - struct vbo_exec_context *exec = &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 (or the vertex program is generated - * from fixed-function state). 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] = &vbo->legacy_currval[i]; - const_inputs |= 1 << i; - } - } - - for (i = 0; i < MAT_ATTRIB_MAX; i++) { - inputs[VERT_ATTRIB_GENERIC0 + i] = &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] = &vbo->generic_currval[i]; - const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); - } - - /* There is no need to make _NEW_ARRAY dirty here for the TnL program, - * because it already takes care of invalidating the state necessary - * to revalidate vertex arrays. Not marking the state as dirty also - * improves performance (quite significantly in some apps). - */ - if (!ctx->VertexProgram._MaintainTnlProgram) - ctx->NewState |= _NEW_ARRAY; - 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] = &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] = &vbo->generic_currval[i - VERT_ATTRIB_GENERIC0]; - const_inputs |= 1 << i; - } - - ctx->NewState |= _NEW_ARRAY; - break; - - case VP_ARB: - /* GL_ARB_vertex_program or GLSL vertex shader - Only the generic[0] - * attribute 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] = &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] = &vbo->legacy_currval[i]; - const_inputs |= 1 << i; - } - } - - for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) { - if (exec->array.generic_array[i]->Enabled) - inputs[VERT_ATTRIB_GENERIC0 + i] = exec->array.generic_array[i]; - else { - inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; - const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); - } - } - - ctx->NewState |= _NEW_ARRAY; - break; - } - - _mesa_set_varying_vp_inputs( ctx, ~const_inputs ); -} - - -/** - * Examine the enabled vertex arrays to set the exec->array.inputs[] values. - * These will point to the arrays to actually use for drawing. Some will - * be user-provided arrays, other will be zero-stride const-valued arrays. - * Note that this might set the _NEW_ARRAY dirty flag so state validation - * must be done after this call. - */ -static void -bind_arrays(struct gl_context *ctx) -{ - if (!ctx->Array.RebindArrays) { - return; - } - - bind_array_obj(ctx); - recalculate_input_bindings(ctx); - ctx->Array.RebindArrays = GL_FALSE; -} - - -/** - * Helper function called by the other DrawArrays() functions below. - * This is where we handle primitive restart for drawing non-indexed - * arrays. If primitive restart is enabled, it typically means - * splitting one DrawArrays() into two. - */ -static void -vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, - GLsizei count, GLuint numInstances) -{ - struct vbo_context *vbo = vbo_context(ctx); - struct vbo_exec_context *exec = &vbo->exec; - struct _mesa_prim prim[2]; - - bind_arrays(ctx); - - /* Again... because we may have changed the bitmask of per-vertex varying - * attributes. If we regenerate the fixed-function vertex program now - * we may be able to prune down the number of vertex attributes which we - * need in the shader. - */ - if (ctx->NewState) - _mesa_update_state(ctx); - - /* init most fields to zero */ - memset(prim, 0, sizeof(prim)); - prim[0].begin = 1; - prim[0].end = 1; - prim[0].mode = mode; - prim[0].num_instances = numInstances; - - /* Implement the primitive restart index */ - if (ctx->Array.PrimitiveRestart && ctx->Array.RestartIndex < count) { - GLuint primCount = 0; - - if (ctx->Array.RestartIndex == start) { - /* special case: RestartIndex at beginning */ - if (count > 1) { - prim[0].start = start + 1; - prim[0].count = count - 1; - primCount = 1; - } - } - else if (ctx->Array.RestartIndex == start + count - 1) { - /* special case: RestartIndex at end */ - if (count > 1) { - prim[0].start = start; - prim[0].count = count - 1; - primCount = 1; - } - } - else { - /* general case: RestartIndex in middle, split into two prims */ - prim[0].start = start; - prim[0].count = ctx->Array.RestartIndex - start; - - prim[1] = prim[0]; - prim[1].start = ctx->Array.RestartIndex + 1; - prim[1].count = count - prim[1].start; - - primCount = 2; - } - - if (primCount > 0) { - /* draw one or two prims */ - check_buffers_are_unmapped(exec->array.inputs); - vbo->draw_prims(ctx, exec->array.inputs, prim, primCount, NULL, - GL_TRUE, start, start + count - 1); - } - } - else { - /* no prim restart */ - prim[0].start = start; - prim[0].count = count; - - check_buffers_are_unmapped(exec->array.inputs); - vbo->draw_prims(ctx, exec->array.inputs, prim, 1, NULL, - GL_TRUE, start, start + count - 1); - } -} - - - -/** - * Called from glDrawArrays when in immediate mode (not display list mode). - */ -static void GLAPIENTRY -vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count) -{ - GET_CURRENT_CONTEXT(ctx); - - if (MESA_VERBOSE & VERBOSE_DRAW) - _mesa_debug(ctx, "glDrawArrays(%s, %d, %d)\n", - _mesa_lookup_enum_by_nr(mode), start, count); - - if (!_mesa_validate_DrawArrays( ctx, mode, start, count )) - return; - - FLUSH_CURRENT( ctx, 0 ); - - if (!_mesa_valid_to_render(ctx, "glDrawArrays")) { - return; - } - - if (0) - check_draw_arrays_data(ctx, start, count); - - vbo_draw_arrays(ctx, mode, start, count, 1); - - if (0) - print_draw_arrays(ctx, mode, start, count); -} - - -/** - * Called from glDrawArraysInstanced when in immediate mode (not - * display list mode). - */ -static void GLAPIENTRY -vbo_exec_DrawArraysInstanced(GLenum mode, GLint start, GLsizei count, - GLsizei numInstances) -{ - GET_CURRENT_CONTEXT(ctx); - - if (MESA_VERBOSE & VERBOSE_DRAW) - _mesa_debug(ctx, "glDrawArraysInstanced(%s, %d, %d, %d)\n", - _mesa_lookup_enum_by_nr(mode), start, count, numInstances); - - if (!_mesa_validate_DrawArraysInstanced(ctx, mode, start, count, numInstances)) - return; - - FLUSH_CURRENT( ctx, 0 ); - - if (!_mesa_valid_to_render(ctx, "glDrawArraysInstanced")) { - return; - } - - if (0) - check_draw_arrays_data(ctx, start, count); - - vbo_draw_arrays(ctx, mode, start, count, numInstances); - - if (0) - print_draw_arrays(ctx, mode, start, count); -} - - -/** - * Map GL_ELEMENT_ARRAY_BUFFER and print contents. - * For debugging. - */ -static void -dump_element_buffer(struct gl_context *ctx, GLenum type) -{ - const GLvoid *map = ctx->Driver.MapBuffer(ctx, - GL_ELEMENT_ARRAY_BUFFER_ARB, - GL_READ_ONLY, - ctx->Array.ElementArrayBufferObj); - switch (type) { - case GL_UNSIGNED_BYTE: - { - const GLubyte *us = (const GLubyte *) map; - GLint i; - for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size; i++) { - printf("%02x ", us[i]); - if (i % 32 == 31) - printf("\n"); - } - printf("\n"); - } - break; - case GL_UNSIGNED_SHORT: - { - const GLushort *us = (const GLushort *) map; - GLint i; - for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 2; i++) { - printf("%04x ", us[i]); - if (i % 16 == 15) - printf("\n"); - } - printf("\n"); - } - break; - case GL_UNSIGNED_INT: - { - const GLuint *us = (const GLuint *) map; - GLint i; - for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 4; i++) { - printf("%08x ", us[i]); - if (i % 8 == 7) - printf("\n"); - } - printf("\n"); - } - break; - default: - ; - } - - ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, - ctx->Array.ElementArrayBufferObj); -} - - -/** - * Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements. - * Do the rendering for a glDrawElements or glDrawRangeElements call after - * we've validated buffer bounds, etc. - */ -static void -vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode, - GLboolean index_bounds_valid, - GLuint start, GLuint end, - GLsizei count, GLenum type, - const GLvoid *indices, - GLint basevertex, GLint numInstances) -{ - struct vbo_context *vbo = vbo_context(ctx); - struct vbo_exec_context *exec = &vbo->exec; - struct _mesa_index_buffer ib; - struct _mesa_prim prim[1]; - - FLUSH_CURRENT( ctx, 0 ); - - if (!_mesa_valid_to_render(ctx, "glDraw[Range]Elements")) { - return; - } - - bind_arrays( ctx ); - - /* check for dirty state again */ - 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; - prim[0].basevertex = basevertex; - prim[0].num_instances = numInstances; - - /* 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 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 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. - */ - - check_buffers_are_unmapped(exec->array.inputs); - vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, - index_bounds_valid, start, end ); -} - - -/** - * Called by glDrawRangeElementsBaseVertex() in immediate mode. - */ -static void GLAPIENTRY -vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, - GLuint start, GLuint end, - GLsizei count, GLenum type, - const GLvoid *indices, - GLint basevertex) -{ - static GLuint warnCount = 0; - GET_CURRENT_CONTEXT(ctx); - - if (MESA_VERBOSE & VERBOSE_DRAW) - _mesa_debug(ctx, - "glDrawRangeElementsBaseVertex(%s, %u, %u, %d, %s, %p, %d)\n", - _mesa_lookup_enum_by_nr(mode), start, end, count, - _mesa_lookup_enum_by_nr(type), indices, basevertex); - - if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, - type, indices, basevertex )) - return; - - /* NOTE: It's important that 'end' is a reasonable value. - * in _tnl_draw_prims(), we use end to determine how many vertices - * to transform. If it's too large, we can unnecessarily split prims - * or we can read/write out of memory in several different places! - */ - - /* Catch/fix some potential user errors */ - if (type == GL_UNSIGNED_BYTE) { - start = MIN2(start, 0xff); - end = MIN2(end, 0xff); - } - else if (type == GL_UNSIGNED_SHORT) { - start = MIN2(start, 0xffff); - end = MIN2(end, 0xffff); - } - - if (end >= ctx->Array.ArrayObj->_MaxElement) { - /* the max element is out of bounds of one or more enabled arrays */ - warnCount++; - - if (warnCount < 10) { - _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, " - "type 0x%x, indices=%p)\n" - "\tend is out of bounds (max=%u) " - "Element Buffer %u (size %d)\n" - "\tThis should probably be fixed in the application.", - start, end, count, type, indices, - ctx->Array.ArrayObj->_MaxElement - 1, - ctx->Array.ElementArrayBufferObj->Name, - (int) ctx->Array.ElementArrayBufferObj->Size); - } - - if (0) - dump_element_buffer(ctx, type); - - if (0) - _mesa_print_arrays(ctx); - - /* 'end' was out of bounds, but now let's check the actual array - * indexes to see if any of them are out of bounds. - */ - if (0) { - GLuint max = _mesa_max_buffer_index(ctx, count, type, indices, - ctx->Array.ElementArrayBufferObj); - if (max >= ctx->Array.ArrayObj->_MaxElement) { - if (warnCount < 10) { - _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, " - "count %d, type 0x%x, indices=%p)\n" - "\tindex=%u is out of bounds (max=%u) " - "Element Buffer %u (size %d)\n" - "\tSkipping the glDrawRangeElements() call", - start, end, count, type, indices, max, - ctx->Array.ArrayObj->_MaxElement - 1, - ctx->Array.ElementArrayBufferObj->Name, - (int) ctx->Array.ElementArrayBufferObj->Size); - } - } - /* XXX we could also find the min index and compare to 'start' - * to see if start is correct. But it's more likely to get the - * upper bound wrong. - */ - } - - /* Set 'end' to the max possible legal value */ - assert(ctx->Array.ArrayObj->_MaxElement >= 1); - end = ctx->Array.ArrayObj->_MaxElement - 1; - - if (end < start) { - return; - } - } - - if (0) { - printf("glDraw[Range]Elements{,BaseVertex}" - "(start %u, end %u, type 0x%x, count %d) ElemBuf %u, " - "base %d\n", - start, end, type, count, - ctx->Array.ElementArrayBufferObj->Name, - basevertex); - } - -#if 0 - check_draw_elements_data(ctx, count, type, indices); -#else - (void) check_draw_elements_data; -#endif - - vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end, - count, type, indices, basevertex, 1); -} - - -/** - * Called by glDrawRangeElements() in immediate mode. - */ -static void GLAPIENTRY -vbo_exec_DrawRangeElements(GLenum mode, GLuint start, GLuint end, - GLsizei count, GLenum type, const GLvoid *indices) -{ - if (MESA_VERBOSE & VERBOSE_DRAW) { - GET_CURRENT_CONTEXT(ctx); - _mesa_debug(ctx, - "glDrawRangeElements(%s, %u, %u, %d, %s, %p)\n", - _mesa_lookup_enum_by_nr(mode), start, end, count, - _mesa_lookup_enum_by_nr(type), indices); - } - - vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, - indices, 0); -} - - -/** - * Called by glDrawElements() in immediate mode. - */ -static void GLAPIENTRY -vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices) -{ - GET_CURRENT_CONTEXT(ctx); - - if (MESA_VERBOSE & VERBOSE_DRAW) - _mesa_debug(ctx, "glDrawElements(%s, %u, %s, %p)\n", - _mesa_lookup_enum_by_nr(mode), count, - _mesa_lookup_enum_by_nr(type), indices); - - if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) - return; - - vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, - count, type, indices, 0, 1); -} - - -/** - * Called by glDrawElementsBaseVertex() in immediate mode. - */ -static void GLAPIENTRY -vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLint basevertex) -{ - GET_CURRENT_CONTEXT(ctx); - - if (MESA_VERBOSE & VERBOSE_DRAW) - _mesa_debug(ctx, "glDrawElementsBaseVertex(%s, %d, %s, %p, %d)\n", - _mesa_lookup_enum_by_nr(mode), count, - _mesa_lookup_enum_by_nr(type), indices, basevertex); - - if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, - basevertex )) - return; - - vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, - count, type, indices, basevertex, 1); -} - - -/** - * Called by glDrawElementsInstanced() in immediate mode. - */ -static void GLAPIENTRY -vbo_exec_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei numInstances) -{ - GET_CURRENT_CONTEXT(ctx); - - if (MESA_VERBOSE & VERBOSE_DRAW) - _mesa_debug(ctx, "glDrawElementsInstanced(%s, %d, %s, %p, %d)\n", - _mesa_lookup_enum_by_nr(mode), count, - _mesa_lookup_enum_by_nr(type), indices, numInstances); - - if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices, - numInstances, 0)) - return; - - vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, - count, type, indices, 0, numInstances); -} - -/** - * Called by glDrawElementsInstancedBaseVertex() in immediate mode. - */ -static void GLAPIENTRY -vbo_exec_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei numInstances, - GLint basevertex) -{ - GET_CURRENT_CONTEXT(ctx); - - if (MESA_VERBOSE & VERBOSE_DRAW) - _mesa_debug(ctx, "glDrawElementsInstancedBaseVertex(%s, %d, %s, %p, %d; %d)\n", - _mesa_lookup_enum_by_nr(mode), count, - _mesa_lookup_enum_by_nr(type), indices, - numInstances, basevertex); - - if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices, - numInstances, basevertex)) - return; - - vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, - count, type, indices, basevertex, numInstances); -} - - -/** - * Inner support for both _mesa_MultiDrawElements() and - * _mesa_MultiDrawRangeElements(). - * This does the actual rendering after we've checked array indexes, etc. - */ -static void -vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, - const GLsizei *count, GLenum type, - const GLvoid **indices, GLsizei primcount, - const GLint *basevertex) -{ - struct vbo_context *vbo = vbo_context(ctx); - struct vbo_exec_context *exec = &vbo->exec; - struct _mesa_index_buffer ib; - struct _mesa_prim *prim; - unsigned int index_type_size = 0; - uintptr_t min_index_ptr, max_index_ptr; - GLboolean fallback = GL_FALSE; - int i; - - if (primcount == 0) - return; - - FLUSH_CURRENT( ctx, 0 ); - - if (!_mesa_valid_to_render(ctx, "glMultiDrawElements")) { - return; - } - - prim = calloc(1, primcount * sizeof(*prim)); - if (prim == NULL) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements"); - return; - } - - /* Decide if we can do this all as one set of primitives sharing the - * same index buffer, or if we have to reset the index pointer per - * primitive. - */ - bind_arrays( ctx ); - - /* check for dirty state again */ - if (ctx->NewState) - _mesa_update_state( ctx ); - - switch (type) { - case GL_UNSIGNED_INT: - index_type_size = 4; - break; - case GL_UNSIGNED_SHORT: - index_type_size = 2; - break; - case GL_UNSIGNED_BYTE: - index_type_size = 1; - break; - default: - assert(0); - } - - min_index_ptr = (uintptr_t)indices[0]; - max_index_ptr = 0; - for (i = 0; i < primcount; i++) { - min_index_ptr = MIN2(min_index_ptr, (uintptr_t)indices[i]); - max_index_ptr = MAX2(max_index_ptr, (uintptr_t)indices[i] + - index_type_size * count[i]); - } - - /* Check if we can handle this thing as a bunch of index offsets from the - * same index pointer. If we can't, then we have to fall back to doing - * a draw_prims per primitive. - * Check that the difference between each prim's indexes is a multiple of - * the index/element size. - */ - if (index_type_size != 1) { - for (i = 0; i < primcount; i++) { - if ((((uintptr_t)indices[i] - min_index_ptr) % index_type_size) != 0) { - fallback = GL_TRUE; - break; - } - } - } - - /* If the index buffer isn't in a VBO, then treating the application's - * subranges of the index buffer as one large index buffer may lead to - * us reading unmapped memory. - */ - if (!_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) - fallback = GL_TRUE; - - if (!fallback) { - ib.count = (max_index_ptr - min_index_ptr) / index_type_size; - ib.type = type; - ib.obj = ctx->Array.ElementArrayBufferObj; - ib.ptr = (void *)min_index_ptr; - - for (i = 0; i < primcount; i++) { - prim[i].begin = (i == 0); - prim[i].end = (i == primcount - 1); - prim[i].weak = 0; - prim[i].pad = 0; - prim[i].mode = mode; - prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size; - prim[i].count = count[i]; - prim[i].indexed = 1; - prim[i].num_instances = 1; - if (basevertex != NULL) - prim[i].basevertex = basevertex[i]; - else - prim[i].basevertex = 0; - } - - check_buffers_are_unmapped(exec->array.inputs); - vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib, - GL_FALSE, ~0, ~0); - } else { - /* render one prim at a time */ - for (i = 0; i < primcount; i++) { - ib.count = count[i]; - ib.type = type; - ib.obj = ctx->Array.ElementArrayBufferObj; - ib.ptr = indices[i]; - - 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[i]; - prim[0].indexed = 1; - prim[0].num_instances = 1; - if (basevertex != NULL) - prim[0].basevertex = basevertex[i]; - else - prim[0].basevertex = 0; - - check_buffers_are_unmapped(exec->array.inputs); - vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib, - GL_FALSE, ~0, ~0); - } - } - - free(prim); -} - - -static void GLAPIENTRY -vbo_exec_MultiDrawElements(GLenum mode, - const GLsizei *count, GLenum type, - const GLvoid **indices, - GLsizei primcount) -{ - GET_CURRENT_CONTEXT(ctx); - GLint i; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - for (i = 0; i < primcount; i++) { - if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], - 0)) - return; - } - - vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, - NULL); -} - - -static void GLAPIENTRY -vbo_exec_MultiDrawElementsBaseVertex(GLenum mode, - const GLsizei *count, GLenum type, - const GLvoid **indices, - GLsizei primcount, - const GLsizei *basevertex) -{ - GET_CURRENT_CONTEXT(ctx); - GLint i; - - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - for (i = 0; i < primcount; i++) { - if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], - basevertex[i])) - return; - } - - vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, - basevertex); -} - - -/** - * Plug in the immediate-mode vertex array drawing commands into the - * givven vbo_exec_context object. - */ -void -vbo_exec_array_init( struct vbo_exec_context *exec ) -{ - exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays; - exec->vtxfmt.DrawElements = vbo_exec_DrawElements; - exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements; - exec->vtxfmt.MultiDrawElementsEXT = vbo_exec_MultiDrawElements; - exec->vtxfmt.DrawElementsBaseVertex = vbo_exec_DrawElementsBaseVertex; - exec->vtxfmt.DrawRangeElementsBaseVertex = vbo_exec_DrawRangeElementsBaseVertex; - exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex; - exec->vtxfmt.DrawArraysInstanced = vbo_exec_DrawArraysInstanced; - exec->vtxfmt.DrawElementsInstanced = vbo_exec_DrawElementsInstanced; - exec->vtxfmt.DrawElementsInstancedBaseVertex = vbo_exec_DrawElementsInstancedBaseVertex; -} - - -void -vbo_exec_array_destroy( struct vbo_exec_context *exec ) -{ - /* nothing to do */ -} - - - -/** - * The following functions are only used for OpenGL ES 1/2 support. - * And some aren't even supported (yet) in ES 1/2. - */ - - -void GLAPIENTRY -_mesa_DrawArrays(GLenum mode, GLint first, GLsizei count) -{ - vbo_exec_DrawArrays(mode, first, count); -} - - -void GLAPIENTRY -_mesa_DrawElements(GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices) -{ - vbo_exec_DrawElements(mode, count, type, indices); -} - - -void GLAPIENTRY -_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLint basevertex) -{ - vbo_exec_DrawElementsBaseVertex(mode, count, type, indices, basevertex); -} - - -void GLAPIENTRY -_mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, - GLenum type, const GLvoid *indices) -{ - vbo_exec_DrawRangeElements(mode, start, end, count, type, indices); -} - - -void GLAPIENTRY -_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, - GLsizei count, GLenum type, - const GLvoid *indices, GLint basevertex) -{ - vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, - indices, basevertex); -} - - -void GLAPIENTRY -_mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type, - const GLvoid **indices, GLsizei primcount) -{ - vbo_exec_MultiDrawElements(mode, count, type, indices, primcount); -} - - -void GLAPIENTRY -_mesa_MultiDrawElementsBaseVertex(GLenum mode, - const GLsizei *count, GLenum type, - const GLvoid **indices, GLsizei primcount, - const GLint *basevertex) -{ - vbo_exec_MultiDrawElementsBaseVertex(mode, count, type, indices, - primcount, basevertex); -} +/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2009 VMware, Inc.
+ * 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/varray.h"
+#include "main/bufferobj.h"
+#include "main/enums.h"
+#include "main/macros.h"
+
+#include "vbo_context.h"
+
+
+/**
+ * All vertex buffers should be in an unmapped state when we're about
+ * to draw. This debug function checks that.
+ */
+static void
+check_buffers_are_unmapped(const struct gl_client_array **inputs)
+{
+#ifdef DEBUG
+ GLuint i;
+
+ for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+ if (inputs[i]) {
+ struct gl_buffer_object *obj = inputs[i]->BufferObj;
+ assert(!_mesa_bufferobj_mapped(obj));
+ (void) obj;
+ }
+ }
+#endif
+}
+
+
+/**
+ * A debug function that may be called from other parts of Mesa as
+ * needed during debugging.
+ */
+void
+vbo_check_buffers_are_unmapped(struct gl_context *ctx)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_exec_context *exec = &vbo->exec;
+ /* check the current vertex arrays */
+ check_buffers_are_unmapped(exec->array.inputs);
+ /* check the current glBegin/glVertex/glEnd-style VBO */
+ assert(!_mesa_bufferobj_mapped(exec->vtx.bufferobj));
+}
+
+
+
+/**
+ * Compute min and max elements by scanning the index buffer for
+ * glDraw[Range]Elements() calls.
+ * If primitive restart is enabled, we need to ignore restart
+ * indexes when computing min/max.
+ */
+void
+vbo_get_minmax_index(struct gl_context *ctx,
+ const struct _mesa_prim *prim,
+ const struct _mesa_index_buffer *ib,
+ GLuint *min_index, GLuint *max_index)
+{
+ const GLboolean restart = ctx->Array.PrimitiveRestart;
+ const GLuint restartIndex = ctx->Array.RestartIndex;
+ const GLuint count = prim->count;
+ const void *indices;
+ GLuint i;
+
+ if (_mesa_is_bufferobj(ib->obj)) {
+ const GLvoid *map =
+ ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY, ib->obj);
+ indices = ADD_POINTERS(map, ib->ptr);
+ } else {
+ indices = ib->ptr;
+ }
+
+ switch (ib->type) {
+ case GL_UNSIGNED_INT: {
+ const GLuint *ui_indices = (const GLuint *)indices;
+ GLuint max_ui = 0;
+ GLuint min_ui = ~0U;
+ if (restart) {
+ for (i = 0; i < count; i++) {
+ if (ui_indices[i] != restartIndex) {
+ if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
+ if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
+ }
+ }
+ }
+ else {
+ 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 = 0;
+ GLuint min_us = ~0U;
+ if (restart) {
+ for (i = 0; i < count; i++) {
+ if (us_indices[i] != restartIndex) {
+ if (us_indices[i] > max_us) max_us = us_indices[i];
+ if (us_indices[i] < min_us) min_us = us_indices[i];
+ }
+ }
+ }
+ else {
+ 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 = 0;
+ GLuint min_ub = ~0U;
+ if (restart) {
+ for (i = 0; i < count; i++) {
+ if (ub_indices[i] != restartIndex) {
+ if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
+ if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
+ }
+ }
+ }
+ else {
+ 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;
+ }
+
+ if (_mesa_is_bufferobj(ib->obj)) {
+ ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, ib->obj);
+ }
+}
+
+
+/**
+ * Check that element 'j' of the array has reasonable data.
+ * Map VBO if needed.
+ * For debugging purposes; not normally used.
+ */
+static void
+check_array_data(struct gl_context *ctx, struct gl_client_array *array,
+ GLuint attrib, GLuint j)
+{
+ if (array->Enabled) {
+ const void *data = array->Ptr;
+ if (_mesa_is_bufferobj(array->BufferObj)) {
+ if (!array->BufferObj->Pointer) {
+ /* need to map now */
+ array->BufferObj->Pointer =
+ ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY, array->BufferObj);
+ }
+ data = ADD_POINTERS(data, array->BufferObj->Pointer);
+ }
+ switch (array->Type) {
+ case GL_FLOAT:
+ {
+ GLfloat *f = (GLfloat *) ((GLubyte *) data + array->StrideB * j);
+ GLint k;
+ for (k = 0; k < array->Size; k++) {
+ if (IS_INF_OR_NAN(f[k]) ||
+ f[k] >= 1.0e20 || f[k] <= -1.0e10) {
+ printf("Bad array data:\n");
+ printf(" Element[%u].%u = %f\n", j, k, f[k]);
+ printf(" Array %u at %p\n", attrib, (void* ) array);
+ printf(" Type 0x%x, Size %d, Stride %d\n",
+ array->Type, array->Size, array->Stride);
+ printf(" Address/offset %p in Buffer Object %u\n",
+ array->Ptr, array->BufferObj->Name);
+ f[k] = 1.0; /* XXX replace the bad value! */
+ }
+ /*assert(!IS_INF_OR_NAN(f[k]));*/
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+
+/**
+ * Unmap the buffer object referenced by given array, if mapped.
+ */
+static void
+unmap_array_buffer(struct gl_context *ctx, struct gl_client_array *array)
+{
+ if (array->Enabled &&
+ _mesa_is_bufferobj(array->BufferObj) &&
+ _mesa_bufferobj_mapped(array->BufferObj)) {
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, array->BufferObj);
+ }
+}
+
+
+/**
+ * Examine the array's data for NaNs, etc.
+ * For debug purposes; not normally used.
+ */
+static void
+check_draw_elements_data(struct gl_context *ctx, GLsizei count, GLenum elemType,
+ const void *elements, GLint basevertex)
+{
+ struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
+ const void *elemMap;
+ GLint i, k;
+
+ if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
+ elemMap = ctx->Driver.MapBuffer(ctx,
+ GL_ELEMENT_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY,
+ ctx->Array.ElementArrayBufferObj);
+ elements = ADD_POINTERS(elements, elemMap);
+ }
+
+ for (i = 0; i < count; i++) {
+ GLuint j;
+
+ /* j = element[i] */
+ switch (elemType) {
+ case GL_UNSIGNED_BYTE:
+ j = ((const GLubyte *) elements)[i];
+ break;
+ case GL_UNSIGNED_SHORT:
+ j = ((const GLushort *) elements)[i];
+ break;
+ case GL_UNSIGNED_INT:
+ j = ((const GLuint *) elements)[i];
+ break;
+ default:
+ assert(0);
+ }
+
+ /* check element j of each enabled array */
+ check_array_data(ctx, &arrayObj->Vertex, VERT_ATTRIB_POS, j);
+ check_array_data(ctx, &arrayObj->Normal, VERT_ATTRIB_NORMAL, j);
+ check_array_data(ctx, &arrayObj->Color, VERT_ATTRIB_COLOR0, j);
+ check_array_data(ctx, &arrayObj->SecondaryColor, VERT_ATTRIB_COLOR1, j);
+ for (k = 0; k < Elements(arrayObj->TexCoord); k++) {
+ check_array_data(ctx, &arrayObj->TexCoord[k], VERT_ATTRIB_TEX0 + k, j);
+ }
+ for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) {
+ check_array_data(ctx, &arrayObj->VertexAttrib[k],
+ VERT_ATTRIB_GENERIC0 + k, j);
+ }
+ }
+
+ if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) {
+ ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB,
+ ctx->Array.ElementArrayBufferObj);
+ }
+
+ unmap_array_buffer(ctx, &arrayObj->Vertex);
+ unmap_array_buffer(ctx, &arrayObj->Normal);
+ unmap_array_buffer(ctx, &arrayObj->Color);
+ for (k = 0; k < Elements(arrayObj->TexCoord); k++) {
+ unmap_array_buffer(ctx, &arrayObj->TexCoord[k]);
+ }
+ for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) {
+ unmap_array_buffer(ctx, &arrayObj->VertexAttrib[k]);
+ }
+}
+
+
+/**
+ * Check array data, looking for NaNs, etc.
+ */
+static void
+check_draw_arrays_data(struct gl_context *ctx, GLint start, GLsizei count)
+{
+ /* TO DO */
+}
+
+
+/**
+ * Print info/data for glDrawArrays(), for debugging.
+ */
+static void
+print_draw_arrays(struct gl_context *ctx,
+ GLenum mode, GLint start, GLsizei count)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_exec_context *exec = &vbo->exec;
+ int i;
+
+ printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n",
+ mode, start, count);
+
+ for (i = 0; i < 32; i++) {
+ struct gl_buffer_object *bufObj = exec->array.inputs[i]->BufferObj;
+ GLuint bufName = bufObj->Name;
+ GLint stride = exec->array.inputs[i]->Stride;
+ 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) {
+ GLubyte *p = ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY_ARB, bufObj);
+ int offset = (int) (GLintptr) 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;
+ printf(" Data at offset %d:\n", offset);
+ for (i = 0; i < n; i++) {
+ printf(" float[%d] = 0x%08x %f\n", i, k[i], f[i]);
+ }
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, bufObj);
+ }
+ }
+}
+
+
+/**
+ * Bind the VBO executor to the current vertex array object prior
+ * to drawing.
+ *
+ * Just translate the arrayobj into a sane layout.
+ */
+static void
+bind_array_obj(struct gl_context *ctx)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_exec_context *exec = &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] = &arrayObj->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 < Elements(arrayObj->TexCoord); i++)
+ exec->array.legacy_array[VERT_ATTRIB_TEX0 + i] = &arrayObj->TexCoord[i];
+
+ for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) {
+ assert(i < Elements(exec->array.generic_array));
+ exec->array.generic_array[i] = &arrayObj->VertexAttrib[i];
+ }
+
+ exec->array.array_obj = arrayObj->Name;
+}
+
+
+/**
+ * Set the vbo->exec->inputs[] pointers to point to the enabled
+ * vertex arrays. This depends on the current vertex program/shader
+ * being executed because of whether or not generic vertex arrays
+ * alias the conventional vertex arrays.
+ * For arrays that aren't enabled, we set the input[attrib] pointer
+ * to point at a zero-stride current value "array".
+ */
+static void
+recalculate_input_bindings(struct gl_context *ctx)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_exec_context *exec = &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 (or the vertex program is generated
+ * from fixed-function state). 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] = &vbo->legacy_currval[i];
+ const_inputs |= 1 << i;
+ }
+ }
+
+ for (i = 0; i < MAT_ATTRIB_MAX; i++) {
+ inputs[VERT_ATTRIB_GENERIC0 + i] = &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] = &vbo->generic_currval[i];
+ const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i);
+ }
+
+ /* There is no need to make _NEW_ARRAY dirty here for the TnL program,
+ * because it already takes care of invalidating the state necessary
+ * to revalidate vertex arrays. Not marking the state as dirty also
+ * improves performance (quite significantly in some apps).
+ */
+ if (!ctx->VertexProgram._MaintainTnlProgram)
+ ctx->NewState |= _NEW_ARRAY;
+ 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] = &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] = &vbo->generic_currval[i - VERT_ATTRIB_GENERIC0];
+ const_inputs |= 1 << i;
+ }
+
+ ctx->NewState |= _NEW_ARRAY;
+ break;
+
+ case VP_ARB:
+ /* GL_ARB_vertex_program or GLSL vertex shader - Only the generic[0]
+ * attribute 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] = &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] = &vbo->legacy_currval[i];
+ const_inputs |= 1 << i;
+ }
+ }
+
+ for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) {
+ if (exec->array.generic_array[i]->Enabled)
+ inputs[VERT_ATTRIB_GENERIC0 + i] = exec->array.generic_array[i];
+ else {
+ inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i];
+ const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i);
+ }
+ }
+
+ ctx->NewState |= _NEW_ARRAY;
+ break;
+ }
+
+ _mesa_set_varying_vp_inputs( ctx, ~const_inputs );
+}
+
+
+/**
+ * Examine the enabled vertex arrays to set the exec->array.inputs[] values.
+ * These will point to the arrays to actually use for drawing. Some will
+ * be user-provided arrays, other will be zero-stride const-valued arrays.
+ * Note that this might set the _NEW_ARRAY dirty flag so state validation
+ * must be done after this call.
+ */
+static void
+bind_arrays(struct gl_context *ctx)
+{
+ if (!ctx->Array.RebindArrays) {
+ return;
+ }
+
+ bind_array_obj(ctx);
+ recalculate_input_bindings(ctx);
+ ctx->Array.RebindArrays = GL_FALSE;
+}
+
+
+/**
+ * Helper function called by the other DrawArrays() functions below.
+ * This is where we handle primitive restart for drawing non-indexed
+ * arrays. If primitive restart is enabled, it typically means
+ * splitting one DrawArrays() into two.
+ */
+static void
+vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start,
+ GLsizei count, GLuint numInstances)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_exec_context *exec = &vbo->exec;
+ struct _mesa_prim prim[2];
+
+ bind_arrays(ctx);
+
+ /* Again... because we may have changed the bitmask of per-vertex varying
+ * attributes. If we regenerate the fixed-function vertex program now
+ * we may be able to prune down the number of vertex attributes which we
+ * need in the shader.
+ */
+ if (ctx->NewState)
+ _mesa_update_state(ctx);
+
+ /* init most fields to zero */
+ memset(prim, 0, sizeof(prim));
+ prim[0].begin = 1;
+ prim[0].end = 1;
+ prim[0].mode = mode;
+ prim[0].num_instances = numInstances;
+
+ /* Implement the primitive restart index */
+ if (ctx->Array.PrimitiveRestart && ctx->Array.RestartIndex < count) {
+ GLuint primCount = 0;
+
+ if (ctx->Array.RestartIndex == start) {
+ /* special case: RestartIndex at beginning */
+ if (count > 1) {
+ prim[0].start = start + 1;
+ prim[0].count = count - 1;
+ primCount = 1;
+ }
+ }
+ else if (ctx->Array.RestartIndex == start + count - 1) {
+ /* special case: RestartIndex at end */
+ if (count > 1) {
+ prim[0].start = start;
+ prim[0].count = count - 1;
+ primCount = 1;
+ }
+ }
+ else {
+ /* general case: RestartIndex in middle, split into two prims */
+ prim[0].start = start;
+ prim[0].count = ctx->Array.RestartIndex - start;
+
+ prim[1] = prim[0];
+ prim[1].start = ctx->Array.RestartIndex + 1;
+ prim[1].count = count - prim[1].start;
+
+ primCount = 2;
+ }
+
+ if (primCount > 0) {
+ /* draw one or two prims */
+ check_buffers_are_unmapped(exec->array.inputs);
+ vbo->draw_prims(ctx, exec->array.inputs, prim, primCount, NULL,
+ GL_TRUE, start, start + count - 1);
+ }
+ }
+ else {
+ /* no prim restart */
+ prim[0].start = start;
+ prim[0].count = count;
+
+ check_buffers_are_unmapped(exec->array.inputs);
+ vbo->draw_prims(ctx, exec->array.inputs, prim, 1, NULL,
+ GL_TRUE, start, start + count - 1);
+ }
+}
+
+
+
+/**
+ * Called from glDrawArrays when in immediate mode (not display list mode).
+ */
+static void GLAPIENTRY
+vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_DRAW)
+ _mesa_debug(ctx, "glDrawArrays(%s, %d, %d)\n",
+ _mesa_lookup_enum_by_nr(mode), start, count);
+
+ if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
+ return;
+
+ FLUSH_CURRENT( ctx, 0 );
+
+ if (!_mesa_valid_to_render(ctx, "glDrawArrays")) {
+ return;
+ }
+
+ if (0)
+ check_draw_arrays_data(ctx, start, count);
+
+ vbo_draw_arrays(ctx, mode, start, count, 1);
+
+ if (0)
+ print_draw_arrays(ctx, mode, start, count);
+}
+
+
+/**
+ * Called from glDrawArraysInstanced when in immediate mode (not
+ * display list mode).
+ */
+static void GLAPIENTRY
+vbo_exec_DrawArraysInstanced(GLenum mode, GLint start, GLsizei count,
+ GLsizei numInstances)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_DRAW)
+ _mesa_debug(ctx, "glDrawArraysInstanced(%s, %d, %d, %d)\n",
+ _mesa_lookup_enum_by_nr(mode), start, count, numInstances);
+
+ if (!_mesa_validate_DrawArraysInstanced(ctx, mode, start, count, numInstances))
+ return;
+
+ FLUSH_CURRENT( ctx, 0 );
+
+ if (!_mesa_valid_to_render(ctx, "glDrawArraysInstanced")) {
+ return;
+ }
+
+ if (0)
+ check_draw_arrays_data(ctx, start, count);
+
+ vbo_draw_arrays(ctx, mode, start, count, numInstances);
+
+ if (0)
+ print_draw_arrays(ctx, mode, start, count);
+}
+
+
+/**
+ * Map GL_ELEMENT_ARRAY_BUFFER and print contents.
+ * For debugging.
+ */
+static void
+dump_element_buffer(struct gl_context *ctx, GLenum type)
+{
+ const GLvoid *map = ctx->Driver.MapBuffer(ctx,
+ GL_ELEMENT_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY,
+ ctx->Array.ElementArrayBufferObj);
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ {
+ const GLubyte *us = (const GLubyte *) map;
+ GLint i;
+ for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size; i++) {
+ printf("%02x ", us[i]);
+ if (i % 32 == 31)
+ printf("\n");
+ }
+ printf("\n");
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ {
+ const GLushort *us = (const GLushort *) map;
+ GLint i;
+ for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 2; i++) {
+ printf("%04x ", us[i]);
+ if (i % 16 == 15)
+ printf("\n");
+ }
+ printf("\n");
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ {
+ const GLuint *us = (const GLuint *) map;
+ GLint i;
+ for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 4; i++) {
+ printf("%08x ", us[i]);
+ if (i % 8 == 7)
+ printf("\n");
+ }
+ printf("\n");
+ }
+ break;
+ default:
+ ;
+ }
+
+ ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB,
+ ctx->Array.ElementArrayBufferObj);
+}
+
+
+/**
+ * Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements.
+ * Do the rendering for a glDrawElements or glDrawRangeElements call after
+ * we've validated buffer bounds, etc.
+ */
+static void
+vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode,
+ GLboolean index_bounds_valid,
+ GLuint start, GLuint end,
+ GLsizei count, GLenum type,
+ const GLvoid *indices,
+ GLint basevertex, GLint numInstances)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_exec_context *exec = &vbo->exec;
+ struct _mesa_index_buffer ib;
+ struct _mesa_prim prim[1];
+
+ FLUSH_CURRENT( ctx, 0 );
+
+ if (!_mesa_valid_to_render(ctx, "glDraw[Range]Elements")) {
+ return;
+ }
+
+ bind_arrays( ctx );
+
+ /* check for dirty state again */
+ 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;
+ prim[0].basevertex = basevertex;
+ prim[0].num_instances = numInstances;
+
+ /* 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 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 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.
+ */
+
+ check_buffers_are_unmapped(exec->array.inputs);
+ vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib,
+ index_bounds_valid, start, end );
+}
+
+
+/**
+ * Called by glDrawRangeElementsBaseVertex() in immediate mode.
+ */
+static void GLAPIENTRY
+vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
+ GLuint start, GLuint end,
+ GLsizei count, GLenum type,
+ const GLvoid *indices,
+ GLint basevertex)
+{
+ static GLuint warnCount = 0;
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_DRAW)
+ _mesa_debug(ctx,
+ "glDrawRangeElementsBaseVertex(%s, %u, %u, %d, %s, %p, %d)\n",
+ _mesa_lookup_enum_by_nr(mode), start, end, count,
+ _mesa_lookup_enum_by_nr(type), indices, basevertex);
+
+ if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count,
+ type, indices, basevertex ))
+ return;
+
+ /* NOTE: It's important that 'end' is a reasonable value.
+ * in _tnl_draw_prims(), we use end to determine how many vertices
+ * to transform. If it's too large, we can unnecessarily split prims
+ * or we can read/write out of memory in several different places!
+ */
+
+ /* Catch/fix some potential user errors */
+ if (type == GL_UNSIGNED_BYTE) {
+ start = MIN2(start, 0xff);
+ end = MIN2(end, 0xff);
+ }
+ else if (type == GL_UNSIGNED_SHORT) {
+ start = MIN2(start, 0xffff);
+ end = MIN2(end, 0xffff);
+ }
+
+ if (end >= ctx->Array.ArrayObj->_MaxElement) {
+ /* the max element is out of bounds of one or more enabled arrays */
+ warnCount++;
+
+ if (warnCount < 10) {
+ _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, "
+ "type 0x%x, indices=%p)\n"
+ "\tend is out of bounds (max=%u) "
+ "Element Buffer %u (size %d)\n"
+ "\tThis should probably be fixed in the application.",
+ start, end, count, type, indices,
+ ctx->Array.ArrayObj->_MaxElement - 1,
+ ctx->Array.ElementArrayBufferObj->Name,
+ (int) ctx->Array.ElementArrayBufferObj->Size);
+ }
+
+ if (0)
+ dump_element_buffer(ctx, type);
+
+ if (0)
+ _mesa_print_arrays(ctx);
+
+ /* 'end' was out of bounds, but now let's check the actual array
+ * indexes to see if any of them are out of bounds.
+ */
+ if (0) {
+ GLuint max = _mesa_max_buffer_index(ctx, count, type, indices,
+ ctx->Array.ElementArrayBufferObj);
+ if (max >= ctx->Array.ArrayObj->_MaxElement) {
+ if (warnCount < 10) {
+ _mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, "
+ "count %d, type 0x%x, indices=%p)\n"
+ "\tindex=%u is out of bounds (max=%u) "
+ "Element Buffer %u (size %d)\n"
+ "\tSkipping the glDrawRangeElements() call",
+ start, end, count, type, indices, max,
+ ctx->Array.ArrayObj->_MaxElement - 1,
+ ctx->Array.ElementArrayBufferObj->Name,
+ (int) ctx->Array.ElementArrayBufferObj->Size);
+ }
+ }
+ /* XXX we could also find the min index and compare to 'start'
+ * to see if start is correct. But it's more likely to get the
+ * upper bound wrong.
+ */
+ }
+
+ /* Set 'end' to the max possible legal value */
+ assert(ctx->Array.ArrayObj->_MaxElement >= 1);
+ end = ctx->Array.ArrayObj->_MaxElement - 1;
+
+ if (end < start) {
+ return;
+ }
+ }
+
+ if (0) {
+ printf("glDraw[Range]Elements{,BaseVertex}"
+ "(start %u, end %u, type 0x%x, count %d) ElemBuf %u, "
+ "base %d\n",
+ start, end, type, count,
+ ctx->Array.ElementArrayBufferObj->Name,
+ basevertex);
+ }
+
+#if 0
+ check_draw_elements_data(ctx, count, type, indices);
+#else
+ (void) check_draw_elements_data;
+#endif
+
+ vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end,
+ count, type, indices, basevertex, 1);
+}
+
+
+/**
+ * Called by glDrawRangeElements() in immediate mode.
+ */
+static void GLAPIENTRY
+vbo_exec_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
+ GLsizei count, GLenum type, const GLvoid *indices)
+{
+ if (MESA_VERBOSE & VERBOSE_DRAW) {
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_debug(ctx,
+ "glDrawRangeElements(%s, %u, %u, %d, %s, %p)\n",
+ _mesa_lookup_enum_by_nr(mode), start, end, count,
+ _mesa_lookup_enum_by_nr(type), indices);
+ }
+
+ vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type,
+ indices, 0);
+}
+
+
+/**
+ * Called by glDrawElements() in immediate mode.
+ */
+static void GLAPIENTRY
+vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_DRAW)
+ _mesa_debug(ctx, "glDrawElements(%s, %u, %s, %p)\n",
+ _mesa_lookup_enum_by_nr(mode), count,
+ _mesa_lookup_enum_by_nr(type), indices);
+
+ if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 ))
+ return;
+
+ vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
+ count, type, indices, 0, 1);
+}
+
+
+/**
+ * Called by glDrawElementsBaseVertex() in immediate mode.
+ */
+static void GLAPIENTRY
+vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLint basevertex)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_DRAW)
+ _mesa_debug(ctx, "glDrawElementsBaseVertex(%s, %d, %s, %p, %d)\n",
+ _mesa_lookup_enum_by_nr(mode), count,
+ _mesa_lookup_enum_by_nr(type), indices, basevertex);
+
+ if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices,
+ basevertex ))
+ return;
+
+ vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
+ count, type, indices, basevertex, 1);
+}
+
+
+/**
+ * Called by glDrawElementsInstanced() in immediate mode.
+ */
+static void GLAPIENTRY
+vbo_exec_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLsizei numInstances)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_DRAW)
+ _mesa_debug(ctx, "glDrawElementsInstanced(%s, %d, %s, %p, %d)\n",
+ _mesa_lookup_enum_by_nr(mode), count,
+ _mesa_lookup_enum_by_nr(type), indices, numInstances);
+
+ if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
+ numInstances, 0))
+ return;
+
+ vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
+ count, type, indices, 0, numInstances);
+}
+
+/**
+ * Called by glDrawElementsInstancedBaseVertex() in immediate mode.
+ */
+static void GLAPIENTRY
+vbo_exec_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLsizei numInstances,
+ GLint basevertex)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_DRAW)
+ _mesa_debug(ctx, "glDrawElementsInstancedBaseVertex(%s, %d, %s, %p, %d; %d)\n",
+ _mesa_lookup_enum_by_nr(mode), count,
+ _mesa_lookup_enum_by_nr(type), indices,
+ numInstances, basevertex);
+
+ if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
+ numInstances, basevertex))
+ return;
+
+ vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
+ count, type, indices, basevertex, numInstances);
+}
+
+
+/**
+ * Inner support for both _mesa_MultiDrawElements() and
+ * _mesa_MultiDrawRangeElements().
+ * This does the actual rendering after we've checked array indexes, etc.
+ */
+static void
+vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode,
+ const GLsizei *count, GLenum type,
+ const GLvoid **indices, GLsizei primcount,
+ const GLint *basevertex)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_exec_context *exec = &vbo->exec;
+ struct _mesa_index_buffer ib;
+ struct _mesa_prim *prim;
+ unsigned int index_type_size = 0;
+ uintptr_t min_index_ptr, max_index_ptr;
+ GLboolean fallback = GL_FALSE;
+ int i;
+
+ if (primcount == 0)
+ return;
+
+ FLUSH_CURRENT( ctx, 0 );
+
+ if (!_mesa_valid_to_render(ctx, "glMultiDrawElements")) {
+ return;
+ }
+
+ prim = calloc(1, primcount * sizeof(*prim));
+ if (prim == NULL) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements");
+ return;
+ }
+
+ /* Decide if we can do this all as one set of primitives sharing the
+ * same index buffer, or if we have to reset the index pointer per
+ * primitive.
+ */
+ bind_arrays( ctx );
+
+ /* check for dirty state again */
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ switch (type) {
+ case GL_UNSIGNED_INT:
+ index_type_size = 4;
+ break;
+ case GL_UNSIGNED_SHORT:
+ index_type_size = 2;
+ break;
+ case GL_UNSIGNED_BYTE:
+ index_type_size = 1;
+ break;
+ default:
+ assert(0);
+ }
+
+ min_index_ptr = (uintptr_t)indices[0];
+ max_index_ptr = 0;
+ for (i = 0; i < primcount; i++) {
+ min_index_ptr = MIN2(min_index_ptr, (uintptr_t)indices[i]);
+ max_index_ptr = MAX2(max_index_ptr, (uintptr_t)indices[i] +
+ index_type_size * count[i]);
+ }
+
+ /* Check if we can handle this thing as a bunch of index offsets from the
+ * same index pointer. If we can't, then we have to fall back to doing
+ * a draw_prims per primitive.
+ * Check that the difference between each prim's indexes is a multiple of
+ * the index/element size.
+ */
+ if (index_type_size != 1) {
+ for (i = 0; i < primcount; i++) {
+ if ((((uintptr_t)indices[i] - min_index_ptr) % index_type_size) != 0) {
+ fallback = GL_TRUE;
+ break;
+ }
+ }
+ }
+
+ /* If the index buffer isn't in a VBO, then treating the application's
+ * subranges of the index buffer as one large index buffer may lead to
+ * us reading unmapped memory.
+ */
+ if (!_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj))
+ fallback = GL_TRUE;
+
+ if (!fallback) {
+ ib.count = (max_index_ptr - min_index_ptr) / index_type_size;
+ ib.type = type;
+ ib.obj = ctx->Array.ElementArrayBufferObj;
+ ib.ptr = (void *)min_index_ptr;
+
+ for (i = 0; i < primcount; i++) {
+ prim[i].begin = (i == 0);
+ prim[i].end = (i == primcount - 1);
+ prim[i].weak = 0;
+ prim[i].pad = 0;
+ prim[i].mode = mode;
+ prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size;
+ prim[i].count = count[i];
+ prim[i].indexed = 1;
+ prim[i].num_instances = 1;
+ if (basevertex != NULL)
+ prim[i].basevertex = basevertex[i];
+ else
+ prim[i].basevertex = 0;
+ }
+
+ check_buffers_are_unmapped(exec->array.inputs);
+ vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib,
+ GL_FALSE, ~0, ~0);
+ } else {
+ /* render one prim at a time */
+ for (i = 0; i < primcount; i++) {
+ ib.count = count[i];
+ ib.type = type;
+ ib.obj = ctx->Array.ElementArrayBufferObj;
+ ib.ptr = indices[i];
+
+ 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[i];
+ prim[0].indexed = 1;
+ prim[0].num_instances = 1;
+ if (basevertex != NULL)
+ prim[0].basevertex = basevertex[i];
+ else
+ prim[0].basevertex = 0;
+
+ check_buffers_are_unmapped(exec->array.inputs);
+ vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib,
+ GL_FALSE, ~0, ~0);
+ }
+ }
+
+ free(prim);
+}
+
+
+static void GLAPIENTRY
+vbo_exec_MultiDrawElements(GLenum mode,
+ const GLsizei *count, GLenum type,
+ const GLvoid **indices,
+ GLsizei primcount)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+ for (i = 0; i < primcount; i++) {
+ if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i],
+ 0))
+ return;
+ }
+
+ vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount,
+ NULL);
+}
+
+
+static void GLAPIENTRY
+vbo_exec_MultiDrawElementsBaseVertex(GLenum mode,
+ const GLsizei *count, GLenum type,
+ const GLvoid **indices,
+ GLsizei primcount,
+ const GLsizei *basevertex)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+ for (i = 0; i < primcount; i++) {
+ if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i],
+ basevertex[i]))
+ return;
+ }
+
+ vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount,
+ basevertex);
+}
+
+
+/**
+ * Plug in the immediate-mode vertex array drawing commands into the
+ * givven vbo_exec_context object.
+ */
+void
+vbo_exec_array_init( struct vbo_exec_context *exec )
+{
+ exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays;
+ exec->vtxfmt.DrawElements = vbo_exec_DrawElements;
+ exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements;
+ exec->vtxfmt.MultiDrawElementsEXT = vbo_exec_MultiDrawElements;
+ exec->vtxfmt.DrawElementsBaseVertex = vbo_exec_DrawElementsBaseVertex;
+ exec->vtxfmt.DrawRangeElementsBaseVertex = vbo_exec_DrawRangeElementsBaseVertex;
+ exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex;
+ exec->vtxfmt.DrawArraysInstanced = vbo_exec_DrawArraysInstanced;
+ exec->vtxfmt.DrawElementsInstanced = vbo_exec_DrawElementsInstanced;
+ exec->vtxfmt.DrawElementsInstancedBaseVertex = vbo_exec_DrawElementsInstancedBaseVertex;
+}
+
+
+void
+vbo_exec_array_destroy( struct vbo_exec_context *exec )
+{
+ /* nothing to do */
+}
+
+
+
+/**
+ * The following functions are only used for OpenGL ES 1/2 support.
+ * And some aren't even supported (yet) in ES 1/2.
+ */
+
+
+void GLAPIENTRY
+_mesa_DrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+ vbo_exec_DrawArrays(mode, first, count);
+}
+
+
+void GLAPIENTRY
+_mesa_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ vbo_exec_DrawElements(mode, count, type, indices);
+}
+
+
+void GLAPIENTRY
+_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLint basevertex)
+{
+ vbo_exec_DrawElementsBaseVertex(mode, count, type, indices, basevertex);
+}
+
+
+void GLAPIENTRY
+_mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
+ GLenum type, const GLvoid *indices)
+{
+ vbo_exec_DrawRangeElements(mode, start, end, count, type, indices);
+}
+
+
+void GLAPIENTRY
+_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end,
+ GLsizei count, GLenum type,
+ const GLvoid *indices, GLint basevertex)
+{
+ vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type,
+ indices, basevertex);
+}
+
+
+void GLAPIENTRY
+_mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type,
+ const GLvoid **indices, GLsizei primcount)
+{
+ vbo_exec_MultiDrawElements(mode, count, type, indices, primcount);
+}
+
+
+void GLAPIENTRY
+_mesa_MultiDrawElementsBaseVertex(GLenum mode,
+ const GLsizei *count, GLenum type,
+ const GLvoid **indices, GLsizei primcount,
+ const GLint *basevertex)
+{
+ vbo_exec_MultiDrawElementsBaseVertex(mode, count, type, indices,
+ primcount, basevertex);
+}
diff --git a/mesalib/src/mesa/vbo/vbo_save_api.c b/mesalib/src/mesa/vbo/vbo_save_api.c index 9041f791e..0b8b7dac8 100644 --- a/mesalib/src/mesa/vbo/vbo_save_api.c +++ b/mesalib/src/mesa/vbo/vbo_save_api.c @@ -1,1403 +1,1403 @@ -/************************************************************************** - -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/eval.h" -#include "main/macros.h" -#include "main/mfeatures.h" -#include "main/api_noop.h" -#include "main/api_validate.h" -#include "main/api_arrayelt.h" -#include "main/vtxfmt.h" -#include "main/dispatch.h" - -#include "vbo_context.h" - - -#if FEATURE_dlist - - -#ifdef ERROR -#undef ERROR -#endif - - -/* An interesting VBO number/name to help with debugging */ -#define VBO_BUF_ID 12345 - - -/* - * NOTE: Old 'parity' issue is gone, but copying can still be - * wrong-footed on replay. - */ -static GLuint -_save_copy_vertices(struct gl_context *ctx, - const struct vbo_save_vertex_list *node, - const GLfloat * src_buffer) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - const struct _mesa_prim *prim = &node->prim[node->prim_count - 1]; - GLuint nr = prim->count; - GLuint sz = save->vertex_size; - const GLfloat *src = src_buffer + prim->start * sz; - GLfloat *dst = save->copied.buffer; - GLuint ovf, i; - - if (prim->end) - return 0; - - switch (prim->mode) { - case GL_POINTS: - return 0; - case GL_LINES: - ovf = nr & 1; - for (i = 0; i < ovf; i++) - 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++) - 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++) - memcpy(dst + i * sz, src + (nr - ovf + i) * sz, - sz * sizeof(GLfloat)); - return i; - case GL_LINE_STRIP: - if (nr == 0) - return 0; - else { - 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) { - memcpy(dst, src + 0, sz * sizeof(GLfloat)); - return 1; - } - else { - memcpy(dst, src + 0, sz * sizeof(GLfloat)); - 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++) - memcpy(dst + i * sz, src + (nr - ovf + i) * sz, - sz * sizeof(GLfloat)); - return i; - default: - assert(0); - return 0; - } -} - - -static struct vbo_save_vertex_store * -alloc_vertex_store(struct gl_context *ctx) -{ - struct vbo_save_vertex_store *vertex_store = - CALLOC_STRUCT(vbo_save_vertex_store); - - /* obj->Name needs to be non-zero, but won't ever be examined more - * closely than that. In particular these buffers won't be entered - * into the hash and can never be confused with ones visible to the - * user. Perhaps there could be a special number for internal - * buffers: - */ - vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, - VBO_BUF_ID, - GL_ARRAY_BUFFER_ARB); - - ctx->Driver.BufferData(ctx, - GL_ARRAY_BUFFER_ARB, - VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat), - NULL, GL_STATIC_DRAW_ARB, vertex_store->bufferobj); - - vertex_store->buffer = NULL; - vertex_store->used = 0; - vertex_store->refcount = 1; - - return vertex_store; -} - - -static void -free_vertex_store(struct gl_context *ctx, - struct 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(struct gl_context *ctx, - struct vbo_save_vertex_store *vertex_store) -{ - assert(vertex_store->bufferobj); - assert(!vertex_store->buffer); - vertex_store->buffer = - (GLfloat *) ctx->Driver.MapBuffer(ctx, - GL_ARRAY_BUFFER_ARB, /* not used */ - GL_WRITE_ONLY, /* not used */ - vertex_store-> - bufferobj); - - assert(vertex_store->buffer); - return vertex_store->buffer + vertex_store->used; -} - - -static void -unmap_vertex_store(struct gl_context *ctx, - struct vbo_save_vertex_store *vertex_store) -{ - ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj); - vertex_store->buffer = NULL; -} - - -static struct vbo_save_primitive_store * -alloc_prim_store(struct gl_context *ctx) -{ - struct vbo_save_primitive_store *store = - CALLOC_STRUCT(vbo_save_primitive_store); - (void) ctx; - store->used = 0; - store->refcount = 1; - return store; -} - - -static void -_save_reset_counters(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - - save->prim = save->prim_store->buffer + save->prim_store->used; - save->buffer = save->vertex_store->buffer + save->vertex_store->used; - - assert(save->buffer == save->buffer_ptr); - - if (save->vertex_size) - save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / - save->vertex_size); - else - save->max_vert = 0; - - save->vert_count = 0; - save->prim_count = 0; - save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used; - save->dangling_attr_ref = 0; -} - - -/** - * Insert the active immediate struct onto the display list currently - * being built. - */ -static void -_save_compile_vertex_list(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - struct vbo_save_vertex_list *node; - - /* Allocate space for this structure in the display list currently - * being compiled. - */ - node = (struct vbo_save_vertex_list *) - _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node)); - - if (!node) - return; - - /* Duplicate our template, increment refcounts to the storage structs: - */ - 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++; - - if (node->prim[0].no_current_update) { - node->current_size = 0; - node->current_data = NULL; - } - else { - 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 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[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); - - vbo_loopback_vertex_list(ctx, - (const GLfloat *) ((const char *) save-> - vertex_store->buffer + - node->buffer_offset), - node->attrsz, node->prim, node->prim_count, - node->wrap_count, node->vertex_size); - - _glapi_set_dispatch(dispatch); - } - - /* Decide whether the storage structs are full, or can be used for - * the next vertex lists as well. - */ - if (save->vertex_store->used > - VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) { - - /* Unmap old store: - */ - unmap_vertex_store(ctx, save->vertex_store); - - /* Release old reference: - */ - save->vertex_store->refcount--; - assert(save->vertex_store->refcount != 0); - save->vertex_store = NULL; - - /* Allocate and map new store: - */ - save->vertex_store = alloc_vertex_store(ctx); - save->buffer_ptr = map_vertex_store(ctx, save->vertex_store); - } - - if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) { - save->prim_store->refcount--; - assert(save->prim_store->refcount != 0); - save->prim_store = alloc_prim_store(ctx); - } - - /* Reset our structures for the next run of vertices: - */ - _save_reset_counters(ctx); -} - - -/** - * TODO -- If no new vertices have been stored, don't bother saving it. - */ -static void -_save_wrap_buffers(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - GLint i = save->prim_count - 1; - GLenum mode; - GLboolean weak; - GLboolean no_current_update; - - 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; - no_current_update = save->prim[i].no_current_update; - - /* 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].no_current_update = no_current_update; - 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[0].num_instances = 1; - 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(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - GLfloat *data = save->copied.buffer; - GLuint i; - - /* Emit a glEnd to close off the last vertex list. - */ - _save_wrap_buffers(ctx); - - /* Copy stored stored vertices to start of new list. - */ - assert(save->max_vert - save->vert_count > save->copied.nr); - - for (i = 0; i < save->copied.nr; i++) { - 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(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - GLuint i; - - for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { - if (save->attrsz[i]) { - save->currentsz[i][0] = save->attrsz[i]; - COPY_CLEAN_4V(save->current[i], save->attrsz[i], save->attrptr[i]); - } - } -} - - -static void -_save_copy_from_current(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - GLint i; - - for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { - switch (save->attrsz[i]) { - case 4: - save->attrptr[i][3] = save->current[i][3]; - case 3: - save->attrptr[i][2] = save->current[i][2]; - case 2: - save->attrptr[i][1] = save->current[i][1]; - case 1: - save->attrptr[i][0] = save->current[i][0]; - case 0: - break; - } - } -} - - -/* Flush existing data, set new attrib size, replay copied vertices. - */ -static void -_save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - GLuint oldsz; - GLuint i; - GLfloat *tmp; - - /* Store the current run of vertices, and emit a GL_END. Emit a - * BEGIN in the new buffer. - */ - if (save->vert_count) - _save_wrap_buffers(ctx); - else - assert(save->copied.nr == 0); - - /* Do a COPY_TO_CURRENT to ensure back-copying works for the case - * when the attribute already exists in the vertex and is having - * its size increased. - */ - _save_copy_to_current(ctx); - - /* Fix up sizes: - */ - oldsz = save->attrsz[attr]; - save->attrsz[attr] = newsz; - - save->vertex_size += newsz - oldsz; - save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / - save->vertex_size); - save->vert_count = 0; - - /* Recalculate all the attrptr[] values: - */ - for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) { - if (save->attrsz[i]) { - save->attrptr[i] = tmp; - tmp += save->attrsz[i]; - } - else { - save->attrptr[i] = NULL; /* will not be dereferenced. */ - } - } - - /* Copy from current to repopulate the vertex with correct values. - */ - _save_copy_from_current(ctx); - - /* Replay stored vertices to translate them to new format here. - * - * If there are copied vertices and the new (upgraded) attribute - * has not been defined before, this list is somewhat degenerate, - * and will need fixup at runtime. - */ - if (save->copied.nr) { - GLfloat *data = save->copied.buffer; - GLfloat *dest = save->buffer; - GLuint j; - - /* Need to note this and fix up at runtime (or loopback): - */ - if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) { - assert(oldsz == 0); - save->dangling_attr_ref = GL_TRUE; - } - - for (i = 0; i < save->copied.nr; i++) { - for (j = 0; j < VBO_ATTRIB_MAX; j++) { - if (save->attrsz[j]) { - if (j == attr) { - if (oldsz) { - COPY_CLEAN_4V(dest, oldsz, data); - data += oldsz; - dest += newsz; - } - else { - COPY_SZ_4V(dest, newsz, save->current[attr]); - dest += newsz; - } - } - else { - GLint sz = save->attrsz[j]; - COPY_SZ_4V(dest, sz, data); - data += sz; - dest += sz; - } - } - } - } - - save->buffer_ptr = dest; - save->vert_count += save->copied.nr; - } -} - - -static void -save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - - if (sz > save->attrsz[attr]) { - /* New size is larger. Need to flush existing vertices and get - * an enlarged vertex format. - */ - _save_upgrade_vertex(ctx, attr, sz); - } - else if (sz < save->active_sz[attr]) { - static GLfloat id[4] = { 0, 0, 0, 1 }; - GLuint i; - - /* New size is equal or smaller - just need to fill in some - * zeros. - */ - for (i = sz; i <= save->attrsz[attr]; i++) - save->attrptr[attr][i - 1] = id[i - 1]; - } - - save->active_sz[attr] = sz; -} - - -static void -_save_reset_vertex(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - GLuint i; - - for (i = 0; i < VBO_ATTRIB_MAX; i++) { - save->attrsz[i] = 0; - save->active_sz[i] = 0; - } - - save->vertex_size = 0; -} - - - -#define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__); - - -/* Only one size for each attribute may be active at once. Eg. if - * Color3f is installed/active, then Color4f may not be, even if the - * vertex actually contains 4 color coordinates. This is because the - * 3f version won't otherwise set color[3] to 1.0 -- this is the job - * of the chooser function when switching between Color4f and Color3f. - */ -#define ATTR(A, N, V0, V1, V2, V3) \ -do { \ - struct vbo_save_context *save = &vbo_context(ctx)->save; \ - \ - if (save->active_sz[A] != N) \ - save_fixup_vertex(ctx, A, N); \ - \ - { \ - GLfloat *dest = save->attrptr[A]; \ - if (N>0) dest[0] = V0; \ - if (N>1) dest[1] = V1; \ - if (N>2) dest[2] = V2; \ - if (N>3) dest[3] = V3; \ - } \ - \ - if ((A) == 0) { \ - GLuint i; \ - \ - for (i = 0; i < save->vertex_size; i++) \ - save->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 "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. - */ -static void -dlist_fallback(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - - if (save->vert_count || save->prim_count) { - if (save->prim_count > 0) { - /* Close off in-progress primitive. */ - GLint i = save->prim_count - 1; - save->prim[i].count = save->vert_count - save->prim[i].start; - } - - /* Need to replay this display list with loopback, - * unfortunately, otherwise this primitive won't be handled - * properly: - */ - save->dangling_attr_ref = 1; - - _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; -} - - -static void GLAPIENTRY -_save_EvalCoord1f(GLfloat u) -{ - GET_CURRENT_CONTEXT(ctx); - dlist_fallback(ctx); - CALL_EvalCoord1f(ctx->Save, (u)); -} - -static void GLAPIENTRY -_save_EvalCoord1fv(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - dlist_fallback(ctx); - CALL_EvalCoord1fv(ctx->Save, (v)); -} - -static void GLAPIENTRY -_save_EvalCoord2f(GLfloat u, GLfloat v) -{ - GET_CURRENT_CONTEXT(ctx); - dlist_fallback(ctx); - CALL_EvalCoord2f(ctx->Save, (u, v)); -} - -static void GLAPIENTRY -_save_EvalCoord2fv(const GLfloat * v) -{ - GET_CURRENT_CONTEXT(ctx); - dlist_fallback(ctx); - CALL_EvalCoord2fv(ctx->Save, (v)); -} - -static void GLAPIENTRY -_save_EvalPoint1(GLint i) -{ - GET_CURRENT_CONTEXT(ctx); - dlist_fallback(ctx); - CALL_EvalPoint1(ctx->Save, (i)); -} - -static void GLAPIENTRY -_save_EvalPoint2(GLint i, GLint j) -{ - GET_CURRENT_CONTEXT(ctx); - dlist_fallback(ctx); - CALL_EvalPoint2(ctx->Save, (i, j)); -} - -static void GLAPIENTRY -_save_CallList(GLuint l) -{ - GET_CURRENT_CONTEXT(ctx); - dlist_fallback(ctx); - CALL_CallList(ctx->Save, (l)); -} - -static void GLAPIENTRY -_save_CallLists(GLsizei n, GLenum type, const GLvoid * v) -{ - GET_CURRENT_CONTEXT(ctx); - dlist_fallback(ctx); - CALL_CallLists(ctx->Save, (n, type, v)); -} - - - -/* This begin is hooked into ... Updating of - * ctx->Driver.CurrentSavePrimitive is already taken care of. - */ -GLboolean -vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - - GLuint i = save->prim_count++; - - assert(i < save->prim_max); - save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK; - save->prim[i].begin = 1; - save->prim[i].end = 0; - save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0; - save->prim[i].no_current_update = - (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0; - save->prim[i].pad = 0; - save->prim[i].start = save->vert_count; - save->prim[i].count = 0; - save->prim[i].num_instances = 1; - - _mesa_install_save_vtxfmt(ctx, &save->vtxfmt); - ctx->Driver.SaveNeedFlush = 1; - return GL_TRUE; -} - - -static void GLAPIENTRY -_save_End(void) -{ - GET_CURRENT_CONTEXT(ctx); - struct vbo_save_context *save = &vbo_context(ctx)->save; - GLint i = save->prim_count - 1; - - ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; - save->prim[i].end = 1; - save->prim[i].count = (save->vert_count - save->prim[i].start); - - if (i == (GLint) save->prim_max - 1) { - _save_compile_vertex_list(ctx); - assert(save->copied.nr == 0); - } - - /* Swap out this vertex format while outside begin/end. Any color, - * etc. received between here and the next begin will be compiled - * as opcodes. - */ - _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); -} - - -/* These are all errors as this vtxfmt is only installed inside - * begin/end pairs. - */ -static void GLAPIENTRY -_save_DrawElements(GLenum mode, GLsizei count, GLenum type, - const GLvoid * indices) -{ - GET_CURRENT_CONTEXT(ctx); - (void) mode; - (void) count; - (void) type; - (void) indices; - _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawElements"); -} - - -static void GLAPIENTRY -_save_DrawRangeElements(GLenum mode, GLuint start, GLuint end, - GLsizei count, GLenum type, const GLvoid * indices) -{ - GET_CURRENT_CONTEXT(ctx); - (void) mode; - (void) start; - (void) end; - (void) count; - (void) type; - (void) indices; - _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawRangeElements"); -} - - -static void GLAPIENTRY -_save_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, - const GLvoid * indices, GLint basevertex) -{ - GET_CURRENT_CONTEXT(ctx); - (void) mode; - (void) count; - (void) type; - (void) indices; - (void) basevertex; - _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawElements"); -} - - -static void GLAPIENTRY -_save_DrawRangeElementsBaseVertex(GLenum mode, - GLuint start, - GLuint end, - GLsizei count, - GLenum type, - const GLvoid * indices, GLint basevertex) -{ - GET_CURRENT_CONTEXT(ctx); - (void) mode; - (void) start; - (void) end; - (void) count; - (void) type; - (void) indices; - (void) basevertex; - _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"); -} - - -static void GLAPIENTRY -_save_PrimitiveRestartNV(void) -{ - GLenum curPrim; - GET_CURRENT_CONTEXT(ctx); - - curPrim = ctx->Driver.CurrentSavePrimitive; - - _save_End(); - _save_Begin(curPrim); -} - - -/* Unlike the functions above, these are to be hooked into the vtxfmt - * maintained in ctx->ListState, active when the list is known or - * suspected to be outside any begin/end primitive. - */ -static void GLAPIENTRY -_save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) -{ - GET_CURRENT_CONTEXT(ctx); - vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK); - CALL_Vertex2f(GET_DISPATCH(), (x1, y1)); - CALL_Vertex2f(GET_DISPATCH(), (x2, y1)); - CALL_Vertex2f(GET_DISPATCH(), (x2, y2)); - CALL_Vertex2f(GET_DISPATCH(), (x1, y2)); - CALL_End(GET_DISPATCH(), ()); -} - - -static void GLAPIENTRY -_save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) -{ - GET_CURRENT_CONTEXT(ctx); - GLint i; - - if (!_mesa_validate_DrawArrays(ctx, mode, start, count)) - return; - - _ae_map_vbos(ctx); - - vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK - | VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); - - for (i = 0; i < count; i++) - CALL_ArrayElement(GET_DISPATCH(), (start + i)); - CALL_End(GET_DISPATCH(), ()); - - _ae_unmap_vbos(ctx); -} - - -/* Could do better by copying the arrays and element list intact and - * then emitting an indexed prim at runtime. - */ -static void GLAPIENTRY -_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, - const GLvoid * indices) -{ - GET_CURRENT_CONTEXT(ctx); - GLint i; - - if (!_mesa_validate_DrawElements(ctx, mode, count, type, indices, 0)) - return; - - _ae_map_vbos(ctx); - - if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) - indices = - ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Pointer, indices); - - vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK | - VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); - - switch (type) { - case GL_UNSIGNED_BYTE: - for (i = 0; i < count; i++) - CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i])); - break; - case GL_UNSIGNED_SHORT: - for (i = 0; i < count; i++) - CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i])); - break; - case GL_UNSIGNED_INT: - for (i = 0; i < count; i++) - CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i])); - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)"); - break; - } - - CALL_End(GET_DISPATCH(), ()); - - _ae_unmap_vbos(ctx); -} - - -static void GLAPIENTRY -_save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end, - GLsizei count, GLenum type, - const GLvoid * indices) -{ - GET_CURRENT_CONTEXT(ctx); - if (_mesa_validate_DrawRangeElements(ctx, mode, - start, end, count, type, indices, 0)) { - _save_OBE_DrawElements(mode, count, type, indices); - } -} - - -static void -_save_vtxfmt_init(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - GLvertexformat *vfmt = &save->vtxfmt; - - _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_); - - 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->PrimitiveRestartNV = _save_PrimitiveRestartNV; - 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; - - /* integer-valued */ - vfmt->VertexAttribI1i = _save_VertexAttribI1i; - vfmt->VertexAttribI2i = _save_VertexAttribI2i; - vfmt->VertexAttribI3i = _save_VertexAttribI3i; - vfmt->VertexAttribI4i = _save_VertexAttribI4i; - vfmt->VertexAttribI2iv = _save_VertexAttribI2iv; - vfmt->VertexAttribI3iv = _save_VertexAttribI3iv; - vfmt->VertexAttribI4iv = _save_VertexAttribI4iv; - - /* unsigned integer-valued */ - vfmt->VertexAttribI1ui = _save_VertexAttribI1ui; - vfmt->VertexAttribI2ui = _save_VertexAttribI2ui; - vfmt->VertexAttribI3ui = _save_VertexAttribI3ui; - vfmt->VertexAttribI4ui = _save_VertexAttribI4ui; - vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv; - vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv; - vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv; - - /* This will all require us to fallback to saving the list as opcodes: - */ - _MESA_INIT_DLIST_VTXFMT(vfmt, _save_); /* inside begin/end */ - - _MESA_INIT_EVAL_VTXFMT(vfmt, _save_); - - /* These are all errors as we at least know we are in some sort of - * begin/end pair: - */ - vfmt->Begin = _save_Begin; - vfmt->Rectf = _save_Rectf; - vfmt->DrawArrays = _save_DrawArrays; - vfmt->DrawElements = _save_DrawElements; - vfmt->DrawRangeElements = _save_DrawRangeElements; - vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex; - vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex; - /* Loops back into vfmt->DrawElements */ - vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; - vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; -} - - -void -vbo_save_SaveFlushVertices(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - - /* Noop when we are actually active: - */ - if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM || - ctx->Driver.CurrentSavePrimitive <= GL_POLYGON) - return; - - if (save->vert_count || save->prim_count) - _save_compile_vertex_list(ctx); - - _save_copy_to_current(ctx); - _save_reset_vertex(ctx); - _save_reset_counters(ctx); - ctx->Driver.SaveNeedFlush = 0; -} - - -void -vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - - (void) list; - (void) mode; - - if (!save->prim_store) - save->prim_store = alloc_prim_store(ctx); - - if (!save->vertex_store) - save->vertex_store = alloc_vertex_store(ctx); - - save->buffer_ptr = map_vertex_store(ctx, save->vertex_store); - - _save_reset_vertex(ctx); - _save_reset_counters(ctx); - ctx->Driver.SaveNeedFlush = 0; -} - - -void -vbo_save_EndList(struct gl_context *ctx) -{ - struct vbo_save_context *save = &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; - 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 -vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - save->replay_flags |= dlist->Flags; -} - - -void -vbo_save_EndCallList(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - - if (ctx->ListState.CallDepth == 1) { - /* This is correct: want to keep only the VBO_SAVE_FALLBACK - * flag, if it is set: - */ - save->replay_flags &= VBO_SAVE_FALLBACK; - } -} - - -static void -vbo_destroy_vertex_list(struct gl_context *ctx, void *data) -{ - struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; - (void) ctx; - - if (--node->vertex_store->refcount == 0) - free_vertex_store(ctx, node->vertex_store); - - if (--node->prim_store->refcount == 0) - FREE(node->prim_store); - - if (node->current_data) { - FREE(node->current_data); - node->current_data = NULL; - } -} - - -static void -vbo_print_vertex_list(struct gl_context *ctx, void *data) -{ - struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; - GLuint i; - (void) ctx; - - printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n", - node->count, node->prim_count, node->vertex_size); - - for (i = 0; i < node->prim_count; i++) { - struct _mesa_prim *prim = &node->prim[i]; - _mesa_debug(NULL, " prim %d: %s%s %d..%d %s %s\n", - i, - _mesa_lookup_prim_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(struct gl_context *ctx) -{ - struct vbo_save_context *save = &vbo_context(ctx)->save; - GLint i; - - for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) { - const GLuint j = i - VBO_ATTRIB_POS; - ASSERT(j < VERT_ATTRIB_MAX); - save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j]; - save->current[i] = ctx->ListState.CurrentAttrib[j]; - } - - for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) { - const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL; - ASSERT(j < MAT_ATTRIB_MAX); - save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j]; - save->current[i] = ctx->ListState.CurrentMaterial[j]; - } -} - - -/** - * Initialize the display list compiler - */ -void -vbo_save_api_init(struct vbo_save_context *save) -{ - struct gl_context *ctx = save->ctx; - GLuint i; - - save->opcode_vertex_list = - _mesa_dlist_alloc_opcode(ctx, - sizeof(struct vbo_save_vertex_list), - vbo_save_playback_vertex_list, - vbo_destroy_vertex_list, - vbo_print_vertex_list); - - ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin; - - _save_vtxfmt_init(ctx); - _save_current_init(ctx); - - /* These will actually get set again when binding/drawing */ - for (i = 0; i < VBO_ATTRIB_MAX; i++) - save->inputs[i] = &save->arrays[i]; - - /* Hook our array functions into the outside-begin-end vtxfmt in - * ctx->ListState. - */ - ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf; - ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays; - ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements; - ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements; - /* loops back into _save_OBE_DrawElements */ - ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = - _mesa_noop_MultiDrawElements; - ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = - _mesa_noop_MultiDrawElementsBaseVertex; - _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt); -} - - -#endif /* FEATURE_dlist */ +/**************************************************************************
+
+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/eval.h"
+#include "main/macros.h"
+#include "main/mfeatures.h"
+#include "main/api_noop.h"
+#include "main/api_validate.h"
+#include "main/api_arrayelt.h"
+#include "main/vtxfmt.h"
+#include "main/dispatch.h"
+
+#include "vbo_context.h"
+
+
+#if FEATURE_dlist
+
+
+#ifdef ERROR
+#undef ERROR
+#endif
+
+
+/* An interesting VBO number/name to help with debugging */
+#define VBO_BUF_ID 12345
+
+
+/*
+ * NOTE: Old 'parity' issue is gone, but copying can still be
+ * wrong-footed on replay.
+ */
+static GLuint
+_save_copy_vertices(struct gl_context *ctx,
+ const struct vbo_save_vertex_list *node,
+ const GLfloat * src_buffer)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
+ GLuint nr = prim->count;
+ GLuint sz = save->vertex_size;
+ const GLfloat *src = src_buffer + prim->start * sz;
+ GLfloat *dst = save->copied.buffer;
+ GLuint ovf, i;
+
+ if (prim->end)
+ return 0;
+
+ switch (prim->mode) {
+ case GL_POINTS:
+ return 0;
+ case GL_LINES:
+ ovf = nr & 1;
+ for (i = 0; i < ovf; i++)
+ 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++)
+ 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++)
+ memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
+ sz * sizeof(GLfloat));
+ return i;
+ case GL_LINE_STRIP:
+ if (nr == 0)
+ return 0;
+ else {
+ 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) {
+ memcpy(dst, src + 0, sz * sizeof(GLfloat));
+ return 1;
+ }
+ else {
+ memcpy(dst, src + 0, sz * sizeof(GLfloat));
+ 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++)
+ memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
+ sz * sizeof(GLfloat));
+ return i;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+
+static struct vbo_save_vertex_store *
+alloc_vertex_store(struct gl_context *ctx)
+{
+ struct vbo_save_vertex_store *vertex_store =
+ CALLOC_STRUCT(vbo_save_vertex_store);
+
+ /* obj->Name needs to be non-zero, but won't ever be examined more
+ * closely than that. In particular these buffers won't be entered
+ * into the hash and can never be confused with ones visible to the
+ * user. Perhaps there could be a special number for internal
+ * buffers:
+ */
+ vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx,
+ VBO_BUF_ID,
+ GL_ARRAY_BUFFER_ARB);
+
+ ctx->Driver.BufferData(ctx,
+ GL_ARRAY_BUFFER_ARB,
+ VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
+ NULL, GL_STATIC_DRAW_ARB, vertex_store->bufferobj);
+
+ vertex_store->buffer = NULL;
+ vertex_store->used = 0;
+ vertex_store->refcount = 1;
+
+ return vertex_store;
+}
+
+
+static void
+free_vertex_store(struct gl_context *ctx,
+ struct 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(struct gl_context *ctx,
+ struct vbo_save_vertex_store *vertex_store)
+{
+ assert(vertex_store->bufferobj);
+ assert(!vertex_store->buffer);
+ vertex_store->buffer =
+ (GLfloat *) ctx->Driver.MapBuffer(ctx,
+ GL_ARRAY_BUFFER_ARB, /* not used */
+ GL_WRITE_ONLY, /* not used */
+ vertex_store->
+ bufferobj);
+
+ assert(vertex_store->buffer);
+ return vertex_store->buffer + vertex_store->used;
+}
+
+
+static void
+unmap_vertex_store(struct gl_context *ctx,
+ struct vbo_save_vertex_store *vertex_store)
+{
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj);
+ vertex_store->buffer = NULL;
+}
+
+
+static struct vbo_save_primitive_store *
+alloc_prim_store(struct gl_context *ctx)
+{
+ struct vbo_save_primitive_store *store =
+ CALLOC_STRUCT(vbo_save_primitive_store);
+ (void) ctx;
+ store->used = 0;
+ store->refcount = 1;
+ return store;
+}
+
+
+static void
+_save_reset_counters(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+ save->prim = save->prim_store->buffer + save->prim_store->used;
+ save->buffer = save->vertex_store->buffer + save->vertex_store->used;
+
+ assert(save->buffer == save->buffer_ptr);
+
+ if (save->vertex_size)
+ save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
+ save->vertex_size);
+ else
+ save->max_vert = 0;
+
+ save->vert_count = 0;
+ save->prim_count = 0;
+ save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
+ save->dangling_attr_ref = 0;
+}
+
+
+/**
+ * Insert the active immediate struct onto the display list currently
+ * being built.
+ */
+static void
+_save_compile_vertex_list(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ struct vbo_save_vertex_list *node;
+
+ /* Allocate space for this structure in the display list currently
+ * being compiled.
+ */
+ node = (struct vbo_save_vertex_list *)
+ _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node));
+
+ if (!node)
+ return;
+
+ /* Duplicate our template, increment refcounts to the storage structs:
+ */
+ 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++;
+
+ if (node->prim[0].no_current_update) {
+ node->current_size = 0;
+ node->current_data = NULL;
+ }
+ else {
+ 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 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[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);
+
+ vbo_loopback_vertex_list(ctx,
+ (const GLfloat *) ((const char *) save->
+ vertex_store->buffer +
+ node->buffer_offset),
+ node->attrsz, node->prim, node->prim_count,
+ node->wrap_count, node->vertex_size);
+
+ _glapi_set_dispatch(dispatch);
+ }
+
+ /* Decide whether the storage structs are full, or can be used for
+ * the next vertex lists as well.
+ */
+ if (save->vertex_store->used >
+ VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
+
+ /* Unmap old store:
+ */
+ unmap_vertex_store(ctx, save->vertex_store);
+
+ /* Release old reference:
+ */
+ save->vertex_store->refcount--;
+ assert(save->vertex_store->refcount != 0);
+ save->vertex_store = NULL;
+
+ /* Allocate and map new store:
+ */
+ save->vertex_store = alloc_vertex_store(ctx);
+ save->buffer_ptr = map_vertex_store(ctx, save->vertex_store);
+ }
+
+ if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
+ save->prim_store->refcount--;
+ assert(save->prim_store->refcount != 0);
+ save->prim_store = alloc_prim_store(ctx);
+ }
+
+ /* Reset our structures for the next run of vertices:
+ */
+ _save_reset_counters(ctx);
+}
+
+
+/**
+ * TODO -- If no new vertices have been stored, don't bother saving it.
+ */
+static void
+_save_wrap_buffers(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ GLint i = save->prim_count - 1;
+ GLenum mode;
+ GLboolean weak;
+ GLboolean no_current_update;
+
+ 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;
+ no_current_update = save->prim[i].no_current_update;
+
+ /* 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].no_current_update = no_current_update;
+ 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[0].num_instances = 1;
+ 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(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ GLfloat *data = save->copied.buffer;
+ GLuint i;
+
+ /* Emit a glEnd to close off the last vertex list.
+ */
+ _save_wrap_buffers(ctx);
+
+ /* Copy stored stored vertices to start of new list.
+ */
+ assert(save->max_vert - save->vert_count > save->copied.nr);
+
+ for (i = 0; i < save->copied.nr; i++) {
+ 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(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ GLuint i;
+
+ for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
+ if (save->attrsz[i]) {
+ save->currentsz[i][0] = save->attrsz[i];
+ COPY_CLEAN_4V(save->current[i], save->attrsz[i], save->attrptr[i]);
+ }
+ }
+}
+
+
+static void
+_save_copy_from_current(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ GLint i;
+
+ for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
+ switch (save->attrsz[i]) {
+ case 4:
+ save->attrptr[i][3] = save->current[i][3];
+ case 3:
+ save->attrptr[i][2] = save->current[i][2];
+ case 2:
+ save->attrptr[i][1] = save->current[i][1];
+ case 1:
+ save->attrptr[i][0] = save->current[i][0];
+ case 0:
+ break;
+ }
+ }
+}
+
+
+/* Flush existing data, set new attrib size, replay copied vertices.
+ */
+static void
+_save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ GLuint oldsz;
+ GLuint i;
+ GLfloat *tmp;
+
+ /* Store the current run of vertices, and emit a GL_END. Emit a
+ * BEGIN in the new buffer.
+ */
+ if (save->vert_count)
+ _save_wrap_buffers(ctx);
+ else
+ assert(save->copied.nr == 0);
+
+ /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
+ * when the attribute already exists in the vertex and is having
+ * its size increased.
+ */
+ _save_copy_to_current(ctx);
+
+ /* Fix up sizes:
+ */
+ oldsz = save->attrsz[attr];
+ save->attrsz[attr] = newsz;
+
+ save->vertex_size += newsz - oldsz;
+ save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
+ save->vertex_size);
+ save->vert_count = 0;
+
+ /* Recalculate all the attrptr[] values:
+ */
+ for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) {
+ if (save->attrsz[i]) {
+ save->attrptr[i] = tmp;
+ tmp += save->attrsz[i];
+ }
+ else {
+ save->attrptr[i] = NULL; /* will not be dereferenced. */
+ }
+ }
+
+ /* Copy from current to repopulate the vertex with correct values.
+ */
+ _save_copy_from_current(ctx);
+
+ /* Replay stored vertices to translate them to new format here.
+ *
+ * If there are copied vertices and the new (upgraded) attribute
+ * has not been defined before, this list is somewhat degenerate,
+ * and will need fixup at runtime.
+ */
+ if (save->copied.nr) {
+ GLfloat *data = save->copied.buffer;
+ GLfloat *dest = save->buffer;
+ GLuint j;
+
+ /* Need to note this and fix up at runtime (or loopback):
+ */
+ if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
+ assert(oldsz == 0);
+ save->dangling_attr_ref = GL_TRUE;
+ }
+
+ for (i = 0; i < save->copied.nr; i++) {
+ for (j = 0; j < VBO_ATTRIB_MAX; j++) {
+ if (save->attrsz[j]) {
+ if (j == attr) {
+ if (oldsz) {
+ COPY_CLEAN_4V(dest, oldsz, data);
+ data += oldsz;
+ dest += newsz;
+ }
+ else {
+ COPY_SZ_4V(dest, newsz, save->current[attr]);
+ dest += newsz;
+ }
+ }
+ else {
+ GLint sz = save->attrsz[j];
+ COPY_SZ_4V(dest, sz, data);
+ data += sz;
+ dest += sz;
+ }
+ }
+ }
+ }
+
+ save->buffer_ptr = dest;
+ save->vert_count += save->copied.nr;
+ }
+}
+
+
+static void
+save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+ if (sz > save->attrsz[attr]) {
+ /* New size is larger. Need to flush existing vertices and get
+ * an enlarged vertex format.
+ */
+ _save_upgrade_vertex(ctx, attr, sz);
+ }
+ else if (sz < save->active_sz[attr]) {
+ static GLfloat id[4] = { 0, 0, 0, 1 };
+ GLuint i;
+
+ /* New size is equal or smaller - just need to fill in some
+ * zeros.
+ */
+ for (i = sz; i <= save->attrsz[attr]; i++)
+ save->attrptr[attr][i - 1] = id[i - 1];
+ }
+
+ save->active_sz[attr] = sz;
+}
+
+
+static void
+_save_reset_vertex(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ GLuint i;
+
+ for (i = 0; i < VBO_ATTRIB_MAX; i++) {
+ save->attrsz[i] = 0;
+ save->active_sz[i] = 0;
+ }
+
+ save->vertex_size = 0;
+}
+
+
+
+#define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__);
+
+
+/* Only one size for each attribute may be active at once. Eg. if
+ * Color3f is installed/active, then Color4f may not be, even if the
+ * vertex actually contains 4 color coordinates. This is because the
+ * 3f version won't otherwise set color[3] to 1.0 -- this is the job
+ * of the chooser function when switching between Color4f and Color3f.
+ */
+#define ATTR(A, N, V0, V1, V2, V3) \
+do { \
+ struct vbo_save_context *save = &vbo_context(ctx)->save; \
+ \
+ if (save->active_sz[A] != N) \
+ save_fixup_vertex(ctx, A, N); \
+ \
+ { \
+ GLfloat *dest = save->attrptr[A]; \
+ if (N>0) dest[0] = V0; \
+ if (N>1) dest[1] = V1; \
+ if (N>2) dest[2] = V2; \
+ if (N>3) dest[3] = V3; \
+ } \
+ \
+ if ((A) == 0) { \
+ GLuint i; \
+ \
+ for (i = 0; i < save->vertex_size; i++) \
+ save->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 "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.
+ */
+static void
+dlist_fallback(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+ if (save->vert_count || save->prim_count) {
+ if (save->prim_count > 0) {
+ /* Close off in-progress primitive. */
+ GLint i = save->prim_count - 1;
+ save->prim[i].count = save->vert_count - save->prim[i].start;
+ }
+
+ /* Need to replay this display list with loopback,
+ * unfortunately, otherwise this primitive won't be handled
+ * properly:
+ */
+ save->dangling_attr_ref = 1;
+
+ _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;
+}
+
+
+static void GLAPIENTRY
+_save_EvalCoord1f(GLfloat u)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ dlist_fallback(ctx);
+ CALL_EvalCoord1f(ctx->Save, (u));
+}
+
+static void GLAPIENTRY
+_save_EvalCoord1fv(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ dlist_fallback(ctx);
+ CALL_EvalCoord1fv(ctx->Save, (v));
+}
+
+static void GLAPIENTRY
+_save_EvalCoord2f(GLfloat u, GLfloat v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ dlist_fallback(ctx);
+ CALL_EvalCoord2f(ctx->Save, (u, v));
+}
+
+static void GLAPIENTRY
+_save_EvalCoord2fv(const GLfloat * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ dlist_fallback(ctx);
+ CALL_EvalCoord2fv(ctx->Save, (v));
+}
+
+static void GLAPIENTRY
+_save_EvalPoint1(GLint i)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ dlist_fallback(ctx);
+ CALL_EvalPoint1(ctx->Save, (i));
+}
+
+static void GLAPIENTRY
+_save_EvalPoint2(GLint i, GLint j)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ dlist_fallback(ctx);
+ CALL_EvalPoint2(ctx->Save, (i, j));
+}
+
+static void GLAPIENTRY
+_save_CallList(GLuint l)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ dlist_fallback(ctx);
+ CALL_CallList(ctx->Save, (l));
+}
+
+static void GLAPIENTRY
+_save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ dlist_fallback(ctx);
+ CALL_CallLists(ctx->Save, (n, type, v));
+}
+
+
+
+/* This begin is hooked into ... Updating of
+ * ctx->Driver.CurrentSavePrimitive is already taken care of.
+ */
+GLboolean
+vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+ GLuint i = save->prim_count++;
+
+ assert(i < save->prim_max);
+ save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
+ save->prim[i].begin = 1;
+ save->prim[i].end = 0;
+ save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
+ save->prim[i].no_current_update =
+ (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0;
+ save->prim[i].pad = 0;
+ save->prim[i].start = save->vert_count;
+ save->prim[i].count = 0;
+ save->prim[i].num_instances = 1;
+
+ _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
+ ctx->Driver.SaveNeedFlush = 1;
+ return GL_TRUE;
+}
+
+
+static void GLAPIENTRY
+_save_End(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ GLint i = save->prim_count - 1;
+
+ ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
+ save->prim[i].end = 1;
+ save->prim[i].count = (save->vert_count - save->prim[i].start);
+
+ if (i == (GLint) save->prim_max - 1) {
+ _save_compile_vertex_list(ctx);
+ assert(save->copied.nr == 0);
+ }
+
+ /* Swap out this vertex format while outside begin/end. Any color,
+ * etc. received between here and the next begin will be compiled
+ * as opcodes.
+ */
+ _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
+}
+
+
+/* These are all errors as this vtxfmt is only installed inside
+ * begin/end pairs.
+ */
+static void GLAPIENTRY
+_save_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid * indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode;
+ (void) count;
+ (void) type;
+ (void) indices;
+ _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawElements");
+}
+
+
+static void GLAPIENTRY
+_save_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
+ GLsizei count, GLenum type, const GLvoid * indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode;
+ (void) start;
+ (void) end;
+ (void) count;
+ (void) type;
+ (void) indices;
+ _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawRangeElements");
+}
+
+
+static void GLAPIENTRY
+_save_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid * indices, GLint basevertex)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode;
+ (void) count;
+ (void) type;
+ (void) indices;
+ (void) basevertex;
+ _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawElements");
+}
+
+
+static void GLAPIENTRY
+_save_DrawRangeElementsBaseVertex(GLenum mode,
+ GLuint start,
+ GLuint end,
+ GLsizei count,
+ GLenum type,
+ const GLvoid * indices, GLint basevertex)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode;
+ (void) start;
+ (void) end;
+ (void) count;
+ (void) type;
+ (void) indices;
+ (void) basevertex;
+ _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");
+}
+
+
+static void GLAPIENTRY
+_save_PrimitiveRestartNV(void)
+{
+ GLenum curPrim;
+ GET_CURRENT_CONTEXT(ctx);
+
+ curPrim = ctx->Driver.CurrentSavePrimitive;
+
+ _save_End();
+ _save_Begin(curPrim);
+}
+
+
+/* Unlike the functions above, these are to be hooked into the vtxfmt
+ * maintained in ctx->ListState, active when the list is known or
+ * suspected to be outside any begin/end primitive.
+ */
+static void GLAPIENTRY
+_save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK);
+ CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
+ CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
+ CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
+ CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
+ CALL_End(GET_DISPATCH(), ());
+}
+
+
+static void GLAPIENTRY
+_save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+
+ if (!_mesa_validate_DrawArrays(ctx, mode, start, count))
+ return;
+
+ _ae_map_vbos(ctx);
+
+ vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK
+ | VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
+
+ for (i = 0; i < count; i++)
+ CALL_ArrayElement(GET_DISPATCH(), (start + i));
+ CALL_End(GET_DISPATCH(), ());
+
+ _ae_unmap_vbos(ctx);
+}
+
+
+/* Could do better by copying the arrays and element list intact and
+ * then emitting an indexed prim at runtime.
+ */
+static void GLAPIENTRY
+_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid * indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+
+ if (!_mesa_validate_DrawElements(ctx, mode, count, type, indices, 0))
+ return;
+
+ _ae_map_vbos(ctx);
+
+ if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj))
+ indices =
+ ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Pointer, indices);
+
+ vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK |
+ VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
+
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ for (i = 0; i < count; i++)
+ CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i]));
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (i = 0; i < count; i++)
+ CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i]));
+ break;
+ case GL_UNSIGNED_INT:
+ for (i = 0; i < count; i++)
+ CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i]));
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
+ break;
+ }
+
+ CALL_End(GET_DISPATCH(), ());
+
+ _ae_unmap_vbos(ctx);
+}
+
+
+static void GLAPIENTRY
+_save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
+ GLsizei count, GLenum type,
+ const GLvoid * indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (_mesa_validate_DrawRangeElements(ctx, mode,
+ start, end, count, type, indices, 0)) {
+ _save_OBE_DrawElements(mode, count, type, indices);
+ }
+}
+
+
+static void
+_save_vtxfmt_init(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ GLvertexformat *vfmt = &save->vtxfmt;
+
+ _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
+
+ 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->PrimitiveRestartNV = _save_PrimitiveRestartNV;
+ 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;
+
+ /* integer-valued */
+ vfmt->VertexAttribI1i = _save_VertexAttribI1i;
+ vfmt->VertexAttribI2i = _save_VertexAttribI2i;
+ vfmt->VertexAttribI3i = _save_VertexAttribI3i;
+ vfmt->VertexAttribI4i = _save_VertexAttribI4i;
+ vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
+ vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
+ vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
+
+ /* unsigned integer-valued */
+ vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
+ vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
+ vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
+ vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
+ vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
+ vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
+ vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
+
+ /* This will all require us to fallback to saving the list as opcodes:
+ */
+ _MESA_INIT_DLIST_VTXFMT(vfmt, _save_); /* inside begin/end */
+
+ _MESA_INIT_EVAL_VTXFMT(vfmt, _save_);
+
+ /* These are all errors as we at least know we are in some sort of
+ * begin/end pair:
+ */
+ vfmt->Begin = _save_Begin;
+ vfmt->Rectf = _save_Rectf;
+ vfmt->DrawArrays = _save_DrawArrays;
+ vfmt->DrawElements = _save_DrawElements;
+ vfmt->DrawRangeElements = _save_DrawRangeElements;
+ vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex;
+ vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex;
+ /* Loops back into vfmt->DrawElements */
+ vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
+ vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
+}
+
+
+void
+vbo_save_SaveFlushVertices(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+ /* Noop when we are actually active:
+ */
+ if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
+ ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
+ return;
+
+ if (save->vert_count || save->prim_count)
+ _save_compile_vertex_list(ctx);
+
+ _save_copy_to_current(ctx);
+ _save_reset_vertex(ctx);
+ _save_reset_counters(ctx);
+ ctx->Driver.SaveNeedFlush = 0;
+}
+
+
+void
+vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+ (void) list;
+ (void) mode;
+
+ if (!save->prim_store)
+ save->prim_store = alloc_prim_store(ctx);
+
+ if (!save->vertex_store)
+ save->vertex_store = alloc_vertex_store(ctx);
+
+ save->buffer_ptr = map_vertex_store(ctx, save->vertex_store);
+
+ _save_reset_vertex(ctx);
+ _save_reset_counters(ctx);
+ ctx->Driver.SaveNeedFlush = 0;
+}
+
+
+void
+vbo_save_EndList(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &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;
+ 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
+vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ save->replay_flags |= dlist->Flags;
+}
+
+
+void
+vbo_save_EndCallList(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+ if (ctx->ListState.CallDepth == 1) {
+ /* This is correct: want to keep only the VBO_SAVE_FALLBACK
+ * flag, if it is set:
+ */
+ save->replay_flags &= VBO_SAVE_FALLBACK;
+ }
+}
+
+
+static void
+vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
+{
+ struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
+ (void) ctx;
+
+ if (--node->vertex_store->refcount == 0)
+ free_vertex_store(ctx, node->vertex_store);
+
+ if (--node->prim_store->refcount == 0)
+ FREE(node->prim_store);
+
+ if (node->current_data) {
+ FREE(node->current_data);
+ node->current_data = NULL;
+ }
+}
+
+
+static void
+vbo_print_vertex_list(struct gl_context *ctx, void *data)
+{
+ struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
+ GLuint i;
+ (void) ctx;
+
+ printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
+ node->count, node->prim_count, node->vertex_size);
+
+ for (i = 0; i < node->prim_count; i++) {
+ struct _mesa_prim *prim = &node->prim[i];
+ _mesa_debug(NULL, " prim %d: %s%s %d..%d %s %s\n",
+ i,
+ _mesa_lookup_prim_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(struct gl_context *ctx)
+{
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+ GLint i;
+
+ for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
+ const GLuint j = i - VBO_ATTRIB_POS;
+ ASSERT(j < VERT_ATTRIB_MAX);
+ save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
+ save->current[i] = ctx->ListState.CurrentAttrib[j];
+ }
+
+ for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
+ const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
+ ASSERT(j < MAT_ATTRIB_MAX);
+ save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
+ save->current[i] = ctx->ListState.CurrentMaterial[j];
+ }
+}
+
+
+/**
+ * Initialize the display list compiler
+ */
+void
+vbo_save_api_init(struct vbo_save_context *save)
+{
+ struct gl_context *ctx = save->ctx;
+ GLuint i;
+
+ save->opcode_vertex_list =
+ _mesa_dlist_alloc_opcode(ctx,
+ sizeof(struct vbo_save_vertex_list),
+ vbo_save_playback_vertex_list,
+ vbo_destroy_vertex_list,
+ vbo_print_vertex_list);
+
+ ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
+
+ _save_vtxfmt_init(ctx);
+ _save_current_init(ctx);
+
+ /* These will actually get set again when binding/drawing */
+ for (i = 0; i < VBO_ATTRIB_MAX; i++)
+ save->inputs[i] = &save->arrays[i];
+
+ /* Hook our array functions into the outside-begin-end vtxfmt in
+ * ctx->ListState.
+ */
+ ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
+ ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
+ ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
+ ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
+ /* loops back into _save_OBE_DrawElements */
+ ctx->ListState.ListVtxfmt.MultiDrawElementsEXT =
+ _mesa_noop_MultiDrawElements;
+ ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex =
+ _mesa_noop_MultiDrawElementsBaseVertex;
+ _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
+}
+
+
+#endif /* FEATURE_dlist */
|