aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa/vbo
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2011-04-10 18:43:19 +0000
committermarha <marha@users.sourceforge.net>2011-04-10 18:43:19 +0000
commit2fb58f16eeec8ef3ec2a25e246477aab64e38a7d (patch)
treea4dbbe4f2c9a6524e99452ab43c972d5dbfa015f /mesalib/src/mesa/vbo
parentde1c6801fc854692d39fb2f8d53bf54ab25a1287 (diff)
downloadvcxsrv-2fb58f16eeec8ef3ec2a25e246477aab64e38a7d.tar.gz
vcxsrv-2fb58f16eeec8ef3ec2a25e246477aab64e38a7d.tar.bz2
vcxsrv-2fb58f16eeec8ef3ec2a25e246477aab64e38a7d.zip
mesa git update
Diffstat (limited to 'mesalib/src/mesa/vbo')
-rw-r--r--mesalib/src/mesa/vbo/vbo_context.c3
-rw-r--r--mesalib/src/mesa/vbo/vbo_exec_api.c2244
-rw-r--r--mesalib/src/mesa/vbo/vbo_exec_array.c2677
-rw-r--r--mesalib/src/mesa/vbo/vbo_exec_draw.c853
-rw-r--r--mesalib/src/mesa/vbo/vbo_save_draw.c613
-rw-r--r--mesalib/src/mesa/vbo/vbo_split_copy.c1253
6 files changed, 3829 insertions, 3814 deletions
diff --git a/mesalib/src/mesa/vbo/vbo_context.c b/mesalib/src/mesa/vbo/vbo_context.c
index bbf422f74..5f03ce547 100644
--- a/mesalib/src/mesa/vbo/vbo_context.c
+++ b/mesalib/src/mesa/vbo/vbo_context.c
@@ -72,6 +72,7 @@ static void init_legacy_currval(struct gl_context *ctx)
cl->Type = GL_FLOAT;
cl->Format = GL_RGBA;
cl->Ptr = (const void *)ctx->Current.Attrib[i];
+ cl->_ElementSize = cl->Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx, &cl->BufferObj,
ctx->Shared->NullBufferObj);
}
@@ -98,6 +99,7 @@ static void init_generic_currval(struct gl_context *ctx)
cl->Stride = 0;
cl->StrideB = 0;
cl->Enabled = 1;
+ cl->_ElementSize = cl->Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx, &cl->BufferObj,
ctx->Shared->NullBufferObj);
}
@@ -143,6 +145,7 @@ static void init_mat_currval(struct gl_context *ctx)
cl->Stride = 0;
cl->StrideB = 0;
cl->Enabled = 1;
+ cl->_ElementSize = cl->Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx, &cl->BufferObj,
ctx->Shared->NullBufferObj);
}
diff --git a/mesalib/src/mesa/vbo/vbo_exec_api.c b/mesalib/src/mesa/vbo/vbo_exec_api.c
index fcd544de7..6b919e8b4 100644
--- a/mesalib/src/mesa/vbo/vbo_exec_api.c
+++ b/mesalib/src/mesa/vbo/vbo_exec_api.c
@@ -1,1121 +1,1123 @@
-/**************************************************************************
-
-Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
-
-All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-on the rights to use, copy, modify, merge, publish, distribute, sub
-license, and/or sell copies of the Software, and to permit persons to whom
-the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice (including the next
-paragraph) shall be included in all copies or substantial portions of the
-Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
-TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-**************************************************************************/
-
-/*
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-#include "main/glheader.h"
-#include "main/bufferobj.h"
-#include "main/context.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-#include "main/vtxfmt.h"
-#include "main/dlist.h"
-#include "main/eval.h"
-#include "main/state.h"
-#include "main/light.h"
-#include "main/api_arrayelt.h"
-#include "main/api_noop.h"
-#include "main/dispatch.h"
-
-#include "vbo_context.h"
-
-#ifdef ERROR
-#undef ERROR
-#endif
-
-
-/** ID/name for immediate-mode VBO */
-#define IMM_BUFFER_NAME 0xaabbccdd
-
-
-static void reset_attrfv( struct vbo_exec_context *exec );
-
-
-/**
- * Close off the last primitive, execute the buffer, restart the
- * primitive.
- */
-static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
-{
- if (exec->vtx.prim_count == 0) {
- exec->vtx.copied.nr = 0;
- exec->vtx.vert_count = 0;
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
- }
- else {
- GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
- GLuint last_count;
-
- if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- GLint i = exec->vtx.prim_count - 1;
- assert(i >= 0);
- exec->vtx.prim[i].count = (exec->vtx.vert_count -
- exec->vtx.prim[i].start);
- }
-
- last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
-
- /* Execute the buffer and save copied vertices.
- */
- if (exec->vtx.vert_count)
- vbo_exec_vtx_flush( exec, GL_FALSE );
- else {
- exec->vtx.prim_count = 0;
- exec->vtx.copied.nr = 0;
- }
-
- /* Emit a glBegin to start the new list.
- */
- assert(exec->vtx.prim_count == 0);
-
- if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
- exec->vtx.prim[0].start = 0;
- exec->vtx.prim[0].count = 0;
- exec->vtx.prim_count++;
-
- if (exec->vtx.copied.nr == last_count)
- exec->vtx.prim[0].begin = last_begin;
- }
- }
-}
-
-
-/**
- * Deal with buffer wrapping where provoked by the vertex buffer
- * filling up, as opposed to upgrade_vertex().
- */
-void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
-{
- GLfloat *data = exec->vtx.copied.buffer;
- GLuint i;
-
- /* Run pipeline on current vertices, copy wrapped vertices
- * to exec->vtx.copied.
- */
- vbo_exec_wrap_buffers( exec );
-
- /* Copy stored stored vertices to start of new list.
- */
- assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
-
- for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
- memcpy( exec->vtx.buffer_ptr, data,
- exec->vtx.vertex_size * sizeof(GLfloat));
- exec->vtx.buffer_ptr += exec->vtx.vertex_size;
- data += exec->vtx.vertex_size;
- exec->vtx.vert_count++;
- }
-
- exec->vtx.copied.nr = 0;
-}
-
-
-/**
- * Copy the active vertex's values to the ctx->Current fields.
- */
-static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
-{
- struct gl_context *ctx = exec->ctx;
- struct vbo_context *vbo = vbo_context(ctx);
- GLuint i;
-
- for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
- if (exec->vtx.attrsz[i]) {
- /* Note: the exec->vtx.current[i] pointers point into the
- * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
- */
- GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
- GLfloat tmp[4];
-
- COPY_CLEAN_4V(tmp,
- exec->vtx.attrsz[i],
- exec->vtx.attrptr[i]);
-
- if (memcmp(current, tmp, sizeof(tmp)) != 0) {
- memcpy(current, tmp, sizeof(tmp));
-
- /* Given that we explicitly state size here, there is no need
- * for the COPY_CLEAN above, could just copy 16 bytes and be
- * done. The only problem is when Mesa accesses ctx->Current
- * directly.
- */
- vbo->currval[i].Size = exec->vtx.attrsz[i];
-
- /* This triggers rather too much recalculation of Mesa state
- * that doesn't get used (eg light positions).
- */
- if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
- i <= VBO_ATTRIB_MAT_BACK_INDEXES)
- ctx->NewState |= _NEW_LIGHT;
-
- ctx->NewState |= _NEW_CURRENT_ATTRIB;
- }
- }
- }
-
- /* Colormaterial -- this kindof sucks.
- */
- if (ctx->Light.ColorMaterialEnabled &&
- exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
- _mesa_update_color_material(ctx,
- ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
- }
-}
-
-
-/**
- * Copy current vertex attribute values into the current vertex.
- */
-static void
-vbo_exec_copy_from_current(struct vbo_exec_context *exec)
-{
- struct gl_context *ctx = exec->ctx;
- struct vbo_context *vbo = vbo_context(ctx);
- GLint i;
-
- for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
- const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr;
- switch (exec->vtx.attrsz[i]) {
- case 4: exec->vtx.attrptr[i][3] = current[3];
- case 3: exec->vtx.attrptr[i][2] = current[2];
- case 2: exec->vtx.attrptr[i][1] = current[1];
- case 1: exec->vtx.attrptr[i][0] = current[0];
- break;
- }
- }
-}
-
-
-/**
- * Flush existing data, set new attrib size, replay copied vertices.
- * This is called when we transition from a small vertex attribute size
- * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
- * We need to go back over the previous 2-component texcoords and insert
- * zero and one values.
- */
-static void
-vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
- GLuint attr, GLuint newSize )
-{
- struct gl_context *ctx = exec->ctx;
- struct vbo_context *vbo = vbo_context(ctx);
- const GLint lastcount = exec->vtx.vert_count;
- GLfloat *old_attrptr[VBO_ATTRIB_MAX];
- const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
- const GLuint oldSize = exec->vtx.attrsz[attr];
- GLuint i;
-
- /* Run pipeline on current vertices, copy wrapped vertices
- * to exec->vtx.copied.
- */
- vbo_exec_wrap_buffers( exec );
-
- if (unlikely(exec->vtx.copied.nr)) {
- /* We're in the middle of a primitive, keep the old vertex
- * format around to be able to translate the copied vertices to
- * the new format.
- */
- memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
- }
-
- if (unlikely(oldSize)) {
- /* 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.
- */
- vbo_exec_copy_to_current( exec );
- }
-
- /* Heuristic: Attempt to isolate attributes received outside
- * begin/end so that they don't bloat the vertices.
- */
- if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
- !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
- vbo_exec_copy_to_current( exec );
- reset_attrfv( exec );
- }
-
- /* Fix up sizes:
- */
- exec->vtx.attrsz[attr] = newSize;
- exec->vtx.vertex_size += newSize - oldSize;
- exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
- (exec->vtx.vertex_size * sizeof(GLfloat)));
- exec->vtx.vert_count = 0;
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
-
- if (unlikely(oldSize)) {
- /* Size changed, recalculate all the attrptr[] values
- */
- GLfloat *tmp = exec->vtx.vertex;
-
- for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
- if (exec->vtx.attrsz[i]) {
- exec->vtx.attrptr[i] = tmp;
- tmp += exec->vtx.attrsz[i];
- }
- else
- exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
- }
-
- /* Copy from current to repopulate the vertex with correct
- * values.
- */
- vbo_exec_copy_from_current( exec );
- }
- else {
- /* Just have to append the new attribute at the end */
- exec->vtx.attrptr[attr] = exec->vtx.vertex +
- exec->vtx.vertex_size - newSize;
- }
-
- /* Replay stored vertices to translate them
- * to new format here.
- *
- * -- No need to replay - just copy piecewise
- */
- if (unlikely(exec->vtx.copied.nr)) {
- GLfloat *data = exec->vtx.copied.buffer;
- GLfloat *dest = exec->vtx.buffer_ptr;
- GLuint j;
-
- assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
-
- for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
- for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
- GLuint sz = exec->vtx.attrsz[j];
-
- if (sz) {
- GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
- GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
-
- if (j == attr) {
- if (oldSize) {
- GLfloat tmp[4];
- COPY_CLEAN_4V(tmp, oldSize, data + old_offset);
- COPY_SZ_4V(dest + new_offset, newSize, tmp);
- } else {
- GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
- COPY_SZ_4V(dest + new_offset, sz, current);
- }
- }
- else {
- COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
- }
- }
- }
-
- data += old_vtx_size;
- dest += exec->vtx.vertex_size;
- }
-
- exec->vtx.buffer_ptr = dest;
- exec->vtx.vert_count += exec->vtx.copied.nr;
- exec->vtx.copied.nr = 0;
- }
-}
-
-
-/**
- * This is when a vertex attribute transitions to a different size.
- * For example, we saw a bunch of glTexCoord2f() calls and now we got a
- * glTexCoord4f() call. We promote the array from size=2 to size=4.
- */
-static void
-vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
- if (newSize > exec->vtx.attrsz[attr]) {
- /* New size is larger. Need to flush existing vertices and get
- * an enlarged vertex format.
- */
- vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
- }
- else if (newSize < exec->vtx.active_sz[attr]) {
- static const GLfloat id[4] = { 0, 0, 0, 1 };
- GLuint i;
-
- /* New size is smaller - just need to fill in some
- * zeros. Don't need to flush or wrap.
- */
- for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
- exec->vtx.attrptr[attr][i-1] = id[i-1];
- }
-
- exec->vtx.active_sz[attr] = newSize;
-
- /* Does setting NeedFlush belong here? Necessitates resetting
- * vtxfmt on each flush (otherwise flags won't get reset
- * afterwards).
- */
- if (attr == 0)
- ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
-}
-
-
-/**
- * This macro is used to implement all the glVertex, glColor, glTexCoord,
- * glVertexAttrib, etc functions.
- */
-#define ATTR( A, N, V0, V1, V2, V3 ) \
-do { \
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
- \
- if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
- ctx->Driver.BeginVertices( ctx ); \
- \
- if (unlikely(exec->vtx.active_sz[A] != N)) \
- vbo_exec_fixup_vertex(ctx, A, N); \
- \
- { \
- GLfloat *dest = exec->vtx.attrptr[A]; \
- if (N>0) dest[0] = V0; \
- if (N>1) dest[1] = V1; \
- if (N>2) dest[2] = V2; \
- if (N>3) dest[3] = V3; \
- } \
- \
- if ((A) == 0) { \
- /* This is a glVertex call */ \
- GLuint i; \
- \
- for (i = 0; i < exec->vtx.vertex_size; i++) \
- exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
- \
- exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
- \
- /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
- /* something to draw (not just updating a color or texcoord).*/ \
- ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
- \
- if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
- vbo_exec_vtx_wrap( exec ); \
- } \
-} while (0)
-
-
-#define ERROR(err) _mesa_error( ctx, err, __FUNCTION__ )
-#define TAG(x) vbo_##x
-
-#include "vbo_attrib_tmp.h"
-
-
-#if FEATURE_beginend
-
-
-#if FEATURE_evaluators
-
-static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
-{
- GET_CURRENT_CONTEXT( ctx );
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
- {
- GLint i;
- if (exec->eval.recalculate_maps)
- vbo_exec_eval_update( exec );
-
- for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
- if (exec->eval.map1[i].map)
- if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
- vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
- }
- }
-
-
- memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
- exec->vtx.vertex_size * sizeof(GLfloat));
-
- vbo_exec_do_EvalCoord1f( exec, u );
-
- memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
- exec->vtx.vertex_size * sizeof(GLfloat));
-}
-
-static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
-{
- GET_CURRENT_CONTEXT( ctx );
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
- {
- GLint i;
- if (exec->eval.recalculate_maps)
- vbo_exec_eval_update( exec );
-
- for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
- if (exec->eval.map2[i].map)
- if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
- vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
- }
-
- if (ctx->Eval.AutoNormal)
- if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
- vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
- }
-
- memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
- exec->vtx.vertex_size * sizeof(GLfloat));
-
- vbo_exec_do_EvalCoord2f( exec, u, v );
-
- memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
- exec->vtx.vertex_size * sizeof(GLfloat));
-}
-
-static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
-{
- vbo_exec_EvalCoord1f( u[0] );
-}
-
-static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
-{
- vbo_exec_EvalCoord2f( u[0], u[1] );
-}
-
-static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
-{
- GET_CURRENT_CONTEXT( ctx );
- GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
- (GLfloat) ctx->Eval.MapGrid1un);
- GLfloat u = i * du + ctx->Eval.MapGrid1u1;
-
- vbo_exec_EvalCoord1f( u );
-}
-
-
-static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
-{
- GET_CURRENT_CONTEXT( ctx );
- GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
- (GLfloat) ctx->Eval.MapGrid2un);
- GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
- (GLfloat) ctx->Eval.MapGrid2vn);
- GLfloat u = i * du + ctx->Eval.MapGrid2u1;
- GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
-
- vbo_exec_EvalCoord2f( u, v );
-}
-
-/* use noop eval mesh */
-#define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
-#define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
-
-#endif /* FEATURE_evaluators */
-
-
-/**
- * Flush (draw) vertices.
- * \param unmap - leave VBO unmapped after flushing?
- */
-static void
-vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
-{
- if (exec->vtx.vert_count || unmap) {
- vbo_exec_vtx_flush( exec, unmap );
- }
-
- if (exec->vtx.vertex_size) {
- vbo_exec_copy_to_current( exec );
- reset_attrfv( exec );
- }
-}
-
-
-/**
- * Called via glBegin.
- */
-static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
-{
- GET_CURRENT_CONTEXT( ctx );
-
- if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- int i;
-
- if (ctx->NewState) {
- _mesa_update_state( ctx );
-
- CALL_Begin(ctx->Exec, (mode));
- return;
- }
-
- if (!_mesa_valid_to_render(ctx, "glBegin")) {
- return;
- }
-
- /* Heuristic: attempt to isolate attributes occuring outside
- * begin/end pairs.
- */
- if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
- vbo_exec_FlushVertices_internal(exec, GL_FALSE);
-
- i = exec->vtx.prim_count++;
- exec->vtx.prim[i].mode = mode;
- exec->vtx.prim[i].begin = 1;
- exec->vtx.prim[i].end = 0;
- exec->vtx.prim[i].indexed = 0;
- exec->vtx.prim[i].weak = 0;
- exec->vtx.prim[i].pad = 0;
- exec->vtx.prim[i].start = exec->vtx.vert_count;
- exec->vtx.prim[i].count = 0;
- exec->vtx.prim[i].num_instances = 1;
-
- ctx->Driver.CurrentExecPrimitive = mode;
- }
- else
- _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
-
-}
-
-
-/**
- * Called via glEnd.
- */
-static void GLAPIENTRY vbo_exec_End( void )
-{
- GET_CURRENT_CONTEXT( ctx );
-
- if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- int idx = exec->vtx.vert_count;
- int i = exec->vtx.prim_count - 1;
-
- exec->vtx.prim[i].end = 1;
- exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
-
- ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
-
- if (exec->vtx.prim_count == VBO_MAX_PRIM)
- vbo_exec_vtx_flush( exec, GL_FALSE );
- }
- else
- _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
-}
-
-
-/**
- * Called via glPrimitiveRestartNV()
- */
-static void GLAPIENTRY
-vbo_exec_PrimitiveRestartNV(void)
-{
- GLenum curPrim;
- GET_CURRENT_CONTEXT( ctx );
-
- curPrim = ctx->Driver.CurrentExecPrimitive;
-
- if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
- _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
- }
- else {
- vbo_exec_End();
- vbo_exec_Begin(curPrim);
- }
-}
-
-
-
-static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
-{
- GLvertexformat *vfmt = &exec->vtxfmt;
-
- _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
-
- vfmt->Begin = vbo_exec_Begin;
- vfmt->End = vbo_exec_End;
- vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
-
- _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
- _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
-
- vfmt->Rectf = _mesa_noop_Rectf;
-
- /* from attrib_tmp.h:
- */
- vfmt->Color3f = vbo_Color3f;
- vfmt->Color3fv = vbo_Color3fv;
- vfmt->Color4f = vbo_Color4f;
- vfmt->Color4fv = vbo_Color4fv;
- vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
- vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
- vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
- vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
- vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
- vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
- vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
- vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
- vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
- vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
- vfmt->Normal3f = vbo_Normal3f;
- vfmt->Normal3fv = vbo_Normal3fv;
- vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
- vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
- vfmt->TexCoord1f = vbo_TexCoord1f;
- vfmt->TexCoord1fv = vbo_TexCoord1fv;
- vfmt->TexCoord2f = vbo_TexCoord2f;
- vfmt->TexCoord2fv = vbo_TexCoord2fv;
- vfmt->TexCoord3f = vbo_TexCoord3f;
- vfmt->TexCoord3fv = vbo_TexCoord3fv;
- vfmt->TexCoord4f = vbo_TexCoord4f;
- vfmt->TexCoord4fv = vbo_TexCoord4fv;
- vfmt->Vertex2f = vbo_Vertex2f;
- vfmt->Vertex2fv = vbo_Vertex2fv;
- vfmt->Vertex3f = vbo_Vertex3f;
- vfmt->Vertex3fv = vbo_Vertex3fv;
- vfmt->Vertex4f = vbo_Vertex4f;
- vfmt->Vertex4fv = vbo_Vertex4fv;
-
- vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
- vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
- vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
- vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
- vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
- vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
- vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
- vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
-
- vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
- vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
- vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
- vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
- vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
- vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
- vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
- vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
-
- /* integer-valued */
- vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
- vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
- vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
- vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
- vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
- vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
- vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
-
- /* unsigned integer-valued */
- vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
- vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
- vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
- vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
- vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
- vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
- vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
-
- vfmt->Materialfv = vbo_Materialfv;
-
- vfmt->EdgeFlag = vbo_EdgeFlag;
- vfmt->Indexf = vbo_Indexf;
- vfmt->Indexfv = vbo_Indexfv;
-
-}
-
-
-#else /* FEATURE_beginend */
-
-
-static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
-{
- /* silence warnings */
- (void) vbo_Color3f;
- (void) vbo_Color3fv;
- (void) vbo_Color4f;
- (void) vbo_Color4fv;
- (void) vbo_FogCoordfEXT;
- (void) vbo_FogCoordfvEXT;
- (void) vbo_MultiTexCoord1f;
- (void) vbo_MultiTexCoord1fv;
- (void) vbo_MultiTexCoord2f;
- (void) vbo_MultiTexCoord2fv;
- (void) vbo_MultiTexCoord3f;
- (void) vbo_MultiTexCoord3fv;
- (void) vbo_MultiTexCoord4f;
- (void) vbo_MultiTexCoord4fv;
- (void) vbo_Normal3f;
- (void) vbo_Normal3fv;
- (void) vbo_SecondaryColor3fEXT;
- (void) vbo_SecondaryColor3fvEXT;
- (void) vbo_TexCoord1f;
- (void) vbo_TexCoord1fv;
- (void) vbo_TexCoord2f;
- (void) vbo_TexCoord2fv;
- (void) vbo_TexCoord3f;
- (void) vbo_TexCoord3fv;
- (void) vbo_TexCoord4f;
- (void) vbo_TexCoord4fv;
- (void) vbo_Vertex2f;
- (void) vbo_Vertex2fv;
- (void) vbo_Vertex3f;
- (void) vbo_Vertex3fv;
- (void) vbo_Vertex4f;
- (void) vbo_Vertex4fv;
-
- (void) vbo_VertexAttrib1fARB;
- (void) vbo_VertexAttrib1fvARB;
- (void) vbo_VertexAttrib2fARB;
- (void) vbo_VertexAttrib2fvARB;
- (void) vbo_VertexAttrib3fARB;
- (void) vbo_VertexAttrib3fvARB;
- (void) vbo_VertexAttrib4fARB;
- (void) vbo_VertexAttrib4fvARB;
-
- (void) vbo_VertexAttrib1fNV;
- (void) vbo_VertexAttrib1fvNV;
- (void) vbo_VertexAttrib2fNV;
- (void) vbo_VertexAttrib2fvNV;
- (void) vbo_VertexAttrib3fNV;
- (void) vbo_VertexAttrib3fvNV;
- (void) vbo_VertexAttrib4fNV;
- (void) vbo_VertexAttrib4fvNV;
-
- (void) vbo_Materialfv;
-
- (void) vbo_EdgeFlag;
- (void) vbo_Indexf;
- (void) vbo_Indexfv;
-}
-
-
-#endif /* FEATURE_beginend */
-
-
-/**
- * Tell the VBO module to use a real OpenGL vertex buffer object to
- * store accumulated immediate-mode vertex data.
- * This replaces the malloced buffer which was created in
- * vb_exec_vtx_init() below.
- */
-void vbo_use_buffer_objects(struct gl_context *ctx)
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- /* Any buffer name but 0 can be used here since this bufferobj won't
- * go into the bufferobj hashtable.
- */
- GLuint bufName = IMM_BUFFER_NAME;
- GLenum target = GL_ARRAY_BUFFER_ARB;
- GLenum usage = GL_STREAM_DRAW_ARB;
- GLsizei size = VBO_VERT_BUFFER_SIZE;
-
- /* Make sure this func is only used once */
- assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
- if (exec->vtx.buffer_map) {
- _mesa_align_free(exec->vtx.buffer_map);
- exec->vtx.buffer_map = NULL;
- exec->vtx.buffer_ptr = NULL;
- }
-
- /* Allocate a real buffer object now */
- _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
- exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
- ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
-}
-
-
-/**
- * If this function is called, all VBO buffers will be unmapped when
- * we flush.
- * Otherwise, if a simple command like glColor3f() is called and we flush,
- * the current VBO may be left mapped.
- */
-void
-vbo_always_unmap_buffers(struct gl_context *ctx)
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
-}
-
-
-void vbo_exec_vtx_init( struct vbo_exec_context *exec )
-{
- struct gl_context *ctx = exec->ctx;
- struct vbo_context *vbo = vbo_context(ctx);
- GLuint i;
-
- /* Allocate a buffer object. Will just reuse this object
- * continuously, unless vbo_use_buffer_objects() is called to enable
- * use of real VBOs.
- */
- _mesa_reference_buffer_object(ctx,
- &exec->vtx.bufferobj,
- ctx->Shared->NullBufferObj);
-
- ASSERT(!exec->vtx.buffer_map);
- exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
-
- vbo_exec_vtxfmt_init( exec );
-
- /* Hook our functions into the dispatch table.
- */
- _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt );
-
- for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
- ASSERT(i < Elements(exec->vtx.attrsz));
- exec->vtx.attrsz[i] = 0;
- ASSERT(i < Elements(exec->vtx.active_sz));
- exec->vtx.active_sz[i] = 0;
- }
- for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
- ASSERT(i < Elements(exec->vtx.inputs));
- ASSERT(i < Elements(exec->vtx.arrays));
- exec->vtx.inputs[i] = &exec->vtx.arrays[i];
- }
-
- {
- struct gl_client_array *arrays = exec->vtx.arrays;
- unsigned i;
-
- memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
- memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
-
- for (i = 0; i < 16; ++i) {
- arrays[i ].BufferObj = NULL;
- arrays[i + 16].BufferObj = NULL;
- _mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj,
- vbo->legacy_currval[i].BufferObj);
- _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj,
- vbo->generic_currval[i].BufferObj);
- }
- }
-
- exec->vtx.vertex_size = 0;
-
- exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
-}
-
-
-void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
-{
- /* using a real VBO for vertex data */
- struct gl_context *ctx = exec->ctx;
- unsigned i;
-
- /* True VBOs should already be unmapped
- */
- if (exec->vtx.buffer_map) {
- ASSERT(exec->vtx.bufferobj->Name == 0 ||
- exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
- if (exec->vtx.bufferobj->Name == 0) {
- _mesa_align_free(exec->vtx.buffer_map);
- exec->vtx.buffer_map = NULL;
- exec->vtx.buffer_ptr = NULL;
- }
- }
-
- /* Drop any outstanding reference to the vertex buffer
- */
- for (i = 0; i < Elements(exec->vtx.arrays); i++) {
- _mesa_reference_buffer_object(ctx,
- &exec->vtx.arrays[i].BufferObj,
- NULL);
- }
-
- /* Free the vertex buffer. Unmap first if needed.
- */
- if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj);
- }
- _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
-}
-
-
-/**
- * Called upon first glVertex, glColor, glTexCoord, etc.
- */
-void vbo_exec_BeginVertices( struct gl_context *ctx )
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
- vbo_exec_vtx_map( exec );
-
- assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
- assert(exec->begin_vertices_flags);
-
- ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
-}
-
-
-/**
- * Called via ctx->Driver.FlushVertices()
- * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
- */
-void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
-#ifdef DEBUG
- /* debug check: make sure we don't get called recursively */
- exec->flush_call_depth++;
- assert(exec->flush_call_depth == 1);
-#endif
-
- if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- /* We've had glBegin but not glEnd! */
-#ifdef DEBUG
- exec->flush_call_depth--;
- assert(exec->flush_call_depth == 0);
-#endif
- return;
- }
-
- /* Flush (draw), and make sure VBO is left unmapped when done */
- vbo_exec_FlushVertices_internal(exec, GL_TRUE);
-
- /* Need to do this to ensure BeginVertices gets called again:
- */
- ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
-
-#ifdef DEBUG
- exec->flush_call_depth--;
- assert(exec->flush_call_depth == 0);
-#endif
-}
-
-
-static void reset_attrfv( struct vbo_exec_context *exec )
-{
- GLuint i;
-
- for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
- exec->vtx.attrsz[i] = 0;
- exec->vtx.active_sz[i] = 0;
- }
-
- exec->vtx.vertex_size = 0;
-}
-
-
-void GLAPIENTRY
-_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
-{
- vbo_Color4f(r, g, b, a);
-}
-
-
-void GLAPIENTRY
-_es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
-{
- vbo_Normal3f(x, y, z);
-}
-
-
-void GLAPIENTRY
-_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
-{
- vbo_MultiTexCoord4f(target, s, t, r, q);
-}
-
-
-void GLAPIENTRY
-_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
-{
- vbo_Materialfv(face, pname, params);
-}
-
-
-void GLAPIENTRY
-_es_Materialf(GLenum face, GLenum pname, GLfloat param)
-{
- GLfloat p[4];
- p[0] = param;
- p[1] = p[2] = p[3] = 0.0F;
- vbo_Materialfv(face, pname, p);
-}
-
-
-/**
- * A special version of glVertexAttrib4f that does not treat index 0 as
- * VBO_ATTRIB_POS.
- */
-static void
-VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
- GET_CURRENT_CONTEXT(ctx);
- if (index < MAX_VERTEX_GENERIC_ATTRIBS)
- ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
- else
- ERROR(GL_INVALID_VALUE);
-}
-
-void GLAPIENTRY
-_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
- VertexAttrib4f_nopos(index, x, y, z, w);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib1f(GLuint indx, GLfloat x)
-{
- VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
-{
- VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
-{
- VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
-{
- VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
-{
- VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
-{
- VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
-}
-
-
-void GLAPIENTRY
-_es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
-{
- VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
-}
+/**************************************************************************
+
+Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "main/mfeatures.h"
+#include "main/vtxfmt.h"
+#include "main/dlist.h"
+#include "main/eval.h"
+#include "main/state.h"
+#include "main/light.h"
+#include "main/api_arrayelt.h"
+#include "main/api_noop.h"
+#include "main/dispatch.h"
+
+#include "vbo_context.h"
+
+#ifdef ERROR
+#undef ERROR
+#endif
+
+
+/** ID/name for immediate-mode VBO */
+#define IMM_BUFFER_NAME 0xaabbccdd
+
+
+static void reset_attrfv( struct vbo_exec_context *exec );
+
+
+/**
+ * Close off the last primitive, execute the buffer, restart the
+ * primitive.
+ */
+static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
+{
+ if (exec->vtx.prim_count == 0) {
+ exec->vtx.copied.nr = 0;
+ exec->vtx.vert_count = 0;
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ }
+ else {
+ GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
+ GLuint last_count;
+
+ if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ GLint i = exec->vtx.prim_count - 1;
+ assert(i >= 0);
+ exec->vtx.prim[i].count = (exec->vtx.vert_count -
+ exec->vtx.prim[i].start);
+ }
+
+ last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
+
+ /* Execute the buffer and save copied vertices.
+ */
+ if (exec->vtx.vert_count)
+ vbo_exec_vtx_flush( exec, GL_FALSE );
+ else {
+ exec->vtx.prim_count = 0;
+ exec->vtx.copied.nr = 0;
+ }
+
+ /* Emit a glBegin to start the new list.
+ */
+ assert(exec->vtx.prim_count == 0);
+
+ if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
+ exec->vtx.prim[0].start = 0;
+ exec->vtx.prim[0].count = 0;
+ exec->vtx.prim_count++;
+
+ if (exec->vtx.copied.nr == last_count)
+ exec->vtx.prim[0].begin = last_begin;
+ }
+ }
+}
+
+
+/**
+ * Deal with buffer wrapping where provoked by the vertex buffer
+ * filling up, as opposed to upgrade_vertex().
+ */
+void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
+{
+ GLfloat *data = exec->vtx.copied.buffer;
+ GLuint i;
+
+ /* Run pipeline on current vertices, copy wrapped vertices
+ * to exec->vtx.copied.
+ */
+ vbo_exec_wrap_buffers( exec );
+
+ /* Copy stored stored vertices to start of new list.
+ */
+ assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
+
+ for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
+ memcpy( exec->vtx.buffer_ptr, data,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+ exec->vtx.buffer_ptr += exec->vtx.vertex_size;
+ data += exec->vtx.vertex_size;
+ exec->vtx.vert_count++;
+ }
+
+ exec->vtx.copied.nr = 0;
+}
+
+
+/**
+ * Copy the active vertex's values to the ctx->Current fields.
+ */
+static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
+{
+ struct gl_context *ctx = exec->ctx;
+ struct vbo_context *vbo = vbo_context(ctx);
+ GLuint i;
+
+ for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
+ if (exec->vtx.attrsz[i]) {
+ /* Note: the exec->vtx.current[i] pointers point into the
+ * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
+ */
+ GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
+ GLfloat tmp[4];
+
+ COPY_CLEAN_4V(tmp,
+ exec->vtx.attrsz[i],
+ exec->vtx.attrptr[i]);
+
+ if (memcmp(current, tmp, sizeof(tmp)) != 0) {
+ memcpy(current, tmp, sizeof(tmp));
+
+ /* Given that we explicitly state size here, there is no need
+ * for the COPY_CLEAN above, could just copy 16 bytes and be
+ * done. The only problem is when Mesa accesses ctx->Current
+ * directly.
+ */
+ vbo->currval[i].Size = exec->vtx.attrsz[i];
+ assert(vbo->currval[i].Type == GL_FLOAT);
+ vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
+
+ /* This triggers rather too much recalculation of Mesa state
+ * that doesn't get used (eg light positions).
+ */
+ if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
+ i <= VBO_ATTRIB_MAT_BACK_INDEXES)
+ ctx->NewState |= _NEW_LIGHT;
+
+ ctx->NewState |= _NEW_CURRENT_ATTRIB;
+ }
+ }
+ }
+
+ /* Colormaterial -- this kindof sucks.
+ */
+ if (ctx->Light.ColorMaterialEnabled &&
+ exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
+ _mesa_update_color_material(ctx,
+ ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
+ }
+}
+
+
+/**
+ * Copy current vertex attribute values into the current vertex.
+ */
+static void
+vbo_exec_copy_from_current(struct vbo_exec_context *exec)
+{
+ struct gl_context *ctx = exec->ctx;
+ struct vbo_context *vbo = vbo_context(ctx);
+ GLint i;
+
+ for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
+ const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr;
+ switch (exec->vtx.attrsz[i]) {
+ case 4: exec->vtx.attrptr[i][3] = current[3];
+ case 3: exec->vtx.attrptr[i][2] = current[2];
+ case 2: exec->vtx.attrptr[i][1] = current[1];
+ case 1: exec->vtx.attrptr[i][0] = current[0];
+ break;
+ }
+ }
+}
+
+
+/**
+ * Flush existing data, set new attrib size, replay copied vertices.
+ * This is called when we transition from a small vertex attribute size
+ * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
+ * We need to go back over the previous 2-component texcoords and insert
+ * zero and one values.
+ */
+static void
+vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
+ GLuint attr, GLuint newSize )
+{
+ struct gl_context *ctx = exec->ctx;
+ struct vbo_context *vbo = vbo_context(ctx);
+ const GLint lastcount = exec->vtx.vert_count;
+ GLfloat *old_attrptr[VBO_ATTRIB_MAX];
+ const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
+ const GLuint oldSize = exec->vtx.attrsz[attr];
+ GLuint i;
+
+ /* Run pipeline on current vertices, copy wrapped vertices
+ * to exec->vtx.copied.
+ */
+ vbo_exec_wrap_buffers( exec );
+
+ if (unlikely(exec->vtx.copied.nr)) {
+ /* We're in the middle of a primitive, keep the old vertex
+ * format around to be able to translate the copied vertices to
+ * the new format.
+ */
+ memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
+ }
+
+ if (unlikely(oldSize)) {
+ /* 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.
+ */
+ vbo_exec_copy_to_current( exec );
+ }
+
+ /* Heuristic: Attempt to isolate attributes received outside
+ * begin/end so that they don't bloat the vertices.
+ */
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
+ !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
+ vbo_exec_copy_to_current( exec );
+ reset_attrfv( exec );
+ }
+
+ /* Fix up sizes:
+ */
+ exec->vtx.attrsz[attr] = newSize;
+ exec->vtx.vertex_size += newSize - oldSize;
+ exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
+ (exec->vtx.vertex_size * sizeof(GLfloat)));
+ exec->vtx.vert_count = 0;
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+
+ if (unlikely(oldSize)) {
+ /* Size changed, recalculate all the attrptr[] values
+ */
+ GLfloat *tmp = exec->vtx.vertex;
+
+ for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
+ if (exec->vtx.attrsz[i]) {
+ exec->vtx.attrptr[i] = tmp;
+ tmp += exec->vtx.attrsz[i];
+ }
+ else
+ exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
+ }
+
+ /* Copy from current to repopulate the vertex with correct
+ * values.
+ */
+ vbo_exec_copy_from_current( exec );
+ }
+ else {
+ /* Just have to append the new attribute at the end */
+ exec->vtx.attrptr[attr] = exec->vtx.vertex +
+ exec->vtx.vertex_size - newSize;
+ }
+
+ /* Replay stored vertices to translate them
+ * to new format here.
+ *
+ * -- No need to replay - just copy piecewise
+ */
+ if (unlikely(exec->vtx.copied.nr)) {
+ GLfloat *data = exec->vtx.copied.buffer;
+ GLfloat *dest = exec->vtx.buffer_ptr;
+ GLuint j;
+
+ assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
+
+ for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
+ for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
+ GLuint sz = exec->vtx.attrsz[j];
+
+ if (sz) {
+ GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
+ GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
+
+ if (j == attr) {
+ if (oldSize) {
+ GLfloat tmp[4];
+ COPY_CLEAN_4V(tmp, oldSize, data + old_offset);
+ COPY_SZ_4V(dest + new_offset, newSize, tmp);
+ } else {
+ GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
+ COPY_SZ_4V(dest + new_offset, sz, current);
+ }
+ }
+ else {
+ COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
+ }
+ }
+ }
+
+ data += old_vtx_size;
+ dest += exec->vtx.vertex_size;
+ }
+
+ exec->vtx.buffer_ptr = dest;
+ exec->vtx.vert_count += exec->vtx.copied.nr;
+ exec->vtx.copied.nr = 0;
+ }
+}
+
+
+/**
+ * This is when a vertex attribute transitions to a different size.
+ * For example, we saw a bunch of glTexCoord2f() calls and now we got a
+ * glTexCoord4f() call. We promote the array from size=2 to size=4.
+ */
+static void
+vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
+{
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+ if (newSize > exec->vtx.attrsz[attr]) {
+ /* New size is larger. Need to flush existing vertices and get
+ * an enlarged vertex format.
+ */
+ vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
+ }
+ else if (newSize < exec->vtx.active_sz[attr]) {
+ static const GLfloat id[4] = { 0, 0, 0, 1 };
+ GLuint i;
+
+ /* New size is smaller - just need to fill in some
+ * zeros. Don't need to flush or wrap.
+ */
+ for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
+ exec->vtx.attrptr[attr][i-1] = id[i-1];
+ }
+
+ exec->vtx.active_sz[attr] = newSize;
+
+ /* Does setting NeedFlush belong here? Necessitates resetting
+ * vtxfmt on each flush (otherwise flags won't get reset
+ * afterwards).
+ */
+ if (attr == 0)
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+}
+
+
+/**
+ * This macro is used to implement all the glVertex, glColor, glTexCoord,
+ * glVertexAttrib, etc functions.
+ */
+#define ATTR( A, N, V0, V1, V2, V3 ) \
+do { \
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
+ \
+ if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
+ ctx->Driver.BeginVertices( ctx ); \
+ \
+ if (unlikely(exec->vtx.active_sz[A] != N)) \
+ vbo_exec_fixup_vertex(ctx, A, N); \
+ \
+ { \
+ GLfloat *dest = exec->vtx.attrptr[A]; \
+ if (N>0) dest[0] = V0; \
+ if (N>1) dest[1] = V1; \
+ if (N>2) dest[2] = V2; \
+ if (N>3) dest[3] = V3; \
+ } \
+ \
+ if ((A) == 0) { \
+ /* This is a glVertex call */ \
+ GLuint i; \
+ \
+ for (i = 0; i < exec->vtx.vertex_size; i++) \
+ exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
+ \
+ exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
+ \
+ /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
+ /* something to draw (not just updating a color or texcoord).*/ \
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
+ \
+ if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
+ vbo_exec_vtx_wrap( exec ); \
+ } \
+} while (0)
+
+
+#define ERROR(err) _mesa_error( ctx, err, __FUNCTION__ )
+#define TAG(x) vbo_##x
+
+#include "vbo_attrib_tmp.h"
+
+
+#if FEATURE_beginend
+
+
+#if FEATURE_evaluators
+
+static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+ {
+ GLint i;
+ if (exec->eval.recalculate_maps)
+ vbo_exec_eval_update( exec );
+
+ for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
+ if (exec->eval.map1[i].map)
+ if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
+ vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
+ }
+ }
+
+
+ memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+
+ vbo_exec_do_EvalCoord1f( exec, u );
+
+ memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+}
+
+static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+ {
+ GLint i;
+ if (exec->eval.recalculate_maps)
+ vbo_exec_eval_update( exec );
+
+ for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
+ if (exec->eval.map2[i].map)
+ if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
+ vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
+ }
+
+ if (ctx->Eval.AutoNormal)
+ if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
+ vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
+ }
+
+ memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+
+ vbo_exec_do_EvalCoord2f( exec, u, v );
+
+ memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
+ exec->vtx.vertex_size * sizeof(GLfloat));
+}
+
+static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
+{
+ vbo_exec_EvalCoord1f( u[0] );
+}
+
+static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
+{
+ vbo_exec_EvalCoord2f( u[0], u[1] );
+}
+
+static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
+ (GLfloat) ctx->Eval.MapGrid1un);
+ GLfloat u = i * du + ctx->Eval.MapGrid1u1;
+
+ vbo_exec_EvalCoord1f( u );
+}
+
+
+static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
+ (GLfloat) ctx->Eval.MapGrid2un);
+ GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
+ (GLfloat) ctx->Eval.MapGrid2vn);
+ GLfloat u = i * du + ctx->Eval.MapGrid2u1;
+ GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
+
+ vbo_exec_EvalCoord2f( u, v );
+}
+
+/* use noop eval mesh */
+#define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
+#define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
+
+#endif /* FEATURE_evaluators */
+
+
+/**
+ * Flush (draw) vertices.
+ * \param unmap - leave VBO unmapped after flushing?
+ */
+static void
+vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
+{
+ if (exec->vtx.vert_count || unmap) {
+ vbo_exec_vtx_flush( exec, unmap );
+ }
+
+ if (exec->vtx.vertex_size) {
+ vbo_exec_copy_to_current( exec );
+ reset_attrfv( exec );
+ }
+}
+
+
+/**
+ * Called via glBegin.
+ */
+static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
+{
+ GET_CURRENT_CONTEXT( ctx );
+
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ int i;
+
+ if (ctx->NewState) {
+ _mesa_update_state( ctx );
+
+ CALL_Begin(ctx->Exec, (mode));
+ return;
+ }
+
+ if (!_mesa_valid_to_render(ctx, "glBegin")) {
+ return;
+ }
+
+ /* Heuristic: attempt to isolate attributes occuring outside
+ * begin/end pairs.
+ */
+ if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
+ vbo_exec_FlushVertices_internal(exec, GL_FALSE);
+
+ i = exec->vtx.prim_count++;
+ exec->vtx.prim[i].mode = mode;
+ exec->vtx.prim[i].begin = 1;
+ exec->vtx.prim[i].end = 0;
+ exec->vtx.prim[i].indexed = 0;
+ exec->vtx.prim[i].weak = 0;
+ exec->vtx.prim[i].pad = 0;
+ exec->vtx.prim[i].start = exec->vtx.vert_count;
+ exec->vtx.prim[i].count = 0;
+ exec->vtx.prim[i].num_instances = 1;
+
+ ctx->Driver.CurrentExecPrimitive = mode;
+ }
+ else
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+
+}
+
+
+/**
+ * Called via glEnd.
+ */
+static void GLAPIENTRY vbo_exec_End( void )
+{
+ GET_CURRENT_CONTEXT( ctx );
+
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ int idx = exec->vtx.vert_count;
+ int i = exec->vtx.prim_count - 1;
+
+ exec->vtx.prim[i].end = 1;
+ exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
+
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+
+ if (exec->vtx.prim_count == VBO_MAX_PRIM)
+ vbo_exec_vtx_flush( exec, GL_FALSE );
+ }
+ else
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
+}
+
+
+/**
+ * Called via glPrimitiveRestartNV()
+ */
+static void GLAPIENTRY
+vbo_exec_PrimitiveRestartNV(void)
+{
+ GLenum curPrim;
+ GET_CURRENT_CONTEXT( ctx );
+
+ curPrim = ctx->Driver.CurrentExecPrimitive;
+
+ if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
+ }
+ else {
+ vbo_exec_End();
+ vbo_exec_Begin(curPrim);
+ }
+}
+
+
+
+static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
+{
+ GLvertexformat *vfmt = &exec->vtxfmt;
+
+ _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
+
+ vfmt->Begin = vbo_exec_Begin;
+ vfmt->End = vbo_exec_End;
+ vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
+
+ _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
+ _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
+
+ vfmt->Rectf = _mesa_noop_Rectf;
+
+ /* from attrib_tmp.h:
+ */
+ vfmt->Color3f = vbo_Color3f;
+ vfmt->Color3fv = vbo_Color3fv;
+ vfmt->Color4f = vbo_Color4f;
+ vfmt->Color4fv = vbo_Color4fv;
+ vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
+ vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
+ vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
+ vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
+ vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
+ vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
+ vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
+ vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
+ vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
+ vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
+ vfmt->Normal3f = vbo_Normal3f;
+ vfmt->Normal3fv = vbo_Normal3fv;
+ vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
+ vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
+ vfmt->TexCoord1f = vbo_TexCoord1f;
+ vfmt->TexCoord1fv = vbo_TexCoord1fv;
+ vfmt->TexCoord2f = vbo_TexCoord2f;
+ vfmt->TexCoord2fv = vbo_TexCoord2fv;
+ vfmt->TexCoord3f = vbo_TexCoord3f;
+ vfmt->TexCoord3fv = vbo_TexCoord3fv;
+ vfmt->TexCoord4f = vbo_TexCoord4f;
+ vfmt->TexCoord4fv = vbo_TexCoord4fv;
+ vfmt->Vertex2f = vbo_Vertex2f;
+ vfmt->Vertex2fv = vbo_Vertex2fv;
+ vfmt->Vertex3f = vbo_Vertex3f;
+ vfmt->Vertex3fv = vbo_Vertex3fv;
+ vfmt->Vertex4f = vbo_Vertex4f;
+ vfmt->Vertex4fv = vbo_Vertex4fv;
+
+ vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
+ vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
+ vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
+ vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
+ vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
+ vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
+ vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
+ vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
+
+ vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
+ vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
+ vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
+ vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
+ vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
+ vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
+ vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
+ vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
+
+ /* integer-valued */
+ vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
+ vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
+ vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
+ vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
+ vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
+ vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
+ vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
+
+ /* unsigned integer-valued */
+ vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
+ vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
+ vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
+ vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
+ vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
+ vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
+ vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
+
+ vfmt->Materialfv = vbo_Materialfv;
+
+ vfmt->EdgeFlag = vbo_EdgeFlag;
+ vfmt->Indexf = vbo_Indexf;
+ vfmt->Indexfv = vbo_Indexfv;
+
+}
+
+
+#else /* FEATURE_beginend */
+
+
+static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
+{
+ /* silence warnings */
+ (void) vbo_Color3f;
+ (void) vbo_Color3fv;
+ (void) vbo_Color4f;
+ (void) vbo_Color4fv;
+ (void) vbo_FogCoordfEXT;
+ (void) vbo_FogCoordfvEXT;
+ (void) vbo_MultiTexCoord1f;
+ (void) vbo_MultiTexCoord1fv;
+ (void) vbo_MultiTexCoord2f;
+ (void) vbo_MultiTexCoord2fv;
+ (void) vbo_MultiTexCoord3f;
+ (void) vbo_MultiTexCoord3fv;
+ (void) vbo_MultiTexCoord4f;
+ (void) vbo_MultiTexCoord4fv;
+ (void) vbo_Normal3f;
+ (void) vbo_Normal3fv;
+ (void) vbo_SecondaryColor3fEXT;
+ (void) vbo_SecondaryColor3fvEXT;
+ (void) vbo_TexCoord1f;
+ (void) vbo_TexCoord1fv;
+ (void) vbo_TexCoord2f;
+ (void) vbo_TexCoord2fv;
+ (void) vbo_TexCoord3f;
+ (void) vbo_TexCoord3fv;
+ (void) vbo_TexCoord4f;
+ (void) vbo_TexCoord4fv;
+ (void) vbo_Vertex2f;
+ (void) vbo_Vertex2fv;
+ (void) vbo_Vertex3f;
+ (void) vbo_Vertex3fv;
+ (void) vbo_Vertex4f;
+ (void) vbo_Vertex4fv;
+
+ (void) vbo_VertexAttrib1fARB;
+ (void) vbo_VertexAttrib1fvARB;
+ (void) vbo_VertexAttrib2fARB;
+ (void) vbo_VertexAttrib2fvARB;
+ (void) vbo_VertexAttrib3fARB;
+ (void) vbo_VertexAttrib3fvARB;
+ (void) vbo_VertexAttrib4fARB;
+ (void) vbo_VertexAttrib4fvARB;
+
+ (void) vbo_VertexAttrib1fNV;
+ (void) vbo_VertexAttrib1fvNV;
+ (void) vbo_VertexAttrib2fNV;
+ (void) vbo_VertexAttrib2fvNV;
+ (void) vbo_VertexAttrib3fNV;
+ (void) vbo_VertexAttrib3fvNV;
+ (void) vbo_VertexAttrib4fNV;
+ (void) vbo_VertexAttrib4fvNV;
+
+ (void) vbo_Materialfv;
+
+ (void) vbo_EdgeFlag;
+ (void) vbo_Indexf;
+ (void) vbo_Indexfv;
+}
+
+
+#endif /* FEATURE_beginend */
+
+
+/**
+ * Tell the VBO module to use a real OpenGL vertex buffer object to
+ * store accumulated immediate-mode vertex data.
+ * This replaces the malloced buffer which was created in
+ * vb_exec_vtx_init() below.
+ */
+void vbo_use_buffer_objects(struct gl_context *ctx)
+{
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ /* Any buffer name but 0 can be used here since this bufferobj won't
+ * go into the bufferobj hashtable.
+ */
+ GLuint bufName = IMM_BUFFER_NAME;
+ GLenum target = GL_ARRAY_BUFFER_ARB;
+ GLenum usage = GL_STREAM_DRAW_ARB;
+ GLsizei size = VBO_VERT_BUFFER_SIZE;
+
+ /* Make sure this func is only used once */
+ assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
+ if (exec->vtx.buffer_map) {
+ _mesa_align_free(exec->vtx.buffer_map);
+ exec->vtx.buffer_map = NULL;
+ exec->vtx.buffer_ptr = NULL;
+ }
+
+ /* Allocate a real buffer object now */
+ _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
+ exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
+ ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
+}
+
+
+/**
+ * If this function is called, all VBO buffers will be unmapped when
+ * we flush.
+ * Otherwise, if a simple command like glColor3f() is called and we flush,
+ * the current VBO may be left mapped.
+ */
+void
+vbo_always_unmap_buffers(struct gl_context *ctx)
+{
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
+}
+
+
+void vbo_exec_vtx_init( struct vbo_exec_context *exec )
+{
+ struct gl_context *ctx = exec->ctx;
+ struct vbo_context *vbo = vbo_context(ctx);
+ GLuint i;
+
+ /* Allocate a buffer object. Will just reuse this object
+ * continuously, unless vbo_use_buffer_objects() is called to enable
+ * use of real VBOs.
+ */
+ _mesa_reference_buffer_object(ctx,
+ &exec->vtx.bufferobj,
+ ctx->Shared->NullBufferObj);
+
+ ASSERT(!exec->vtx.buffer_map);
+ exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+
+ vbo_exec_vtxfmt_init( exec );
+
+ /* Hook our functions into the dispatch table.
+ */
+ _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt );
+
+ for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
+ ASSERT(i < Elements(exec->vtx.attrsz));
+ exec->vtx.attrsz[i] = 0;
+ ASSERT(i < Elements(exec->vtx.active_sz));
+ exec->vtx.active_sz[i] = 0;
+ }
+ for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
+ ASSERT(i < Elements(exec->vtx.inputs));
+ ASSERT(i < Elements(exec->vtx.arrays));
+ exec->vtx.inputs[i] = &exec->vtx.arrays[i];
+ }
+
+ {
+ struct gl_client_array *arrays = exec->vtx.arrays;
+ unsigned i;
+
+ memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
+ memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
+
+ for (i = 0; i < 16; ++i) {
+ arrays[i ].BufferObj = NULL;
+ arrays[i + 16].BufferObj = NULL;
+ _mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj,
+ vbo->legacy_currval[i].BufferObj);
+ _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj,
+ vbo->generic_currval[i].BufferObj);
+ }
+ }
+
+ exec->vtx.vertex_size = 0;
+
+ exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
+}
+
+
+void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
+{
+ /* using a real VBO for vertex data */
+ struct gl_context *ctx = exec->ctx;
+ unsigned i;
+
+ /* True VBOs should already be unmapped
+ */
+ if (exec->vtx.buffer_map) {
+ ASSERT(exec->vtx.bufferobj->Name == 0 ||
+ exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
+ if (exec->vtx.bufferobj->Name == 0) {
+ _mesa_align_free(exec->vtx.buffer_map);
+ exec->vtx.buffer_map = NULL;
+ exec->vtx.buffer_ptr = NULL;
+ }
+ }
+
+ /* Drop any outstanding reference to the vertex buffer
+ */
+ for (i = 0; i < Elements(exec->vtx.arrays); i++) {
+ _mesa_reference_buffer_object(ctx,
+ &exec->vtx.arrays[i].BufferObj,
+ NULL);
+ }
+
+ /* Free the vertex buffer. Unmap first if needed.
+ */
+ if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj);
+ }
+ _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
+}
+
+
+/**
+ * Called upon first glVertex, glColor, glTexCoord, etc.
+ */
+void vbo_exec_BeginVertices( struct gl_context *ctx )
+{
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+ vbo_exec_vtx_map( exec );
+
+ assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
+ assert(exec->begin_vertices_flags);
+
+ ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
+}
+
+
+/**
+ * Called via ctx->Driver.FlushVertices()
+ * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
+ */
+void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
+{
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+
+#ifdef DEBUG
+ /* debug check: make sure we don't get called recursively */
+ exec->flush_call_depth++;
+ assert(exec->flush_call_depth == 1);
+#endif
+
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ /* We've had glBegin but not glEnd! */
+#ifdef DEBUG
+ exec->flush_call_depth--;
+ assert(exec->flush_call_depth == 0);
+#endif
+ return;
+ }
+
+ /* Flush (draw), and make sure VBO is left unmapped when done */
+ vbo_exec_FlushVertices_internal(exec, GL_TRUE);
+
+ /* Need to do this to ensure BeginVertices gets called again:
+ */
+ ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
+
+#ifdef DEBUG
+ exec->flush_call_depth--;
+ assert(exec->flush_call_depth == 0);
+#endif
+}
+
+
+static void reset_attrfv( struct vbo_exec_context *exec )
+{
+ GLuint i;
+
+ for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
+ exec->vtx.attrsz[i] = 0;
+ exec->vtx.active_sz[i] = 0;
+ }
+
+ exec->vtx.vertex_size = 0;
+}
+
+
+void GLAPIENTRY
+_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+{
+ vbo_Color4f(r, g, b, a);
+}
+
+
+void GLAPIENTRY
+_es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
+{
+ vbo_Normal3f(x, y, z);
+}
+
+
+void GLAPIENTRY
+_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+ vbo_MultiTexCoord4f(target, s, t, r, q);
+}
+
+
+void GLAPIENTRY
+_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
+{
+ vbo_Materialfv(face, pname, params);
+}
+
+
+void GLAPIENTRY
+_es_Materialf(GLenum face, GLenum pname, GLfloat param)
+{
+ GLfloat p[4];
+ p[0] = param;
+ p[1] = p[2] = p[3] = 0.0F;
+ vbo_Materialfv(face, pname, p);
+}
+
+
+/**
+ * A special version of glVertexAttrib4f that does not treat index 0 as
+ * VBO_ATTRIB_POS.
+ */
+static void
+VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
+void GLAPIENTRY
+_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ VertexAttrib4f_nopos(index, x, y, z, w);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib1f(GLuint indx, GLfloat x)
+{
+ VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+{
+ VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+{
+ VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
+}
+
+
+void GLAPIENTRY
+_es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
+{
+ VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
+}
diff --git a/mesalib/src/mesa/vbo/vbo_exec_array.c b/mesalib/src/mesa/vbo/vbo_exec_array.c
index 98d6badc4..a189ab76b 100644
--- a/mesalib/src/mesa/vbo/vbo_exec_array.c
+++ b/mesalib/src/mesa/vbo/vbo_exec_array.c
@@ -1,1336 +1,1341 @@
-/**************************************************************************
- *
- * 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++) {
- GLuint bufName = exec->array.inputs[i]->BufferObj->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) {
- struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, bufName);
- GLubyte *p = ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
- GL_READ_ONLY_ARB, buf);
- int offset = (int) (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, buf);
- }
- }
-}
-
-
-/**
- * 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);
-
- prim[0].begin = 1;
- prim[0].end = 1;
- prim[0].weak = 0;
- prim[0].pad = 0;
- prim[0].mode = mode;
- prim[0].start = 0; /* filled in below */
- prim[0].count = 0; /* filled in below */
- prim[0].indexed = 0;
- prim[0].basevertex = 0;
- 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);
-
-#ifdef DEBUG
- /* 'end' was out of bounds, but now let's check the actual array
- * indexes to see if any of them are out of bounds.
- */
- {
- 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.
- */
- }
-#endif
-
- /* Set 'end' to the max possible legal value */
- assert(ctx->Array.ArrayObj->_MaxElement >= 1);
- end = ctx->Array.ArrayObj->_MaxElement - 1;
- }
- else 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)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- if (MESA_VERBOSE & VERBOSE_DRAW)
- _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))
- return;
-
- vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
- count, type, indices, 0, 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;
-}
-
-
-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++) {
+ GLuint bufName = exec->array.inputs[i]->BufferObj->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) {
+ struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, bufName);
+ GLubyte *p = ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY_ARB, buf);
+ int offset = (int) (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, buf);
+ }
+ }
+}
+
+
+/**
+ * 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);
+
+ prim[0].begin = 1;
+ prim[0].end = 1;
+ prim[0].weak = 0;
+ prim[0].pad = 0;
+ prim[0].mode = mode;
+ prim[0].start = 0; /* filled in below */
+ prim[0].count = 0; /* filled in below */
+ prim[0].indexed = 0;
+ prim[0].basevertex = 0;
+ 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);
+
+#ifdef DEBUG
+ /* 'end' was out of bounds, but now let's check the actual array
+ * indexes to see if any of them are out of bounds.
+ */
+ {
+ 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.
+ */
+ }
+#endif
+
+ /* 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)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (MESA_VERBOSE & VERBOSE_DRAW)
+ _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))
+ return;
+
+ vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
+ count, type, indices, 0, 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;
+}
+
+
+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_exec_draw.c b/mesalib/src/mesa/vbo/vbo_exec_draw.c
index 539658021..98f585792 100644
--- a/mesalib/src/mesa/vbo/vbo_exec_draw.c
+++ b/mesalib/src/mesa/vbo/vbo_exec_draw.c
@@ -1,426 +1,427 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.2
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-#include "main/glheader.h"
-#include "main/bufferobj.h"
-#include "main/compiler.h"
-#include "main/enums.h"
-#include "main/mfeatures.h"
-#include "main/state.h"
-
-#include "vbo_context.h"
-
-
-#if FEATURE_beginend
-
-
-static void
-vbo_exec_debug_verts( struct vbo_exec_context *exec )
-{
- GLuint count = exec->vtx.vert_count;
- GLuint i;
-
- printf("%s: %u vertices %d primitives, %d vertsize\n",
- __FUNCTION__,
- count,
- exec->vtx.prim_count,
- exec->vtx.vertex_size);
-
- for (i = 0 ; i < exec->vtx.prim_count ; i++) {
- struct _mesa_prim *prim = &exec->vtx.prim[i];
- printf(" 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)");
- }
-}
-
-
-/*
- * NOTE: Need to have calculated primitives by this point -- do it on the fly.
- * NOTE: Old 'parity' issue is gone.
- */
-static GLuint
-vbo_copy_vertices( struct vbo_exec_context *exec )
-{
- GLuint nr = exec->vtx.prim[exec->vtx.prim_count-1].count;
- GLuint ovf, i;
- GLuint sz = exec->vtx.vertex_size;
- GLfloat *dst = exec->vtx.copied.buffer;
- const GLfloat *src = (exec->vtx.buffer_map +
- exec->vtx.prim[exec->vtx.prim_count-1].start *
- exec->vtx.vertex_size);
-
-
- switch (exec->ctx->Driver.CurrentExecPrimitive) {
- case GL_POINTS:
- return 0;
- case GL_LINES:
- ovf = nr&1;
- for (i = 0 ; i < ovf ; i++)
- 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:
- /* no parity issue, but need to make sure the tri is not drawn twice */
- if (nr & 1) {
- exec->vtx.prim[exec->vtx.prim_count-1].count--;
- }
- /* fallthrough */
- case GL_QUAD_STRIP:
- switch (nr) {
- case 0:
- ovf = 0;
- break;
- case 1:
- ovf = 1;
- break;
- default:
- ovf = 2 + (nr & 1);
- break;
- }
- for (i = 0 ; i < ovf ; i++)
- memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
- return i;
- case PRIM_OUTSIDE_BEGIN_END:
- return 0;
- default:
- assert(0);
- return 0;
- }
-}
-
-
-
-/* TODO: populate these as the vertex is defined:
- */
-static void
-vbo_exec_bind_arrays( struct gl_context *ctx )
-{
- struct vbo_context *vbo = vbo_context(ctx);
- struct vbo_exec_context *exec = &vbo->exec;
- struct gl_client_array *arrays = exec->vtx.arrays;
- const GLuint count = exec->vtx.vert_count;
- const GLuint *map;
- GLuint attr;
- GLbitfield varying_inputs = 0x0;
-
- /* Install the default (ie Current) attributes first, then overlay
- * all active ones.
- */
- switch (get_program_mode(exec->ctx)) {
- case VP_NONE:
- for (attr = 0; attr < 16; attr++) {
- exec->vtx.inputs[attr] = &vbo->legacy_currval[attr];
- }
- for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
- ASSERT(attr + 16 < Elements(exec->vtx.inputs));
- exec->vtx.inputs[attr + 16] = &vbo->mat_currval[attr];
- }
- map = vbo->map_vp_none;
- break;
- case VP_NV:
- case VP_ARB:
- /* The aliasing of attributes for NV vertex programs has already
- * occurred. NV vertex programs cannot access material values,
- * nor attributes greater than VERT_ATTRIB_TEX7.
- */
- for (attr = 0; attr < 16; attr++) {
- exec->vtx.inputs[attr] = &vbo->legacy_currval[attr];
- ASSERT(attr + 16 < Elements(exec->vtx.inputs));
- exec->vtx.inputs[attr + 16] = &vbo->generic_currval[attr];
- }
- map = vbo->map_vp_arb;
-
- /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
- * In that case we effectively need to route the data from
- * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
- */
- if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
- (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
- exec->vtx.inputs[16] = exec->vtx.inputs[0];
- exec->vtx.attrsz[16] = exec->vtx.attrsz[0];
- exec->vtx.attrptr[16] = exec->vtx.attrptr[0];
- exec->vtx.attrsz[0] = 0;
- }
- break;
- default:
- assert(0);
- }
-
- /* Make all active attributes (including edgeflag) available as
- * arrays of floats.
- */
- for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) {
- const GLuint src = map[attr];
-
- if (exec->vtx.attrsz[src]) {
- GLsizeiptr offset = (GLbyte *)exec->vtx.attrptr[src] -
- (GLbyte *)exec->vtx.vertex;
-
- /* override the default array set above */
- ASSERT(attr < Elements(exec->vtx.inputs));
- ASSERT(attr < Elements(exec->vtx.arrays)); /* arrays[] */
- exec->vtx.inputs[attr] = &arrays[attr];
-
- if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
- /* a real buffer obj: Ptr is an offset, not a pointer*/
- assert(exec->vtx.bufferobj->Pointer); /* buf should be mapped */
- assert(offset >= 0);
- arrays[attr].Ptr = (GLubyte *)exec->vtx.bufferobj->Offset + offset;
- }
- else {
- /* Ptr into ordinary app memory */
- arrays[attr].Ptr = (GLubyte *)exec->vtx.buffer_map + offset;
- }
- arrays[attr].Size = exec->vtx.attrsz[src];
- arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat);
- arrays[attr].Stride = exec->vtx.vertex_size * sizeof(GLfloat);
- arrays[attr].Type = GL_FLOAT;
- arrays[attr].Format = GL_RGBA;
- arrays[attr].Enabled = 1;
- _mesa_reference_buffer_object(ctx,
- &arrays[attr].BufferObj,
- exec->vtx.bufferobj);
- arrays[attr]._MaxElement = count; /* ??? */
-
- varying_inputs |= 1 << attr;
- ctx->NewState |= _NEW_ARRAY;
- }
- }
-
- _mesa_set_varying_vp_inputs( ctx, varying_inputs );
-}
-
-
-/**
- * Unmap the VBO. This is called before drawing.
- */
-static void
-vbo_exec_vtx_unmap( struct vbo_exec_context *exec )
-{
- GLenum target = GL_ARRAY_BUFFER_ARB;
-
- if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
- struct gl_context *ctx = exec->ctx;
-
- if (ctx->Driver.FlushMappedBufferRange) {
- GLintptr offset = exec->vtx.buffer_used - exec->vtx.bufferobj->Offset;
- GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * sizeof(float);
-
- if (length)
- ctx->Driver.FlushMappedBufferRange(ctx, target,
- offset, length,
- exec->vtx.bufferobj);
- }
-
- exec->vtx.buffer_used += (exec->vtx.buffer_ptr -
- exec->vtx.buffer_map) * sizeof(float);
-
- assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE);
- assert(exec->vtx.buffer_ptr != NULL);
-
- ctx->Driver.UnmapBuffer(ctx, target, exec->vtx.bufferobj);
- exec->vtx.buffer_map = NULL;
- exec->vtx.buffer_ptr = NULL;
- exec->vtx.max_vert = 0;
- }
-}
-
-
-/**
- * Map the vertex buffer to begin storing glVertex, glColor, etc data.
- */
-void
-vbo_exec_vtx_map( struct vbo_exec_context *exec )
-{
- struct gl_context *ctx = exec->ctx;
- const GLenum target = GL_ARRAY_BUFFER_ARB;
- const GLenum access = GL_READ_WRITE_ARB; /* for MapBuffer */
- const GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */
- GL_MAP_INVALIDATE_RANGE_BIT |
- GL_MAP_UNSYNCHRONIZED_BIT |
- GL_MAP_FLUSH_EXPLICIT_BIT |
- MESA_MAP_NOWAIT_BIT;
- const GLenum usage = GL_STREAM_DRAW_ARB;
-
- if (!_mesa_is_bufferobj(exec->vtx.bufferobj))
- return;
-
- assert(!exec->vtx.buffer_map);
- assert(!exec->vtx.buffer_ptr);
-
- if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024 &&
- ctx->Driver.MapBufferRange) {
- /* The VBO exists and there's room for more */
- exec->vtx.buffer_map =
- (GLfloat *)ctx->Driver.MapBufferRange(ctx,
- target,
- exec->vtx.buffer_used,
- (VBO_VERT_BUFFER_SIZE -
- exec->vtx.buffer_used),
- accessRange,
- exec->vtx.bufferobj);
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
- }
-
- if (!exec->vtx.buffer_map) {
- /* Need to allocate a new VBO */
- exec->vtx.buffer_used = 0;
-
- ctx->Driver.BufferData(ctx, target,
- VBO_VERT_BUFFER_SIZE,
- NULL, usage, exec->vtx.bufferobj);
-
-
- if (ctx->Driver.MapBufferRange)
- exec->vtx.buffer_map =
- (GLfloat *)ctx->Driver.MapBufferRange(ctx, target,
- 0, VBO_VERT_BUFFER_SIZE,
- accessRange,
- exec->vtx.bufferobj);
- if (!exec->vtx.buffer_map)
- exec->vtx.buffer_map =
- (GLfloat *)ctx->Driver.MapBuffer(ctx, target, access, exec->vtx.bufferobj);
- assert(exec->vtx.buffer_map);
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
- }
-
- if (0)
- printf("map %d..\n", exec->vtx.buffer_used);
-}
-
-
-
-/**
- * Execute the buffer and save copied verts.
- * \param keep_unmapped if true, leave the VBO unmapped when we're done.
- */
-void
-vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped)
-{
- if (0)
- vbo_exec_debug_verts( exec );
-
- if (exec->vtx.prim_count &&
- exec->vtx.vert_count) {
-
- exec->vtx.copied.nr = vbo_copy_vertices( exec );
-
- if (exec->vtx.copied.nr != exec->vtx.vert_count) {
- struct gl_context *ctx = exec->ctx;
-
- /* Before the update_state() as this may raise _NEW_ARRAY
- * from _mesa_set_varying_vp_inputs().
- */
- vbo_exec_bind_arrays( ctx );
-
- if (ctx->NewState)
- _mesa_update_state( ctx );
-
- if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
- vbo_exec_vtx_unmap( exec );
- }
-
- if (0)
- printf("%s %d %d\n", __FUNCTION__, exec->vtx.prim_count,
- exec->vtx.vert_count);
-
- vbo_context(ctx)->draw_prims( ctx,
- exec->vtx.inputs,
- exec->vtx.prim,
- exec->vtx.prim_count,
- NULL,
- GL_TRUE,
- 0,
- exec->vtx.vert_count - 1);
-
- /* If using a real VBO, get new storage -- unless asked not to.
- */
- if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !keepUnmapped) {
- vbo_exec_vtx_map( exec );
- }
- }
- }
-
- /* May have to unmap explicitly if we didn't draw:
- */
- if (keepUnmapped &&
- _mesa_is_bufferobj(exec->vtx.bufferobj) &&
- exec->vtx.buffer_map) {
- vbo_exec_vtx_unmap( exec );
- }
-
- if (keepUnmapped || exec->vtx.vertex_size == 0)
- exec->vtx.max_vert = 0;
- else
- exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
- (exec->vtx.vertex_size * sizeof(GLfloat)));
-
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
- exec->vtx.prim_count = 0;
- exec->vtx.vert_count = 0;
-}
-
-
-#endif /* FEATURE_beginend */
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.2
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/compiler.h"
+#include "main/enums.h"
+#include "main/mfeatures.h"
+#include "main/state.h"
+
+#include "vbo_context.h"
+
+
+#if FEATURE_beginend
+
+
+static void
+vbo_exec_debug_verts( struct vbo_exec_context *exec )
+{
+ GLuint count = exec->vtx.vert_count;
+ GLuint i;
+
+ printf("%s: %u vertices %d primitives, %d vertsize\n",
+ __FUNCTION__,
+ count,
+ exec->vtx.prim_count,
+ exec->vtx.vertex_size);
+
+ for (i = 0 ; i < exec->vtx.prim_count ; i++) {
+ struct _mesa_prim *prim = &exec->vtx.prim[i];
+ printf(" 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)");
+ }
+}
+
+
+/*
+ * NOTE: Need to have calculated primitives by this point -- do it on the fly.
+ * NOTE: Old 'parity' issue is gone.
+ */
+static GLuint
+vbo_copy_vertices( struct vbo_exec_context *exec )
+{
+ GLuint nr = exec->vtx.prim[exec->vtx.prim_count-1].count;
+ GLuint ovf, i;
+ GLuint sz = exec->vtx.vertex_size;
+ GLfloat *dst = exec->vtx.copied.buffer;
+ const GLfloat *src = (exec->vtx.buffer_map +
+ exec->vtx.prim[exec->vtx.prim_count-1].start *
+ exec->vtx.vertex_size);
+
+
+ switch (exec->ctx->Driver.CurrentExecPrimitive) {
+ case GL_POINTS:
+ return 0;
+ case GL_LINES:
+ ovf = nr&1;
+ for (i = 0 ; i < ovf ; i++)
+ 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:
+ /* no parity issue, but need to make sure the tri is not drawn twice */
+ if (nr & 1) {
+ exec->vtx.prim[exec->vtx.prim_count-1].count--;
+ }
+ /* fallthrough */
+ case GL_QUAD_STRIP:
+ switch (nr) {
+ case 0:
+ ovf = 0;
+ break;
+ case 1:
+ ovf = 1;
+ break;
+ default:
+ ovf = 2 + (nr & 1);
+ break;
+ }
+ for (i = 0 ; i < ovf ; i++)
+ memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+ return i;
+ case PRIM_OUTSIDE_BEGIN_END:
+ return 0;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+
+
+/* TODO: populate these as the vertex is defined:
+ */
+static void
+vbo_exec_bind_arrays( struct gl_context *ctx )
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_exec_context *exec = &vbo->exec;
+ struct gl_client_array *arrays = exec->vtx.arrays;
+ const GLuint count = exec->vtx.vert_count;
+ const GLuint *map;
+ GLuint attr;
+ GLbitfield varying_inputs = 0x0;
+
+ /* Install the default (ie Current) attributes first, then overlay
+ * all active ones.
+ */
+ switch (get_program_mode(exec->ctx)) {
+ case VP_NONE:
+ for (attr = 0; attr < 16; attr++) {
+ exec->vtx.inputs[attr] = &vbo->legacy_currval[attr];
+ }
+ for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
+ ASSERT(attr + 16 < Elements(exec->vtx.inputs));
+ exec->vtx.inputs[attr + 16] = &vbo->mat_currval[attr];
+ }
+ map = vbo->map_vp_none;
+ break;
+ case VP_NV:
+ case VP_ARB:
+ /* The aliasing of attributes for NV vertex programs has already
+ * occurred. NV vertex programs cannot access material values,
+ * nor attributes greater than VERT_ATTRIB_TEX7.
+ */
+ for (attr = 0; attr < 16; attr++) {
+ exec->vtx.inputs[attr] = &vbo->legacy_currval[attr];
+ ASSERT(attr + 16 < Elements(exec->vtx.inputs));
+ exec->vtx.inputs[attr + 16] = &vbo->generic_currval[attr];
+ }
+ map = vbo->map_vp_arb;
+
+ /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
+ * In that case we effectively need to route the data from
+ * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
+ */
+ if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
+ (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
+ exec->vtx.inputs[16] = exec->vtx.inputs[0];
+ exec->vtx.attrsz[16] = exec->vtx.attrsz[0];
+ exec->vtx.attrptr[16] = exec->vtx.attrptr[0];
+ exec->vtx.attrsz[0] = 0;
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ /* Make all active attributes (including edgeflag) available as
+ * arrays of floats.
+ */
+ for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) {
+ const GLuint src = map[attr];
+
+ if (exec->vtx.attrsz[src]) {
+ GLsizeiptr offset = (GLbyte *)exec->vtx.attrptr[src] -
+ (GLbyte *)exec->vtx.vertex;
+
+ /* override the default array set above */
+ ASSERT(attr < Elements(exec->vtx.inputs));
+ ASSERT(attr < Elements(exec->vtx.arrays)); /* arrays[] */
+ exec->vtx.inputs[attr] = &arrays[attr];
+
+ if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
+ /* a real buffer obj: Ptr is an offset, not a pointer*/
+ assert(exec->vtx.bufferobj->Pointer); /* buf should be mapped */
+ assert(offset >= 0);
+ arrays[attr].Ptr = (GLubyte *)exec->vtx.bufferobj->Offset + offset;
+ }
+ else {
+ /* Ptr into ordinary app memory */
+ arrays[attr].Ptr = (GLubyte *)exec->vtx.buffer_map + offset;
+ }
+ arrays[attr].Size = exec->vtx.attrsz[src];
+ arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat);
+ arrays[attr].Stride = exec->vtx.vertex_size * sizeof(GLfloat);
+ arrays[attr].Type = GL_FLOAT;
+ arrays[attr].Format = GL_RGBA;
+ arrays[attr].Enabled = 1;
+ arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat);
+ _mesa_reference_buffer_object(ctx,
+ &arrays[attr].BufferObj,
+ exec->vtx.bufferobj);
+ arrays[attr]._MaxElement = count; /* ??? */
+
+ varying_inputs |= 1 << attr;
+ ctx->NewState |= _NEW_ARRAY;
+ }
+ }
+
+ _mesa_set_varying_vp_inputs( ctx, varying_inputs );
+}
+
+
+/**
+ * Unmap the VBO. This is called before drawing.
+ */
+static void
+vbo_exec_vtx_unmap( struct vbo_exec_context *exec )
+{
+ GLenum target = GL_ARRAY_BUFFER_ARB;
+
+ if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
+ struct gl_context *ctx = exec->ctx;
+
+ if (ctx->Driver.FlushMappedBufferRange) {
+ GLintptr offset = exec->vtx.buffer_used - exec->vtx.bufferobj->Offset;
+ GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * sizeof(float);
+
+ if (length)
+ ctx->Driver.FlushMappedBufferRange(ctx, target,
+ offset, length,
+ exec->vtx.bufferobj);
+ }
+
+ exec->vtx.buffer_used += (exec->vtx.buffer_ptr -
+ exec->vtx.buffer_map) * sizeof(float);
+
+ assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE);
+ assert(exec->vtx.buffer_ptr != NULL);
+
+ ctx->Driver.UnmapBuffer(ctx, target, exec->vtx.bufferobj);
+ exec->vtx.buffer_map = NULL;
+ exec->vtx.buffer_ptr = NULL;
+ exec->vtx.max_vert = 0;
+ }
+}
+
+
+/**
+ * Map the vertex buffer to begin storing glVertex, glColor, etc data.
+ */
+void
+vbo_exec_vtx_map( struct vbo_exec_context *exec )
+{
+ struct gl_context *ctx = exec->ctx;
+ const GLenum target = GL_ARRAY_BUFFER_ARB;
+ const GLenum access = GL_READ_WRITE_ARB; /* for MapBuffer */
+ const GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */
+ GL_MAP_INVALIDATE_RANGE_BIT |
+ GL_MAP_UNSYNCHRONIZED_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT |
+ MESA_MAP_NOWAIT_BIT;
+ const GLenum usage = GL_STREAM_DRAW_ARB;
+
+ if (!_mesa_is_bufferobj(exec->vtx.bufferobj))
+ return;
+
+ assert(!exec->vtx.buffer_map);
+ assert(!exec->vtx.buffer_ptr);
+
+ if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024 &&
+ ctx->Driver.MapBufferRange) {
+ /* The VBO exists and there's room for more */
+ exec->vtx.buffer_map =
+ (GLfloat *)ctx->Driver.MapBufferRange(ctx,
+ target,
+ exec->vtx.buffer_used,
+ (VBO_VERT_BUFFER_SIZE -
+ exec->vtx.buffer_used),
+ accessRange,
+ exec->vtx.bufferobj);
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ }
+
+ if (!exec->vtx.buffer_map) {
+ /* Need to allocate a new VBO */
+ exec->vtx.buffer_used = 0;
+
+ ctx->Driver.BufferData(ctx, target,
+ VBO_VERT_BUFFER_SIZE,
+ NULL, usage, exec->vtx.bufferobj);
+
+
+ if (ctx->Driver.MapBufferRange)
+ exec->vtx.buffer_map =
+ (GLfloat *)ctx->Driver.MapBufferRange(ctx, target,
+ 0, VBO_VERT_BUFFER_SIZE,
+ accessRange,
+ exec->vtx.bufferobj);
+ if (!exec->vtx.buffer_map)
+ exec->vtx.buffer_map =
+ (GLfloat *)ctx->Driver.MapBuffer(ctx, target, access, exec->vtx.bufferobj);
+ assert(exec->vtx.buffer_map);
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ }
+
+ if (0)
+ printf("map %d..\n", exec->vtx.buffer_used);
+}
+
+
+
+/**
+ * Execute the buffer and save copied verts.
+ * \param keep_unmapped if true, leave the VBO unmapped when we're done.
+ */
+void
+vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped)
+{
+ if (0)
+ vbo_exec_debug_verts( exec );
+
+ if (exec->vtx.prim_count &&
+ exec->vtx.vert_count) {
+
+ exec->vtx.copied.nr = vbo_copy_vertices( exec );
+
+ if (exec->vtx.copied.nr != exec->vtx.vert_count) {
+ struct gl_context *ctx = exec->ctx;
+
+ /* Before the update_state() as this may raise _NEW_ARRAY
+ * from _mesa_set_varying_vp_inputs().
+ */
+ vbo_exec_bind_arrays( ctx );
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
+ vbo_exec_vtx_unmap( exec );
+ }
+
+ if (0)
+ printf("%s %d %d\n", __FUNCTION__, exec->vtx.prim_count,
+ exec->vtx.vert_count);
+
+ vbo_context(ctx)->draw_prims( ctx,
+ exec->vtx.inputs,
+ exec->vtx.prim,
+ exec->vtx.prim_count,
+ NULL,
+ GL_TRUE,
+ 0,
+ exec->vtx.vert_count - 1);
+
+ /* If using a real VBO, get new storage -- unless asked not to.
+ */
+ if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !keepUnmapped) {
+ vbo_exec_vtx_map( exec );
+ }
+ }
+ }
+
+ /* May have to unmap explicitly if we didn't draw:
+ */
+ if (keepUnmapped &&
+ _mesa_is_bufferobj(exec->vtx.bufferobj) &&
+ exec->vtx.buffer_map) {
+ vbo_exec_vtx_unmap( exec );
+ }
+
+ if (keepUnmapped || exec->vtx.vertex_size == 0)
+ exec->vtx.max_vert = 0;
+ else
+ exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
+ (exec->vtx.vertex_size * sizeof(GLfloat)));
+
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ exec->vtx.prim_count = 0;
+ exec->vtx.vert_count = 0;
+}
+
+
+#endif /* FEATURE_beginend */
diff --git a/mesalib/src/mesa/vbo/vbo_save_draw.c b/mesalib/src/mesa/vbo/vbo_save_draw.c
index 634a6d3f8..d0f627a35 100644
--- a/mesalib/src/mesa/vbo/vbo_save_draw.c
+++ b/mesalib/src/mesa/vbo/vbo_save_draw.c
@@ -1,305 +1,308 @@
-/*
- * Mesa 3-D graphics library
- * Version: 7.2
- *
- * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/* Author:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-#include "main/glheader.h"
-#include "main/bufferobj.h"
-#include "main/context.h"
-#include "main/imports.h"
-#include "main/mfeatures.h"
-#include "main/mtypes.h"
-#include "main/macros.h"
-#include "main/light.h"
-#include "main/state.h"
-
-#include "vbo_context.h"
-
-
-#if FEATURE_dlist
-
-
-/**
- * After playback, copy everything but the position from the
- * last vertex to the saved state
- */
-static void
-_playback_copy_to_current(struct gl_context *ctx,
- const struct vbo_save_vertex_list *node)
-{
- struct vbo_context *vbo = vbo_context(ctx);
- GLfloat vertex[VBO_ATTRIB_MAX * 4];
- GLfloat *data;
- GLuint i, offset;
-
- if (node->current_size == 0)
- return;
-
- if (node->current_data) {
- data = node->current_data;
- }
- else {
- data = vertex;
-
- if (node->count)
- offset = (node->buffer_offset +
- (node->count-1) * node->vertex_size * sizeof(GLfloat));
- else
- offset = node->buffer_offset;
-
- ctx->Driver.GetBufferSubData( ctx, 0, offset,
- node->vertex_size * sizeof(GLfloat),
- data, node->vertex_store->bufferobj );
-
- data += node->attrsz[0]; /* skip vertex position */
- }
-
- for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
- if (node->attrsz[i]) {
- GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
- GLfloat tmp[4];
-
- COPY_CLEAN_4V(tmp,
- node->attrsz[i],
- data);
-
- if (memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) {
- memcpy(current, tmp, 4 * sizeof(GLfloat));
-
- vbo->currval[i].Size = node->attrsz[i];
-
- if (i >= VBO_ATTRIB_FIRST_MATERIAL &&
- i <= VBO_ATTRIB_LAST_MATERIAL)
- ctx->NewState |= _NEW_LIGHT;
-
- ctx->NewState |= _NEW_CURRENT_ATTRIB;
- }
-
- data += node->attrsz[i];
- }
- }
-
- /* Colormaterial -- this kindof sucks.
- */
- if (ctx->Light.ColorMaterialEnabled) {
- _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
- }
-
- /* CurrentExecPrimitive
- */
- if (node->prim_count) {
- const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
- if (prim->end)
- ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
- else
- ctx->Driver.CurrentExecPrimitive = prim->mode;
- }
-}
-
-
-
-/**
- * Treat the vertex storage as a VBO, define vertex arrays pointing
- * into it:
- */
-static void vbo_bind_vertex_list(struct gl_context *ctx,
- const struct vbo_save_vertex_list *node)
-{
- struct vbo_context *vbo = vbo_context(ctx);
- struct vbo_save_context *save = &vbo->save;
- struct gl_client_array *arrays = save->arrays;
- GLuint buffer_offset = node->buffer_offset;
- const GLuint *map;
- GLuint attr;
- GLubyte node_attrsz[VBO_ATTRIB_MAX]; /* copy of node->attrsz[] */
- GLbitfield varying_inputs = 0x0;
-
- memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz));
-
- /* Install the default (ie Current) attributes first, then overlay
- * all active ones.
- */
- switch (get_program_mode(ctx)) {
- case VP_NONE:
- for (attr = 0; attr < 16; attr++) {
- save->inputs[attr] = &vbo->legacy_currval[attr];
- }
- for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
- save->inputs[attr + 16] = &vbo->mat_currval[attr];
- }
- map = vbo->map_vp_none;
- break;
- case VP_NV:
- case VP_ARB:
- /* The aliasing of attributes for NV vertex programs has already
- * occurred. NV vertex programs cannot access material values,
- * nor attributes greater than VERT_ATTRIB_TEX7.
- */
- for (attr = 0; attr < 16; attr++) {
- save->inputs[attr] = &vbo->legacy_currval[attr];
- save->inputs[attr + 16] = &vbo->generic_currval[attr];
- }
- map = vbo->map_vp_arb;
-
- /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
- * In that case we effectively need to route the data from
- * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
- */
- if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
- (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
- save->inputs[16] = save->inputs[0];
- node_attrsz[16] = node_attrsz[0];
- node_attrsz[0] = 0;
- }
- break;
- default:
- assert(0);
- }
-
- for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
- const GLuint src = map[attr];
-
- if (node_attrsz[src]) {
- /* override the default array set above */
- save->inputs[attr] = &arrays[attr];
-
- arrays[attr].Ptr = (const GLubyte *) NULL + buffer_offset;
- arrays[attr].Size = node->attrsz[src];
- arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat);
- arrays[attr].Stride = node->vertex_size * sizeof(GLfloat);
- arrays[attr].Type = GL_FLOAT;
- arrays[attr].Format = GL_RGBA;
- arrays[attr].Enabled = 1;
- _mesa_reference_buffer_object(ctx,
- &arrays[attr].BufferObj,
- node->vertex_store->bufferobj);
- arrays[attr]._MaxElement = node->count; /* ??? */
-
- assert(arrays[attr].BufferObj->Name);
-
- buffer_offset += node->attrsz[src] * sizeof(GLfloat);
- varying_inputs |= 1<<attr;
- ctx->NewState |= _NEW_ARRAY;
- }
- }
-
- _mesa_set_varying_vp_inputs( ctx, varying_inputs );
-}
-
-
-static void
-vbo_save_loopback_vertex_list(struct gl_context *ctx,
- const struct vbo_save_vertex_list *list)
-{
- const char *buffer = ctx->Driver.MapBuffer(ctx,
- GL_ARRAY_BUFFER_ARB,
- GL_READ_ONLY, /* ? */
- list->vertex_store->bufferobj);
-
- vbo_loopback_vertex_list(ctx,
- (const GLfloat *)(buffer + list->buffer_offset),
- list->attrsz,
- list->prim,
- list->prim_count,
- list->wrap_count,
- list->vertex_size);
-
- ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
- list->vertex_store->bufferobj);
-}
-
-
-/**
- * Execute the buffer and save copied verts.
- * This is called from the display list code when executing
- * a drawing command.
- */
-void
-vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
-{
- const struct vbo_save_vertex_list *node =
- (const struct vbo_save_vertex_list *) data;
- struct vbo_save_context *save = &vbo_context(ctx)->save;
-
- FLUSH_CURRENT(ctx, 0);
-
- if (node->prim_count > 0 && node->count > 0) {
-
- if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END &&
- node->prim[0].begin) {
-
- /* Degenerate case: list is called inside begin/end pair and
- * includes operations such as glBegin or glDrawArrays.
- */
- if (0)
- printf("displaylist recursive begin");
-
- vbo_save_loopback_vertex_list( ctx, node );
- return;
- }
- else if (save->replay_flags) {
- /* Various degnerate cases: translate into immediate mode
- * calls rather than trying to execute in place.
- */
- vbo_save_loopback_vertex_list( ctx, node );
- return;
- }
-
- if (ctx->NewState)
- _mesa_update_state( ctx );
-
- /* XXX also need to check if shader enabled, but invalid */
- if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
- (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glBegin (invalid vertex/fragment program)");
- return;
- }
-
- vbo_bind_vertex_list( ctx, node );
-
- /* Again...
- */
- if (ctx->NewState)
- _mesa_update_state( ctx );
-
- vbo_context(ctx)->draw_prims(ctx,
- save->inputs,
- node->prim,
- node->prim_count,
- NULL,
- GL_TRUE,
- 0, /* Node is a VBO, so this is ok */
- node->count - 1);
- }
-
- /* Copy to current?
- */
- _playback_copy_to_current( ctx, node );
-}
-
-
-#endif /* FEATURE_dlist */
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.2
+ *
+ * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* Author:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/context.h"
+#include "main/imports.h"
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
+#include "main/macros.h"
+#include "main/light.h"
+#include "main/state.h"
+
+#include "vbo_context.h"
+
+
+#if FEATURE_dlist
+
+
+/**
+ * After playback, copy everything but the position from the
+ * last vertex to the saved state
+ */
+static void
+_playback_copy_to_current(struct gl_context *ctx,
+ const struct vbo_save_vertex_list *node)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ GLfloat vertex[VBO_ATTRIB_MAX * 4];
+ GLfloat *data;
+ GLuint i, offset;
+
+ if (node->current_size == 0)
+ return;
+
+ if (node->current_data) {
+ data = node->current_data;
+ }
+ else {
+ data = vertex;
+
+ if (node->count)
+ offset = (node->buffer_offset +
+ (node->count-1) * node->vertex_size * sizeof(GLfloat));
+ else
+ offset = node->buffer_offset;
+
+ ctx->Driver.GetBufferSubData( ctx, 0, offset,
+ node->vertex_size * sizeof(GLfloat),
+ data, node->vertex_store->bufferobj );
+
+ data += node->attrsz[0]; /* skip vertex position */
+ }
+
+ for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
+ if (node->attrsz[i]) {
+ GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
+ GLfloat tmp[4];
+
+ COPY_CLEAN_4V(tmp,
+ node->attrsz[i],
+ data);
+
+ if (memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) {
+ memcpy(current, tmp, 4 * sizeof(GLfloat));
+
+ vbo->currval[i].Size = node->attrsz[i];
+ assert(vbo->currval[i].Type == GL_FLOAT);
+ vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
+
+ if (i >= VBO_ATTRIB_FIRST_MATERIAL &&
+ i <= VBO_ATTRIB_LAST_MATERIAL)
+ ctx->NewState |= _NEW_LIGHT;
+
+ ctx->NewState |= _NEW_CURRENT_ATTRIB;
+ }
+
+ data += node->attrsz[i];
+ }
+ }
+
+ /* Colormaterial -- this kindof sucks.
+ */
+ if (ctx->Light.ColorMaterialEnabled) {
+ _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
+ }
+
+ /* CurrentExecPrimitive
+ */
+ if (node->prim_count) {
+ const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
+ if (prim->end)
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+ else
+ ctx->Driver.CurrentExecPrimitive = prim->mode;
+ }
+}
+
+
+
+/**
+ * Treat the vertex storage as a VBO, define vertex arrays pointing
+ * into it:
+ */
+static void vbo_bind_vertex_list(struct gl_context *ctx,
+ const struct vbo_save_vertex_list *node)
+{
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_save_context *save = &vbo->save;
+ struct gl_client_array *arrays = save->arrays;
+ GLuint buffer_offset = node->buffer_offset;
+ const GLuint *map;
+ GLuint attr;
+ GLubyte node_attrsz[VBO_ATTRIB_MAX]; /* copy of node->attrsz[] */
+ GLbitfield varying_inputs = 0x0;
+
+ memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz));
+
+ /* Install the default (ie Current) attributes first, then overlay
+ * all active ones.
+ */
+ switch (get_program_mode(ctx)) {
+ case VP_NONE:
+ for (attr = 0; attr < 16; attr++) {
+ save->inputs[attr] = &vbo->legacy_currval[attr];
+ }
+ for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
+ save->inputs[attr + 16] = &vbo->mat_currval[attr];
+ }
+ map = vbo->map_vp_none;
+ break;
+ case VP_NV:
+ case VP_ARB:
+ /* The aliasing of attributes for NV vertex programs has already
+ * occurred. NV vertex programs cannot access material values,
+ * nor attributes greater than VERT_ATTRIB_TEX7.
+ */
+ for (attr = 0; attr < 16; attr++) {
+ save->inputs[attr] = &vbo->legacy_currval[attr];
+ save->inputs[attr + 16] = &vbo->generic_currval[attr];
+ }
+ map = vbo->map_vp_arb;
+
+ /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
+ * In that case we effectively need to route the data from
+ * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
+ */
+ if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
+ (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
+ save->inputs[16] = save->inputs[0];
+ node_attrsz[16] = node_attrsz[0];
+ node_attrsz[0] = 0;
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
+ const GLuint src = map[attr];
+
+ if (node_attrsz[src]) {
+ /* override the default array set above */
+ save->inputs[attr] = &arrays[attr];
+
+ arrays[attr].Ptr = (const GLubyte *) NULL + buffer_offset;
+ arrays[attr].Size = node->attrsz[src];
+ arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat);
+ arrays[attr].Stride = node->vertex_size * sizeof(GLfloat);
+ arrays[attr].Type = GL_FLOAT;
+ arrays[attr].Format = GL_RGBA;
+ arrays[attr].Enabled = 1;
+ arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat);
+ _mesa_reference_buffer_object(ctx,
+ &arrays[attr].BufferObj,
+ node->vertex_store->bufferobj);
+ arrays[attr]._MaxElement = node->count; /* ??? */
+
+ assert(arrays[attr].BufferObj->Name);
+
+ buffer_offset += node->attrsz[src] * sizeof(GLfloat);
+ varying_inputs |= 1<<attr;
+ ctx->NewState |= _NEW_ARRAY;
+ }
+ }
+
+ _mesa_set_varying_vp_inputs( ctx, varying_inputs );
+}
+
+
+static void
+vbo_save_loopback_vertex_list(struct gl_context *ctx,
+ const struct vbo_save_vertex_list *list)
+{
+ const char *buffer = ctx->Driver.MapBuffer(ctx,
+ GL_ARRAY_BUFFER_ARB,
+ GL_READ_ONLY, /* ? */
+ list->vertex_store->bufferobj);
+
+ vbo_loopback_vertex_list(ctx,
+ (const GLfloat *)(buffer + list->buffer_offset),
+ list->attrsz,
+ list->prim,
+ list->prim_count,
+ list->wrap_count,
+ list->vertex_size);
+
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB,
+ list->vertex_store->bufferobj);
+}
+
+
+/**
+ * Execute the buffer and save copied verts.
+ * This is called from the display list code when executing
+ * a drawing command.
+ */
+void
+vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
+{
+ const struct vbo_save_vertex_list *node =
+ (const struct vbo_save_vertex_list *) data;
+ struct vbo_save_context *save = &vbo_context(ctx)->save;
+
+ FLUSH_CURRENT(ctx, 0);
+
+ if (node->prim_count > 0 && node->count > 0) {
+
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END &&
+ node->prim[0].begin) {
+
+ /* Degenerate case: list is called inside begin/end pair and
+ * includes operations such as glBegin or glDrawArrays.
+ */
+ if (0)
+ printf("displaylist recursive begin");
+
+ vbo_save_loopback_vertex_list( ctx, node );
+ return;
+ }
+ else if (save->replay_flags) {
+ /* Various degnerate cases: translate into immediate mode
+ * calls rather than trying to execute in place.
+ */
+ vbo_save_loopback_vertex_list( ctx, node );
+ return;
+ }
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ /* XXX also need to check if shader enabled, but invalid */
+ if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
+ (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBegin (invalid vertex/fragment program)");
+ return;
+ }
+
+ vbo_bind_vertex_list( ctx, node );
+
+ /* Again...
+ */
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ vbo_context(ctx)->draw_prims(ctx,
+ save->inputs,
+ node->prim,
+ node->prim_count,
+ NULL,
+ GL_TRUE,
+ 0, /* Node is a VBO, so this is ok */
+ node->count - 1);
+ }
+
+ /* Copy to current?
+ */
+ _playback_copy_to_current( ctx, node );
+}
+
+
+#endif /* FEATURE_dlist */
diff --git a/mesalib/src/mesa/vbo/vbo_split_copy.c b/mesalib/src/mesa/vbo/vbo_split_copy.c
index 8c981f93e..3a869d712 100644
--- a/mesalib/src/mesa/vbo/vbo_split_copy.c
+++ b/mesalib/src/mesa/vbo/vbo_split_copy.c
@@ -1,626 +1,627 @@
-
-/*
- * Mesa 3-D graphics library
- * Version: 6.5
- *
- * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-/* Split indexed primitives with per-vertex copying.
- */
-
-#include "main/glheader.h"
-#include "main/bufferobj.h"
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/macros.h"
-#include "main/mtypes.h"
-
-#include "vbo_split.h"
-#include "vbo.h"
-
-
-#define ELT_TABLE_SIZE 16
-
-/**
- * Used for vertex-level splitting of indexed buffers. Note that
- * non-indexed primitives may be converted to indexed in some cases
- * (eg loops, fans) in order to use this splitting path.
- */
-struct copy_context {
-
- struct gl_context *ctx;
- const struct gl_client_array **array;
- const struct _mesa_prim *prim;
- GLuint nr_prims;
- const struct _mesa_index_buffer *ib;
- vbo_draw_func draw;
-
- const struct split_limits *limits;
-
- struct {
- GLuint attr;
- GLuint size;
- const struct gl_client_array *array;
- const GLubyte *src_ptr;
-
- struct gl_client_array dstarray;
-
- } varying[VERT_ATTRIB_MAX];
- GLuint nr_varying;
-
- const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX];
- struct _mesa_index_buffer dstib;
-
- GLuint *translated_elt_buf;
- const GLuint *srcelt;
-
- /** A baby hash table to avoid re-emitting (some) duplicate
- * vertices when splitting indexed primitives.
- */
- struct {
- GLuint in;
- GLuint out;
- } vert_cache[ELT_TABLE_SIZE];
-
- GLuint vertex_size;
- GLubyte *dstbuf;
- GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */
- GLuint dstbuf_size; /**< in vertices */
- GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value
- * in dstelt. Our MaxIndex.
- */
-
- GLuint *dstelt;
- GLuint dstelt_nr;
- GLuint dstelt_size;
-
-#define MAX_PRIM 32
- struct _mesa_prim dstprim[MAX_PRIM];
- GLuint dstprim_nr;
-
-};
-
-
-static GLuint attr_size( const struct gl_client_array *array )
-{
- return array->Size * _mesa_sizeof_type(array->Type);
-}
-
-
-/**
- * Starts returning true slightly before the buffer fills, to ensure
- * that there is sufficient room for any remaining vertices to finish
- * off the prim:
- */
-static GLboolean
-check_flush( struct copy_context *copy )
-{
- GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
-
- if (GL_TRIANGLE_STRIP == mode &&
- copy->dstelt_nr & 1) { /* see bug9962 */
- return GL_FALSE;
- }
-
- if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
- return GL_TRUE;
-
- if (copy->dstelt_nr + 4 > copy->dstelt_size)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Dump the parameters/info for a vbo->draw() call.
- */
-static void
-dump_draw_info(struct gl_context *ctx,
- const struct gl_client_array **arrays,
- const struct _mesa_prim *prims,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLuint min_index,
- GLuint max_index)
-{
- GLuint i, j;
-
- printf("VBO Draw:\n");
- for (i = 0; i < nr_prims; i++) {
- printf("Prim %u of %u\n", i, nr_prims);
- printf(" Prim mode 0x%x\n", prims[i].mode);
- printf(" IB: %p\n", (void*) ib);
- for (j = 0; j < VERT_ATTRIB_MAX; j++) {
- printf(" array %d at %p:\n", j, (void*) arrays[j]);
- printf(" enabled %d, ptr %p, size %d, type 0x%x, stride %d\n",
- arrays[j]->Enabled, arrays[j]->Ptr,
- arrays[j]->Size, arrays[j]->Type, arrays[j]->StrideB);
- if (0) {
- GLint k = prims[i].start + prims[i].count - 1;
- GLfloat *last = (GLfloat *) (arrays[j]->Ptr + arrays[j]->Stride * k);
- printf(" last: %f %f %f\n",
- last[0], last[1], last[2]);
- }
- }
- }
-}
-
-
-static void
-flush( struct copy_context *copy )
-{
- GLuint i;
-
- /* Set some counters:
- */
- copy->dstib.count = copy->dstelt_nr;
-
-#if 0
- dump_draw_info(copy->ctx,
- copy->dstarray_ptr,
- copy->dstprim,
- copy->dstprim_nr,
- &copy->dstib,
- 0,
- copy->dstbuf_nr);
-#else
- (void) dump_draw_info;
-#endif
-
- copy->draw( copy->ctx,
- copy->dstarray_ptr,
- copy->dstprim,
- copy->dstprim_nr,
- &copy->dstib,
- GL_TRUE,
- 0,
- copy->dstbuf_nr - 1 );
-
- /* Reset all pointers:
- */
- copy->dstprim_nr = 0;
- copy->dstelt_nr = 0;
- copy->dstbuf_nr = 0;
- copy->dstptr = copy->dstbuf;
-
- /* Clear the vertex cache:
- */
- for (i = 0; i < ELT_TABLE_SIZE; i++)
- copy->vert_cache[i].in = ~0;
-}
-
-
-/**
- * Called at begin of each primitive during replay.
- */
-static void
-begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
-{
- struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
-
- prim->mode = mode;
- prim->begin = begin_flag;
- prim->num_instances = 1;
-}
-
-
-/**
- * Use a hashtable to attempt to identify recently-emitted vertices
- * and avoid re-emitting them.
- */
-static GLuint
-elt(struct copy_context *copy, GLuint elt_idx)
-{
- GLuint elt = copy->srcelt[elt_idx];
- GLuint slot = elt & (ELT_TABLE_SIZE-1);
-
-/* printf("elt %d\n", elt); */
-
- /* Look up the incoming element in the vertex cache. Re-emit if
- * necessary.
- */
- if (copy->vert_cache[slot].in != elt) {
- GLubyte *csr = copy->dstptr;
- GLuint i;
-
-/* printf(" --> emit to dstelt %d\n", copy->dstbuf_nr); */
-
- for (i = 0; i < copy->nr_varying; i++) {
- const struct gl_client_array *srcarray = copy->varying[i].array;
- const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
-
- memcpy(csr, srcptr, copy->varying[i].size);
- csr += copy->varying[i].size;
-
-#ifdef NAN_CHECK
- if (srcarray->Type == GL_FLOAT) {
- GLuint k;
- GLfloat *f = (GLfloat *) srcptr;
- for (k = 0; k < srcarray->Size; k++) {
- assert(!IS_INF_OR_NAN(f[k]));
- assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
- }
- }
-#endif
-
- if (0)
- {
- const GLuint *f = (const GLuint *)srcptr;
- GLuint j;
- printf(" varying %d: ", i);
- for(j = 0; j < copy->varying[i].size / 4; j++)
- printf("%x ", f[j]);
- printf("\n");
- }
- }
-
- copy->vert_cache[slot].in = elt;
- copy->vert_cache[slot].out = copy->dstbuf_nr++;
- copy->dstptr += copy->vertex_size;
-
- assert(csr == copy->dstptr);
- assert(copy->dstptr == (copy->dstbuf +
- copy->dstbuf_nr * copy->vertex_size));
- }
-/* else */
-/* printf(" --> reuse vertex\n"); */
-
-/* printf(" --> emit %d\n", copy->vert_cache[slot].out); */
- copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
- return check_flush(copy);
-}
-
-
-/**
- * Called at end of each primitive during replay.
- */
-static void
-end( struct copy_context *copy, GLboolean end_flag )
-{
- struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
-
-/* printf("end (%d)\n", end_flag); */
-
- prim->end = end_flag;
- prim->count = copy->dstelt_nr - prim->start;
-
- if (++copy->dstprim_nr == MAX_PRIM ||
- check_flush(copy))
- flush(copy);
-}
-
-
-static void
-replay_elts( struct copy_context *copy )
-{
- GLuint i, j, k;
- GLboolean split;
-
- for (i = 0; i < copy->nr_prims; i++) {
- const struct _mesa_prim *prim = &copy->prim[i];
- const GLuint start = prim->start;
- GLuint first, incr;
-
- switch (prim->mode) {
-
- case GL_LINE_LOOP:
- /* Convert to linestrip and emit the final vertex explicitly,
- * but only in the resultant strip that requires it.
- */
- j = 0;
- while (j != prim->count) {
- begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
-
- for (split = GL_FALSE; j != prim->count && !split; j++)
- split = elt(copy, start + j);
-
- if (j == prim->count) {
- /* Done, emit final line. Split doesn't matter as
- * it is always raised a bit early so we can emit
- * the last verts if necessary!
- */
- if (prim->end)
- (void)elt(copy, start + 0);
-
- end(copy, prim->end);
- }
- else {
- /* Wrap
- */
- assert(split);
- end(copy, 0);
- j--;
- }
- }
- break;
-
- case GL_TRIANGLE_FAN:
- case GL_POLYGON:
- j = 2;
- while (j != prim->count) {
- begin(copy, prim->mode, prim->begin && j == 0);
-
- split = elt(copy, start+0);
- assert(!split);
-
- split = elt(copy, start+j-1);
- assert(!split);
-
- for (; j != prim->count && !split; j++)
- split = elt(copy, start+j);
-
- end(copy, prim->end && j == prim->count);
-
- if (j != prim->count) {
- /* Wrapped the primitive, need to repeat some vertices:
- */
- j -= 1;
- }
- }
- break;
-
- default:
- (void)split_prim_inplace(prim->mode, &first, &incr);
-
- j = 0;
- while (j != prim->count) {
-
- begin(copy, prim->mode, prim->begin && j == 0);
-
- split = 0;
- for (k = 0; k < first; k++, j++)
- split |= elt(copy, start+j);
-
- assert(!split);
-
- for (; j != prim->count && !split; )
- for (k = 0; k < incr; k++, j++)
- split |= elt(copy, start+j);
-
- end(copy, prim->end && j == prim->count);
-
- if (j != prim->count) {
- /* Wrapped the primitive, need to repeat some vertices:
- */
- assert(j > first - incr);
- j -= (first - incr);
- }
- }
- break;
- }
- }
-
- if (copy->dstprim_nr)
- flush(copy);
-}
-
-
-static void
-replay_init( struct copy_context *copy )
-{
- struct gl_context *ctx = copy->ctx;
- GLuint i;
- GLuint offset;
- const GLvoid *srcptr;
-
- /* Make a list of varying attributes and their vbo's. Also
- * calculate vertex size.
- */
- copy->vertex_size = 0;
- for (i = 0; i < VERT_ATTRIB_MAX; i++) {
- struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
-
- if (copy->array[i]->StrideB == 0) {
- copy->dstarray_ptr[i] = copy->array[i];
- }
- else {
- GLuint j = copy->nr_varying++;
-
- copy->varying[j].attr = i;
- copy->varying[j].array = copy->array[i];
- copy->varying[j].size = attr_size(copy->array[i]);
- copy->vertex_size += attr_size(copy->array[i]);
-
- if (_mesa_is_bufferobj(vbo) && !_mesa_bufferobj_mapped(vbo))
- ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY, vbo);
-
- copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer,
- copy->array[i]->Ptr);
-
- copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
- }
- }
-
- /* There must always be an index buffer. Currently require the
- * caller convert non-indexed prims to indexed. Could alternately
- * do it internally.
- */
- if (_mesa_is_bufferobj(copy->ib->obj) &&
- !_mesa_bufferobj_mapped(copy->ib->obj))
- ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY,
- copy->ib->obj);
-
- srcptr = (const GLubyte *) ADD_POINTERS(copy->ib->obj->Pointer,
- copy->ib->ptr);
-
- switch (copy->ib->type) {
- case GL_UNSIGNED_BYTE:
- copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
- copy->srcelt = copy->translated_elt_buf;
-
- for (i = 0; i < copy->ib->count; i++)
- copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
- break;
-
- case GL_UNSIGNED_SHORT:
- copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
- copy->srcelt = copy->translated_elt_buf;
-
- for (i = 0; i < copy->ib->count; i++)
- copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
- break;
-
- case GL_UNSIGNED_INT:
- copy->translated_elt_buf = NULL;
- copy->srcelt = (const GLuint *)srcptr;
- break;
- }
-
- /* Figure out the maximum allowed vertex buffer size:
- */
- if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
- copy->dstbuf_size = copy->limits->max_verts;
- }
- else {
- copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
- }
-
- /* Allocate an output vertex buffer:
- *
- * XXX: This should be a VBO!
- */
- copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);
- copy->dstptr = copy->dstbuf;
-
- /* Setup new vertex arrays to point into the output buffer:
- */
- for (offset = 0, i = 0; i < copy->nr_varying; i++) {
- const struct gl_client_array *src = copy->varying[i].array;
- struct gl_client_array *dst = &copy->varying[i].dstarray;
-
- dst->Size = src->Size;
- dst->Type = src->Type;
- dst->Format = GL_RGBA;
- dst->Stride = copy->vertex_size;
- dst->StrideB = copy->vertex_size;
- dst->Ptr = copy->dstbuf + offset;
- dst->Enabled = GL_TRUE;
- dst->Normalized = src->Normalized;
- dst->BufferObj = ctx->Shared->NullBufferObj;
- dst->_MaxElement = copy->dstbuf_size; /* may be less! */
-
- offset += copy->varying[i].size;
- }
-
- /* Allocate an output element list:
- */
- copy->dstelt_size = MIN2(65536,
- copy->ib->count * 2 + 3);
- copy->dstelt_size = MIN2(copy->dstelt_size,
- copy->limits->max_indices);
- copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
- copy->dstelt_nr = 0;
-
- /* Setup the new index buffer to point to the allocated element
- * list:
- */
- copy->dstib.count = 0; /* duplicates dstelt_nr */
- copy->dstib.type = GL_UNSIGNED_INT;
- copy->dstib.obj = ctx->Shared->NullBufferObj;
- copy->dstib.ptr = copy->dstelt;
-}
-
-
-/**
- * Free up everything allocated during split/replay.
- */
-static void
-replay_finish( struct copy_context *copy )
-{
- struct gl_context *ctx = copy->ctx;
- GLuint i;
-
- /* Free our vertex and index buffers:
- */
- free(copy->translated_elt_buf);
- free(copy->dstbuf);
- free(copy->dstelt);
-
- /* Unmap VBO's
- */
- for (i = 0; i < copy->nr_varying; i++) {
- struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
- if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo))
- ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, vbo);
- }
-
- /* Unmap index buffer:
- */
- if (_mesa_is_bufferobj(copy->ib->obj) &&
- _mesa_bufferobj_mapped(copy->ib->obj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, copy->ib->obj);
- }
-}
-
-
-/**
- * Split VBO into smaller pieces, draw the pieces.
- */
-void vbo_split_copy( struct gl_context *ctx,
- const struct gl_client_array *arrays[],
- const struct _mesa_prim *prim,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- vbo_draw_func draw,
- const struct split_limits *limits )
-{
- struct copy_context copy;
- GLuint i, this_nr_prims;
-
- for (i = 0; i < nr_prims;) {
- /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
- * will rebase the elements to the basevertex, and we'll only
- * emit strings of prims with the same basevertex in one draw call.
- */
- for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
- this_nr_prims++) {
- if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
- break;
- }
-
- memset(&copy, 0, sizeof(copy));
-
- /* Require indexed primitives:
- */
- assert(ib);
-
- copy.ctx = ctx;
- copy.array = arrays;
- copy.prim = &prim[i];
- copy.nr_prims = this_nr_prims;
- copy.ib = ib;
- copy.draw = draw;
- copy.limits = limits;
-
- /* Clear the vertex cache:
- */
- for (i = 0; i < ELT_TABLE_SIZE; i++)
- copy.vert_cache[i].in = ~0;
-
- replay_init(&copy);
- replay_elts(&copy);
- replay_finish(&copy);
- }
-}
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.5
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+/* Split indexed primitives with per-vertex copying.
+ */
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/imports.h"
+#include "main/image.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+
+#include "vbo_split.h"
+#include "vbo.h"
+
+
+#define ELT_TABLE_SIZE 16
+
+/**
+ * Used for vertex-level splitting of indexed buffers. Note that
+ * non-indexed primitives may be converted to indexed in some cases
+ * (eg loops, fans) in order to use this splitting path.
+ */
+struct copy_context {
+
+ struct gl_context *ctx;
+ const struct gl_client_array **array;
+ const struct _mesa_prim *prim;
+ GLuint nr_prims;
+ const struct _mesa_index_buffer *ib;
+ vbo_draw_func draw;
+
+ const struct split_limits *limits;
+
+ struct {
+ GLuint attr;
+ GLuint size;
+ const struct gl_client_array *array;
+ const GLubyte *src_ptr;
+
+ struct gl_client_array dstarray;
+
+ } varying[VERT_ATTRIB_MAX];
+ GLuint nr_varying;
+
+ const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX];
+ struct _mesa_index_buffer dstib;
+
+ GLuint *translated_elt_buf;
+ const GLuint *srcelt;
+
+ /** A baby hash table to avoid re-emitting (some) duplicate
+ * vertices when splitting indexed primitives.
+ */
+ struct {
+ GLuint in;
+ GLuint out;
+ } vert_cache[ELT_TABLE_SIZE];
+
+ GLuint vertex_size;
+ GLubyte *dstbuf;
+ GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */
+ GLuint dstbuf_size; /**< in vertices */
+ GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value
+ * in dstelt. Our MaxIndex.
+ */
+
+ GLuint *dstelt;
+ GLuint dstelt_nr;
+ GLuint dstelt_size;
+
+#define MAX_PRIM 32
+ struct _mesa_prim dstprim[MAX_PRIM];
+ GLuint dstprim_nr;
+
+};
+
+
+static GLuint attr_size( const struct gl_client_array *array )
+{
+ return array->Size * _mesa_sizeof_type(array->Type);
+}
+
+
+/**
+ * Starts returning true slightly before the buffer fills, to ensure
+ * that there is sufficient room for any remaining vertices to finish
+ * off the prim:
+ */
+static GLboolean
+check_flush( struct copy_context *copy )
+{
+ GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
+
+ if (GL_TRIANGLE_STRIP == mode &&
+ copy->dstelt_nr & 1) { /* see bug9962 */
+ return GL_FALSE;
+ }
+
+ if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
+ return GL_TRUE;
+
+ if (copy->dstelt_nr + 4 > copy->dstelt_size)
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+
+/**
+ * Dump the parameters/info for a vbo->draw() call.
+ */
+static void
+dump_draw_info(struct gl_context *ctx,
+ const struct gl_client_array **arrays,
+ const struct _mesa_prim *prims,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index)
+{
+ GLuint i, j;
+
+ printf("VBO Draw:\n");
+ for (i = 0; i < nr_prims; i++) {
+ printf("Prim %u of %u\n", i, nr_prims);
+ printf(" Prim mode 0x%x\n", prims[i].mode);
+ printf(" IB: %p\n", (void*) ib);
+ for (j = 0; j < VERT_ATTRIB_MAX; j++) {
+ printf(" array %d at %p:\n", j, (void*) arrays[j]);
+ printf(" enabled %d, ptr %p, size %d, type 0x%x, stride %d\n",
+ arrays[j]->Enabled, arrays[j]->Ptr,
+ arrays[j]->Size, arrays[j]->Type, arrays[j]->StrideB);
+ if (0) {
+ GLint k = prims[i].start + prims[i].count - 1;
+ GLfloat *last = (GLfloat *) (arrays[j]->Ptr + arrays[j]->Stride * k);
+ printf(" last: %f %f %f\n",
+ last[0], last[1], last[2]);
+ }
+ }
+ }
+}
+
+
+static void
+flush( struct copy_context *copy )
+{
+ GLuint i;
+
+ /* Set some counters:
+ */
+ copy->dstib.count = copy->dstelt_nr;
+
+#if 0
+ dump_draw_info(copy->ctx,
+ copy->dstarray_ptr,
+ copy->dstprim,
+ copy->dstprim_nr,
+ &copy->dstib,
+ 0,
+ copy->dstbuf_nr);
+#else
+ (void) dump_draw_info;
+#endif
+
+ copy->draw( copy->ctx,
+ copy->dstarray_ptr,
+ copy->dstprim,
+ copy->dstprim_nr,
+ &copy->dstib,
+ GL_TRUE,
+ 0,
+ copy->dstbuf_nr - 1 );
+
+ /* Reset all pointers:
+ */
+ copy->dstprim_nr = 0;
+ copy->dstelt_nr = 0;
+ copy->dstbuf_nr = 0;
+ copy->dstptr = copy->dstbuf;
+
+ /* Clear the vertex cache:
+ */
+ for (i = 0; i < ELT_TABLE_SIZE; i++)
+ copy->vert_cache[i].in = ~0;
+}
+
+
+/**
+ * Called at begin of each primitive during replay.
+ */
+static void
+begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
+{
+ struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
+
+ prim->mode = mode;
+ prim->begin = begin_flag;
+ prim->num_instances = 1;
+}
+
+
+/**
+ * Use a hashtable to attempt to identify recently-emitted vertices
+ * and avoid re-emitting them.
+ */
+static GLuint
+elt(struct copy_context *copy, GLuint elt_idx)
+{
+ GLuint elt = copy->srcelt[elt_idx];
+ GLuint slot = elt & (ELT_TABLE_SIZE-1);
+
+/* printf("elt %d\n", elt); */
+
+ /* Look up the incoming element in the vertex cache. Re-emit if
+ * necessary.
+ */
+ if (copy->vert_cache[slot].in != elt) {
+ GLubyte *csr = copy->dstptr;
+ GLuint i;
+
+/* printf(" --> emit to dstelt %d\n", copy->dstbuf_nr); */
+
+ for (i = 0; i < copy->nr_varying; i++) {
+ const struct gl_client_array *srcarray = copy->varying[i].array;
+ const GLubyte *srcptr = copy->varying[i].src_ptr + elt * srcarray->StrideB;
+
+ memcpy(csr, srcptr, copy->varying[i].size);
+ csr += copy->varying[i].size;
+
+#ifdef NAN_CHECK
+ if (srcarray->Type == GL_FLOAT) {
+ GLuint k;
+ GLfloat *f = (GLfloat *) srcptr;
+ for (k = 0; k < srcarray->Size; k++) {
+ assert(!IS_INF_OR_NAN(f[k]));
+ assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
+ }
+ }
+#endif
+
+ if (0)
+ {
+ const GLuint *f = (const GLuint *)srcptr;
+ GLuint j;
+ printf(" varying %d: ", i);
+ for(j = 0; j < copy->varying[i].size / 4; j++)
+ printf("%x ", f[j]);
+ printf("\n");
+ }
+ }
+
+ copy->vert_cache[slot].in = elt;
+ copy->vert_cache[slot].out = copy->dstbuf_nr++;
+ copy->dstptr += copy->vertex_size;
+
+ assert(csr == copy->dstptr);
+ assert(copy->dstptr == (copy->dstbuf +
+ copy->dstbuf_nr * copy->vertex_size));
+ }
+/* else */
+/* printf(" --> reuse vertex\n"); */
+
+/* printf(" --> emit %d\n", copy->vert_cache[slot].out); */
+ copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
+ return check_flush(copy);
+}
+
+
+/**
+ * Called at end of each primitive during replay.
+ */
+static void
+end( struct copy_context *copy, GLboolean end_flag )
+{
+ struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
+
+/* printf("end (%d)\n", end_flag); */
+
+ prim->end = end_flag;
+ prim->count = copy->dstelt_nr - prim->start;
+
+ if (++copy->dstprim_nr == MAX_PRIM ||
+ check_flush(copy))
+ flush(copy);
+}
+
+
+static void
+replay_elts( struct copy_context *copy )
+{
+ GLuint i, j, k;
+ GLboolean split;
+
+ for (i = 0; i < copy->nr_prims; i++) {
+ const struct _mesa_prim *prim = &copy->prim[i];
+ const GLuint start = prim->start;
+ GLuint first, incr;
+
+ switch (prim->mode) {
+
+ case GL_LINE_LOOP:
+ /* Convert to linestrip and emit the final vertex explicitly,
+ * but only in the resultant strip that requires it.
+ */
+ j = 0;
+ while (j != prim->count) {
+ begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
+
+ for (split = GL_FALSE; j != prim->count && !split; j++)
+ split = elt(copy, start + j);
+
+ if (j == prim->count) {
+ /* Done, emit final line. Split doesn't matter as
+ * it is always raised a bit early so we can emit
+ * the last verts if necessary!
+ */
+ if (prim->end)
+ (void)elt(copy, start + 0);
+
+ end(copy, prim->end);
+ }
+ else {
+ /* Wrap
+ */
+ assert(split);
+ end(copy, 0);
+ j--;
+ }
+ }
+ break;
+
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ j = 2;
+ while (j != prim->count) {
+ begin(copy, prim->mode, prim->begin && j == 0);
+
+ split = elt(copy, start+0);
+ assert(!split);
+
+ split = elt(copy, start+j-1);
+ assert(!split);
+
+ for (; j != prim->count && !split; j++)
+ split = elt(copy, start+j);
+
+ end(copy, prim->end && j == prim->count);
+
+ if (j != prim->count) {
+ /* Wrapped the primitive, need to repeat some vertices:
+ */
+ j -= 1;
+ }
+ }
+ break;
+
+ default:
+ (void)split_prim_inplace(prim->mode, &first, &incr);
+
+ j = 0;
+ while (j != prim->count) {
+
+ begin(copy, prim->mode, prim->begin && j == 0);
+
+ split = 0;
+ for (k = 0; k < first; k++, j++)
+ split |= elt(copy, start+j);
+
+ assert(!split);
+
+ for (; j != prim->count && !split; )
+ for (k = 0; k < incr; k++, j++)
+ split |= elt(copy, start+j);
+
+ end(copy, prim->end && j == prim->count);
+
+ if (j != prim->count) {
+ /* Wrapped the primitive, need to repeat some vertices:
+ */
+ assert(j > first - incr);
+ j -= (first - incr);
+ }
+ }
+ break;
+ }
+ }
+
+ if (copy->dstprim_nr)
+ flush(copy);
+}
+
+
+static void
+replay_init( struct copy_context *copy )
+{
+ struct gl_context *ctx = copy->ctx;
+ GLuint i;
+ GLuint offset;
+ const GLvoid *srcptr;
+
+ /* Make a list of varying attributes and their vbo's. Also
+ * calculate vertex size.
+ */
+ copy->vertex_size = 0;
+ for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+ struct gl_buffer_object *vbo = copy->array[i]->BufferObj;
+
+ if (copy->array[i]->StrideB == 0) {
+ copy->dstarray_ptr[i] = copy->array[i];
+ }
+ else {
+ GLuint j = copy->nr_varying++;
+
+ copy->varying[j].attr = i;
+ copy->varying[j].array = copy->array[i];
+ copy->varying[j].size = attr_size(copy->array[i]);
+ copy->vertex_size += attr_size(copy->array[i]);
+
+ if (_mesa_is_bufferobj(vbo) && !_mesa_bufferobj_mapped(vbo))
+ ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY, vbo);
+
+ copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer,
+ copy->array[i]->Ptr);
+
+ copy->dstarray_ptr[i] = &copy->varying[j].dstarray;
+ }
+ }
+
+ /* There must always be an index buffer. Currently require the
+ * caller convert non-indexed prims to indexed. Could alternately
+ * do it internally.
+ */
+ if (_mesa_is_bufferobj(copy->ib->obj) &&
+ !_mesa_bufferobj_mapped(copy->ib->obj))
+ ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY,
+ copy->ib->obj);
+
+ srcptr = (const GLubyte *) ADD_POINTERS(copy->ib->obj->Pointer,
+ copy->ib->ptr);
+
+ switch (copy->ib->type) {
+ case GL_UNSIGNED_BYTE:
+ copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
+ copy->srcelt = copy->translated_elt_buf;
+
+ for (i = 0; i < copy->ib->count; i++)
+ copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
+ break;
+
+ case GL_UNSIGNED_SHORT:
+ copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
+ copy->srcelt = copy->translated_elt_buf;
+
+ for (i = 0; i < copy->ib->count; i++)
+ copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
+ break;
+
+ case GL_UNSIGNED_INT:
+ copy->translated_elt_buf = NULL;
+ copy->srcelt = (const GLuint *)srcptr;
+ break;
+ }
+
+ /* Figure out the maximum allowed vertex buffer size:
+ */
+ if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
+ copy->dstbuf_size = copy->limits->max_verts;
+ }
+ else {
+ copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
+ }
+
+ /* Allocate an output vertex buffer:
+ *
+ * XXX: This should be a VBO!
+ */
+ copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);
+ copy->dstptr = copy->dstbuf;
+
+ /* Setup new vertex arrays to point into the output buffer:
+ */
+ for (offset = 0, i = 0; i < copy->nr_varying; i++) {
+ const struct gl_client_array *src = copy->varying[i].array;
+ struct gl_client_array *dst = &copy->varying[i].dstarray;
+
+ dst->Size = src->Size;
+ dst->Type = src->Type;
+ dst->Format = GL_RGBA;
+ dst->Stride = copy->vertex_size;
+ dst->StrideB = copy->vertex_size;
+ dst->Ptr = copy->dstbuf + offset;
+ dst->Enabled = GL_TRUE;
+ dst->Normalized = src->Normalized;
+ dst->BufferObj = ctx->Shared->NullBufferObj;
+ dst->_ElementSize = src->_ElementSize;
+ dst->_MaxElement = copy->dstbuf_size; /* may be less! */
+
+ offset += copy->varying[i].size;
+ }
+
+ /* Allocate an output element list:
+ */
+ copy->dstelt_size = MIN2(65536,
+ copy->ib->count * 2 + 3);
+ copy->dstelt_size = MIN2(copy->dstelt_size,
+ copy->limits->max_indices);
+ copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
+ copy->dstelt_nr = 0;
+
+ /* Setup the new index buffer to point to the allocated element
+ * list:
+ */
+ copy->dstib.count = 0; /* duplicates dstelt_nr */
+ copy->dstib.type = GL_UNSIGNED_INT;
+ copy->dstib.obj = ctx->Shared->NullBufferObj;
+ copy->dstib.ptr = copy->dstelt;
+}
+
+
+/**
+ * Free up everything allocated during split/replay.
+ */
+static void
+replay_finish( struct copy_context *copy )
+{
+ struct gl_context *ctx = copy->ctx;
+ GLuint i;
+
+ /* Free our vertex and index buffers:
+ */
+ free(copy->translated_elt_buf);
+ free(copy->dstbuf);
+ free(copy->dstelt);
+
+ /* Unmap VBO's
+ */
+ for (i = 0; i < copy->nr_varying; i++) {
+ struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj;
+ if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo))
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, vbo);
+ }
+
+ /* Unmap index buffer:
+ */
+ if (_mesa_is_bufferobj(copy->ib->obj) &&
+ _mesa_bufferobj_mapped(copy->ib->obj)) {
+ ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, copy->ib->obj);
+ }
+}
+
+
+/**
+ * Split VBO into smaller pieces, draw the pieces.
+ */
+void vbo_split_copy( struct gl_context *ctx,
+ const struct gl_client_array *arrays[],
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ vbo_draw_func draw,
+ const struct split_limits *limits )
+{
+ struct copy_context copy;
+ GLuint i, this_nr_prims;
+
+ for (i = 0; i < nr_prims;) {
+ /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
+ * will rebase the elements to the basevertex, and we'll only
+ * emit strings of prims with the same basevertex in one draw call.
+ */
+ for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
+ this_nr_prims++) {
+ if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
+ break;
+ }
+
+ memset(&copy, 0, sizeof(copy));
+
+ /* Require indexed primitives:
+ */
+ assert(ib);
+
+ copy.ctx = ctx;
+ copy.array = arrays;
+ copy.prim = &prim[i];
+ copy.nr_prims = this_nr_prims;
+ copy.ib = ib;
+ copy.draw = draw;
+ copy.limits = limits;
+
+ /* Clear the vertex cache:
+ */
+ for (i = 0; i < ELT_TABLE_SIZE; i++)
+ copy.vert_cache[i].in = ~0;
+
+ replay_init(&copy);
+ replay_elts(&copy);
+ replay_finish(&copy);
+ }
+}