Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 4357 → Rev 4358

/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo.h
0,0 → 1,226
/*
* mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
/**
* \file vbo_context.h
* \brief VBO builder module datatypes and definitions.
* \author Keith Whitwell
*/
 
 
#ifndef _VBO_H
#define _VBO_H
 
#include <stdbool.h>
#include "main/glheader.h"
 
struct gl_client_array;
struct gl_context;
struct gl_transform_feedback_object;
 
struct _mesa_prim {
GLuint mode:8; /**< GL_POINTS, GL_LINES, GL_QUAD_STRIP, etc */
GLuint indexed:1;
GLuint begin:1;
GLuint end:1;
GLuint weak:1;
GLuint no_current_update:1;
GLuint pad:19;
 
GLuint start;
GLuint count;
GLint basevertex;
GLuint num_instances;
GLuint base_instance;
};
 
/* Would like to call this a "vbo_index_buffer", but this would be
* confusing as the indices are not neccessarily yet in a non-null
* buffer object.
*/
struct _mesa_index_buffer {
GLuint count;
GLenum type;
struct gl_buffer_object *obj;
const void *ptr;
};
 
 
 
GLboolean _vbo_CreateContext( struct gl_context *ctx );
void _vbo_DestroyContext( struct gl_context *ctx );
void _vbo_InvalidateState( struct gl_context *ctx, GLuint new_state );
 
 
void
vbo_initialize_exec_dispatch(const struct gl_context *ctx,
struct _glapi_table *exec);
 
void
vbo_initialize_save_dispatch(const struct gl_context *ctx,
struct _glapi_table *exec);
 
 
typedef void (*vbo_draw_func)( struct gl_context *ctx,
const struct _mesa_prim *prims,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLboolean index_bounds_valid,
GLuint min_index,
GLuint max_index,
struct gl_transform_feedback_object *tfb_vertcount );
 
 
 
 
/* Utility function to cope with various constraints on tnl modules or
* hardware. This can be used to split an incoming set of arrays and
* primitives against the following constraints:
* - Maximum number of indices in index buffer.
* - Maximum number of vertices referenced by index buffer.
* - Maximum hardware vertex buffer size.
*/
struct split_limits {
GLuint max_verts;
GLuint max_indices;
GLuint max_vb_size; /* bytes */
};
 
 
void vbo_split_prims( struct gl_context *ctx,
const struct gl_client_array *arrays[],
const struct _mesa_prim *prim,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index,
vbo_draw_func draw,
const struct split_limits *limits );
 
 
/* Helpers for dealing translating away non-zero min_index.
*/
GLboolean vbo_all_varyings_in_vbos( const struct gl_client_array *arrays[] );
GLboolean vbo_any_varyings_in_vbos( const struct gl_client_array *arrays[] );
 
void vbo_rebase_prims( struct gl_context *ctx,
const struct gl_client_array *arrays[],
const struct _mesa_prim *prim,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index,
vbo_draw_func draw );
 
static inline int
vbo_sizeof_ib_type(GLenum type)
{
switch (type) {
case GL_UNSIGNED_INT:
return sizeof(GLuint);
case GL_UNSIGNED_SHORT:
return sizeof(GLushort);
case GL_UNSIGNED_BYTE:
return sizeof(GLubyte);
default:
assert(!"unsupported index data type");
/* In case assert is turned off */
return 0;
}
}
 
void
vbo_get_minmax_indices(struct gl_context *ctx, const struct _mesa_prim *prim,
const struct _mesa_index_buffer *ib,
GLuint *min_index, GLuint *max_index, GLuint nr_prims);
 
void vbo_use_buffer_objects(struct gl_context *ctx);
 
void vbo_always_unmap_buffers(struct gl_context *ctx);
 
void vbo_set_draw_func(struct gl_context *ctx, vbo_draw_func func);
 
void vbo_check_buffers_are_unmapped(struct gl_context *ctx);
 
void vbo_bind_arrays(struct gl_context *ctx);
 
size_t
vbo_count_tessellated_primitives(GLenum mode, GLuint count,
GLuint num_instances);
 
void
vbo_try_prim_conversion(struct _mesa_prim *p);
 
bool
vbo_can_merge_prims(const struct _mesa_prim *p0, const struct _mesa_prim *p1);
 
void
vbo_merge_prims(struct _mesa_prim *p0, const struct _mesa_prim *p1);
 
void
vbo_sw_primitive_restart(struct gl_context *ctx,
const struct _mesa_prim *prim,
GLuint nr_prims,
const struct _mesa_index_buffer *ib);
 
void GLAPIENTRY
_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
 
void GLAPIENTRY
_es_Normal3f(GLfloat x, GLfloat y, GLfloat z);
 
void GLAPIENTRY
_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
 
void GLAPIENTRY
_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
 
void GLAPIENTRY
_es_Materialf(GLenum face, GLenum pname, GLfloat param);
 
void GLAPIENTRY
_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
 
void GLAPIENTRY
_es_VertexAttrib1f(GLuint indx, GLfloat x);
 
void GLAPIENTRY
_es_VertexAttrib1fv(GLuint indx, const GLfloat* values);
 
void GLAPIENTRY
_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y);
 
void GLAPIENTRY
_es_VertexAttrib2fv(GLuint indx, const GLfloat* values);
 
void GLAPIENTRY
_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z);
 
void GLAPIENTRY
_es_VertexAttrib3fv(GLuint indx, const GLfloat* values);
 
void GLAPIENTRY
_es_VertexAttrib4fv(GLuint indx, const GLfloat* values);
 
#endif
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_attrib.h
0,0 → 1,108
/*
Copyright (C) Intel Corp. 2006. All Rights Reserved.
Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
develop this 3D driver.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice (including the
next paragraph) shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**********************************************************************/
/*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
 
#ifndef VBO_ATTRIB_H
#define VBO_ATTRIB_H
 
 
/*
* Note: The first attributes match the VERT_ATTRIB_* definitions
* in mtypes.h. However, the tnl module has additional attributes
* for materials, color indexes, edge flags, etc.
*/
/* Although it's nice to use these as bit indexes in a DWORD flag, we
* could manage without if necessary. Another limit currently is the
* number of bits allocated for these numbers in places like vertex
* program instruction formats and register layouts.
*/
enum {
VBO_ATTRIB_POS = 0,
VBO_ATTRIB_WEIGHT = 1,
VBO_ATTRIB_NORMAL = 2,
VBO_ATTRIB_COLOR0 = 3,
VBO_ATTRIB_COLOR1 = 4,
VBO_ATTRIB_FOG = 5,
VBO_ATTRIB_INDEX = 6,
VBO_ATTRIB_EDGEFLAG = 7,
VBO_ATTRIB_TEX0 = 8,
VBO_ATTRIB_TEX1 = 9,
VBO_ATTRIB_TEX2 = 10,
VBO_ATTRIB_TEX3 = 11,
VBO_ATTRIB_TEX4 = 12,
VBO_ATTRIB_TEX5 = 13,
VBO_ATTRIB_TEX6 = 14,
VBO_ATTRIB_TEX7 = 15,
VBO_ATTRIB_POINT_SIZE = 16,
 
VBO_ATTRIB_GENERIC0 = 17, /* Not used? */
VBO_ATTRIB_GENERIC1 = 18,
VBO_ATTRIB_GENERIC2 = 19,
VBO_ATTRIB_GENERIC3 = 20,
VBO_ATTRIB_GENERIC4 = 21,
VBO_ATTRIB_GENERIC5 = 22,
VBO_ATTRIB_GENERIC6 = 23,
VBO_ATTRIB_GENERIC7 = 24,
VBO_ATTRIB_GENERIC8 = 25,
VBO_ATTRIB_GENERIC9 = 26,
VBO_ATTRIB_GENERIC10 = 27,
VBO_ATTRIB_GENERIC11 = 28,
VBO_ATTRIB_GENERIC12 = 29,
VBO_ATTRIB_GENERIC13 = 30,
VBO_ATTRIB_GENERIC14 = 31,
VBO_ATTRIB_GENERIC15 = 32,
 
/* XXX: in the vertex program InputsRead flag, we alias
* materials and generics and use knowledge about the program
* (whether it is a fixed-function emulation) to
* differentiate. Here we must keep them apart instead.
*/
VBO_ATTRIB_MAT_FRONT_AMBIENT = 33,
VBO_ATTRIB_MAT_BACK_AMBIENT = 34,
VBO_ATTRIB_MAT_FRONT_DIFFUSE = 35,
VBO_ATTRIB_MAT_BACK_DIFFUSE = 36,
VBO_ATTRIB_MAT_FRONT_SPECULAR = 37,
VBO_ATTRIB_MAT_BACK_SPECULAR = 38,
VBO_ATTRIB_MAT_FRONT_EMISSION = 39,
VBO_ATTRIB_MAT_BACK_EMISSION = 40,
VBO_ATTRIB_MAT_FRONT_SHININESS = 41,
VBO_ATTRIB_MAT_BACK_SHININESS = 42,
VBO_ATTRIB_MAT_FRONT_INDEXES = 43,
VBO_ATTRIB_MAT_BACK_INDEXES = 44,
 
VBO_ATTRIB_MAX = 45
};
 
#define VBO_ATTRIB_FIRST_MATERIAL VBO_ATTRIB_MAT_FRONT_AMBIENT
#define VBO_ATTRIB_LAST_MATERIAL VBO_ATTRIB_MAT_BACK_INDEXES
 
#define VBO_MAX_COPIED_VERTS 3
 
#endif
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_attrib_tmp.h
0,0 → 1,1177
/**************************************************************************
 
Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
Copyright 2011 Dave Airlie (ARB_vertex_type_2_10_10_10_rev support)
All Rights Reserved.
 
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
on the rights to use, copy, modify, merge, publish, distribute, sub
license, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
 
**************************************************************************/
 
/* float */
#define ATTR1FV( A, V ) ATTR( A, 1, GL_FLOAT, (V)[0], 0, 0, 1 )
#define ATTR2FV( A, V ) ATTR( A, 2, GL_FLOAT, (V)[0], (V)[1], 0, 1 )
#define ATTR3FV( A, V ) ATTR( A, 3, GL_FLOAT, (V)[0], (V)[1], (V)[2], 1 )
#define ATTR4FV( A, V ) ATTR( A, 4, GL_FLOAT, (V)[0], (V)[1], (V)[2], (V)[3] )
 
#define ATTR1F( A, X ) ATTR( A, 1, GL_FLOAT, X, 0, 0, 1 )
#define ATTR2F( A, X, Y ) ATTR( A, 2, GL_FLOAT, X, Y, 0, 1 )
#define ATTR3F( A, X, Y, Z ) ATTR( A, 3, GL_FLOAT, X, Y, Z, 1 )
#define ATTR4F( A, X, Y, Z, W ) ATTR( A, 4, GL_FLOAT, X, Y, Z, W )
 
/* int */
#define ATTRI( A, N, X, Y, Z, W) ATTR( A, N, GL_INT, \
INT_AS_FLT(X), INT_AS_FLT(Y), \
INT_AS_FLT(Z), INT_AS_FLT(W) )
 
#define ATTR2IV( A, V ) ATTRI( A, 2, (V)[0], (V)[1], 0, 1 )
#define ATTR3IV( A, V ) ATTRI( A, 3, (V)[0], (V)[1], (V)[2], 1 )
#define ATTR4IV( A, V ) ATTRI( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] )
 
#define ATTR1I( A, X ) ATTRI( A, 1, X, 0, 0, 1 )
#define ATTR2I( A, X, Y ) ATTRI( A, 2, X, Y, 0, 1 )
#define ATTR3I( A, X, Y, Z ) ATTRI( A, 3, X, Y, Z, 1 )
#define ATTR4I( A, X, Y, Z, W ) ATTRI( A, 4, X, Y, Z, W )
 
 
/* uint */
#define ATTRUI( A, N, X, Y, Z, W) ATTR( A, N, GL_UNSIGNED_INT, \
UINT_AS_FLT(X), UINT_AS_FLT(Y), \
UINT_AS_FLT(Z), UINT_AS_FLT(W) )
 
#define ATTR2UIV( A, V ) ATTRUI( A, 2, (V)[0], (V)[1], 0, 1 )
#define ATTR3UIV( A, V ) ATTRUI( A, 3, (V)[0], (V)[1], (V)[2], 1 )
#define ATTR4UIV( A, V ) ATTRUI( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] )
 
#define ATTR1UI( A, X ) ATTRUI( A, 1, X, 0, 0, 1 )
#define ATTR2UI( A, X, Y ) ATTRUI( A, 2, X, Y, 0, 1 )
#define ATTR3UI( A, X, Y, Z ) ATTRUI( A, 3, X, Y, Z, 1 )
#define ATTR4UI( A, X, Y, Z, W ) ATTRUI( A, 4, X, Y, Z, W )
 
#define MAT_ATTR( A, N, V ) ATTR( A, N, GL_FLOAT, (V)[0], (V)[1], (V)[2], (V)[3] )
 
static inline float conv_ui10_to_norm_float(unsigned ui10)
{
return ui10 / 1023.0f;
}
 
static inline float conv_ui2_to_norm_float(unsigned ui2)
{
return ui2 / 3.0f;
}
 
#define ATTRUI10_1( A, UI ) ATTR( A, 1, GL_FLOAT, (UI) & 0x3ff, 0, 0, 1 )
#define ATTRUI10_2( A, UI ) ATTR( A, 2, GL_FLOAT, (UI) & 0x3ff, ((UI) >> 10) & 0x3ff, 0, 1 )
#define ATTRUI10_3( A, UI ) ATTR( A, 3, GL_FLOAT, (UI) & 0x3ff, ((UI) >> 10) & 0x3ff, ((UI) >> 20) & 0x3ff, 1 )
#define ATTRUI10_4( A, UI ) ATTR( A, 4, GL_FLOAT, (UI) & 0x3ff, ((UI) >> 10) & 0x3ff, ((UI) >> 20) & 0x3ff, ((UI) >> 30) & 0x3 )
 
#define ATTRUI10N_1( A, UI ) ATTR( A, 1, GL_FLOAT, conv_ui10_to_norm_float((UI) & 0x3ff), 0, 0, 1 )
#define ATTRUI10N_2( A, UI ) ATTR( A, 2, GL_FLOAT, \
conv_ui10_to_norm_float((UI) & 0x3ff), \
conv_ui10_to_norm_float(((UI) >> 10) & 0x3ff), 0, 1 )
#define ATTRUI10N_3( A, UI ) ATTR( A, 3, GL_FLOAT, \
conv_ui10_to_norm_float((UI) & 0x3ff), \
conv_ui10_to_norm_float(((UI) >> 10) & 0x3ff), \
conv_ui10_to_norm_float(((UI) >> 20) & 0x3ff), 1 )
#define ATTRUI10N_4( A, UI ) ATTR( A, 4, GL_FLOAT, \
conv_ui10_to_norm_float((UI) & 0x3ff), \
conv_ui10_to_norm_float(((UI) >> 10) & 0x3ff), \
conv_ui10_to_norm_float(((UI) >> 20) & 0x3ff), \
conv_ui2_to_norm_float(((UI) >> 30) & 0x3) )
 
struct attr_bits_10 {signed int x:10;};
struct attr_bits_2 {signed int x:2;};
 
static inline float conv_i10_to_i(int i10)
{
struct attr_bits_10 val;
val.x = i10;
return (float)val.x;
}
 
static inline float conv_i2_to_i(int i2)
{
struct attr_bits_2 val;
val.x = i2;
return (float)val.x;
}
 
static inline float conv_i10_to_norm_float(const struct gl_context *ctx, int i10)
{
struct attr_bits_10 val;
val.x = i10;
 
/* Traditionally, OpenGL has had two equations for converting from
* normalized fixed-point data to floating-point data. In the OpenGL 3.2
* specification, these are equations 2.2 and 2.3, respectively:
*
* f = (2c + 1)/(2^b - 1). (2.2)
*
* Comments below this equation state: "In general, this representation is
* used for signed normalized fixed-point parameters in GL commands, such
* as vertex attribute values." Which is what we're doing here.
*
* f = max{c/(2^(b-1) - 1), -1.0} (2.3)
*
* Comments below this equation state: "In general, this representation is
* used for signed normalized fixed-point texture or floating point values."
*
* OpenGL 4.2+ and ES 3.0 remedy this and state that equation 2.3 (above)
* is used in every case. They remove equation 2.2 completely.
*/
if (_mesa_is_gles3(ctx) ||
(ctx->API == API_OPENGL_CORE && ctx->Version >= 42)) {
/* Equation 2.3 above. */
float f = ((float) val.x) / 511.0F;
return MAX2(f, -1.0);
} else {
/* Equation 2.2 above. */
return (2.0F * (float)val.x + 1.0F) * (1.0F / 1023.0F);
}
}
 
static inline float conv_i2_to_norm_float(const struct gl_context *ctx, int i2)
{
struct attr_bits_2 val;
val.x = i2;
 
if (_mesa_is_gles3(ctx) ||
(ctx->API == API_OPENGL_CORE && ctx->Version >= 42)) {
/* Equation 2.3 above. */
float f = (float) val.x;
return MAX2(f, -1.0);
} else {
/* Equation 2.2 above. */
return (2.0F * (float)val.x + 1.0F) * (1.0F / 3.0F);
}
}
 
#define ATTRI10_1( A, I10 ) ATTR( A, 1, GL_FLOAT, conv_i10_to_i((I10) & 0x3ff), 0, 0, 1 )
#define ATTRI10_2( A, I10 ) ATTR( A, 2, GL_FLOAT, \
conv_i10_to_i((I10) & 0x3ff), \
conv_i10_to_i(((I10) >> 10) & 0x3ff), 0, 1 )
#define ATTRI10_3( A, I10 ) ATTR( A, 3, GL_FLOAT, \
conv_i10_to_i((I10) & 0x3ff), \
conv_i10_to_i(((I10) >> 10) & 0x3ff), \
conv_i10_to_i(((I10) >> 20) & 0x3ff), 1 )
#define ATTRI10_4( A, I10 ) ATTR( A, 4, GL_FLOAT, \
conv_i10_to_i((I10) & 0x3ff), \
conv_i10_to_i(((I10) >> 10) & 0x3ff), \
conv_i10_to_i(((I10) >> 20) & 0x3ff), \
conv_i2_to_i(((I10) >> 30) & 0x3))
 
 
#define ATTRI10N_1(ctx, A, I10) ATTR(A, 1, GL_FLOAT, conv_i10_to_norm_float(ctx, (I10) & 0x3ff), 0, 0, 1 )
#define ATTRI10N_2(ctx, A, I10) ATTR(A, 2, GL_FLOAT, \
conv_i10_to_norm_float(ctx, (I10) & 0x3ff), \
conv_i10_to_norm_float(ctx, ((I10) >> 10) & 0x3ff), 0, 1 )
#define ATTRI10N_3(ctx, A, I10) ATTR(A, 3, GL_FLOAT, \
conv_i10_to_norm_float(ctx, (I10) & 0x3ff), \
conv_i10_to_norm_float(ctx, ((I10) >> 10) & 0x3ff), \
conv_i10_to_norm_float(ctx, ((I10) >> 20) & 0x3ff), 1 )
#define ATTRI10N_4(ctx, A, I10) ATTR(A, 4, GL_FLOAT, \
conv_i10_to_norm_float(ctx, (I10) & 0x3ff), \
conv_i10_to_norm_float(ctx, ((I10) >> 10) & 0x3ff), \
conv_i10_to_norm_float(ctx, ((I10) >> 20) & 0x3ff), \
conv_i2_to_norm_float(ctx, ((I10) >> 30) & 0x3))
 
#define ATTR_UI(ctx, val, type, normalized, attr, arg) do { \
if ((type) == GL_UNSIGNED_INT_2_10_10_10_REV) { \
if (normalized) { \
ATTRUI10N_##val((attr), (arg)); \
} else { \
ATTRUI10_##val((attr), (arg)); \
} \
} else if ((type) == GL_INT_2_10_10_10_REV) { \
if (normalized) { \
ATTRI10N_##val(ctx, (attr), (arg)); \
} else { \
ATTRI10_##val((attr), (arg)); \
} \
} else \
ERROR(GL_INVALID_VALUE); \
} while(0)
 
#define ATTR_UI_INDEX(ctx, val, type, normalized, index, arg) do { \
if ((index) == 0) { \
ATTR_UI(ctx, val, (type), normalized, 0, (arg)); \
} else if ((index) < MAX_VERTEX_GENERIC_ATTRIBS) { \
ATTR_UI(ctx, val, (type), normalized, VBO_ATTRIB_GENERIC0 + (index), (arg)); \
} else \
ERROR(GL_INVALID_VALUE); \
} while(0)
 
static void GLAPIENTRY
TAG(Vertex2f)(GLfloat x, GLfloat y)
{
GET_CURRENT_CONTEXT(ctx);
ATTR2F(VBO_ATTRIB_POS, x, y);
}
 
static void GLAPIENTRY
TAG(Vertex2fv)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR2FV(VBO_ATTRIB_POS, v);
}
 
static void GLAPIENTRY
TAG(Vertex3f)(GLfloat x, GLfloat y, GLfloat z)
{
GET_CURRENT_CONTEXT(ctx);
ATTR3F(VBO_ATTRIB_POS, x, y, z);
}
 
static void GLAPIENTRY
TAG(Vertex3fv)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR3FV(VBO_ATTRIB_POS, v);
}
 
static void GLAPIENTRY
TAG(Vertex4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GET_CURRENT_CONTEXT(ctx);
ATTR4F(VBO_ATTRIB_POS, x, y, z, w);
}
 
static void GLAPIENTRY
TAG(Vertex4fv)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR4FV(VBO_ATTRIB_POS, v);
}
 
 
 
static void GLAPIENTRY
TAG(TexCoord1f)(GLfloat x)
{
GET_CURRENT_CONTEXT(ctx);
ATTR1F(VBO_ATTRIB_TEX0, x);
}
 
static void GLAPIENTRY
TAG(TexCoord1fv)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR1FV(VBO_ATTRIB_TEX0, v);
}
 
static void GLAPIENTRY
TAG(TexCoord2f)(GLfloat x, GLfloat y)
{
GET_CURRENT_CONTEXT(ctx);
ATTR2F(VBO_ATTRIB_TEX0, x, y);
}
 
static void GLAPIENTRY
TAG(TexCoord2fv)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR2FV(VBO_ATTRIB_TEX0, v);
}
 
static void GLAPIENTRY
TAG(TexCoord3f)(GLfloat x, GLfloat y, GLfloat z)
{
GET_CURRENT_CONTEXT(ctx);
ATTR3F(VBO_ATTRIB_TEX0, x, y, z);
}
 
static void GLAPIENTRY
TAG(TexCoord3fv)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR3FV(VBO_ATTRIB_TEX0, v);
}
 
static void GLAPIENTRY
TAG(TexCoord4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GET_CURRENT_CONTEXT(ctx);
ATTR4F(VBO_ATTRIB_TEX0, x, y, z, w);
}
 
static void GLAPIENTRY
TAG(TexCoord4fv)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR4FV(VBO_ATTRIB_TEX0, v);
}
 
 
 
static void GLAPIENTRY
TAG(Normal3f)(GLfloat x, GLfloat y, GLfloat z)
{
GET_CURRENT_CONTEXT(ctx);
ATTR3F(VBO_ATTRIB_NORMAL, x, y, z);
}
 
static void GLAPIENTRY
TAG(Normal3fv)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR3FV(VBO_ATTRIB_NORMAL, v);
}
 
 
 
static void GLAPIENTRY
TAG(FogCoordfEXT)(GLfloat x)
{
GET_CURRENT_CONTEXT(ctx);
ATTR1F(VBO_ATTRIB_FOG, x);
}
 
 
 
static void GLAPIENTRY
TAG(FogCoordfvEXT)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR1FV(VBO_ATTRIB_FOG, v);
}
 
static void GLAPIENTRY
TAG(Color3f)(GLfloat x, GLfloat y, GLfloat z)
{
GET_CURRENT_CONTEXT(ctx);
ATTR3F(VBO_ATTRIB_COLOR0, x, y, z);
}
 
static void GLAPIENTRY
TAG(Color3fv)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR3FV(VBO_ATTRIB_COLOR0, v);
}
 
static void GLAPIENTRY
TAG(Color4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GET_CURRENT_CONTEXT(ctx);
ATTR4F(VBO_ATTRIB_COLOR0, x, y, z, w);
}
 
static void GLAPIENTRY
TAG(Color4fv)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR4FV(VBO_ATTRIB_COLOR0, v);
}
 
 
 
static void GLAPIENTRY
TAG(SecondaryColor3fEXT)(GLfloat x, GLfloat y, GLfloat z)
{
GET_CURRENT_CONTEXT(ctx);
ATTR3F(VBO_ATTRIB_COLOR1, x, y, z);
}
 
static void GLAPIENTRY
TAG(SecondaryColor3fvEXT)(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
ATTR3FV(VBO_ATTRIB_COLOR1, v);
}
 
 
 
static void GLAPIENTRY
TAG(EdgeFlag)(GLboolean b)
{
GET_CURRENT_CONTEXT(ctx);
ATTR1F(VBO_ATTRIB_EDGEFLAG, (GLfloat) b);
}
 
 
 
static void GLAPIENTRY
TAG(Indexf)(GLfloat f)
{
GET_CURRENT_CONTEXT(ctx);
ATTR1F(VBO_ATTRIB_INDEX, f);
}
 
static void GLAPIENTRY
TAG(Indexfv)(const GLfloat * f)
{
GET_CURRENT_CONTEXT(ctx);
ATTR1FV(VBO_ATTRIB_INDEX, f);
}
 
 
 
static void GLAPIENTRY
TAG(MultiTexCoord1f)(GLenum target, GLfloat x)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ATTR1F(attr, x);
}
 
static void GLAPIENTRY
TAG(MultiTexCoord1fv)(GLenum target, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ATTR1FV(attr, v);
}
 
static void GLAPIENTRY
TAG(MultiTexCoord2f)(GLenum target, GLfloat x, GLfloat y)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ATTR2F(attr, x, y);
}
 
static void GLAPIENTRY
TAG(MultiTexCoord2fv)(GLenum target, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ATTR2FV(attr, v);
}
 
static void GLAPIENTRY
TAG(MultiTexCoord3f)(GLenum target, GLfloat x, GLfloat y, GLfloat z)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ATTR3F(attr, x, y, z);
}
 
static void GLAPIENTRY
TAG(MultiTexCoord3fv)(GLenum target, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ATTR3FV(attr, v);
}
 
static void GLAPIENTRY
TAG(MultiTexCoord4f)(GLenum target, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ATTR4F(attr, x, y, z, w);
}
 
static void GLAPIENTRY
TAG(MultiTexCoord4fv)(GLenum target, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ATTR4FV(attr, v);
}
 
 
 
static void GLAPIENTRY
TAG(VertexAttrib1fARB)(GLuint index, GLfloat x)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR1F(0, x);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR1F(VBO_ATTRIB_GENERIC0 + index, x);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttrib1fvARB)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR1FV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR1FV(VBO_ATTRIB_GENERIC0 + index, v);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttrib2fARB)(GLuint index, GLfloat x, GLfloat y)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR2F(0, x, y);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2F(VBO_ATTRIB_GENERIC0 + index, x, y);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttrib2fvARB)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR2FV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2FV(VBO_ATTRIB_GENERIC0 + index, v);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttrib3fARB)(GLuint index, GLfloat x, GLfloat y, GLfloat z)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR3F(0, x, y, z);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3F(VBO_ATTRIB_GENERIC0 + index, x, y, z);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttrib3fvARB)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR3FV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3FV(VBO_ATTRIB_GENERIC0 + index, v);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttrib4fARB)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR4F(0, x, y, z, w);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4F(VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttrib4fvARB)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR4FV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4FV(VBO_ATTRIB_GENERIC0 + index, v);
else
ERROR(GL_INVALID_VALUE);
}
 
 
 
/* Integer-valued generic attributes.
* XXX: the integers just get converted to floats at this time
*/
static void GLAPIENTRY
TAG(VertexAttribI1i)(GLuint index, GLint x)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR1I(0, x);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR1I(VBO_ATTRIB_GENERIC0 + index, x);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI2i)(GLuint index, GLint x, GLint y)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR2I(0, x, y);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2I(VBO_ATTRIB_GENERIC0 + index, x, y);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI3i)(GLuint index, GLint x, GLint y, GLint z)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR3I(0, x, y, z);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3I(VBO_ATTRIB_GENERIC0 + index, x, y, z);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI4i)(GLuint index, GLint x, GLint y, GLint z, GLint w)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR4I(0, x, y, z, w);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4I(VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI2iv)(GLuint index, const GLint *v)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR2IV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2IV(VBO_ATTRIB_GENERIC0 + index, v);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI3iv)(GLuint index, const GLint *v)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR3IV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3IV(VBO_ATTRIB_GENERIC0 + index, v);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI4iv)(GLuint index, const GLint *v)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR4IV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4IV(VBO_ATTRIB_GENERIC0 + index, v);
else
ERROR(GL_INVALID_VALUE);
}
 
 
 
/* Unsigned integer-valued generic attributes.
* XXX: the integers just get converted to floats at this time
*/
static void GLAPIENTRY
TAG(VertexAttribI1ui)(GLuint index, GLuint x)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR1UI(0, x);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR1UI(VBO_ATTRIB_GENERIC0 + index, x);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI2ui)(GLuint index, GLuint x, GLuint y)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR2UI(0, x, y);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2UI(VBO_ATTRIB_GENERIC0 + index, x, y);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI3ui)(GLuint index, GLuint x, GLuint y, GLuint z)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR3UI(0, x, y, z);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3UI(VBO_ATTRIB_GENERIC0 + index, x, y, z);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI4ui)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR4UI(0, x, y, z, w);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4UI(VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI2uiv)(GLuint index, const GLuint *v)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR2UIV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2UIV(VBO_ATTRIB_GENERIC0 + index, v);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI3uiv)(GLuint index, const GLuint *v)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR3UIV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3UIV(VBO_ATTRIB_GENERIC0 + index, v);
else
ERROR(GL_INVALID_VALUE);
}
 
static void GLAPIENTRY
TAG(VertexAttribI4uiv)(GLuint index, const GLuint *v)
{
GET_CURRENT_CONTEXT(ctx);
if (index == 0)
ATTR4UIV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4UIV(VBO_ATTRIB_GENERIC0 + index, v);
else
ERROR(GL_INVALID_VALUE);
}
 
 
 
/* In addition to supporting NV_vertex_program, these entrypoints are
* used by the display list and other code specifically because of
* their property of aliasing with other attributes. (See
* vbo_save_loopback.c)
*/
static void GLAPIENTRY
TAG(VertexAttrib1fNV)(GLuint index, GLfloat x)
{
GET_CURRENT_CONTEXT(ctx);
if (index < VBO_ATTRIB_MAX)
ATTR1F(index, x);
}
 
static void GLAPIENTRY
TAG(VertexAttrib1fvNV)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
if (index < VBO_ATTRIB_MAX)
ATTR1FV(index, v);
}
 
static void GLAPIENTRY
TAG(VertexAttrib2fNV)(GLuint index, GLfloat x, GLfloat y)
{
GET_CURRENT_CONTEXT(ctx);
if (index < VBO_ATTRIB_MAX)
ATTR2F(index, x, y);
}
 
static void GLAPIENTRY
TAG(VertexAttrib2fvNV)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
if (index < VBO_ATTRIB_MAX)
ATTR2FV(index, v);
}
 
static void GLAPIENTRY
TAG(VertexAttrib3fNV)(GLuint index, GLfloat x, GLfloat y, GLfloat z)
{
GET_CURRENT_CONTEXT(ctx);
if (index < VBO_ATTRIB_MAX)
ATTR3F(index, x, y, z);
}
 
static void GLAPIENTRY
TAG(VertexAttrib3fvNV)(GLuint index,
const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
if (index < VBO_ATTRIB_MAX)
ATTR3FV(index, v);
}
 
static void GLAPIENTRY
TAG(VertexAttrib4fNV)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GET_CURRENT_CONTEXT(ctx);
if (index < VBO_ATTRIB_MAX)
ATTR4F(index, x, y, z, w);
}
 
static void GLAPIENTRY
TAG(VertexAttrib4fvNV)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
if (index < VBO_ATTRIB_MAX)
ATTR4FV(index, v);
}
 
#define ERROR_IF_NOT_PACKED_TYPE(ctx, type, func) \
if (type != GL_INT_2_10_10_10_REV && type != GL_UNSIGNED_INT_2_10_10_10_REV) { \
_mesa_error(ctx, GL_INVALID_ENUM, "%s(type)", func); \
return; \
}
 
static void GLAPIENTRY
TAG(VertexP2ui)(GLenum type, GLuint value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexP2ui");
ATTR_UI(ctx, 2, type, 0, VBO_ATTRIB_POS, value);
}
 
static void GLAPIENTRY
TAG(VertexP2uiv)(GLenum type, const GLuint *value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexP2uiv");
ATTR_UI(ctx, 2, type, 0, VBO_ATTRIB_POS, value[0]);
}
 
static void GLAPIENTRY
TAG(VertexP3ui)(GLenum type, GLuint value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexP3ui");
ATTR_UI(ctx, 3, type, 0, VBO_ATTRIB_POS, value);
}
 
static void GLAPIENTRY
TAG(VertexP3uiv)(GLenum type, const GLuint *value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexP3uiv");
ATTR_UI(ctx, 3, type, 0, VBO_ATTRIB_POS, value[0]);
}
 
static void GLAPIENTRY
TAG(VertexP4ui)(GLenum type, GLuint value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexP4ui");
ATTR_UI(ctx, 4, type, 0, VBO_ATTRIB_POS, value);
}
 
static void GLAPIENTRY
TAG(VertexP4uiv)(GLenum type, const GLuint *value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexP4uiv");
ATTR_UI(ctx, 4, type, 0, VBO_ATTRIB_POS, value[0]);
}
 
static void GLAPIENTRY
TAG(TexCoordP1ui)(GLenum type, GLuint coords)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glTexCoordP1ui");
ATTR_UI(ctx, 1, type, 0, VBO_ATTRIB_TEX0, coords);
}
 
static void GLAPIENTRY
TAG(TexCoordP1uiv)(GLenum type, const GLuint *coords)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glTexCoordP1uiv");
ATTR_UI(ctx, 1, type, 0, VBO_ATTRIB_TEX0, coords[0]);
}
 
static void GLAPIENTRY
TAG(TexCoordP2ui)(GLenum type, GLuint coords)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glTexCoordP2ui");
ATTR_UI(ctx, 2, type, 0, VBO_ATTRIB_TEX0, coords);
}
 
static void GLAPIENTRY
TAG(TexCoordP2uiv)(GLenum type, const GLuint *coords)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glTexCoordP2uiv");
ATTR_UI(ctx, 2, type, 0, VBO_ATTRIB_TEX0, coords[0]);
}
 
static void GLAPIENTRY
TAG(TexCoordP3ui)(GLenum type, GLuint coords)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glTexCoordP3ui");
ATTR_UI(ctx, 3, type, 0, VBO_ATTRIB_TEX0, coords);
}
 
static void GLAPIENTRY
TAG(TexCoordP3uiv)(GLenum type, const GLuint *coords)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glTexCoordP3uiv");
ATTR_UI(ctx, 3, type, 0, VBO_ATTRIB_TEX0, coords[0]);
}
 
static void GLAPIENTRY
TAG(TexCoordP4ui)(GLenum type, GLuint coords)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glTexCoordP4ui");
ATTR_UI(ctx, 4, type, 0, VBO_ATTRIB_TEX0, coords);
}
 
static void GLAPIENTRY
TAG(TexCoordP4uiv)(GLenum type, const GLuint *coords)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glTexCoordP4uiv");
ATTR_UI(ctx, 4, type, 0, VBO_ATTRIB_TEX0, coords[0]);
}
 
static void GLAPIENTRY
TAG(MultiTexCoordP1ui)(GLenum target, GLenum type, GLuint coords)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glMultiTexCoordP1ui");
ATTR_UI(ctx, 1, type, 0, attr, coords);
}
 
static void GLAPIENTRY
TAG(MultiTexCoordP1uiv)(GLenum target, GLenum type, const GLuint *coords)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glMultiTexCoordP1uiv");
ATTR_UI(ctx, 1, type, 0, attr, coords[0]);
}
 
static void GLAPIENTRY
TAG(MultiTexCoordP2ui)(GLenum target, GLenum type, GLuint coords)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glMultiTexCoordP2ui");
ATTR_UI(ctx, 2, type, 0, attr, coords);
}
 
static void GLAPIENTRY
TAG(MultiTexCoordP2uiv)(GLenum target, GLenum type, const GLuint *coords)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glMultiTexCoordP2uiv");
ATTR_UI(ctx, 2, type, 0, attr, coords[0]);
}
 
static void GLAPIENTRY
TAG(MultiTexCoordP3ui)(GLenum target, GLenum type, GLuint coords)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glMultiTexCoordP3ui");
ATTR_UI(ctx, 3, type, 0, attr, coords);
}
 
static void GLAPIENTRY
TAG(MultiTexCoordP3uiv)(GLenum target, GLenum type, const GLuint *coords)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glMultiTexCoordP3uiv");
ATTR_UI(ctx, 3, type, 0, attr, coords[0]);
}
 
static void GLAPIENTRY
TAG(MultiTexCoordP4ui)(GLenum target, GLenum type, GLuint coords)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glMultiTexCoordP4ui");
ATTR_UI(ctx, 4, type, 0, attr, coords);
}
 
static void GLAPIENTRY
TAG(MultiTexCoordP4uiv)(GLenum target, GLenum type, const GLuint *coords)
{
GET_CURRENT_CONTEXT(ctx);
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0;
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glMultiTexCoordP4uiv");
ATTR_UI(ctx, 4, type, 0, attr, coords[0]);
}
 
static void GLAPIENTRY
TAG(NormalP3ui)(GLenum type, GLuint coords)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glNormalP3ui");
ATTR_UI(ctx, 3, type, 1, VBO_ATTRIB_NORMAL, coords);
}
 
static void GLAPIENTRY
TAG(NormalP3uiv)(GLenum type, const GLuint *coords)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glNormalP3uiv");
ATTR_UI(ctx, 3, type, 1, VBO_ATTRIB_NORMAL, coords[0]);
}
 
static void GLAPIENTRY
TAG(ColorP3ui)(GLenum type, GLuint color)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glColorP3ui");
ATTR_UI(ctx, 3, type, 1, VBO_ATTRIB_COLOR0, color);
}
 
static void GLAPIENTRY
TAG(ColorP3uiv)(GLenum type, const GLuint *color)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glColorP3uiv");
ATTR_UI(ctx, 3, type, 1, VBO_ATTRIB_COLOR0, color[0]);
}
 
static void GLAPIENTRY
TAG(ColorP4ui)(GLenum type, GLuint color)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glColorP4ui");
ATTR_UI(ctx, 4, type, 1, VBO_ATTRIB_COLOR0, color);
}
 
static void GLAPIENTRY
TAG(ColorP4uiv)(GLenum type, const GLuint *color)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glColorP4uiv");
ATTR_UI(ctx, 4, type, 1, VBO_ATTRIB_COLOR0, color[0]);
}
 
static void GLAPIENTRY
TAG(SecondaryColorP3ui)(GLenum type, GLuint color)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glSecondaryColorP3ui");
ATTR_UI(ctx, 3, type, 1, VBO_ATTRIB_COLOR1, color);
}
 
static void GLAPIENTRY
TAG(SecondaryColorP3uiv)(GLenum type, const GLuint *color)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glSecondaryColorP3uiv");
ATTR_UI(ctx, 3, type, 1, VBO_ATTRIB_COLOR1, color[0]);
}
 
static void GLAPIENTRY
TAG(VertexAttribP1ui)(GLuint index, GLenum type, GLboolean normalized,
GLuint value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP1ui");
ATTR_UI_INDEX(ctx, 1, type, normalized, index, value);
}
 
static void GLAPIENTRY
TAG(VertexAttribP2ui)(GLuint index, GLenum type, GLboolean normalized,
GLuint value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP2ui");
ATTR_UI_INDEX(ctx, 2, type, normalized, index, value);
}
 
static void GLAPIENTRY
TAG(VertexAttribP3ui)(GLuint index, GLenum type, GLboolean normalized,
GLuint value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP3ui");
ATTR_UI_INDEX(ctx, 3, type, normalized, index, value);
}
 
static void GLAPIENTRY
TAG(VertexAttribP4ui)(GLuint index, GLenum type, GLboolean normalized,
GLuint value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP4ui");
ATTR_UI_INDEX(ctx, 4, type, normalized, index, value);
}
 
static void GLAPIENTRY
TAG(VertexAttribP1uiv)(GLuint index, GLenum type, GLboolean normalized,
const GLuint *value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP1uiv");
ATTR_UI_INDEX(ctx, 1, type, normalized, index, *value);
}
 
static void GLAPIENTRY
TAG(VertexAttribP2uiv)(GLuint index, GLenum type, GLboolean normalized,
const GLuint *value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP2uiv");
ATTR_UI_INDEX(ctx, 2, type, normalized, index, *value);
}
 
static void GLAPIENTRY
TAG(VertexAttribP3uiv)(GLuint index, GLenum type, GLboolean normalized,
const GLuint *value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP3uiv");
ATTR_UI_INDEX(ctx, 3, type, normalized, index, *value);
}
 
static void GLAPIENTRY
TAG(VertexAttribP4uiv)(GLuint index, GLenum type, GLboolean normalized,
const GLuint *value)
{
GET_CURRENT_CONTEXT(ctx);
ERROR_IF_NOT_PACKED_TYPE(ctx, type, "glVertexAttribP4uiv");
ATTR_UI_INDEX(ctx, 4, type, normalized, index, *value);
}
 
 
#undef ATTR1FV
#undef ATTR2FV
#undef ATTR3FV
#undef ATTR4FV
 
#undef ATTR1F
#undef ATTR2F
#undef ATTR3F
#undef ATTR4F
 
#undef ATTR_UI
 
#undef MAT
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_context.c
0,0 → 1,237
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
 
#include "main/imports.h"
#include "main/mtypes.h"
#include "main/api_arrayelt.h"
#include "main/bufferobj.h"
#include "math/m_eval.h"
#include "vbo.h"
#include "vbo_context.h"
 
#define NR_MAT_ATTRIBS 12
 
static GLuint check_size( const GLfloat *attr )
{
if (attr[3] != 1.0) return 4;
if (attr[2] != 0.0) return 3;
if (attr[1] != 0.0) return 2;
return 1;
}
 
 
static void init_legacy_currval(struct gl_context *ctx)
{
struct vbo_context *vbo = vbo_context(ctx);
struct gl_client_array *arrays = &vbo->currval[VBO_ATTRIB_POS];
GLuint i;
 
memset(arrays, 0, sizeof(*arrays) * VERT_ATTRIB_FF_MAX);
 
/* Set up a constant (StrideB == 0) array for each current
* attribute:
*/
for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) {
struct gl_client_array *cl = &arrays[i];
 
/* Size will have to be determined at runtime:
*/
cl->Size = check_size(ctx->Current.Attrib[i]);
cl->Stride = 0;
cl->StrideB = 0;
cl->Enabled = 1;
cl->Type = GL_FLOAT;
cl->Format = GL_RGBA;
cl->Ptr = (const void *)ctx->Current.Attrib[i];
cl->_ElementSize = cl->Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx, &cl->BufferObj,
ctx->Shared->NullBufferObj);
}
}
 
 
static void init_generic_currval(struct gl_context *ctx)
{
struct vbo_context *vbo = vbo_context(ctx);
struct gl_client_array *arrays = &vbo->currval[VBO_ATTRIB_GENERIC0];
GLuint i;
 
memset(arrays, 0, sizeof(*arrays) * VERT_ATTRIB_GENERIC_MAX);
 
for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) {
struct gl_client_array *cl = &arrays[i];
 
/* This will have to be determined at runtime:
*/
cl->Size = 1;
cl->Type = GL_FLOAT;
cl->Format = GL_RGBA;
cl->Ptr = (const void *)ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + i];
cl->Stride = 0;
cl->StrideB = 0;
cl->Enabled = 1;
cl->_ElementSize = cl->Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx, &cl->BufferObj,
ctx->Shared->NullBufferObj);
}
}
 
 
static void init_mat_currval(struct gl_context *ctx)
{
struct vbo_context *vbo = vbo_context(ctx);
struct gl_client_array *arrays =
&vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT];
GLuint i;
 
ASSERT(NR_MAT_ATTRIBS == MAT_ATTRIB_MAX);
 
memset(arrays, 0, sizeof(*arrays) * NR_MAT_ATTRIBS);
 
/* Set up a constant (StrideB == 0) array for each current
* attribute:
*/
for (i = 0; i < NR_MAT_ATTRIBS; i++) {
struct gl_client_array *cl = &arrays[i];
 
/* Size is fixed for the material attributes, for others will
* be determined at runtime:
*/
switch (i - VERT_ATTRIB_GENERIC0) {
case MAT_ATTRIB_FRONT_SHININESS:
case MAT_ATTRIB_BACK_SHININESS:
cl->Size = 1;
break;
case MAT_ATTRIB_FRONT_INDEXES:
case MAT_ATTRIB_BACK_INDEXES:
cl->Size = 3;
break;
default:
cl->Size = 4;
break;
}
 
cl->Ptr = (const void *)ctx->Light.Material.Attrib[i];
cl->Type = GL_FLOAT;
cl->Format = GL_RGBA;
cl->Stride = 0;
cl->StrideB = 0;
cl->Enabled = 1;
cl->_ElementSize = cl->Size * sizeof(GLfloat);
_mesa_reference_buffer_object(ctx, &cl->BufferObj,
ctx->Shared->NullBufferObj);
}
}
 
 
GLboolean _vbo_CreateContext( struct gl_context *ctx )
{
struct vbo_context *vbo = CALLOC_STRUCT(vbo_context);
 
ctx->swtnl_im = (void *)vbo;
 
/* Initialize the arrayelt helper
*/
if (!ctx->aelt_context &&
!_ae_create_context( ctx )) {
return GL_FALSE;
}
 
init_legacy_currval( ctx );
init_generic_currval( ctx );
init_mat_currval( ctx );
 
/* Build mappings from VERT_ATTRIB -> VBO_ATTRIB depending on type
* of vertex program active.
*/
{
GLuint i;
 
/* identity mapping */
for (i = 0; i < Elements(vbo->map_vp_none); i++)
vbo->map_vp_none[i] = i;
/* map material attribs to generic slots */
for (i = 0; i < NR_MAT_ATTRIBS; i++)
vbo->map_vp_none[VERT_ATTRIB_GENERIC(i)]
= VBO_ATTRIB_MAT_FRONT_AMBIENT + i;
 
for (i = 0; i < Elements(vbo->map_vp_arb); i++)
vbo->map_vp_arb[i] = i;
}
 
 
/* Hook our functions into exec and compile dispatch tables. These
* will pretty much be permanently installed, which means that the
* vtxfmt mechanism can be removed now.
*/
vbo_exec_init( ctx );
if (ctx->API == API_OPENGL_COMPAT)
vbo_save_init( ctx );
 
_math_init_eval();
 
return GL_TRUE;
}
 
 
void _vbo_InvalidateState( struct gl_context *ctx, GLuint new_state )
{
vbo_exec_invalidate_state(ctx, new_state);
}
 
 
void _vbo_DestroyContext( struct gl_context *ctx )
{
struct vbo_context *vbo = vbo_context(ctx);
 
if (ctx->aelt_context) {
_ae_destroy_context( ctx );
ctx->aelt_context = NULL;
}
 
if (vbo) {
GLuint i;
 
for (i = 0; i < VBO_ATTRIB_MAX; i++) {
_mesa_reference_buffer_object(ctx, &vbo->currval[i].BufferObj, NULL);
}
 
vbo_exec_destroy(ctx);
if (ctx->API == API_OPENGL_COMPAT)
vbo_save_destroy(ctx);
free(vbo);
ctx->swtnl_im = NULL;
}
}
 
 
void vbo_set_draw_func(struct gl_context *ctx, vbo_draw_func func)
{
struct vbo_context *vbo = vbo_context(ctx);
vbo->draw_prims = func;
}
 
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_context.h
0,0 → 1,192
/*
* mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
/**
* \file vbo_context.h
* \brief VBO builder module datatypes and definitions.
* \author Keith Whitwell
*/
 
 
/**
* \mainpage The VBO builder module
*
* This module hooks into the GL dispatch table and catches all vertex
* building and drawing commands, such as glVertex3f, glBegin and
* glDrawArrays. The module stores all incoming vertex data as arrays
* in GL vertex buffer objects (VBOs), and translates all drawing
* commands into calls to a driver supplied DrawPrimitives() callback.
*
* The module captures both immediate mode and display list drawing,
* and manages the allocation, reference counting and deallocation of
* vertex buffer objects itself.
*
* The DrawPrimitives() callback can be either implemented by the
* driver itself or hooked to the tnl module's _tnl_draw_primitives()
* function for hardware without tnl capablilties or during fallbacks.
*/
 
 
#ifndef _VBO_CONTEXT_H
#define _VBO_CONTEXT_H
 
#include "vbo.h"
#include "vbo_attrib.h"
#include "vbo_exec.h"
#include "vbo_save.h"
 
 
/** Used to signal when transitioning from one kind of drawing method
* to another.
*/
enum draw_method
{
DRAW_NONE, /**< Initial value only */
DRAW_BEGIN_END,
DRAW_DISPLAY_LIST,
DRAW_ARRAYS
};
 
 
struct vbo_context {
struct gl_client_array currval[VBO_ATTRIB_MAX];
/** Map VERT_ATTRIB_x to VBO_ATTRIB_y */
GLuint map_vp_none[VERT_ATTRIB_MAX];
GLuint map_vp_arb[VERT_ATTRIB_MAX];
 
struct vbo_exec_context exec;
struct vbo_save_context save;
 
/* Callback into the driver. This must always succeed, the driver
* is responsible for initiating any fallback actions required:
*/
vbo_draw_func draw_prims;
 
enum draw_method last_draw_method;
};
 
 
static inline struct vbo_context *vbo_context(struct gl_context *ctx)
{
return (struct vbo_context *)(ctx->swtnl_im);
}
 
 
/**
* Return VP_x token to indicate whether we're running fixed-function
* vertex transformation, an NV vertex program or ARB vertex program/shader.
*/
static inline enum vp_mode
get_program_mode( struct gl_context *ctx )
{
if (!ctx->VertexProgram._Current)
return VP_NONE;
else if (ctx->VertexProgram._Current == ctx->VertexProgram._TnlProgram)
return VP_NONE;
else
return VP_ARB;
}
 
 
/**
* This is called by glBegin, glDrawArrays and glDrawElements (and
* variations of those calls). When we transition from immediate mode
* drawing to array drawing we need to invalidate the array state.
*
* glBegin/End builds vertex arrays. Those arrays may look identical
* to glDrawArrays arrays except that the position of the elements may
* be different. For example, arrays of (position3v, normal3f) vs. arrays
* of (normal3f, position3f). So we need to make sure we notify drivers
* that arrays may be changing.
*/
static inline void
vbo_draw_method(struct vbo_context *vbo, enum draw_method method)
{
if (vbo->last_draw_method != method) {
struct gl_context *ctx = vbo->exec.ctx;
 
switch (method) {
case DRAW_ARRAYS:
ctx->Array._DrawArrays = vbo->exec.array.inputs;
break;
case DRAW_BEGIN_END:
ctx->Array._DrawArrays = vbo->exec.vtx.inputs;
break;
case DRAW_DISPLAY_LIST:
ctx->Array._DrawArrays = vbo->save.inputs;
break;
default:
ASSERT(0);
}
 
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
vbo->last_draw_method = method;
}
}
 
/**
* Return if format is integer. The immediate mode commands only emit floats
* for non-integer types, thus everything else is integer.
*/
static inline GLboolean
vbo_attrtype_to_integer_flag(GLenum format)
{
switch (format) {
case GL_FLOAT:
return GL_FALSE;
case GL_INT:
case GL_UNSIGNED_INT:
return GL_TRUE;
default:
ASSERT(0);
return GL_FALSE;
}
}
 
 
/**
* Return default component values for the given format.
* The return type is an array of floats, because that's how we declare
* the vertex storage despite the fact we sometimes store integers in there.
*/
static inline const GLfloat *
vbo_get_default_vals_as_float(GLenum format)
{
static const GLfloat default_float[4] = { 0, 0, 0, 1 };
static const GLint default_int[4] = { 0, 0, 0, 1 };
 
switch (format) {
case GL_FLOAT:
return default_float;
case GL_INT:
case GL_UNSIGNED_INT:
return (const GLfloat*)default_int;
default:
ASSERT(0);
return NULL;
}
}
 
#endif
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_exec.c
0,0 → 1,257
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
 
 
#include "main/api_arrayelt.h"
#include "main/glheader.h"
#include "main/mtypes.h"
#include "main/vtxfmt.h"
#include "vbo_context.h"
 
 
 
void vbo_exec_init( struct gl_context *ctx )
{
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
 
exec->ctx = ctx;
 
/* Initialize the arrayelt helper
*/
if (!ctx->aelt_context &&
!_ae_create_context( ctx ))
return;
 
vbo_exec_vtx_init( exec );
 
ctx->Driver.NeedFlush = 0;
ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
ctx->Driver.BeginVertices = vbo_exec_BeginVertices;
ctx->Driver.FlushVertices = vbo_exec_FlushVertices;
 
vbo_exec_invalidate_state( ctx, ~0 );
}
 
 
void vbo_exec_destroy( struct gl_context *ctx )
{
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
 
if (ctx->aelt_context) {
_ae_destroy_context( ctx );
ctx->aelt_context = NULL;
}
 
vbo_exec_vtx_destroy( exec );
}
 
 
/**
* Really want to install these callbacks to a central facility to be
* invoked according to the state flags. That will have to wait for a
* mesa rework:
*/
void vbo_exec_invalidate_state( struct gl_context *ctx, GLuint new_state )
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_exec_context *exec = &vbo->exec;
 
if (!exec->validating && new_state & (_NEW_PROGRAM|_NEW_ARRAY)) {
exec->array.recalculate_inputs = GL_TRUE;
 
/* If we ended up here because a VAO was deleted, the _DrawArrays
* pointer which pointed to the VAO might be invalid now, so set it
* to NULL. This prevents crashes in driver functions like Clear
* where driver state validation might occur, but the vbo module is
* still in an invalid state.
*
* Drivers should skip vertex array state validation if _DrawArrays
* is NULL. It also has no effect on performance, because attrib
* bindings will be recalculated anyway.
*/
if (vbo->last_draw_method == DRAW_ARRAYS) {
ctx->Array._DrawArrays = NULL;
vbo->last_draw_method = DRAW_NONE;
}
}
 
if (new_state & _NEW_EVAL)
exec->eval.recalculate_maps = 1;
 
_ae_invalidate_state(ctx, new_state);
}
 
 
/**
* Figure out the number of transform feedback primitives that will be output
* considering the drawing mode, number of vertices, and instance count,
* assuming that no geometry shading is done and primitive restart is not
* used.
*
* This is used by driver back-ends in implementing the PRIMITIVES_GENERATED
* and TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN queries. It is also used to
* pre-validate draw calls in GLES3 (where draw calls only succeed if there is
* enough room in the transform feedback buffer for the result).
*/
size_t
vbo_count_tessellated_primitives(GLenum mode, GLuint count,
GLuint num_instances)
{
size_t num_primitives;
switch (mode) {
case GL_POINTS:
num_primitives = count;
break;
case GL_LINE_STRIP:
num_primitives = count >= 2 ? count - 1 : 0;
break;
case GL_LINE_LOOP:
num_primitives = count >= 2 ? count : 0;
break;
case GL_LINES:
num_primitives = count / 2;
break;
case GL_TRIANGLE_STRIP:
case GL_TRIANGLE_FAN:
case GL_POLYGON:
num_primitives = count >= 3 ? count - 2 : 0;
break;
case GL_TRIANGLES:
num_primitives = count / 3;
break;
case GL_QUAD_STRIP:
num_primitives = count >= 4 ? ((count / 2) - 1) * 2 : 0;
break;
case GL_QUADS:
num_primitives = (count / 4) * 2;
break;
default:
assert(!"Unexpected primitive type in count_tessellated_primitives");
num_primitives = 0;
break;
}
return num_primitives * num_instances;
}
 
 
 
/**
* In some degenarate cases we can improve our ability to merge
* consecutive primitives. For example:
* glBegin(GL_LINE_STRIP);
* glVertex(1);
* glVertex(1);
* glEnd();
* glBegin(GL_LINE_STRIP);
* glVertex(1);
* glVertex(1);
* glEnd();
* Can be merged as a GL_LINES prim with four vertices.
*
* This function converts 2-vertex line strips/loops into GL_LINES, etc.
*/
void
vbo_try_prim_conversion(struct _mesa_prim *p)
{
if (p->mode == GL_LINE_STRIP && p->count == 2) {
/* convert 2-vertex line strip to a separate line */
p->mode = GL_LINES;
}
else if ((p->mode == GL_TRIANGLE_STRIP || p->mode == GL_TRIANGLE_FAN)
&& p->count == 3) {
/* convert 3-vertex tri strip or fan to a separate triangle */
p->mode = GL_TRIANGLES;
}
 
/* Note: we can't convert a 4-vertex quad strip to a separate quad
* because the vertex ordering is different. We'd have to muck
* around in the vertex data to make it work.
*/
}
 
 
/**
* Helper function for determining if two subsequent glBegin/glEnd
* primitives can be combined. This is only possible for GL_POINTS,
* GL_LINES, GL_TRIANGLES and GL_QUADS.
* If we return true, it means that we can concatenate p1 onto p0 (and
* discard p1).
*/
bool
vbo_can_merge_prims(const struct _mesa_prim *p0, const struct _mesa_prim *p1)
{
if (!p0->begin ||
!p1->begin ||
!p0->end ||
!p1->end)
return false;
 
/* The prim mode must match (ex: both GL_TRIANGLES) */
if (p0->mode != p1->mode)
return false;
 
/* p1's vertices must come right after p0 */
if (p0->start + p0->count != p1->start)
return false;
 
if (p0->basevertex != p1->basevertex ||
p0->num_instances != p1->num_instances ||
p0->base_instance != p1->base_instance)
return false;
 
/* can always merge subsequent GL_POINTS primitives */
if (p0->mode == GL_POINTS)
return true;
 
/* independent lines with no extra vertices */
if (p0->mode == GL_LINES && p0->count % 2 == 0 && p1->count % 2 == 0)
return true;
 
/* independent tris */
if (p0->mode == GL_TRIANGLES && p0->count % 3 == 0 && p1->count % 3 == 0)
return true;
 
/* independent quads */
if (p0->mode == GL_QUADS && p0->count % 4 == 0 && p1->count % 4 == 0)
return true;
 
return false;
}
 
 
/**
* If we've determined that p0 and p1 can be merged, this function
* concatenates p1 onto p0.
*/
void
vbo_merge_prims(struct _mesa_prim *p0, const struct _mesa_prim *p1)
{
assert(vbo_can_merge_prims(p0, p1));
 
p0->count += p1->count;
p0->end = p1->end;
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_exec.h
0,0 → 1,174
/**************************************************************************
 
Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
 
All Rights Reserved.
 
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
on the rights to use, copy, modify, merge, publish, distribute, sub
license, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
 
**************************************************************************/
 
/*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*
*/
 
#ifndef __VBO_EXEC_H__
#define __VBO_EXEC_H__
 
#include "main/mtypes.h"
#include "vbo.h"
#include "vbo_attrib.h"
 
 
/**
* Max number of primitives (number of glBegin/End pairs) per VBO.
*/
#define VBO_MAX_PRIM 64
 
 
/**
* Size of the VBO to use for glBegin/glVertex/glEnd-style rendering.
*/
#define VBO_VERT_BUFFER_SIZE (1024*64) /* bytes */
 
 
/** Current vertex program mode */
enum vp_mode {
VP_NONE, /**< fixed function */
VP_ARB /**< ARB vertex program or GLSL vertex shader */
};
 
 
struct vbo_exec_eval1_map {
struct gl_1d_map *map;
GLuint sz;
};
 
struct vbo_exec_eval2_map {
struct gl_2d_map *map;
GLuint sz;
};
 
 
 
struct vbo_exec_copied_vtx {
GLfloat buffer[VBO_ATTRIB_MAX * 4 * VBO_MAX_COPIED_VERTS];
GLuint nr;
};
 
 
struct vbo_exec_context
{
struct gl_context *ctx;
GLvertexformat vtxfmt;
GLvertexformat vtxfmt_noop;
GLboolean validating; /**< if we're in the middle of state validation */
 
struct {
struct gl_buffer_object *bufferobj;
 
GLuint vertex_size; /* in dwords */
 
struct _mesa_prim prim[VBO_MAX_PRIM];
GLuint prim_count;
 
GLfloat *buffer_map;
GLfloat *buffer_ptr; /* cursor, points into buffer */
GLuint buffer_used; /* in bytes */
GLfloat vertex[VBO_ATTRIB_MAX*4]; /* current vertex */
 
GLuint vert_count;
GLuint max_vert;
struct vbo_exec_copied_vtx copied;
 
GLubyte attrsz[VBO_ATTRIB_MAX];
GLenum attrtype[VBO_ATTRIB_MAX];
GLubyte active_sz[VBO_ATTRIB_MAX];
 
GLfloat *attrptr[VBO_ATTRIB_MAX];
struct gl_client_array arrays[VERT_ATTRIB_MAX];
 
/* According to program mode, the values above plus current
* values are squashed down to the 32 attributes passed to the
* vertex program below:
*/
const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
} vtx;
 
struct {
GLboolean recalculate_maps;
struct vbo_exec_eval1_map map1[VERT_ATTRIB_MAX];
struct vbo_exec_eval2_map map2[VERT_ATTRIB_MAX];
} eval;
 
struct {
/* Arrays and current values manipulated according to program
* mode, etc. These are the attributes as seen by vertex
* programs:
*/
const struct gl_client_array *inputs[VERT_ATTRIB_MAX];
GLboolean recalculate_inputs;
} array;
 
/* Which flags to set in vbo_exec_BeginVertices() */
GLbitfield begin_vertices_flags;
 
#ifdef DEBUG
GLint flush_call_depth;
#endif
};
 
 
 
/* External API:
*/
void vbo_exec_init( struct gl_context *ctx );
void vbo_exec_destroy( struct gl_context *ctx );
void vbo_exec_invalidate_state( struct gl_context *ctx, GLuint new_state );
 
void vbo_exec_BeginVertices( struct gl_context *ctx );
void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags );
 
 
/* Internal functions:
*/
 
void vbo_exec_vtx_init( struct vbo_exec_context *exec );
void vbo_exec_vtx_destroy( struct vbo_exec_context *exec );
 
 
void vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap );
void vbo_exec_vtx_map( struct vbo_exec_context *exec );
 
 
void vbo_exec_vtx_wrap( struct vbo_exec_context *exec );
 
void vbo_exec_eval_update( struct vbo_exec_context *exec );
 
void vbo_exec_do_EvalCoord2f( struct vbo_exec_context *exec,
GLfloat u, GLfloat v );
 
void vbo_exec_do_EvalCoord1f( struct vbo_exec_context *exec,
GLfloat u);
 
#endif
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_exec_api.c
0,0 → 1,1296
/**************************************************************************
 
Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
 
All Rights Reserved.
 
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
on the rights to use, copy, modify, merge, publish, distribute, sub
license, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
 
**************************************************************************/
 
/*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
 
#include "main/glheader.h"
#include "main/bufferobj.h"
#include "main/context.h"
#include "main/macros.h"
#include "main/vtxfmt.h"
#include "main/dlist.h"
#include "main/eval.h"
#include "main/state.h"
#include "main/light.h"
#include "main/api_arrayelt.h"
#include "main/api_validate.h"
#include "main/dispatch.h"
 
#include "vbo_context.h"
#include "vbo_noop.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 (_mesa_inside_begin_end(exec->ctx)) {
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 (_mesa_inside_begin_end(exec->ctx)) {
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 );
if (!exec->vtx.buffer_ptr) {
/* probably ran out of memory earlier when allocating the VBO */
return;
}
 
/* 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_TYPE_AS_FLOAT(tmp,
exec->vtx.attrsz[i],
exec->vtx.attrptr[i],
exec->vtx.attrtype[i]);
if (exec->vtx.attrtype[i] != vbo->currval[i].Type ||
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];
vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
vbo->currval[i].Type = exec->vtx.attrtype[i];
vbo->currval[i].Integer =
vbo_attrtype_to_integer_flag(exec->vtx.attrtype[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 (!_mesa_inside_begin_end(ctx) &&
!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_TYPE_AS_FLOAT(tmp, oldSize,
data + old_offset,
exec->vtx.attrtype[j]);
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]) {
GLuint i;
const GLfloat *id =
vbo_get_default_vals_as_float(exec->vtx.attrtype[attr]);
 
/* 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, T, 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; \
exec->vtx.attrtype[A] = T; \
} \
\
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"
 
 
 
/**
* Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled,
* this may be a (partial) no-op.
*/
static void GLAPIENTRY
vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
{
GLbitfield updateMats;
GET_CURRENT_CONTEXT(ctx);
 
/* This function should be a no-op when it tries to update material
* attributes which are currently tracking glColor via glColorMaterial.
* The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
* indicating which material attributes can actually be updated below.
*/
if (ctx->Light.ColorMaterialEnabled) {
updateMats = ~ctx->Light._ColorMaterialBitmask;
}
else {
/* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
updateMats = ALL_MATERIAL_BITS;
}
 
if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) {
updateMats &= FRONT_MATERIAL_BITS;
}
else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) {
updateMats &= BACK_MATERIAL_BITS;
}
else if (face != GL_FRONT_AND_BACK) {
_mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
return;
}
 
switch (pname) {
case GL_EMISSION:
if (updateMats & MAT_BIT_FRONT_EMISSION)
MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
if (updateMats & MAT_BIT_BACK_EMISSION)
MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
break;
case GL_AMBIENT:
if (updateMats & MAT_BIT_FRONT_AMBIENT)
MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
if (updateMats & MAT_BIT_BACK_AMBIENT)
MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
break;
case GL_DIFFUSE:
if (updateMats & MAT_BIT_FRONT_DIFFUSE)
MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
if (updateMats & MAT_BIT_BACK_DIFFUSE)
MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
break;
case GL_SPECULAR:
if (updateMats & MAT_BIT_FRONT_SPECULAR)
MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
if (updateMats & MAT_BIT_BACK_SPECULAR)
MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
break;
case GL_SHININESS:
if (*params < 0 || *params > ctx->Const.MaxShininess) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glMaterial(invalid shininess: %f out range [0, %f])",
*params, ctx->Const.MaxShininess);
return;
}
if (updateMats & MAT_BIT_FRONT_SHININESS)
MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
if (updateMats & MAT_BIT_BACK_SHININESS)
MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
break;
case GL_COLOR_INDEXES:
if (ctx->API != API_OPENGL_COMPAT) {
_mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
return;
}
if (updateMats & MAT_BIT_FRONT_INDEXES)
MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
if (updateMats & MAT_BIT_BACK_INDEXES)
MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
break;
case GL_AMBIENT_AND_DIFFUSE:
if (updateMats & MAT_BIT_FRONT_AMBIENT)
MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
if (updateMats & MAT_BIT_FRONT_DIFFUSE)
MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
if (updateMats & MAT_BIT_BACK_AMBIENT)
MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
if (updateMats & MAT_BIT_BACK_DIFFUSE)
MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
return;
}
}
 
 
/**
* 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 );
}
}
 
 
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 );
}
 
 
/**
* Called via glBegin.
*/
static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
{
GET_CURRENT_CONTEXT( ctx );
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
int i;
 
if (_mesa_inside_begin_end(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
return;
}
 
if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
return;
}
 
vbo_draw_method(vbo_context(ctx), DRAW_BEGIN_END);
 
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;
exec->vtx.prim[i].base_instance = 0;
 
ctx->Driver.CurrentExecPrimitive = mode;
 
ctx->Exec = ctx->BeginEnd;
/* We may have been called from a display list, in which case we should
* leave dlist.c's dispatch table in place.
*/
if (ctx->CurrentDispatch == ctx->OutsideBeginEnd) {
ctx->CurrentDispatch = ctx->BeginEnd;
_glapi_set_dispatch(ctx->CurrentDispatch);
} else {
assert(ctx->CurrentDispatch == ctx->Save);
}
}
 
 
/**
* Try to merge / concatenate the two most recent VBO primitives.
*/
static void
try_vbo_merge(struct vbo_exec_context *exec)
{
struct _mesa_prim *cur = &exec->vtx.prim[exec->vtx.prim_count - 1];
 
assert(exec->vtx.prim_count >= 1);
 
vbo_try_prim_conversion(cur);
 
if (exec->vtx.prim_count >= 2) {
struct _mesa_prim *prev = &exec->vtx.prim[exec->vtx.prim_count - 2];
assert(prev == cur - 1);
 
if (vbo_can_merge_prims(prev, cur)) {
assert(cur->begin);
assert(cur->end);
assert(prev->begin);
assert(prev->end);
vbo_merge_prims(prev, cur);
exec->vtx.prim_count--; /* drop the last primitive */
}
}
}
 
 
/**
* Called via glEnd.
*/
static void GLAPIENTRY vbo_exec_End( void )
{
GET_CURRENT_CONTEXT( ctx );
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
 
if (!_mesa_inside_begin_end(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
return;
}
 
ctx->Exec = ctx->OutsideBeginEnd;
if (ctx->CurrentDispatch == ctx->BeginEnd) {
ctx->CurrentDispatch = ctx->OutsideBeginEnd;
_glapi_set_dispatch(ctx->CurrentDispatch);
}
 
if (exec->vtx.prim_count > 0) {
/* close off current primitive */
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;
 
try_vbo_merge(exec);
}
 
ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
 
if (exec->vtx.prim_count == VBO_MAX_PRIM)
vbo_exec_vtx_flush( exec, GL_FALSE );
 
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
_mesa_flush(ctx);
}
}
 
 
/**
* 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 )
{
struct gl_context *ctx = exec->ctx;
GLvertexformat *vfmt = &exec->vtxfmt;
 
vfmt->ArrayElement = _ae_ArrayElement;
 
vfmt->Begin = vbo_exec_Begin;
vfmt->End = vbo_exec_End;
vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
 
vfmt->CallList = _mesa_CallList;
vfmt->CallLists = _mesa_CallLists;
 
vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
 
/* 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;
if (ctx->API == API_OPENGLES2) {
vfmt->VertexAttrib1fARB = _es_VertexAttrib1f;
vfmt->VertexAttrib1fvARB = _es_VertexAttrib1fv;
vfmt->VertexAttrib2fARB = _es_VertexAttrib2f;
vfmt->VertexAttrib2fvARB = _es_VertexAttrib2fv;
vfmt->VertexAttrib3fARB = _es_VertexAttrib3f;
vfmt->VertexAttrib3fvARB = _es_VertexAttrib3fv;
vfmt->VertexAttrib4fARB = _es_VertexAttrib4f;
vfmt->VertexAttrib4fvARB = _es_VertexAttrib4fv;
} else {
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;
}
 
/* Note that VertexAttrib4fNV is used from dlist.c and api_arrayelt.c so
* they can have a single entrypoint for updating any of the legacy
* attribs.
*/
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;
 
/* ARB_vertex_type_2_10_10_10_rev */
vfmt->VertexP2ui = vbo_VertexP2ui;
vfmt->VertexP2uiv = vbo_VertexP2uiv;
vfmt->VertexP3ui = vbo_VertexP3ui;
vfmt->VertexP3uiv = vbo_VertexP3uiv;
vfmt->VertexP4ui = vbo_VertexP4ui;
vfmt->VertexP4uiv = vbo_VertexP4uiv;
 
vfmt->TexCoordP1ui = vbo_TexCoordP1ui;
vfmt->TexCoordP1uiv = vbo_TexCoordP1uiv;
vfmt->TexCoordP2ui = vbo_TexCoordP2ui;
vfmt->TexCoordP2uiv = vbo_TexCoordP2uiv;
vfmt->TexCoordP3ui = vbo_TexCoordP3ui;
vfmt->TexCoordP3uiv = vbo_TexCoordP3uiv;
vfmt->TexCoordP4ui = vbo_TexCoordP4ui;
vfmt->TexCoordP4uiv = vbo_TexCoordP4uiv;
 
vfmt->MultiTexCoordP1ui = vbo_MultiTexCoordP1ui;
vfmt->MultiTexCoordP1uiv = vbo_MultiTexCoordP1uiv;
vfmt->MultiTexCoordP2ui = vbo_MultiTexCoordP2ui;
vfmt->MultiTexCoordP2uiv = vbo_MultiTexCoordP2uiv;
vfmt->MultiTexCoordP3ui = vbo_MultiTexCoordP3ui;
vfmt->MultiTexCoordP3uiv = vbo_MultiTexCoordP3uiv;
vfmt->MultiTexCoordP4ui = vbo_MultiTexCoordP4ui;
vfmt->MultiTexCoordP4uiv = vbo_MultiTexCoordP4uiv;
vfmt->NormalP3ui = vbo_NormalP3ui;
vfmt->NormalP3uiv = vbo_NormalP3uiv;
 
vfmt->ColorP3ui = vbo_ColorP3ui;
vfmt->ColorP3uiv = vbo_ColorP3uiv;
vfmt->ColorP4ui = vbo_ColorP4ui;
vfmt->ColorP4uiv = vbo_ColorP4uiv;
 
vfmt->SecondaryColorP3ui = vbo_SecondaryColorP3ui;
vfmt->SecondaryColorP3uiv = vbo_SecondaryColorP3uiv;
 
vfmt->VertexAttribP1ui = vbo_VertexAttribP1ui;
vfmt->VertexAttribP1uiv = vbo_VertexAttribP1uiv;
vfmt->VertexAttribP2ui = vbo_VertexAttribP2ui;
vfmt->VertexAttribP2uiv = vbo_VertexAttribP2uiv;
vfmt->VertexAttribP3ui = vbo_VertexAttribP3ui;
vfmt->VertexAttribP3uiv = vbo_VertexAttribP3uiv;
vfmt->VertexAttribP4ui = vbo_VertexAttribP4ui;
vfmt->VertexAttribP4uiv = vbo_VertexAttribP4uiv;
}
 
 
/**
* 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);
if (!ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj)) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
}
}
 
 
/**
* 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 = _mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
exec->vtx.buffer_ptr = exec->vtx.buffer_map;
 
vbo_exec_vtxfmt_init( exec );
_mesa_noop_vtxfmt_init(&exec->vtxfmt_noop);
 
for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
ASSERT(i < Elements(exec->vtx.attrsz));
exec->vtx.attrsz[i] = 0;
ASSERT(i < Elements(exec->vtx.attrtype));
exec->vtx.attrtype[i] = GL_FLOAT;
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->currval[VBO_ATTRIB_POS],
VERT_ATTRIB_FF_MAX * sizeof(arrays[0]));
for (i = 0; i < VERT_ATTRIB_FF_MAX; ++i) {
struct gl_client_array *array;
array = &arrays[VERT_ATTRIB_FF(i)];
array->BufferObj = NULL;
_mesa_reference_buffer_object(ctx, &arrays->BufferObj,
vbo->currval[VBO_ATTRIB_POS+i].BufferObj);
}
 
memcpy(arrays + VERT_ATTRIB_GENERIC(0),
&vbo->currval[VBO_ATTRIB_GENERIC0],
VERT_ATTRIB_GENERIC_MAX * sizeof(arrays[0]));
 
for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; ++i) {
struct gl_client_array *array;
array = &arrays[VERT_ATTRIB_GENERIC(i)];
array->BufferObj = NULL;
_mesa_reference_buffer_object(ctx, &array->BufferObj,
vbo->currval[VBO_ATTRIB_GENERIC0+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, 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 (_mesa_inside_begin_end(ctx)) {
/* 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.attrtype[i] = GL_FLOAT;
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, GL_FLOAT, 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]);
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_exec_array.c
0,0 → 1,1662
/**************************************************************************
*
* 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/dispatch.h"
#include "main/varray.h"
#include "main/bufferobj.h"
#include "main/enums.h"
#include "main/macros.h"
#include "main/transformfeedback.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.
*/
static 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 GLuint count)
{
const GLboolean restart = ctx->Array._PrimitiveRestart;
const GLuint restartIndex = _mesa_primitive_restart_index(ctx, ib->type);
const int index_size = vbo_sizeof_ib_type(ib->type);
const char *indices;
GLuint i;
 
indices = (char *) ib->ptr + prim->start * index_size;
if (_mesa_is_bufferobj(ib->obj)) {
GLsizeiptr size = MIN2(count * index_size, ib->obj->Size);
indices = ctx->Driver.MapBufferRange(ctx, (GLintptr) indices, size,
GL_MAP_READ_BIT, ib->obj);
}
 
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, ib->obj);
}
}
 
/**
* Compute min and max elements for nr_prims
*/
void
vbo_get_minmax_indices(struct gl_context *ctx,
const struct _mesa_prim *prims,
const struct _mesa_index_buffer *ib,
GLuint *min_index,
GLuint *max_index,
GLuint nr_prims)
{
GLuint tmp_min, tmp_max;
GLuint i;
GLuint count;
 
*min_index = ~0;
*max_index = 0;
 
for (i = 0; i < nr_prims; i++) {
const struct _mesa_prim *start_prim;
 
start_prim = &prims[i];
count = start_prim->count;
/* Do combination if possible to reduce map/unmap count */
while ((i + 1 < nr_prims) &&
(prims[i].start + prims[i].count == prims[i+1].start)) {
count += prims[i+1].count;
i++;
}
vbo_get_minmax_index(ctx, start_prim, ib, &tmp_min, &tmp_max, count);
*min_index = MIN2(*min_index, tmp_min);
*max_index = MAX2(*max_index, tmp_max);
}
}
 
 
/**
* 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.MapBufferRange(ctx, 0, array->BufferObj->Size,
GL_MAP_READ_BIT, 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, 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.ArrayObj->ElementArrayBufferObj)) {
elemMap = ctx->Driver.MapBufferRange(ctx, 0,
ctx->Array.ArrayObj->ElementArrayBufferObj->Size,
GL_MAP_READ_BIT,
ctx->Array.ArrayObj->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 */
for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) {
check_array_data(ctx, &arrayObj->VertexAttrib[k], k, j);
}
}
 
if (_mesa_is_bufferobj(arrayObj->ElementArrayBufferObj)) {
ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj);
}
 
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;
struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
int i;
 
printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n",
mode, start, count);
 
for (i = 0; i < 32; i++) {
struct gl_buffer_object *bufObj = exec->array.inputs[i]->BufferObj;
GLuint bufName = bufObj->Name;
GLint stride = exec->array.inputs[i]->Stride;
printf("attr %2d: size %d stride %d enabled %d "
"ptr %p Bufobj %u\n",
i,
exec->array.inputs[i]->Size,
stride,
/*exec->array.inputs[i]->Enabled,*/
arrayObj->VertexAttrib[VERT_ATTRIB_FF(i)].Enabled,
exec->array.inputs[i]->Ptr,
bufName);
 
if (bufName) {
GLubyte *p = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size,
GL_MAP_READ_BIT, bufObj);
int offset = (int) (GLintptr) exec->array.inputs[i]->Ptr;
float *f = (float *) (p + offset);
int *k = (int *) f;
int i;
int n = (count * stride) / 4;
if (n > 32)
n = 32;
printf(" Data at offset %d:\n", offset);
for (i = 0; i < n; i++) {
printf(" float[%d] = 0x%08x %f\n", i, k[i], f[i]);
}
ctx->Driver.UnmapBuffer(ctx, bufObj);
}
}
}
 
 
/**
* 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;
struct gl_client_array *vertexAttrib = ctx->Array.ArrayObj->VertexAttrib;
const struct gl_client_array **inputs = &exec->array.inputs[0];
GLbitfield64 const_inputs = 0x0;
GLuint i;
 
switch (get_program_mode(ctx)) {
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_FF_MAX; i++) {
if (vertexAttrib[VERT_ATTRIB_FF(i)].Enabled)
inputs[i] = &vertexAttrib[VERT_ATTRIB_FF(i)];
else {
inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
const_inputs |= VERT_BIT(i);
}
}
 
for (i = 0; i < MAT_ATTRIB_MAX; i++) {
inputs[VERT_ATTRIB_GENERIC(i)] =
&vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+i];
const_inputs |= VERT_BIT_GENERIC(i);
}
 
/* Could use just about anything, just to fill in the empty
* slots:
*/
for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_GENERIC_MAX; i++) {
inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->currval[VBO_ATTRIB_GENERIC0+i];
const_inputs |= VERT_BIT_GENERIC(i);
}
break;
 
case VP_ARB:
/* There are no shaders in OpenGL ES 1.x, so this code path should be
* impossible to reach. The meta code is careful to not use shaders in
* ES1.
*/
assert(ctx->API != API_OPENGLES);
 
/* In the compatibility profile of desktop OpenGL, 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.
*
* In all other APIs, only the generic attributes exist, and none of the
* slots are considered "magic."
*/
if (ctx->API == API_OPENGL_COMPAT) {
if (vertexAttrib[VERT_ATTRIB_GENERIC0].Enabled)
inputs[0] = &vertexAttrib[VERT_ATTRIB_GENERIC0];
else if (vertexAttrib[VERT_ATTRIB_POS].Enabled)
inputs[0] = &vertexAttrib[VERT_ATTRIB_POS];
else {
inputs[0] = &vbo->currval[VBO_ATTRIB_POS];
const_inputs |= VERT_BIT_POS;
}
 
for (i = 1; i < VERT_ATTRIB_FF_MAX; i++) {
if (vertexAttrib[VERT_ATTRIB_FF(i)].Enabled)
inputs[i] = &vertexAttrib[VERT_ATTRIB_FF(i)];
else {
inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
const_inputs |= VERT_BIT_FF(i);
}
}
 
for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) {
if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
inputs[VERT_ATTRIB_GENERIC(i)] =
&vertexAttrib[VERT_ATTRIB_GENERIC(i)];
else {
inputs[VERT_ATTRIB_GENERIC(i)] =
&vbo->currval[VBO_ATTRIB_GENERIC0+i];
const_inputs |= VERT_BIT_GENERIC(i);
}
}
 
inputs[VERT_ATTRIB_GENERIC0] = inputs[0];
} else {
/* Other parts of the code assume that inputs[0] through
* inputs[VERT_ATTRIB_FF_MAX] will be non-NULL. However, in OpenGL
* ES 2.0+ or OpenGL core profile, none of these arrays should ever
* be enabled.
*/
for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) {
assert(!vertexAttrib[VERT_ATTRIB_FF(i)].Enabled);
 
inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
const_inputs |= VERT_BIT_FF(i);
}
 
for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) {
if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
inputs[VERT_ATTRIB_GENERIC(i)] =
&vertexAttrib[VERT_ATTRIB_GENERIC(i)];
else {
inputs[VERT_ATTRIB_GENERIC(i)] =
&vbo->currval[VBO_ATTRIB_GENERIC0+i];
const_inputs |= VERT_BIT_GENERIC(i);
}
}
}
 
break;
}
 
_mesa_set_varying_vp_inputs( ctx, VERT_BIT_ALL & (~const_inputs) );
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
}
 
 
/**
* 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_VARYING_VP_INPUTS dirty flag so state
* validation must be done after this call.
*/
void
vbo_bind_arrays(struct gl_context *ctx)
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_exec_context *exec = &vbo->exec;
 
vbo_draw_method(vbo, DRAW_ARRAYS);
 
if (exec->array.recalculate_inputs) {
recalculate_input_bindings(ctx);
exec->array.recalculate_inputs = GL_FALSE;
 
/* 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) {
/* Setting "validating" to TRUE prevents _mesa_update_state from
* invalidating what we just did.
*/
exec->validating = GL_TRUE;
_mesa_update_state(ctx);
exec->validating = GL_FALSE;
}
}
}
 
 
/**
* Handle a draw case that potentially has primitive restart enabled.
*
* If primitive restart is enabled, and PrimitiveRestartInSoftware is
* set, then vbo_sw_primitive_restart is used to handle the primitive
* restart case in software.
*/
static void
vbo_handle_primitive_restart(struct gl_context *ctx,
const struct _mesa_prim *prim,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLboolean index_bounds_valid,
GLuint min_index,
GLuint max_index)
{
struct vbo_context *vbo = vbo_context(ctx);
 
if ((ib != NULL) &&
ctx->Const.PrimitiveRestartInSoftware &&
ctx->Array._PrimitiveRestart) {
/* Handle primitive restart in software */
vbo_sw_primitive_restart(ctx, prim, nr_prims, ib);
} else {
/* Call driver directly for draw_prims */
vbo->draw_prims(ctx, prim, nr_prims, ib,
index_bounds_valid, min_index, max_index, NULL);
}
}
 
 
/**
* 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, GLuint baseInstance)
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_exec_context *exec = &vbo->exec;
struct _mesa_prim prim[2];
 
vbo_bind_arrays(ctx);
 
/* init most fields to zero */
memset(prim, 0, sizeof(prim));
prim[0].begin = 1;
prim[0].end = 1;
prim[0].mode = mode;
prim[0].num_instances = numInstances;
prim[0].base_instance = baseInstance;
 
/* 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, prim, primCount, NULL,
GL_TRUE, start, start + count - 1, NULL);
}
}
else {
/* no prim restart */
prim[0].start = start;
prim[0].count = count;
 
check_buffers_are_unmapped(exec->array.inputs);
vbo->draw_prims(ctx, prim, 1, NULL,
GL_TRUE, start, start + count - 1,
NULL);
}
 
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
_mesa_flush(ctx);
}
}
 
 
/**
* Execute a glRectf() function.
*/
static void GLAPIENTRY
vbo_exec_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
 
CALL_Begin(GET_DISPATCH(), (GL_QUADS));
CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
CALL_End(GET_DISPATCH(), ());
}
 
 
static void GLAPIENTRY
vbo_exec_EvalMesh1(GLenum mode, GLint i1, GLint i2)
{
GET_CURRENT_CONTEXT(ctx);
GLint i;
GLfloat u, du;
GLenum prim;
 
switch (mode) {
case GL_POINT:
prim = GL_POINTS;
break;
case GL_LINE:
prim = GL_LINE_STRIP;
break;
default:
_mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" );
return;
}
 
/* No effect if vertex maps disabled.
*/
if (!ctx->Eval.Map1Vertex4 &&
!ctx->Eval.Map1Vertex3)
return;
 
du = ctx->Eval.MapGrid1du;
u = ctx->Eval.MapGrid1u1 + i1 * du;
 
CALL_Begin(GET_DISPATCH(), (prim));
for (i=i1;i<=i2;i++,u+=du) {
CALL_EvalCoord1f(GET_DISPATCH(), (u));
}
CALL_End(GET_DISPATCH(), ());
}
 
 
static void GLAPIENTRY
vbo_exec_EvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2)
{
GET_CURRENT_CONTEXT(ctx);
GLfloat u, du, v, dv, v1, u1;
GLint i, j;
 
switch (mode) {
case GL_POINT:
case GL_LINE:
case GL_FILL:
break;
default:
_mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" );
return;
}
 
/* No effect if vertex maps disabled.
*/
if (!ctx->Eval.Map2Vertex4 &&
!ctx->Eval.Map2Vertex3)
return;
 
du = ctx->Eval.MapGrid2du;
dv = ctx->Eval.MapGrid2dv;
v1 = ctx->Eval.MapGrid2v1 + j1 * dv;
u1 = ctx->Eval.MapGrid2u1 + i1 * du;
 
switch (mode) {
case GL_POINT:
CALL_Begin(GET_DISPATCH(), (GL_POINTS));
for (v=v1,j=j1;j<=j2;j++,v+=dv) {
for (u=u1,i=i1;i<=i2;i++,u+=du) {
CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
}
}
CALL_End(GET_DISPATCH(), ());
break;
case GL_LINE:
for (v=v1,j=j1;j<=j2;j++,v+=dv) {
CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
for (u=u1,i=i1;i<=i2;i++,u+=du) {
CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
}
CALL_End(GET_DISPATCH(), ());
}
for (u=u1,i=i1;i<=i2;i++,u+=du) {
CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
for (v=v1,j=j1;j<=j2;j++,v+=dv) {
CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
}
CALL_End(GET_DISPATCH(), ());
}
break;
case GL_FILL:
for (v=v1,j=j1;j<j2;j++,v+=dv) {
CALL_Begin(GET_DISPATCH(), (GL_TRIANGLE_STRIP));
for (u=u1,i=i1;i<=i2;i++,u+=du) {
CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
CALL_EvalCoord2f(GET_DISPATCH(), (u, v+dv));
}
CALL_End(GET_DISPATCH(), ());
}
break;
}
}
 
 
/**
* 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;
 
if (0)
check_draw_arrays_data(ctx, start, count);
 
vbo_draw_arrays(ctx, mode, start, count, 1, 0);
 
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;
 
if (0)
check_draw_arrays_data(ctx, start, count);
 
vbo_draw_arrays(ctx, mode, start, count, numInstances, 0);
 
if (0)
print_draw_arrays(ctx, mode, start, count);
}
 
 
/**
* Called from glDrawArraysInstancedBaseInstance when in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count,
GLsizei numInstances, GLuint baseInstance)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawArraysInstancedBaseInstance(%s, %d, %d, %d, %d)\n",
_mesa_lookup_enum_by_nr(mode), first, count,
numInstances, baseInstance);
 
if (!_mesa_validate_DrawArraysInstanced(ctx, mode, first, count,
numInstances))
return;
 
if (0)
check_draw_arrays_data(ctx, first, count);
 
vbo_draw_arrays(ctx, mode, first, count, numInstances, baseInstance);
 
if (0)
print_draw_arrays(ctx, mode, first, count);
}
 
 
 
/**
* Map GL_ELEMENT_ARRAY_BUFFER and print contents.
* For debugging.
*/
#if 0
static void
dump_element_buffer(struct gl_context *ctx, GLenum type)
{
const GLvoid *map =
ctx->Driver.MapBufferRange(ctx, 0,
ctx->Array.ArrayObj->ElementArrayBufferObj->Size,
GL_MAP_READ_BIT,
ctx->Array.ArrayObj->ElementArrayBufferObj);
switch (type) {
case GL_UNSIGNED_BYTE:
{
const GLubyte *us = (const GLubyte *) map;
GLint i;
for (i = 0; i < ctx->Array.ArrayObj->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.ArrayObj->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.ArrayObj->ElementArrayBufferObj->Size / 4; i++) {
printf("%08x ", us[i]);
if (i % 8 == 7)
printf("\n");
}
printf("\n");
}
break;
default:
;
}
 
ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj);
}
#endif
 
 
/**
* 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, GLuint numInstances,
GLuint baseInstance)
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_exec_context *exec = &vbo->exec;
struct _mesa_index_buffer ib;
struct _mesa_prim prim[1];
 
vbo_bind_arrays(ctx);
 
ib.count = count;
ib.type = type;
ib.obj = ctx->Array.ArrayObj->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;
prim[0].base_instance = baseInstance;
 
/* 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_handle_primitive_restart(ctx, prim, 1, &ib,
index_bounds_valid, start, end);
 
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
_mesa_flush(ctx);
}
}
 
 
/**
* 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;
GLboolean index_bounds_valid = GL_TRUE;
GLuint max_element;
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;
 
if (ctx->Const.CheckArrayBounds) {
/* _MaxElement was computed, so we can use it.
* This path is used for drivers which need strict bounds checking.
*/
max_element = ctx->Array.ArrayObj->_MaxElement;
}
else {
/* Generally, hardware drivers don't need to know the buffer bounds
* if all vertex attributes are in VBOs.
* However, if none of vertex attributes are in VBOs, _MaxElement
* is always set to some random big number anyway, so bounds checking
* is mostly useless.
*
* This is only useful to catch invalid values in the "end" parameter
* like ~0.
*/
max_element = 2 * 1000 * 1000 * 1000; /* just a big number */
}
 
if ((int) end + basevertex < 0 ||
start + basevertex >= max_element) {
/* The application requested we draw using a range of indices that's
* outside the bounds of the current VBO. This is invalid and appears
* to give undefined results. The safest thing to do is to simply
* ignore the range, in case the application botched their range tracking
* but did provide valid indices. Also issue a warning indicating that
* the application is broken.
*/
if (warnCount++ < 10) {
_mesa_warning(ctx, "glDrawRangeElements(start %u, end %u, "
"basevertex %d, count %d, type 0x%x, indices=%p):\n"
"\trange is outside VBO bounds (max=%u); ignoring.\n"
"\tThis should be fixed in the application.",
start, end, basevertex, count, type, indices,
max_element - 1);
}
index_bounds_valid = GL_FALSE;
}
 
/* 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 (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.ArrayObj->ElementArrayBufferObj->Name,
basevertex);
}
 
if ((int) start + basevertex < 0 ||
end + basevertex >= max_element)
index_bounds_valid = GL_FALSE;
 
#if 0
check_draw_elements_data(ctx, count, type, indices);
#else
(void) check_draw_elements_data;
#endif
 
vbo_validated_drawrangeelements(ctx, mode, index_bounds_valid, start, end,
count, type, indices, basevertex, 1, 0);
}
 
 
/**
* Called by glDrawRangeElements() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
GLsizei count, GLenum type, const GLvoid *indices)
{
if (MESA_VERBOSE & VERBOSE_DRAW) {
GET_CURRENT_CONTEXT(ctx);
_mesa_debug(ctx,
"glDrawRangeElements(%s, %u, %u, %d, %s, %p)\n",
_mesa_lookup_enum_by_nr(mode), start, end, count,
_mesa_lookup_enum_by_nr(type), indices);
}
 
vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type,
indices, 0);
}
 
 
/**
* Called by glDrawElements() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawElements(%s, %u, %s, %p)\n",
_mesa_lookup_enum_by_nr(mode), count,
_mesa_lookup_enum_by_nr(type), indices);
 
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 ))
return;
 
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
count, type, indices, 0, 1, 0);
}
 
 
/**
* 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, 0);
}
 
 
/**
* Called by glDrawElementsInstanced() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices, GLsizei numInstances)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawElementsInstanced(%s, %d, %s, %p, %d)\n",
_mesa_lookup_enum_by_nr(mode), count,
_mesa_lookup_enum_by_nr(type), indices, numInstances);
 
if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
numInstances, 0))
return;
 
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
count, type, indices, 0, numInstances, 0);
}
 
 
/**
* Called by glDrawElementsInstancedBaseVertex() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices, GLsizei numInstances,
GLint basevertex)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawElementsInstancedBaseVertex(%s, %d, %s, %p, %d; %d)\n",
_mesa_lookup_enum_by_nr(mode), count,
_mesa_lookup_enum_by_nr(type), indices,
numInstances, basevertex);
 
if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
numInstances, basevertex))
return;
 
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
count, type, indices, basevertex, numInstances, 0);
}
 
 
/**
* Called by glDrawElementsInstancedBaseInstance() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices, GLsizei numInstances,
GLuint baseInstance)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawElementsInstancedBaseInstance(%s, %d, %s, %p, %d, %d)\n",
_mesa_lookup_enum_by_nr(mode), count,
_mesa_lookup_enum_by_nr(type), indices,
numInstances, baseInstance);
 
if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
numInstances, 0))
return;
 
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
count, type, indices, 0, numInstances,
baseInstance);
}
 
 
/**
* Called by glDrawElementsInstancedBaseVertexBaseInstance() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices, GLsizei numInstances,
GLint basevertex, GLuint baseInstance)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawElementsInstancedBaseVertexBaseInstance(%s, %d, %s, %p, %d, %d, %d)\n",
_mesa_lookup_enum_by_nr(mode), count,
_mesa_lookup_enum_by_nr(type), indices,
numInstances, basevertex, baseInstance);
 
if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
numInstances, basevertex))
return;
 
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
count, type, indices, basevertex, numInstances,
baseInstance);
}
 
 
/**
* 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 * const *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 = vbo_sizeof_ib_type(type);
uintptr_t min_index_ptr, max_index_ptr;
GLboolean fallback = GL_FALSE;
int i;
 
if (primcount == 0)
return;
 
prim = calloc(1, primcount * sizeof(*prim));
if (prim == NULL) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements");
return;
}
 
vbo_bind_arrays(ctx);
 
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.ArrayObj->ElementArrayBufferObj))
fallback = GL_TRUE;
 
if (!fallback) {
ib.count = (max_index_ptr - min_index_ptr) / index_type_size;
ib.type = type;
ib.obj = ctx->Array.ArrayObj->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;
prim[i].base_instance = 0;
if (basevertex != NULL)
prim[i].basevertex = basevertex[i];
else
prim[i].basevertex = 0;
}
 
check_buffers_are_unmapped(exec->array.inputs);
vbo_handle_primitive_restart(ctx, 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.ArrayObj->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;
prim[0].base_instance = 0;
if (basevertex != NULL)
prim[0].basevertex = basevertex[i];
else
prim[0].basevertex = 0;
 
check_buffers_are_unmapped(exec->array.inputs);
vbo_handle_primitive_restart(ctx, prim, 1, &ib,
GL_FALSE, ~0, ~0);
}
}
 
free(prim);
 
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
_mesa_flush(ctx);
}
}
 
 
static void GLAPIENTRY
vbo_exec_MultiDrawElements(GLenum mode,
const GLsizei *count, GLenum type,
const GLvoid * const *indices,
GLsizei primcount)
{
GET_CURRENT_CONTEXT(ctx);
 
if (!_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices,
primcount, NULL))
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 * const *indices,
GLsizei primcount,
const GLsizei *basevertex)
{
GET_CURRENT_CONTEXT(ctx);
 
if (!_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices,
primcount, basevertex))
return;
 
vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount,
basevertex);
}
 
static void
vbo_draw_transform_feedback(struct gl_context *ctx, GLenum mode,
struct gl_transform_feedback_object *obj,
GLuint stream, GLuint numInstances)
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_exec_context *exec = &vbo->exec;
struct _mesa_prim prim[2];
 
if (!_mesa_validate_DrawTransformFeedback(ctx, mode, obj, stream,
numInstances)) {
return;
}
 
vbo_bind_arrays(ctx);
 
/* init most fields to zero */
memset(prim, 0, sizeof(prim));
prim[0].begin = 1;
prim[0].end = 1;
prim[0].mode = mode;
prim[0].num_instances = numInstances;
prim[0].base_instance = 0;
 
/* Maybe we should do some primitive splitting for primitive restart
* (like in DrawArrays), but we have no way to know how many vertices
* will be rendered. */
 
check_buffers_are_unmapped(exec->array.inputs);
vbo->draw_prims(ctx, prim, 1, NULL,
GL_TRUE, 0, 0, obj);
 
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
_mesa_flush(ctx);
}
}
 
/**
* Like DrawArrays, but take the count from a transform feedback object.
* \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
* \param name the transform feedback object
* User still has to setup of the vertex attribute info with
* glVertexPointer, glColorPointer, etc.
* Part of GL_ARB_transform_feedback2.
*/
static void GLAPIENTRY
vbo_exec_DrawTransformFeedback(GLenum mode, GLuint name)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_transform_feedback_object *obj =
_mesa_lookup_transform_feedback_object(ctx, name);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawTransformFeedback(%s, %d)\n",
_mesa_lookup_enum_by_nr(mode), name);
 
vbo_draw_transform_feedback(ctx, mode, obj, 0, 1);
}
 
static void GLAPIENTRY
vbo_exec_DrawTransformFeedbackStream(GLenum mode, GLuint name, GLuint stream)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_transform_feedback_object *obj =
_mesa_lookup_transform_feedback_object(ctx, name);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawTransformFeedbackStream(%s, %u, %u)\n",
_mesa_lookup_enum_by_nr(mode), name, stream);
 
vbo_draw_transform_feedback(ctx, mode, obj, stream, 1);
}
 
static void GLAPIENTRY
vbo_exec_DrawTransformFeedbackInstanced(GLenum mode, GLuint name,
GLsizei primcount)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_transform_feedback_object *obj =
_mesa_lookup_transform_feedback_object(ctx, name);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawTransformFeedbackInstanced(%s, %d)\n",
_mesa_lookup_enum_by_nr(mode), name);
 
vbo_draw_transform_feedback(ctx, mode, obj, 0, primcount);
}
 
static void GLAPIENTRY
vbo_exec_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name,
GLuint stream, GLsizei primcount)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_transform_feedback_object *obj =
_mesa_lookup_transform_feedback_object(ctx, name);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawTransformFeedbackStreamInstanced"
"(%s, %u, %u, %i)\n",
_mesa_lookup_enum_by_nr(mode), name, stream, primcount);
 
vbo_draw_transform_feedback(ctx, mode, obj, stream, primcount);
}
 
 
/**
* Initialize the dispatch table with the VBO functions for drawing.
*/
void
vbo_initialize_exec_dispatch(const struct gl_context *ctx,
struct _glapi_table *exec)
{
SET_DrawArrays(exec, vbo_exec_DrawArrays);
SET_DrawElements(exec, vbo_exec_DrawElements);
 
if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
SET_DrawRangeElements(exec, vbo_exec_DrawRangeElements);
}
 
SET_MultiDrawElementsEXT(exec, vbo_exec_MultiDrawElements);
 
if (ctx->API == API_OPENGL_COMPAT) {
SET_Rectf(exec, vbo_exec_Rectf);
SET_EvalMesh1(exec, vbo_exec_EvalMesh1);
SET_EvalMesh2(exec, vbo_exec_EvalMesh2);
}
 
if (_mesa_is_desktop_gl(ctx)) {
SET_DrawElementsBaseVertex(exec, vbo_exec_DrawElementsBaseVertex);
SET_DrawRangeElementsBaseVertex(exec, vbo_exec_DrawRangeElementsBaseVertex);
SET_MultiDrawElementsBaseVertex(exec, vbo_exec_MultiDrawElementsBaseVertex);
SET_DrawArraysInstancedBaseInstance(exec, vbo_exec_DrawArraysInstancedBaseInstance);
SET_DrawElementsInstancedBaseInstance(exec, vbo_exec_DrawElementsInstancedBaseInstance);
SET_DrawElementsInstancedBaseVertex(exec, vbo_exec_DrawElementsInstancedBaseVertex);
SET_DrawElementsInstancedBaseVertexBaseInstance(exec, vbo_exec_DrawElementsInstancedBaseVertexBaseInstance);
}
 
if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
SET_DrawArraysInstancedARB(exec, vbo_exec_DrawArraysInstanced);
SET_DrawElementsInstancedARB(exec, vbo_exec_DrawElementsInstanced);
}
 
if (_mesa_is_desktop_gl(ctx)) {
SET_DrawTransformFeedback(exec, vbo_exec_DrawTransformFeedback);
SET_DrawTransformFeedbackStream(exec, vbo_exec_DrawTransformFeedbackStream);
SET_DrawTransformFeedbackInstanced(exec, vbo_exec_DrawTransformFeedbackInstanced);
SET_DrawTransformFeedbackStreamInstanced(exec, vbo_exec_DrawTransformFeedbackStreamInstanced);
}
}
 
 
 
/**
* 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);
}
 
void GLAPIENTRY
_mesa_DrawTransformFeedback(GLenum mode, GLuint name)
{
vbo_exec_DrawTransformFeedback(mode, name);
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_exec_array.c.bak
0,0 → 1,1664
/**************************************************************************
*
* 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/dispatch.h"
#include "main/varray.h"
#include "main/bufferobj.h"
#include "main/enums.h"
#include "main/macros.h"
#include "main/transformfeedback.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.
*/
static 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 GLuint count)
{
const GLboolean restart = ctx->Array._PrimitiveRestart;
const GLuint restartIndex = _mesa_primitive_restart_index(ctx, ib->type);
const int index_size = vbo_sizeof_ib_type(ib->type);
const char *indices;
GLuint i;
 
indices = (char *) ib->ptr + prim->start * index_size;
if (_mesa_is_bufferobj(ib->obj)) {
GLsizeiptr size = MIN2(count * index_size, ib->obj->Size);
indices = ctx->Driver.MapBufferRange(ctx, (GLintptr) indices, size,
GL_MAP_READ_BIT, ib->obj);
}
 
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, ib->obj);
}
}
 
/**
* Compute min and max elements for nr_prims
*/
void
vbo_get_minmax_indices(struct gl_context *ctx,
const struct _mesa_prim *prims,
const struct _mesa_index_buffer *ib,
GLuint *min_index,
GLuint *max_index,
GLuint nr_prims)
{
GLuint tmp_min, tmp_max;
GLuint i;
GLuint count;
 
*min_index = ~0;
*max_index = 0;
 
for (i = 0; i < nr_prims; i++) {
const struct _mesa_prim *start_prim;
 
start_prim = &prims[i];
count = start_prim->count;
/* Do combination if possible to reduce map/unmap count */
while ((i + 1 < nr_prims) &&
(prims[i].start + prims[i].count == prims[i+1].start)) {
count += prims[i+1].count;
i++;
}
vbo_get_minmax_index(ctx, start_prim, ib, &tmp_min, &tmp_max, count);
*min_index = MIN2(*min_index, tmp_min);
*max_index = MAX2(*max_index, tmp_max);
}
}
 
 
/**
* 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.MapBufferRange(ctx, 0, array->BufferObj->Size,
GL_MAP_READ_BIT, 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, 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.ArrayObj->ElementArrayBufferObj)) {
elemMap = ctx->Driver.MapBufferRange(ctx, 0,
ctx->Array.ArrayObj->ElementArrayBufferObj->Size,
GL_MAP_READ_BIT,
ctx->Array.ArrayObj->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 */
for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) {
check_array_data(ctx, &arrayObj->VertexAttrib[k], k, j);
}
}
 
if (_mesa_is_bufferobj(arrayObj->ElementArrayBufferObj)) {
ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj);
}
 
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;
struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
int i;
 
printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n",
mode, start, count);
 
for (i = 0; i < 32; i++) {
struct gl_buffer_object *bufObj = exec->array.inputs[i]->BufferObj;
GLuint bufName = bufObj->Name;
GLint stride = exec->array.inputs[i]->Stride;
printf("attr %2d: size %d stride %d enabled %d "
"ptr %p Bufobj %u\n",
i,
exec->array.inputs[i]->Size,
stride,
/*exec->array.inputs[i]->Enabled,*/
arrayObj->VertexAttrib[VERT_ATTRIB_FF(i)].Enabled,
exec->array.inputs[i]->Ptr,
bufName);
 
if (bufName) {
GLubyte *p = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size,
GL_MAP_READ_BIT, bufObj);
int offset = (int) (GLintptr) exec->array.inputs[i]->Ptr;
float *f = (float *) (p + offset);
int *k = (int *) f;
int i;
int n = (count * stride) / 4;
if (n > 32)
n = 32;
printf(" Data at offset %d:\n", offset);
for (i = 0; i < n; i++) {
printf(" float[%d] = 0x%08x %f\n", i, k[i], f[i]);
}
ctx->Driver.UnmapBuffer(ctx, bufObj);
}
}
}
 
 
/**
* 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;
struct gl_client_array *vertexAttrib = ctx->Array.ArrayObj->VertexAttrib;
const struct gl_client_array **inputs = &exec->array.inputs[0];
GLbitfield64 const_inputs = 0x0;
GLuint i;
 
switch (get_program_mode(ctx)) {
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_FF_MAX; i++) {
if (vertexAttrib[VERT_ATTRIB_FF(i)].Enabled)
inputs[i] = &vertexAttrib[VERT_ATTRIB_FF(i)];
else {
inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
const_inputs |= VERT_BIT(i);
}
}
 
for (i = 0; i < MAT_ATTRIB_MAX; i++) {
inputs[VERT_ATTRIB_GENERIC(i)] =
&vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+i];
const_inputs |= VERT_BIT_GENERIC(i);
}
 
/* Could use just about anything, just to fill in the empty
* slots:
*/
for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_GENERIC_MAX; i++) {
inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->currval[VBO_ATTRIB_GENERIC0+i];
const_inputs |= VERT_BIT_GENERIC(i);
}
break;
 
case VP_ARB:
/* There are no shaders in OpenGL ES 1.x, so this code path should be
* impossible to reach. The meta code is careful to not use shaders in
* ES1.
*/
assert(ctx->API != API_OPENGLES);
 
/* In the compatibility profile of desktop OpenGL, 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.
*
* In all other APIs, only the generic attributes exist, and none of the
* slots are considered "magic."
*/
if (ctx->API == API_OPENGL_COMPAT) {
if (vertexAttrib[VERT_ATTRIB_GENERIC0].Enabled)
inputs[0] = &vertexAttrib[VERT_ATTRIB_GENERIC0];
else if (vertexAttrib[VERT_ATTRIB_POS].Enabled)
inputs[0] = &vertexAttrib[VERT_ATTRIB_POS];
else {
inputs[0] = &vbo->currval[VBO_ATTRIB_POS];
const_inputs |= VERT_BIT_POS;
}
 
for (i = 1; i < VERT_ATTRIB_FF_MAX; i++) {
if (vertexAttrib[VERT_ATTRIB_FF(i)].Enabled)
inputs[i] = &vertexAttrib[VERT_ATTRIB_FF(i)];
else {
inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
const_inputs |= VERT_BIT_FF(i);
}
}
 
for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) {
if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
inputs[VERT_ATTRIB_GENERIC(i)] =
&vertexAttrib[VERT_ATTRIB_GENERIC(i)];
else {
inputs[VERT_ATTRIB_GENERIC(i)] =
&vbo->currval[VBO_ATTRIB_GENERIC0+i];
const_inputs |= VERT_BIT_GENERIC(i);
}
}
 
inputs[VERT_ATTRIB_GENERIC0] = inputs[0];
} else {
/* Other parts of the code assume that inputs[0] through
* inputs[VERT_ATTRIB_FF_MAX] will be non-NULL. However, in OpenGL
* ES 2.0+ or OpenGL core profile, none of these arrays should ever
* be enabled.
*/
for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) {
assert(!vertexAttrib[VERT_ATTRIB_FF(i)].Enabled);
 
inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
const_inputs |= VERT_BIT_FF(i);
}
 
for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) {
if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
inputs[VERT_ATTRIB_GENERIC(i)] =
&vertexAttrib[VERT_ATTRIB_GENERIC(i)];
else {
inputs[VERT_ATTRIB_GENERIC(i)] =
&vbo->currval[VBO_ATTRIB_GENERIC0+i];
const_inputs |= VERT_BIT_GENERIC(i);
}
}
}
 
break;
}
 
_mesa_set_varying_vp_inputs( ctx, VERT_BIT_ALL & (~const_inputs) );
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
}
 
 
/**
* 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_VARYING_VP_INPUTS dirty flag so state
* validation must be done after this call.
*/
void
vbo_bind_arrays(struct gl_context *ctx)
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_exec_context *exec = &vbo->exec;
ENTER();
vbo_draw_method(vbo, DRAW_ARRAYS);
 
if (exec->array.recalculate_inputs) {
recalculate_input_bindings(ctx);
exec->array.recalculate_inputs = GL_FALSE;
 
/* 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) {
/* Setting "validating" to TRUE prevents _mesa_update_state from
* invalidating what we just did.
*/
exec->validating = GL_TRUE;
_mesa_update_state(ctx);
exec->validating = GL_FALSE;
}
}
LEAVE();
}
 
 
/**
* Handle a draw case that potentially has primitive restart enabled.
*
* If primitive restart is enabled, and PrimitiveRestartInSoftware is
* set, then vbo_sw_primitive_restart is used to handle the primitive
* restart case in software.
*/
static void
vbo_handle_primitive_restart(struct gl_context *ctx,
const struct _mesa_prim *prim,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLboolean index_bounds_valid,
GLuint min_index,
GLuint max_index)
{
struct vbo_context *vbo = vbo_context(ctx);
 
if ((ib != NULL) &&
ctx->Const.PrimitiveRestartInSoftware &&
ctx->Array._PrimitiveRestart) {
/* Handle primitive restart in software */
vbo_sw_primitive_restart(ctx, prim, nr_prims, ib);
} else {
/* Call driver directly for draw_prims */
vbo->draw_prims(ctx, prim, nr_prims, ib,
index_bounds_valid, min_index, max_index, NULL);
}
}
 
 
/**
* 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, GLuint baseInstance)
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_exec_context *exec = &vbo->exec;
struct _mesa_prim prim[2];
ENTER();
vbo_bind_arrays(ctx);
 
/* init most fields to zero */
memset(prim, 0, sizeof(prim));
prim[0].begin = 1;
prim[0].end = 1;
prim[0].mode = mode;
prim[0].num_instances = numInstances;
prim[0].base_instance = baseInstance;
 
/* 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, prim, primCount, NULL,
GL_TRUE, start, start + count - 1, NULL);
}
}
else {
/* no prim restart */
prim[0].start = start;
prim[0].count = count;
 
check_buffers_are_unmapped(exec->array.inputs);
vbo->draw_prims(ctx, prim, 1, NULL,
GL_TRUE, start, start + count - 1,
NULL);
}
 
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
_mesa_flush(ctx);
}
LEAVE();
}
 
 
/**
* Execute a glRectf() function.
*/
static void GLAPIENTRY
vbo_exec_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
 
CALL_Begin(GET_DISPATCH(), (GL_QUADS));
CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
CALL_End(GET_DISPATCH(), ());
}
 
 
static void GLAPIENTRY
vbo_exec_EvalMesh1(GLenum mode, GLint i1, GLint i2)
{
GET_CURRENT_CONTEXT(ctx);
GLint i;
GLfloat u, du;
GLenum prim;
 
switch (mode) {
case GL_POINT:
prim = GL_POINTS;
break;
case GL_LINE:
prim = GL_LINE_STRIP;
break;
default:
_mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" );
return;
}
 
/* No effect if vertex maps disabled.
*/
if (!ctx->Eval.Map1Vertex4 &&
!ctx->Eval.Map1Vertex3)
return;
 
du = ctx->Eval.MapGrid1du;
u = ctx->Eval.MapGrid1u1 + i1 * du;
 
CALL_Begin(GET_DISPATCH(), (prim));
for (i=i1;i<=i2;i++,u+=du) {
CALL_EvalCoord1f(GET_DISPATCH(), (u));
}
CALL_End(GET_DISPATCH(), ());
}
 
 
static void GLAPIENTRY
vbo_exec_EvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2)
{
GET_CURRENT_CONTEXT(ctx);
GLfloat u, du, v, dv, v1, u1;
GLint i, j;
 
switch (mode) {
case GL_POINT:
case GL_LINE:
case GL_FILL:
break;
default:
_mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" );
return;
}
 
/* No effect if vertex maps disabled.
*/
if (!ctx->Eval.Map2Vertex4 &&
!ctx->Eval.Map2Vertex3)
return;
 
du = ctx->Eval.MapGrid2du;
dv = ctx->Eval.MapGrid2dv;
v1 = ctx->Eval.MapGrid2v1 + j1 * dv;
u1 = ctx->Eval.MapGrid2u1 + i1 * du;
 
switch (mode) {
case GL_POINT:
CALL_Begin(GET_DISPATCH(), (GL_POINTS));
for (v=v1,j=j1;j<=j2;j++,v+=dv) {
for (u=u1,i=i1;i<=i2;i++,u+=du) {
CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
}
}
CALL_End(GET_DISPATCH(), ());
break;
case GL_LINE:
for (v=v1,j=j1;j<=j2;j++,v+=dv) {
CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
for (u=u1,i=i1;i<=i2;i++,u+=du) {
CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
}
CALL_End(GET_DISPATCH(), ());
}
for (u=u1,i=i1;i<=i2;i++,u+=du) {
CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
for (v=v1,j=j1;j<=j2;j++,v+=dv) {
CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
}
CALL_End(GET_DISPATCH(), ());
}
break;
case GL_FILL:
for (v=v1,j=j1;j<j2;j++,v+=dv) {
CALL_Begin(GET_DISPATCH(), (GL_TRIANGLE_STRIP));
for (u=u1,i=i1;i<=i2;i++,u+=du) {
CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
CALL_EvalCoord2f(GET_DISPATCH(), (u, v+dv));
}
CALL_End(GET_DISPATCH(), ());
}
break;
}
}
 
 
/**
* 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;
 
if (0)
check_draw_arrays_data(ctx, start, count);
 
vbo_draw_arrays(ctx, mode, start, count, 1, 0);
 
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;
 
if (0)
check_draw_arrays_data(ctx, start, count);
 
vbo_draw_arrays(ctx, mode, start, count, numInstances, 0);
 
if (0)
print_draw_arrays(ctx, mode, start, count);
}
 
 
/**
* Called from glDrawArraysInstancedBaseInstance when in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count,
GLsizei numInstances, GLuint baseInstance)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawArraysInstancedBaseInstance(%s, %d, %d, %d, %d)\n",
_mesa_lookup_enum_by_nr(mode), first, count,
numInstances, baseInstance);
 
if (!_mesa_validate_DrawArraysInstanced(ctx, mode, first, count,
numInstances))
return;
 
if (0)
check_draw_arrays_data(ctx, first, count);
 
vbo_draw_arrays(ctx, mode, first, count, numInstances, baseInstance);
 
if (0)
print_draw_arrays(ctx, mode, first, count);
}
 
 
 
/**
* Map GL_ELEMENT_ARRAY_BUFFER and print contents.
* For debugging.
*/
#if 0
static void
dump_element_buffer(struct gl_context *ctx, GLenum type)
{
const GLvoid *map =
ctx->Driver.MapBufferRange(ctx, 0,
ctx->Array.ArrayObj->ElementArrayBufferObj->Size,
GL_MAP_READ_BIT,
ctx->Array.ArrayObj->ElementArrayBufferObj);
switch (type) {
case GL_UNSIGNED_BYTE:
{
const GLubyte *us = (const GLubyte *) map;
GLint i;
for (i = 0; i < ctx->Array.ArrayObj->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.ArrayObj->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.ArrayObj->ElementArrayBufferObj->Size / 4; i++) {
printf("%08x ", us[i]);
if (i % 8 == 7)
printf("\n");
}
printf("\n");
}
break;
default:
;
}
 
ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj);
}
#endif
 
 
/**
* 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, GLuint numInstances,
GLuint baseInstance)
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_exec_context *exec = &vbo->exec;
struct _mesa_index_buffer ib;
struct _mesa_prim prim[1];
 
vbo_bind_arrays(ctx);
 
ib.count = count;
ib.type = type;
ib.obj = ctx->Array.ArrayObj->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;
prim[0].base_instance = baseInstance;
 
/* 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_handle_primitive_restart(ctx, prim, 1, &ib,
index_bounds_valid, start, end);
 
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
_mesa_flush(ctx);
}
}
 
 
/**
* 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;
GLboolean index_bounds_valid = GL_TRUE;
GLuint max_element;
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;
 
if (ctx->Const.CheckArrayBounds) {
/* _MaxElement was computed, so we can use it.
* This path is used for drivers which need strict bounds checking.
*/
max_element = ctx->Array.ArrayObj->_MaxElement;
}
else {
/* Generally, hardware drivers don't need to know the buffer bounds
* if all vertex attributes are in VBOs.
* However, if none of vertex attributes are in VBOs, _MaxElement
* is always set to some random big number anyway, so bounds checking
* is mostly useless.
*
* This is only useful to catch invalid values in the "end" parameter
* like ~0.
*/
max_element = 2 * 1000 * 1000 * 1000; /* just a big number */
}
 
if ((int) end + basevertex < 0 ||
start + basevertex >= max_element) {
/* The application requested we draw using a range of indices that's
* outside the bounds of the current VBO. This is invalid and appears
* to give undefined results. The safest thing to do is to simply
* ignore the range, in case the application botched their range tracking
* but did provide valid indices. Also issue a warning indicating that
* the application is broken.
*/
if (warnCount++ < 10) {
_mesa_warning(ctx, "glDrawRangeElements(start %u, end %u, "
"basevertex %d, count %d, type 0x%x, indices=%p):\n"
"\trange is outside VBO bounds (max=%u); ignoring.\n"
"\tThis should be fixed in the application.",
start, end, basevertex, count, type, indices,
max_element - 1);
}
index_bounds_valid = GL_FALSE;
}
 
/* 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 (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.ArrayObj->ElementArrayBufferObj->Name,
basevertex);
}
 
if ((int) start + basevertex < 0 ||
end + basevertex >= max_element)
index_bounds_valid = GL_FALSE;
 
#if 0
check_draw_elements_data(ctx, count, type, indices);
#else
(void) check_draw_elements_data;
#endif
 
vbo_validated_drawrangeelements(ctx, mode, index_bounds_valid, start, end,
count, type, indices, basevertex, 1, 0);
}
 
 
/**
* Called by glDrawRangeElements() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
GLsizei count, GLenum type, const GLvoid *indices)
{
if (MESA_VERBOSE & VERBOSE_DRAW) {
GET_CURRENT_CONTEXT(ctx);
_mesa_debug(ctx,
"glDrawRangeElements(%s, %u, %u, %d, %s, %p)\n",
_mesa_lookup_enum_by_nr(mode), start, end, count,
_mesa_lookup_enum_by_nr(type), indices);
}
 
vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type,
indices, 0);
}
 
 
/**
* Called by glDrawElements() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawElements(%s, %u, %s, %p)\n",
_mesa_lookup_enum_by_nr(mode), count,
_mesa_lookup_enum_by_nr(type), indices);
 
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 ))
return;
 
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
count, type, indices, 0, 1, 0);
}
 
 
/**
* 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, 0);
}
 
 
/**
* Called by glDrawElementsInstanced() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices, GLsizei numInstances)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawElementsInstanced(%s, %d, %s, %p, %d)\n",
_mesa_lookup_enum_by_nr(mode), count,
_mesa_lookup_enum_by_nr(type), indices, numInstances);
 
if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
numInstances, 0))
return;
 
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
count, type, indices, 0, numInstances, 0);
}
 
 
/**
* Called by glDrawElementsInstancedBaseVertex() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices, GLsizei numInstances,
GLint basevertex)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawElementsInstancedBaseVertex(%s, %d, %s, %p, %d; %d)\n",
_mesa_lookup_enum_by_nr(mode), count,
_mesa_lookup_enum_by_nr(type), indices,
numInstances, basevertex);
 
if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
numInstances, basevertex))
return;
 
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
count, type, indices, basevertex, numInstances, 0);
}
 
 
/**
* Called by glDrawElementsInstancedBaseInstance() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices, GLsizei numInstances,
GLuint baseInstance)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawElementsInstancedBaseInstance(%s, %d, %s, %p, %d, %d)\n",
_mesa_lookup_enum_by_nr(mode), count,
_mesa_lookup_enum_by_nr(type), indices,
numInstances, baseInstance);
 
if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
numInstances, 0))
return;
 
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
count, type, indices, 0, numInstances,
baseInstance);
}
 
 
/**
* Called by glDrawElementsInstancedBaseVertexBaseInstance() in immediate mode.
*/
static void GLAPIENTRY
vbo_exec_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type,
const GLvoid *indices, GLsizei numInstances,
GLint basevertex, GLuint baseInstance)
{
GET_CURRENT_CONTEXT(ctx);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawElementsInstancedBaseVertexBaseInstance(%s, %d, %s, %p, %d, %d, %d)\n",
_mesa_lookup_enum_by_nr(mode), count,
_mesa_lookup_enum_by_nr(type), indices,
numInstances, basevertex, baseInstance);
 
if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
numInstances, basevertex))
return;
 
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
count, type, indices, basevertex, numInstances,
baseInstance);
}
 
 
/**
* 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 * const *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 = vbo_sizeof_ib_type(type);
uintptr_t min_index_ptr, max_index_ptr;
GLboolean fallback = GL_FALSE;
int i;
 
if (primcount == 0)
return;
 
prim = calloc(1, primcount * sizeof(*prim));
if (prim == NULL) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements");
return;
}
 
vbo_bind_arrays(ctx);
 
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.ArrayObj->ElementArrayBufferObj))
fallback = GL_TRUE;
 
if (!fallback) {
ib.count = (max_index_ptr - min_index_ptr) / index_type_size;
ib.type = type;
ib.obj = ctx->Array.ArrayObj->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;
prim[i].base_instance = 0;
if (basevertex != NULL)
prim[i].basevertex = basevertex[i];
else
prim[i].basevertex = 0;
}
 
check_buffers_are_unmapped(exec->array.inputs);
vbo_handle_primitive_restart(ctx, 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.ArrayObj->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;
prim[0].base_instance = 0;
if (basevertex != NULL)
prim[0].basevertex = basevertex[i];
else
prim[0].basevertex = 0;
 
check_buffers_are_unmapped(exec->array.inputs);
vbo_handle_primitive_restart(ctx, prim, 1, &ib,
GL_FALSE, ~0, ~0);
}
}
 
free(prim);
 
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
_mesa_flush(ctx);
}
}
 
 
static void GLAPIENTRY
vbo_exec_MultiDrawElements(GLenum mode,
const GLsizei *count, GLenum type,
const GLvoid * const *indices,
GLsizei primcount)
{
GET_CURRENT_CONTEXT(ctx);
 
if (!_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices,
primcount, NULL))
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 * const *indices,
GLsizei primcount,
const GLsizei *basevertex)
{
GET_CURRENT_CONTEXT(ctx);
 
if (!_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices,
primcount, basevertex))
return;
 
vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount,
basevertex);
}
 
static void
vbo_draw_transform_feedback(struct gl_context *ctx, GLenum mode,
struct gl_transform_feedback_object *obj,
GLuint stream, GLuint numInstances)
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_exec_context *exec = &vbo->exec;
struct _mesa_prim prim[2];
 
if (!_mesa_validate_DrawTransformFeedback(ctx, mode, obj, stream,
numInstances)) {
return;
}
 
vbo_bind_arrays(ctx);
 
/* init most fields to zero */
memset(prim, 0, sizeof(prim));
prim[0].begin = 1;
prim[0].end = 1;
prim[0].mode = mode;
prim[0].num_instances = numInstances;
prim[0].base_instance = 0;
 
/* Maybe we should do some primitive splitting for primitive restart
* (like in DrawArrays), but we have no way to know how many vertices
* will be rendered. */
 
check_buffers_are_unmapped(exec->array.inputs);
vbo->draw_prims(ctx, prim, 1, NULL,
GL_TRUE, 0, 0, obj);
 
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
_mesa_flush(ctx);
}
}
 
/**
* Like DrawArrays, but take the count from a transform feedback object.
* \param mode GL_POINTS, GL_LINES, GL_TRIANGLE_STRIP, etc.
* \param name the transform feedback object
* User still has to setup of the vertex attribute info with
* glVertexPointer, glColorPointer, etc.
* Part of GL_ARB_transform_feedback2.
*/
static void GLAPIENTRY
vbo_exec_DrawTransformFeedback(GLenum mode, GLuint name)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_transform_feedback_object *obj =
_mesa_lookup_transform_feedback_object(ctx, name);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawTransformFeedback(%s, %d)\n",
_mesa_lookup_enum_by_nr(mode), name);
 
vbo_draw_transform_feedback(ctx, mode, obj, 0, 1);
}
 
static void GLAPIENTRY
vbo_exec_DrawTransformFeedbackStream(GLenum mode, GLuint name, GLuint stream)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_transform_feedback_object *obj =
_mesa_lookup_transform_feedback_object(ctx, name);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawTransformFeedbackStream(%s, %u, %u)\n",
_mesa_lookup_enum_by_nr(mode), name, stream);
 
vbo_draw_transform_feedback(ctx, mode, obj, stream, 1);
}
 
static void GLAPIENTRY
vbo_exec_DrawTransformFeedbackInstanced(GLenum mode, GLuint name,
GLsizei primcount)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_transform_feedback_object *obj =
_mesa_lookup_transform_feedback_object(ctx, name);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawTransformFeedbackInstanced(%s, %d)\n",
_mesa_lookup_enum_by_nr(mode), name);
 
vbo_draw_transform_feedback(ctx, mode, obj, 0, primcount);
}
 
static void GLAPIENTRY
vbo_exec_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name,
GLuint stream, GLsizei primcount)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_transform_feedback_object *obj =
_mesa_lookup_transform_feedback_object(ctx, name);
 
if (MESA_VERBOSE & VERBOSE_DRAW)
_mesa_debug(ctx, "glDrawTransformFeedbackStreamInstanced"
"(%s, %u, %u, %i)\n",
_mesa_lookup_enum_by_nr(mode), name, stream, primcount);
 
vbo_draw_transform_feedback(ctx, mode, obj, stream, primcount);
}
 
 
/**
* Initialize the dispatch table with the VBO functions for drawing.
*/
void
vbo_initialize_exec_dispatch(const struct gl_context *ctx,
struct _glapi_table *exec)
{
SET_DrawArrays(exec, vbo_exec_DrawArrays);
SET_DrawElements(exec, vbo_exec_DrawElements);
 
if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
SET_DrawRangeElements(exec, vbo_exec_DrawRangeElements);
}
 
SET_MultiDrawElementsEXT(exec, vbo_exec_MultiDrawElements);
 
if (ctx->API == API_OPENGL_COMPAT) {
SET_Rectf(exec, vbo_exec_Rectf);
SET_EvalMesh1(exec, vbo_exec_EvalMesh1);
SET_EvalMesh2(exec, vbo_exec_EvalMesh2);
}
 
if (_mesa_is_desktop_gl(ctx)) {
SET_DrawElementsBaseVertex(exec, vbo_exec_DrawElementsBaseVertex);
SET_DrawRangeElementsBaseVertex(exec, vbo_exec_DrawRangeElementsBaseVertex);
SET_MultiDrawElementsBaseVertex(exec, vbo_exec_MultiDrawElementsBaseVertex);
SET_DrawArraysInstancedBaseInstance(exec, vbo_exec_DrawArraysInstancedBaseInstance);
SET_DrawElementsInstancedBaseInstance(exec, vbo_exec_DrawElementsInstancedBaseInstance);
SET_DrawElementsInstancedBaseVertex(exec, vbo_exec_DrawElementsInstancedBaseVertex);
SET_DrawElementsInstancedBaseVertexBaseInstance(exec, vbo_exec_DrawElementsInstancedBaseVertexBaseInstance);
}
 
if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
SET_DrawArraysInstancedARB(exec, vbo_exec_DrawArraysInstanced);
SET_DrawElementsInstancedARB(exec, vbo_exec_DrawElementsInstanced);
}
 
if (_mesa_is_desktop_gl(ctx)) {
SET_DrawTransformFeedback(exec, vbo_exec_DrawTransformFeedback);
SET_DrawTransformFeedbackStream(exec, vbo_exec_DrawTransformFeedbackStream);
SET_DrawTransformFeedbackInstanced(exec, vbo_exec_DrawTransformFeedbackInstanced);
SET_DrawTransformFeedbackStreamInstanced(exec, vbo_exec_DrawTransformFeedbackStreamInstanced);
}
}
 
 
 
/**
* 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);
}
 
void GLAPIENTRY
_mesa_DrawTransformFeedback(GLenum mode, GLuint name)
{
vbo_exec_DrawTransformFeedback(mode, name);
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_exec_draw.c
0,0 → 1,433
/*
* Mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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/context.h"
#include "main/enums.h"
#include "main/state.h"
#include "main/vtxfmt.h"
 
#include "vbo_context.h"
#include "vbo_noop.h"
 
 
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;
GLbitfield64 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 < VERT_ATTRIB_FF_MAX; attr++) {
exec->vtx.inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
}
for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
ASSERT(VERT_ATTRIB_GENERIC(attr) < Elements(exec->vtx.inputs));
exec->vtx.inputs[VERT_ATTRIB_GENERIC(attr)] =
&vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr];
}
map = vbo->map_vp_none;
break;
case VP_ARB:
for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
exec->vtx.inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
}
for (attr = 0; attr < VERT_ATTRIB_GENERIC_MAX; attr++) {
ASSERT(VERT_ATTRIB_GENERIC(attr) < Elements(exec->vtx.inputs));
exec->vtx.inputs[VERT_ATTRIB_GENERIC(attr)] =
&vbo->currval[VBO_ATTRIB_GENERIC0+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[VERT_ATTRIB_GENERIC0] = exec->vtx.inputs[0];
exec->vtx.attrsz[VERT_ATTRIB_GENERIC0] = exec->vtx.attrsz[0];
exec->vtx.attrptr[VERT_ATTRIB_GENERIC0] = exec->vtx.attrptr[0];
exec->vtx.attrsz[0] = 0;
}
break;
default:
assert(0);
}
 
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 = exec->vtx.attrtype[src];
arrays[attr].Integer =
vbo_attrtype_to_integer_flag(exec->vtx.attrtype[src]);
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 |= VERT_BIT(attr);
}
}
 
_mesa_set_varying_vp_inputs( ctx, varying_inputs );
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
}
 
 
/**
* Unmap the VBO. This is called before drawing.
*/
static void
vbo_exec_vtx_unmap( struct vbo_exec_context *exec )
{
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, 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, 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 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) {
/* The VBO exists and there's room for more */
if (exec->vtx.bufferobj->Size > 0) {
exec->vtx.buffer_map =
(GLfloat *)ctx->Driver.MapBufferRange(ctx,
exec->vtx.buffer_used,
(VBO_VERT_BUFFER_SIZE -
exec->vtx.buffer_used),
accessRange,
exec->vtx.bufferobj);
exec->vtx.buffer_ptr = exec->vtx.buffer_map;
}
else {
exec->vtx.buffer_ptr = exec->vtx.buffer_map = NULL;
}
}
if (!exec->vtx.buffer_map) {
/* Need to allocate a new VBO */
exec->vtx.buffer_used = 0;
 
if (ctx->Driver.BufferData(ctx, GL_ARRAY_BUFFER_ARB,
VBO_VERT_BUFFER_SIZE,
NULL, usage, exec->vtx.bufferobj)) {
/* buffer allocation worked, now map the buffer */
exec->vtx.buffer_map =
(GLfloat *)ctx->Driver.MapBufferRange(ctx,
0, VBO_VERT_BUFFER_SIZE,
accessRange,
exec->vtx.bufferobj);
}
else {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
exec->vtx.buffer_map = NULL;
}
}
 
exec->vtx.buffer_ptr = exec->vtx.buffer_map;
 
if (!exec->vtx.buffer_map) {
/* out of memory */
_mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt_noop );
}
else {
if (_mesa_using_noop_vtxfmt(ctx->Exec)) {
/* The no-op functions are installed so switch back to regular
* functions. We do this test just to avoid frequent and needless
* calls to _mesa_install_exec_vtxfmt().
*/
_mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt);
}
}
 
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_VARYING_VP_INPUTS
* 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.prim,
exec->vtx.prim_count,
NULL,
GL_TRUE,
0,
exec->vtx.vert_count - 1,
NULL);
 
/* 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;
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_exec_eval.c
0,0 → 1,246
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/macros.h"
#include "math/m_eval.h"
#include "main/dispatch.h"
#include "vbo_exec.h"
 
 
static void clear_active_eval1( struct vbo_exec_context *exec, GLuint attr )
{
assert(attr < Elements(exec->eval.map1));
exec->eval.map1[attr].map = NULL;
}
 
static void clear_active_eval2( struct vbo_exec_context *exec, GLuint attr )
{
assert(attr < Elements(exec->eval.map2));
exec->eval.map2[attr].map = NULL;
}
 
static void set_active_eval1( struct vbo_exec_context *exec, GLuint attr, GLuint dim,
struct gl_1d_map *map )
{
assert(attr < Elements(exec->eval.map1));
if (!exec->eval.map1[attr].map) {
exec->eval.map1[attr].map = map;
exec->eval.map1[attr].sz = dim;
}
}
 
static void set_active_eval2( struct vbo_exec_context *exec, GLuint attr, GLuint dim,
struct gl_2d_map *map )
{
assert(attr < Elements(exec->eval.map2));
if (!exec->eval.map2[attr].map) {
exec->eval.map2[attr].map = map;
exec->eval.map2[attr].sz = dim;
}
}
 
void vbo_exec_eval_update( struct vbo_exec_context *exec )
{
struct gl_context *ctx = exec->ctx;
GLuint attr;
 
/* Vertex program maps have priority over conventional attribs */
 
for (attr = 0; attr < VBO_ATTRIB_FIRST_MATERIAL; attr++) {
clear_active_eval1( exec, attr );
clear_active_eval2( exec, attr );
}
 
if (ctx->Eval.Map1Color4)
set_active_eval1( exec, VBO_ATTRIB_COLOR0, 4, &ctx->EvalMap.Map1Color4 );
if (ctx->Eval.Map2Color4)
set_active_eval2( exec, VBO_ATTRIB_COLOR0, 4, &ctx->EvalMap.Map2Color4 );
 
if (ctx->Eval.Map1TextureCoord4)
set_active_eval1( exec, VBO_ATTRIB_TEX0, 4, &ctx->EvalMap.Map1Texture4 );
else if (ctx->Eval.Map1TextureCoord3)
set_active_eval1( exec, VBO_ATTRIB_TEX0, 3, &ctx->EvalMap.Map1Texture3 );
else if (ctx->Eval.Map1TextureCoord2)
set_active_eval1( exec, VBO_ATTRIB_TEX0, 2, &ctx->EvalMap.Map1Texture2 );
else if (ctx->Eval.Map1TextureCoord1)
set_active_eval1( exec, VBO_ATTRIB_TEX0, 1, &ctx->EvalMap.Map1Texture1 );
 
if (ctx->Eval.Map2TextureCoord4)
set_active_eval2( exec, VBO_ATTRIB_TEX0, 4, &ctx->EvalMap.Map2Texture4 );
else if (ctx->Eval.Map2TextureCoord3)
set_active_eval2( exec, VBO_ATTRIB_TEX0, 3, &ctx->EvalMap.Map2Texture3 );
else if (ctx->Eval.Map2TextureCoord2)
set_active_eval2( exec, VBO_ATTRIB_TEX0, 2, &ctx->EvalMap.Map2Texture2 );
else if (ctx->Eval.Map2TextureCoord1)
set_active_eval2( exec, VBO_ATTRIB_TEX0, 1, &ctx->EvalMap.Map2Texture1 );
 
if (ctx->Eval.Map1Normal)
set_active_eval1( exec, VBO_ATTRIB_NORMAL, 3, &ctx->EvalMap.Map1Normal );
 
if (ctx->Eval.Map2Normal)
set_active_eval2( exec, VBO_ATTRIB_NORMAL, 3, &ctx->EvalMap.Map2Normal );
 
if (ctx->Eval.Map1Vertex4)
set_active_eval1( exec, VBO_ATTRIB_POS, 4, &ctx->EvalMap.Map1Vertex4 );
else if (ctx->Eval.Map1Vertex3)
set_active_eval1( exec, VBO_ATTRIB_POS, 3, &ctx->EvalMap.Map1Vertex3 );
 
if (ctx->Eval.Map2Vertex4)
set_active_eval2( exec, VBO_ATTRIB_POS, 4, &ctx->EvalMap.Map2Vertex4 );
else if (ctx->Eval.Map2Vertex3)
set_active_eval2( exec, VBO_ATTRIB_POS, 3, &ctx->EvalMap.Map2Vertex3 );
 
exec->eval.recalculate_maps = 0;
}
 
 
 
void vbo_exec_do_EvalCoord1f(struct vbo_exec_context *exec, GLfloat u)
{
GLuint attr;
 
for (attr = 1; attr <= VBO_ATTRIB_TEX7; attr++) {
struct gl_1d_map *map = exec->eval.map1[attr].map;
if (map) {
GLfloat uu = (u - map->u1) * map->du;
GLfloat data[4];
 
ASSIGN_4V(data, 0, 0, 0, 1);
 
_math_horner_bezier_curve(map->Points, data, uu,
exec->eval.map1[attr].sz,
map->Order);
 
COPY_SZ_4V( exec->vtx.attrptr[attr],
exec->vtx.attrsz[attr],
data );
}
}
 
/** Vertex -- EvalCoord1f is a noop if this map not enabled:
**/
if (exec->eval.map1[0].map) {
struct gl_1d_map *map = exec->eval.map1[0].map;
GLfloat uu = (u - map->u1) * map->du;
GLfloat vertex[4];
 
ASSIGN_4V(vertex, 0, 0, 0, 1);
 
_math_horner_bezier_curve(map->Points, vertex, uu,
exec->eval.map1[0].sz,
map->Order);
 
if (exec->eval.map1[0].sz == 4)
CALL_Vertex4fv(GET_DISPATCH(), ( vertex ));
else
CALL_Vertex3fv(GET_DISPATCH(), ( vertex ));
}
}
 
 
 
void vbo_exec_do_EvalCoord2f( struct vbo_exec_context *exec,
GLfloat u, GLfloat v )
{
GLuint attr;
 
for (attr = 1; attr <= VBO_ATTRIB_TEX7; attr++) {
struct gl_2d_map *map = exec->eval.map2[attr].map;
if (map) {
GLfloat uu = (u - map->u1) * map->du;
GLfloat vv = (v - map->v1) * map->dv;
GLfloat data[4];
 
ASSIGN_4V(data, 0, 0, 0, 1);
 
_math_horner_bezier_surf(map->Points,
data,
uu, vv,
exec->eval.map2[attr].sz,
map->Uorder, map->Vorder);
 
COPY_SZ_4V( exec->vtx.attrptr[attr],
exec->vtx.attrsz[attr],
data );
}
}
 
/** Vertex -- EvalCoord2f is a noop if this map not enabled:
**/
if (exec->eval.map2[0].map) {
struct gl_2d_map *map = exec->eval.map2[0].map;
GLfloat uu = (u - map->u1) * map->du;
GLfloat vv = (v - map->v1) * map->dv;
GLfloat vertex[4];
 
ASSIGN_4V(vertex, 0, 0, 0, 1);
 
if (exec->ctx->Eval.AutoNormal) {
GLfloat normal[4];
GLfloat du[4], dv[4];
 
_math_de_casteljau_surf(map->Points, vertex, du, dv, uu, vv,
exec->eval.map2[0].sz,
map->Uorder, map->Vorder);
 
if (exec->eval.map2[0].sz == 4) {
du[0] = du[0]*vertex[3] - du[3]*vertex[0];
du[1] = du[1]*vertex[3] - du[3]*vertex[1];
du[2] = du[2]*vertex[3] - du[3]*vertex[2];
dv[0] = dv[0]*vertex[3] - dv[3]*vertex[0];
dv[1] = dv[1]*vertex[3] - dv[3]*vertex[1];
dv[2] = dv[2]*vertex[3] - dv[3]*vertex[2];
}
 
 
CROSS3(normal, du, dv);
NORMALIZE_3FV(normal);
normal[3] = 1.0;
 
COPY_SZ_4V( exec->vtx.attrptr[VBO_ATTRIB_NORMAL],
exec->vtx.attrsz[VBO_ATTRIB_NORMAL],
normal );
 
}
else {
_math_horner_bezier_surf(map->Points, vertex, uu, vv,
exec->eval.map2[0].sz,
map->Uorder, map->Vorder);
}
 
if (exec->vtx.attrsz[0] == 4)
CALL_Vertex4fv(GET_DISPATCH(), ( vertex ));
else
CALL_Vertex3fv(GET_DISPATCH(), ( vertex ));
}
}
 
 
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_noop.c
0,0 → 1,443
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
* Copyright (C) 2011 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, 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
 
 
/**
* GLvertexformat no-op functions. Used in out-of-memory situations.
*/
 
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/dispatch.h"
#include "main/dlist.h"
#include "main/eval.h"
#include "vbo/vbo_noop.h"
 
static void GLAPIENTRY
_mesa_noop_EdgeFlag(GLboolean b)
{
}
 
static void GLAPIENTRY
_mesa_noop_Indexf(GLfloat f)
{
}
 
static void GLAPIENTRY
_mesa_noop_Indexfv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_FogCoordfEXT(GLfloat a)
{
}
 
static void GLAPIENTRY
_mesa_noop_FogCoordfvEXT(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_Normal3f(GLfloat a, GLfloat b, GLfloat c)
{
}
 
static void GLAPIENTRY
_mesa_noop_Normal3fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_Color4f(GLfloat a, GLfloat b, GLfloat c, GLfloat d)
{
}
 
static void GLAPIENTRY
_mesa_noop_Color4fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_Color3f(GLfloat a, GLfloat b, GLfloat c)
{
}
 
static void GLAPIENTRY
_mesa_noop_Color3fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_MultiTexCoord1fARB(GLenum target, GLfloat a)
{
}
 
static void GLAPIENTRY
_mesa_noop_MultiTexCoord1fvARB(GLenum target, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_MultiTexCoord2fARB(GLenum target, GLfloat a, GLfloat b)
{
}
 
static void GLAPIENTRY
_mesa_noop_MultiTexCoord2fvARB(GLenum target, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_MultiTexCoord3fARB(GLenum target, GLfloat a, GLfloat b, GLfloat c)
{
}
 
static void GLAPIENTRY
_mesa_noop_MultiTexCoord3fvARB(GLenum target, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_MultiTexCoord4fARB(GLenum target, GLfloat a, GLfloat b,
GLfloat c, GLfloat d)
{
}
 
static void GLAPIENTRY
_mesa_noop_MultiTexCoord4fvARB(GLenum target, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_SecondaryColor3fEXT(GLfloat a, GLfloat b, GLfloat c)
{
}
 
static void GLAPIENTRY
_mesa_noop_SecondaryColor3fvEXT(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_TexCoord1f(GLfloat a)
{
}
 
static void GLAPIENTRY
_mesa_noop_TexCoord1fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_TexCoord2f(GLfloat a, GLfloat b)
{
}
 
static void GLAPIENTRY
_mesa_noop_TexCoord2fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_TexCoord3f(GLfloat a, GLfloat b, GLfloat c)
{
}
 
static void GLAPIENTRY
_mesa_noop_TexCoord3fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_TexCoord4f(GLfloat a, GLfloat b, GLfloat c, GLfloat d)
{
}
 
static void GLAPIENTRY
_mesa_noop_TexCoord4fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib1fNV(GLuint index, GLfloat x)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib1fvNV(GLuint index, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib2fNV(GLuint index, GLfloat x, GLfloat y)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib2fvNV(GLuint index, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib3fNV(GLuint index, GLfloat x, GLfloat y, GLfloat z)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib3fvNV(GLuint index, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib4fNV(GLuint index, GLfloat x,
GLfloat y, GLfloat z, GLfloat w)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib4fvNV(GLuint index, const GLfloat * v)
{
}
 
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib1fARB(GLuint index, GLfloat x)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib1fvARB(GLuint index, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib2fARB(GLuint index, GLfloat x, GLfloat y)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib2fvARB(GLuint index, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib3fARB(GLuint index, GLfloat x, GLfloat y, GLfloat z)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib3fvARB(GLuint index, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib4fARB(GLuint index, GLfloat x,
GLfloat y, GLfloat z, GLfloat w)
{
}
 
static void GLAPIENTRY
_mesa_noop_VertexAttrib4fvARB(GLuint index, const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_Materialfv(GLenum face, GLenum pname, const GLfloat * params)
{
}
 
static void GLAPIENTRY
_mesa_noop_Vertex2fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_Vertex3fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_Vertex4fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_Vertex2f(GLfloat a, GLfloat b)
{
}
 
static void GLAPIENTRY
_mesa_noop_Vertex3f(GLfloat a, GLfloat b, GLfloat c)
{
}
 
static void GLAPIENTRY
_mesa_noop_Vertex4f(GLfloat a, GLfloat b, GLfloat c, GLfloat d)
{
}
 
static void GLAPIENTRY
_mesa_noop_EvalCoord1f(GLfloat a)
{
}
 
static void GLAPIENTRY
_mesa_noop_EvalCoord1fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_EvalCoord2f(GLfloat a, GLfloat b)
{
}
 
static void GLAPIENTRY
_mesa_noop_EvalCoord2fv(const GLfloat * v)
{
}
 
static void GLAPIENTRY
_mesa_noop_EvalPoint1(GLint a)
{
}
 
static void GLAPIENTRY
_mesa_noop_EvalPoint2(GLint a, GLint b)
{
}
 
static void GLAPIENTRY
_mesa_noop_ArrayElement(GLint elem)
{
}
 
 
static void GLAPIENTRY
_mesa_noop_Begin(GLenum mode)
{
}
 
static void GLAPIENTRY
_mesa_noop_End(void)
{
}
 
static void GLAPIENTRY
_mesa_noop_PrimitiveRestartNV(void)
{
}
 
 
/**
* Build a vertexformat of functions that are no-ops.
* These are used in out-of-memory situations when we have no VBO
* to put the vertex data into.
*/
void
_mesa_noop_vtxfmt_init(GLvertexformat * vfmt)
{
vfmt->ArrayElement = _mesa_noop_ArrayElement;
 
vfmt->Begin = _mesa_noop_Begin;
 
vfmt->CallList = _mesa_CallList;
vfmt->CallLists = _mesa_CallLists;
 
vfmt->Color3f = _mesa_noop_Color3f;
vfmt->Color3fv = _mesa_noop_Color3fv;
vfmt->Color4f = _mesa_noop_Color4f;
vfmt->Color4fv = _mesa_noop_Color4fv;
vfmt->EdgeFlag = _mesa_noop_EdgeFlag;
vfmt->End = _mesa_noop_End;
 
vfmt->PrimitiveRestartNV = _mesa_noop_PrimitiveRestartNV;
 
vfmt->EvalCoord1f = _mesa_noop_EvalCoord1f;
vfmt->EvalCoord1fv = _mesa_noop_EvalCoord1fv;
vfmt->EvalCoord2f = _mesa_noop_EvalCoord2f;
vfmt->EvalCoord2fv = _mesa_noop_EvalCoord2fv;
vfmt->EvalPoint1 = _mesa_noop_EvalPoint1;
vfmt->EvalPoint2 = _mesa_noop_EvalPoint2;
 
vfmt->FogCoordfEXT = _mesa_noop_FogCoordfEXT;
vfmt->FogCoordfvEXT = _mesa_noop_FogCoordfvEXT;
vfmt->Indexf = _mesa_noop_Indexf;
vfmt->Indexfv = _mesa_noop_Indexfv;
vfmt->Materialfv = _mesa_noop_Materialfv;
vfmt->MultiTexCoord1fARB = _mesa_noop_MultiTexCoord1fARB;
vfmt->MultiTexCoord1fvARB = _mesa_noop_MultiTexCoord1fvARB;
vfmt->MultiTexCoord2fARB = _mesa_noop_MultiTexCoord2fARB;
vfmt->MultiTexCoord2fvARB = _mesa_noop_MultiTexCoord2fvARB;
vfmt->MultiTexCoord3fARB = _mesa_noop_MultiTexCoord3fARB;
vfmt->MultiTexCoord3fvARB = _mesa_noop_MultiTexCoord3fvARB;
vfmt->MultiTexCoord4fARB = _mesa_noop_MultiTexCoord4fARB;
vfmt->MultiTexCoord4fvARB = _mesa_noop_MultiTexCoord4fvARB;
vfmt->Normal3f = _mesa_noop_Normal3f;
vfmt->Normal3fv = _mesa_noop_Normal3fv;
vfmt->SecondaryColor3fEXT = _mesa_noop_SecondaryColor3fEXT;
vfmt->SecondaryColor3fvEXT = _mesa_noop_SecondaryColor3fvEXT;
vfmt->TexCoord1f = _mesa_noop_TexCoord1f;
vfmt->TexCoord1fv = _mesa_noop_TexCoord1fv;
vfmt->TexCoord2f = _mesa_noop_TexCoord2f;
vfmt->TexCoord2fv = _mesa_noop_TexCoord2fv;
vfmt->TexCoord3f = _mesa_noop_TexCoord3f;
vfmt->TexCoord3fv = _mesa_noop_TexCoord3fv;
vfmt->TexCoord4f = _mesa_noop_TexCoord4f;
vfmt->TexCoord4fv = _mesa_noop_TexCoord4fv;
vfmt->Vertex2f = _mesa_noop_Vertex2f;
vfmt->Vertex2fv = _mesa_noop_Vertex2fv;
vfmt->Vertex3f = _mesa_noop_Vertex3f;
vfmt->Vertex3fv = _mesa_noop_Vertex3fv;
vfmt->Vertex4f = _mesa_noop_Vertex4f;
vfmt->Vertex4fv = _mesa_noop_Vertex4fv;
vfmt->VertexAttrib1fNV = _mesa_noop_VertexAttrib1fNV;
vfmt->VertexAttrib1fvNV = _mesa_noop_VertexAttrib1fvNV;
vfmt->VertexAttrib2fNV = _mesa_noop_VertexAttrib2fNV;
vfmt->VertexAttrib2fvNV = _mesa_noop_VertexAttrib2fvNV;
vfmt->VertexAttrib3fNV = _mesa_noop_VertexAttrib3fNV;
vfmt->VertexAttrib3fvNV = _mesa_noop_VertexAttrib3fvNV;
vfmt->VertexAttrib4fNV = _mesa_noop_VertexAttrib4fNV;
vfmt->VertexAttrib4fvNV = _mesa_noop_VertexAttrib4fvNV;
vfmt->VertexAttrib1fARB = _mesa_noop_VertexAttrib1fARB;
vfmt->VertexAttrib1fvARB = _mesa_noop_VertexAttrib1fvARB;
vfmt->VertexAttrib2fARB = _mesa_noop_VertexAttrib2fARB;
vfmt->VertexAttrib2fvARB = _mesa_noop_VertexAttrib2fvARB;
vfmt->VertexAttrib3fARB = _mesa_noop_VertexAttrib3fARB;
vfmt->VertexAttrib3fvARB = _mesa_noop_VertexAttrib3fvARB;
vfmt->VertexAttrib4fARB = _mesa_noop_VertexAttrib4fARB;
vfmt->VertexAttrib4fvARB = _mesa_noop_VertexAttrib4fvARB;
}
 
 
/**
* Is the given dispatch table using the no-op functions?
*/
GLboolean
_mesa_using_noop_vtxfmt(const struct _glapi_table *dispatch)
{
return GET_Begin((struct _glapi_table *) dispatch) == _mesa_noop_Begin;
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_noop.h
0,0 → 1,40
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
* Copyright (C) 2011 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, 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
 
#ifndef _API_NOOP_H
#define _API_NOOP_H
 
 
#include "main/mtypes.h"
 
 
extern void
_mesa_noop_vtxfmt_init(GLvertexformat *vfmt);
 
extern GLboolean
_mesa_using_noop_vtxfmt(const struct _glapi_table *dispatch);
 
 
#endif /* _API_NOOP_H */
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_primitive_restart.c
0,0 → 1,232
/*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Copyright © 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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:
* Jordan Justen <jordan.l.justen@intel.com>
*
*/
 
#include "main/imports.h"
#include "main/bufferobj.h"
#include "main/macros.h"
#include "main/varray.h"
 
#include "vbo.h"
#include "vbo_context.h"
 
#define UPDATE_MIN2(a, b) (a) = MIN2((a), (b))
#define UPDATE_MAX2(a, b) (a) = MAX2((a), (b))
 
/*
* Notes on primitive restart:
* The code below is used when the driver does not support primitive
* restart itself. (ctx->Const.PrimitiveRestartInSoftware == GL_TRUE)
*
* We map the index buffer, find the restart indexes, unmap
* the index buffer then draw the sub-primitives delineated by the restarts.
*
* A couple possible optimizations:
* 1. Save the list of sub-primitive (start, count) values in a list attached
* to the index buffer for re-use in subsequent draws. The list would be
* invalidated when the contents of the buffer changed.
* 2. If drawing triangle strips or quad strips, create a new index buffer
* that uses duplicated vertices to render the disjoint strips as one
* long strip. We'd have to be careful to avoid using too much memory
* for this.
*
* Finally, some apps might perform better if they don't use primitive restart
* at all rather than this fallback path. Set MESA_EXTENSION_OVERRIDE to
* "-GL_NV_primitive_restart" to test that.
*/
 
 
struct sub_primitive
{
GLuint start;
GLuint count;
GLuint min_index;
GLuint max_index;
};
 
 
/**
* Scan the elements array to find restart indexes. Return an array
* of struct sub_primitive to indicate how to draw the sub-primitives
* are delineated by the restart index.
*/
static struct sub_primitive *
find_sub_primitives(const void *elements, unsigned element_size,
unsigned start, unsigned end, unsigned restart_index,
unsigned *num_sub_prims)
{
const unsigned max_prims = end - start;
struct sub_primitive *sub_prims;
unsigned i, cur_start, cur_count;
GLuint scan_index;
unsigned scan_num;
 
sub_prims =
malloc(max_prims * sizeof(struct sub_primitive));
 
if (!sub_prims) {
*num_sub_prims = 0;
return NULL;
}
 
cur_start = start;
cur_count = 0;
scan_num = 0;
 
#define IB_INDEX_READ(TYPE, INDEX) (((const GL##TYPE *) elements)[INDEX])
 
#define SCAN_ELEMENTS(TYPE) \
sub_prims[scan_num].min_index = (GL##TYPE) 0xffffffff; \
sub_prims[scan_num].max_index = 0; \
for (i = start; i < end; i++) { \
scan_index = IB_INDEX_READ(TYPE, i); \
if (scan_index == restart_index) { \
if (cur_count > 0) { \
assert(scan_num < max_prims); \
sub_prims[scan_num].start = cur_start; \
sub_prims[scan_num].count = cur_count; \
scan_num++; \
sub_prims[scan_num].min_index = (GL##TYPE) 0xffffffff; \
sub_prims[scan_num].max_index = 0; \
} \
cur_start = i + 1; \
cur_count = 0; \
} \
else { \
UPDATE_MIN2(sub_prims[scan_num].min_index, scan_index); \
UPDATE_MAX2(sub_prims[scan_num].max_index, scan_index); \
cur_count++; \
} \
} \
if (cur_count > 0) { \
assert(scan_num < max_prims); \
sub_prims[scan_num].start = cur_start; \
sub_prims[scan_num].count = cur_count; \
scan_num++; \
}
 
switch (element_size) {
case 1:
SCAN_ELEMENTS(ubyte);
break;
case 2:
SCAN_ELEMENTS(ushort);
break;
case 4:
SCAN_ELEMENTS(uint);
break;
default:
assert(0 && "bad index_size in find_sub_primitives()");
}
 
#undef SCAN_ELEMENTS
 
*num_sub_prims = scan_num;
 
return sub_prims;
}
 
 
/**
* Handle primitive restart in software.
*
* This function breaks up calls into the driver so primitive restart
* support is not required in the driver.
*/
void
vbo_sw_primitive_restart(struct gl_context *ctx,
const struct _mesa_prim *prims,
GLuint nr_prims,
const struct _mesa_index_buffer *ib)
{
GLuint prim_num;
struct sub_primitive *sub_prims;
struct sub_primitive *sub_prim;
GLuint num_sub_prims;
GLuint sub_prim_num;
GLuint end_index;
GLuint sub_end_index;
GLuint restart_index = _mesa_primitive_restart_index(ctx, ib->type);
struct _mesa_prim temp_prim;
struct vbo_context *vbo = vbo_context(ctx);
vbo_draw_func draw_prims_func = vbo->draw_prims;
GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer;
void *ptr;
 
/* Find the sub-primitives. These are regions in the index buffer which
* are split based on the primitive restart index value.
*/
if (map_ib) {
ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT,
ib->obj);
}
 
ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
 
sub_prims = find_sub_primitives(ptr, vbo_sizeof_ib_type(ib->type),
0, ib->count, restart_index,
&num_sub_prims);
 
if (map_ib) {
ctx->Driver.UnmapBuffer(ctx, ib->obj);
}
 
/* Loop over the primitives, and use the located sub-primitives to draw
* each primitive with a break to implement each primitive restart.
*/
for (prim_num = 0; prim_num < nr_prims; prim_num++) {
end_index = prims[prim_num].start + prims[prim_num].count;
memcpy(&temp_prim, &prims[prim_num], sizeof (temp_prim));
/* Loop over the sub-primitives drawing sub-ranges of the primitive. */
for (sub_prim_num = 0; sub_prim_num < num_sub_prims; sub_prim_num++) {
sub_prim = &sub_prims[sub_prim_num];
sub_end_index = sub_prim->start + sub_prim->count;
if (prims[prim_num].start <= sub_prim->start) {
temp_prim.start = MAX2(prims[prim_num].start, sub_prim->start);
temp_prim.count = MIN2(sub_end_index, end_index) - temp_prim.start;
if ((temp_prim.start == sub_prim->start) &&
(temp_prim.count == sub_prim->count)) {
draw_prims_func(ctx, &temp_prim, 1, ib,
GL_TRUE, sub_prim->min_index, sub_prim->max_index,
NULL);
} else {
draw_prims_func(ctx, &temp_prim, 1, ib,
GL_FALSE, -1, -1,
NULL);
}
}
if (sub_end_index >= end_index) {
break;
}
}
}
 
free(sub_prims);
}
 
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_rebase.c
0,0 → 1,251
 
/*
* Mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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>
*/
 
/* Helper for drivers which find themselves rendering a range of
* indices starting somewhere above zero. Typically the application
* is issuing multiple DrawArrays() or DrawElements() to draw
* successive primitives layed out linearly in the vertex arrays.
* Unless the vertex arrays are all in a VBO, the OpenGL semantics
* imply that we need to re-upload the vertex data on each draw call.
* In that case, 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 will be transformed and lit.
*
* If we just upload the new data, however, the indices will be
* incorrect as we tend to upload each set of vertex data to a new
* region.
*
* This file provides a helper to adjust the arrays, primitives and
* indices of a draw call so that it can be re-issued with a min_index
* of zero.
*/
 
#include "main/glheader.h"
#include "main/imports.h"
#include "main/mtypes.h"
 
#include "vbo.h"
 
 
#define REBASE(TYPE) \
static void *rebase_##TYPE( const void *ptr, \
GLuint count, \
TYPE min_index ) \
{ \
const TYPE *in = (TYPE *)ptr; \
TYPE *tmp_indices = malloc(count * sizeof(TYPE)); \
GLuint i; \
\
for (i = 0; i < count; i++) \
tmp_indices[i] = in[i] - min_index; \
\
return (void *)tmp_indices; \
}
 
 
REBASE(GLuint)
REBASE(GLushort)
REBASE(GLubyte)
 
GLboolean vbo_all_varyings_in_vbos( const struct gl_client_array *arrays[] )
{
GLuint i;
for (i = 0; i < VERT_ATTRIB_MAX; i++)
if (arrays[i]->StrideB &&
arrays[i]->BufferObj->Name == 0)
return GL_FALSE;
 
return GL_TRUE;
}
 
GLboolean vbo_any_varyings_in_vbos( const struct gl_client_array *arrays[] )
{
GLuint i;
 
for (i = 0; i < VERT_ATTRIB_MAX; i++)
if (arrays[i]->BufferObj->Name != 0)
return GL_TRUE;
 
return GL_FALSE;
}
 
/* Adjust primitives, indices and vertex definitions so that min_index
* becomes zero. There are lots of reasons for wanting to do this, eg:
*
* Software tnl:
* - any time min_index != 0, otherwise unused vertices lower than
* min_index will be transformed.
*
* Hardware tnl:
* - if ib != NULL and min_index != 0, otherwise vertices lower than
* min_index will be uploaded. Requires adjusting index values.
*
* - if ib == NULL and min_index != 0, just for convenience so this doesn't
* have to be handled within the driver.
*
* Hardware tnl with VBO support:
* - as above, but only when vertices are not (all?) in VBO's.
* - can't save time by trying to upload half a vbo - typically it is
* all or nothing.
*/
void vbo_rebase_prims( struct gl_context *ctx,
const struct gl_client_array *arrays[],
const struct _mesa_prim *prim,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index,
vbo_draw_func draw )
{
struct gl_client_array tmp_arrays[VERT_ATTRIB_MAX];
const struct gl_client_array *tmp_array_pointers[VERT_ATTRIB_MAX];
 
struct _mesa_index_buffer tmp_ib;
struct _mesa_prim *tmp_prims = NULL;
const struct gl_client_array **saved_arrays = ctx->Array._DrawArrays;
void *tmp_indices = NULL;
GLuint i;
 
assert(min_index != 0);
 
if (0)
printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
 
 
/* XXX this path is disabled for now.
* There's rendering corruption in some apps when it's enabled.
*/
if (0 && ib && ctx->Extensions.ARB_draw_elements_base_vertex) {
/* If we can just tell the hardware or the TNL to interpret our
* indices with a different base, do so.
*/
tmp_prims = malloc(sizeof(*prim) * nr_prims);
 
for (i = 0; i < nr_prims; i++) {
tmp_prims[i] = prim[i];
tmp_prims[i].basevertex -= min_index;
}
 
prim = tmp_prims;
} else if (ib) {
/* Unfortunately need to adjust each index individually.
*/
GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer;
void *ptr;
 
if (map_ib)
ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT,
ib->obj);
 
 
ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
 
/* Some users might prefer it if we translated elements to
* GLuints here. Others wouldn't...
*/
switch (ib->type) {
case GL_UNSIGNED_INT:
tmp_indices = rebase_GLuint( ptr, ib->count, min_index );
break;
case GL_UNSIGNED_SHORT:
tmp_indices = rebase_GLushort( ptr, ib->count, min_index );
break;
case GL_UNSIGNED_BYTE:
tmp_indices = rebase_GLubyte( ptr, ib->count, min_index );
break;
}
 
if (map_ib)
ctx->Driver.UnmapBuffer(ctx, ib->obj);
 
tmp_ib.obj = ctx->Shared->NullBufferObj;
tmp_ib.ptr = tmp_indices;
tmp_ib.count = ib->count;
tmp_ib.type = ib->type;
 
ib = &tmp_ib;
}
else {
/* Otherwise the primitives need adjustment.
*/
tmp_prims = malloc(sizeof(*prim) * nr_prims);
 
for (i = 0; i < nr_prims; i++) {
/* If this fails, it could indicate an application error:
*/
assert(prim[i].start >= min_index);
 
tmp_prims[i] = prim[i];
tmp_prims[i].start -= min_index;
}
 
prim = tmp_prims;
}
 
/* Just need to adjust the pointer values on each incoming array.
* This works for VBO and non-vbo rendering and shouldn't pesimize
* VBO-based upload schemes. However this may still not be a fast
* path for hardware tnl for VBO based rendering as most machines
* will be happier if you just specify a starting vertex value in
* each primitive.
*
* For drivers with hardware tnl, you only want to do this if you
* are forced to, eg non-VBO indexed rendering with start != 0.
*/
for (i = 0; i < VERT_ATTRIB_MAX; i++) {
tmp_arrays[i] = *arrays[i];
tmp_arrays[i].Ptr += min_index * tmp_arrays[i].StrideB;
tmp_array_pointers[i] = &tmp_arrays[i];
}
/* Re-issue the draw call.
*/
ctx->Array._DrawArrays = tmp_array_pointers;
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
 
draw( ctx,
prim,
nr_prims,
ib,
GL_TRUE,
0,
max_index - min_index,
NULL );
 
ctx->Array._DrawArrays = saved_arrays;
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
free(tmp_indices);
free(tmp_prims);
}
 
 
 
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_save.c
0,0 → 1,129
/*
* Mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
 
 
#include "main/mtypes.h"
#include "main/bufferobj.h"
#include "main/imports.h"
 
#include "vbo_context.h"
 
 
static void vbo_save_callback_init( struct gl_context *ctx )
{
ctx->Driver.NewList = vbo_save_NewList;
ctx->Driver.EndList = vbo_save_EndList;
ctx->Driver.SaveFlushVertices = vbo_save_SaveFlushVertices;
ctx->Driver.BeginCallList = vbo_save_BeginCallList;
ctx->Driver.EndCallList = vbo_save_EndCallList;
ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
}
 
 
 
/**
* Called at context creation time.
*/
void vbo_save_init( struct gl_context *ctx )
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_save_context *save = &vbo->save;
 
save->ctx = ctx;
 
vbo_save_api_init( save );
vbo_save_callback_init(ctx);
 
{
struct gl_client_array *arrays = save->arrays;
unsigned i;
 
memcpy(arrays, &vbo->currval[VBO_ATTRIB_POS],
VERT_ATTRIB_FF_MAX * sizeof(arrays[0]));
for (i = 0; i < VERT_ATTRIB_FF_MAX; ++i) {
struct gl_client_array *array;
array = &arrays[VERT_ATTRIB_FF(i)];
array->BufferObj = NULL;
_mesa_reference_buffer_object(ctx, &arrays->BufferObj,
vbo->currval[VBO_ATTRIB_POS+i].BufferObj);
}
 
memcpy(arrays + VERT_ATTRIB_GENERIC(0),
&vbo->currval[VBO_ATTRIB_GENERIC0],
VERT_ATTRIB_GENERIC_MAX * sizeof(arrays[0]));
 
for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; ++i) {
struct gl_client_array *array;
array = &arrays[VERT_ATTRIB_GENERIC(i)];
array->BufferObj = NULL;
_mesa_reference_buffer_object(ctx, &array->BufferObj,
vbo->currval[VBO_ATTRIB_GENERIC0+i].BufferObj);
}
}
 
ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
}
 
 
void vbo_save_destroy( struct gl_context *ctx )
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_save_context *save = &vbo->save;
GLuint i;
 
if (save->prim_store) {
if ( --save->prim_store->refcount == 0 ) {
free(save->prim_store);
save->prim_store = NULL;
}
if ( --save->vertex_store->refcount == 0 ) {
_mesa_reference_buffer_object(ctx,
&save->vertex_store->bufferobj, NULL);
free(save->vertex_store);
save->vertex_store = NULL;
}
}
 
for (i = 0; i < VBO_ATTRIB_MAX; i++) {
_mesa_reference_buffer_object(ctx, &save->arrays[i].BufferObj, NULL);
}
}
 
 
 
 
/* Note that this can occur during the playback of a display list:
*/
void vbo_save_fallback( struct gl_context *ctx, GLboolean fallback )
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
 
if (fallback)
save->replay_flags |= VBO_SAVE_FALLBACK;
else
save->replay_flags &= ~VBO_SAVE_FALLBACK;
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_save.h
0,0 → 1,197
/**************************************************************************
 
Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
 
All Rights Reserved.
 
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
on the rights to use, copy, modify, merge, publish, distribute, sub
license, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
 
**************************************************************************/
 
/*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*
*/
 
#ifndef VBO_SAVE_H
#define VBO_SAVE_H
 
#include "main/mtypes.h"
#include "vbo.h"
#include "vbo_attrib.h"
 
 
struct vbo_save_copied_vtx {
GLfloat buffer[VBO_ATTRIB_MAX * 4 * VBO_MAX_COPIED_VERTS];
GLuint nr;
};
 
 
/* For display lists, this structure holds a run of vertices of the
* same format, and a strictly well-formed set of begin/end pairs,
* starting on the first vertex and ending at the last. Vertex
* copying on buffer breaks is precomputed according to these
* primitives, though there are situations where the copying will need
* correction at execute-time, perhaps by replaying the list as
* immediate mode commands.
*
* On executing this list, the 'current' values may be updated with
* the values of the final vertex, and often no fixup of the start of
* the vertex list is required.
*
* Eval and other commands that don't fit into these vertex lists are
* compiled using the fallback opcode mechanism provided by dlist.c.
*/
struct vbo_save_vertex_list {
GLubyte attrsz[VBO_ATTRIB_MAX];
GLenum attrtype[VBO_ATTRIB_MAX];
GLuint vertex_size;
 
/* Copy of the final vertex from node->vertex_store->bufferobj.
* Keep this in regular (non-VBO) memory to avoid repeated
* map/unmap of the VBO when updating GL current data.
*/
GLfloat *current_data;
GLuint current_size;
 
GLuint buffer_offset;
GLuint count; /**< vertex count */
GLuint wrap_count; /* number of copied vertices at start */
GLboolean dangling_attr_ref; /* current attr implicitly referenced
outside the list */
 
struct _mesa_prim *prim;
GLuint prim_count;
 
struct vbo_save_vertex_store *vertex_store;
struct vbo_save_primitive_store *prim_store;
};
 
/* These buffers should be a reasonable size to support upload to
* hardware. Current vbo implementation will re-upload on any
* changes, so don't make too big or apps which dynamically create
* dlists and use only a few times will suffer.
*
* Consider stategy of uploading regions from the VBO on demand in the
* case of dynamic vbos. Then make the dlist code signal that
* likelyhood as it occurs. No reason we couldn't change usage
* internally even though this probably isn't allowed for client VBOs?
*/
#define VBO_SAVE_BUFFER_SIZE (8*1024) /* dwords */
#define VBO_SAVE_PRIM_SIZE 128
#define VBO_SAVE_PRIM_MODE_MASK 0x3f
#define VBO_SAVE_PRIM_WEAK 0x40
#define VBO_SAVE_PRIM_NO_CURRENT_UPDATE 0x80
 
#define VBO_SAVE_FALLBACK 0x10000000
 
/* Storage to be shared among several vertex_lists.
*/
struct vbo_save_vertex_store {
struct gl_buffer_object *bufferobj;
GLfloat *buffer;
GLuint used;
GLuint refcount;
};
 
struct vbo_save_primitive_store {
struct _mesa_prim buffer[VBO_SAVE_PRIM_SIZE];
GLuint used;
GLuint refcount;
};
 
 
struct vbo_save_context {
struct gl_context *ctx;
GLvertexformat vtxfmt;
GLvertexformat vtxfmt_noop; /**< Used if out_of_memory is true */
struct gl_client_array arrays[VBO_ATTRIB_MAX];
const struct gl_client_array *inputs[VBO_ATTRIB_MAX];
 
GLubyte attrsz[VBO_ATTRIB_MAX]; /**< 1, 2, 3 or 4 */
GLenum attrtype[VBO_ATTRIB_MAX]; /**< GL_FLOAT, GL_INT, etc */
GLubyte active_sz[VBO_ATTRIB_MAX]; /**< 1, 2, 3 or 4 */
GLuint vertex_size; /**< size in GLfloats */
 
GLboolean out_of_memory; /**< True if last VBO allocation failed */
 
GLfloat *buffer;
GLuint count;
GLuint wrap_count;
GLuint replay_flags;
 
struct _mesa_prim *prim;
GLuint prim_count, prim_max;
 
struct vbo_save_vertex_store *vertex_store;
struct vbo_save_primitive_store *prim_store;
 
GLfloat *buffer_ptr; /* cursor, points into buffer */
GLfloat vertex[VBO_ATTRIB_MAX*4]; /* current values */
GLfloat *attrptr[VBO_ATTRIB_MAX];
GLuint vert_count;
GLuint max_vert;
GLboolean dangling_attr_ref;
 
GLuint opcode_vertex_list;
 
struct vbo_save_copied_vtx copied;
GLfloat *current[VBO_ATTRIB_MAX]; /* points into ctx->ListState */
GLubyte *currentsz[VBO_ATTRIB_MAX];
};
 
void vbo_save_init( struct gl_context *ctx );
void vbo_save_destroy( struct gl_context *ctx );
void vbo_save_fallback( struct gl_context *ctx, GLboolean fallback );
 
/* save_loopback.c:
*/
void vbo_loopback_vertex_list( struct gl_context *ctx,
const GLfloat *buffer,
const GLubyte *attrsz,
const struct _mesa_prim *prim,
GLuint prim_count,
GLuint wrap_count,
GLuint vertex_size);
 
/* Callbacks:
*/
void vbo_save_EndList( struct gl_context *ctx );
void vbo_save_NewList( struct gl_context *ctx, GLuint list, GLenum mode );
void vbo_save_EndCallList( struct gl_context *ctx );
void vbo_save_BeginCallList( struct gl_context *ctx, struct gl_display_list *list );
void vbo_save_SaveFlushVertices( struct gl_context *ctx );
GLboolean vbo_save_NotifyBegin( struct gl_context *ctx, GLenum mode );
 
void vbo_save_playback_vertex_list( struct gl_context *ctx, void *data );
 
void vbo_save_api_init( struct vbo_save_context *save );
 
GLfloat *
vbo_save_map_vertex_store(struct gl_context *ctx,
struct vbo_save_vertex_store *vertex_store);
 
void
vbo_save_unmap_vertex_store(struct gl_context *ctx,
struct vbo_save_vertex_store *vertex_store);
 
#endif /* VBO_SAVE_H */
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_save_api.c
0,0 → 1,1571
/**************************************************************************
 
Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
 
All Rights Reserved.
 
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
on the rights to use, copy, modify, merge, publish, distribute, sub
license, and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
 
**************************************************************************/
 
/*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
 
 
 
/* Display list compiler attempts to store lists of vertices with the
* same vertex layout. Additionally it attempts to minimize the need
* for execute-time fixup of these vertex lists, allowing them to be
* cached on hardware.
*
* There are still some circumstances where this can be thwarted, for
* example by building a list that consists of one very long primitive
* (eg Begin(Triangles), 1000 vertices, End), and calling that list
* from inside a different begin/end object (Begin(Lines), CallList,
* End).
*
* In that case the code will have to replay the list as individual
* commands through the Exec dispatch table, or fix up the copied
* vertices at execute-time.
*
* The other case where fixup is required is when a vertex attribute
* is introduced in the middle of a primitive. Eg:
* Begin(Lines)
* TexCoord1f() Vertex2f()
* TexCoord1f() Color3f() Vertex2f()
* End()
*
* If the current value of Color isn't known at compile-time, this
* primitive will require fixup.
*
*
* The list compiler currently doesn't attempt to compile lists
* containing EvalCoord or EvalPoint commands. On encountering one of
* these, compilation falls back to opcodes.
*
* This could be improved to fallback only when a mix of EvalCoord and
* Vertex commands are issued within a single primitive.
*/
 
 
#include "main/glheader.h"
#include "main/bufferobj.h"
#include "main/context.h"
#include "main/dlist.h"
#include "main/enums.h"
#include "main/eval.h"
#include "main/macros.h"
#include "main/api_validate.h"
#include "main/api_arrayelt.h"
#include "main/vtxfmt.h"
#include "main/dispatch.h"
 
#include "vbo_context.h"
#include "vbo_noop.h"
 
 
#ifdef ERROR
#undef ERROR
#endif
 
 
/* An interesting VBO number/name to help with debugging */
#define VBO_BUF_ID 12345
 
 
/*
* NOTE: Old 'parity' issue is gone, but copying can still be
* wrong-footed on replay.
*/
static GLuint
_save_copy_vertices(struct gl_context *ctx,
const struct vbo_save_vertex_list *node,
const GLfloat * src_buffer)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
GLuint nr = prim->count;
GLuint sz = save->vertex_size;
const GLfloat *src = src_buffer + prim->start * sz;
GLfloat *dst = save->copied.buffer;
GLuint ovf, i;
 
if (prim->end)
return 0;
 
switch (prim->mode) {
case GL_POINTS:
return 0;
case GL_LINES:
ovf = nr & 1;
for (i = 0; i < ovf; i++)
memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
sz * sizeof(GLfloat));
return i;
case GL_TRIANGLES:
ovf = nr % 3;
for (i = 0; i < ovf; i++)
memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
sz * sizeof(GLfloat));
return i;
case GL_QUADS:
ovf = nr & 3;
for (i = 0; i < ovf; i++)
memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
sz * sizeof(GLfloat));
return i;
case GL_LINE_STRIP:
if (nr == 0)
return 0;
else {
memcpy(dst, src + (nr - 1) * sz, sz * sizeof(GLfloat));
return 1;
}
case GL_LINE_LOOP:
case GL_TRIANGLE_FAN:
case GL_POLYGON:
if (nr == 0)
return 0;
else if (nr == 1) {
memcpy(dst, src + 0, sz * sizeof(GLfloat));
return 1;
}
else {
memcpy(dst, src + 0, sz * sizeof(GLfloat));
memcpy(dst + sz, src + (nr - 1) * sz, sz * sizeof(GLfloat));
return 2;
}
case GL_TRIANGLE_STRIP:
case GL_QUAD_STRIP:
switch (nr) {
case 0:
ovf = 0;
break;
case 1:
ovf = 1;
break;
default:
ovf = 2 + (nr & 1);
break;
}
for (i = 0; i < ovf; i++)
memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
sz * sizeof(GLfloat));
return i;
default:
assert(0);
return 0;
}
}
 
 
static struct vbo_save_vertex_store *
alloc_vertex_store(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
struct vbo_save_vertex_store *vertex_store =
CALLOC_STRUCT(vbo_save_vertex_store);
 
/* obj->Name needs to be non-zero, but won't ever be examined more
* closely than that. In particular these buffers won't be entered
* into the hash and can never be confused with ones visible to the
* user. Perhaps there could be a special number for internal
* buffers:
*/
vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx,
VBO_BUF_ID,
GL_ARRAY_BUFFER_ARB);
if (vertex_store->bufferobj) {
save->out_of_memory =
!ctx->Driver.BufferData(ctx,
GL_ARRAY_BUFFER_ARB,
VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
NULL, GL_STATIC_DRAW_ARB,
vertex_store->bufferobj);
}
else {
save->out_of_memory = GL_TRUE;
}
 
if (save->out_of_memory) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation");
_mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
}
 
vertex_store->buffer = NULL;
vertex_store->used = 0;
vertex_store->refcount = 1;
 
return vertex_store;
}
 
 
static void
free_vertex_store(struct gl_context *ctx,
struct vbo_save_vertex_store *vertex_store)
{
assert(!vertex_store->buffer);
 
if (vertex_store->bufferobj) {
_mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
}
 
free(vertex_store);
}
 
 
GLfloat *
vbo_save_map_vertex_store(struct gl_context *ctx,
struct vbo_save_vertex_store *vertex_store)
{
assert(vertex_store->bufferobj);
assert(!vertex_store->buffer);
if (vertex_store->bufferobj->Size > 0) {
vertex_store->buffer =
(GLfloat *) ctx->Driver.MapBufferRange(ctx, 0,
vertex_store->bufferobj->Size,
GL_MAP_WRITE_BIT, /* not used */
vertex_store->bufferobj);
assert(vertex_store->buffer);
return vertex_store->buffer + vertex_store->used;
}
else {
/* probably ran out of memory for buffers */
return NULL;
}
}
 
 
void
vbo_save_unmap_vertex_store(struct gl_context *ctx,
struct vbo_save_vertex_store *vertex_store)
{
if (vertex_store->bufferobj->Size > 0) {
ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj);
}
vertex_store->buffer = NULL;
}
 
 
static struct vbo_save_primitive_store *
alloc_prim_store(struct gl_context *ctx)
{
struct vbo_save_primitive_store *store =
CALLOC_STRUCT(vbo_save_primitive_store);
(void) ctx;
store->used = 0;
store->refcount = 1;
return store;
}
 
 
static void
_save_reset_counters(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
 
save->prim = save->prim_store->buffer + save->prim_store->used;
save->buffer = save->vertex_store->buffer + save->vertex_store->used;
 
assert(save->buffer == save->buffer_ptr);
 
if (save->vertex_size)
save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
save->vertex_size);
else
save->max_vert = 0;
 
save->vert_count = 0;
save->prim_count = 0;
save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
save->dangling_attr_ref = 0;
}
 
/**
* For a list of prims, try merging prims that can just be extensions of the
* previous prim.
*/
static void
merge_prims(struct gl_context *ctx,
struct _mesa_prim *prim_list,
GLuint *prim_count)
{
GLuint i;
struct _mesa_prim *prev_prim = prim_list;
 
for (i = 1; i < *prim_count; i++) {
struct _mesa_prim *this_prim = prim_list + i;
 
vbo_try_prim_conversion(this_prim);
 
if (vbo_can_merge_prims(prev_prim, this_prim)) {
/* We've found a prim that just extend the previous one. Tack it
* onto the previous one, and let this primitive struct get dropped.
*/
vbo_merge_prims(prev_prim, this_prim);
continue;
}
 
/* If any previous primitives have been dropped, then we need to copy
* this later one into the next available slot.
*/
prev_prim++;
if (prev_prim != this_prim)
*prev_prim = *this_prim;
}
 
*prim_count = prev_prim - prim_list + 1;
}
 
/**
* Insert the active immediate struct onto the display list currently
* being built.
*/
static void
_save_compile_vertex_list(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
struct vbo_save_vertex_list *node;
 
/* Allocate space for this structure in the display list currently
* being compiled.
*/
node = (struct vbo_save_vertex_list *)
_mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node));
 
if (!node)
return;
 
/* Duplicate our template, increment refcounts to the storage structs:
*/
memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz));
memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype));
node->vertex_size = save->vertex_size;
node->buffer_offset =
(save->buffer - save->vertex_store->buffer) * sizeof(GLfloat);
node->count = save->vert_count;
node->wrap_count = save->copied.nr;
node->dangling_attr_ref = save->dangling_attr_ref;
node->prim = save->prim;
node->prim_count = save->prim_count;
node->vertex_store = save->vertex_store;
node->prim_store = save->prim_store;
 
node->vertex_store->refcount++;
node->prim_store->refcount++;
 
if (node->prim[0].no_current_update) {
node->current_size = 0;
node->current_data = NULL;
}
else {
node->current_size = node->vertex_size - node->attrsz[0];
node->current_data = NULL;
 
if (node->current_size) {
/* If the malloc fails, we just pull the data out of the VBO
* later instead.
*/
node->current_data = malloc(node->current_size * sizeof(GLfloat));
if (node->current_data) {
const char *buffer = (const char *) save->vertex_store->buffer;
unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
unsigned vertex_offset = 0;
 
if (node->count)
vertex_offset =
(node->count - 1) * node->vertex_size * sizeof(GLfloat);
 
memcpy(node->current_data,
buffer + node->buffer_offset + vertex_offset + attr_offset,
node->current_size * sizeof(GLfloat));
}
}
}
 
assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0);
 
if (save->dangling_attr_ref)
ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
 
save->vertex_store->used += save->vertex_size * node->count;
save->prim_store->used += node->prim_count;
 
/* Copy duplicated vertices
*/
save->copied.nr = _save_copy_vertices(ctx, node, save->buffer);
 
merge_prims(ctx, node->prim, &node->prim_count);
 
/* Deal with GL_COMPILE_AND_EXECUTE:
*/
if (ctx->ExecuteFlag) {
struct _glapi_table *dispatch = GET_DISPATCH();
 
_glapi_set_dispatch(ctx->Exec);
 
vbo_loopback_vertex_list(ctx,
(const GLfloat *) ((const char *) save->
vertex_store->buffer +
node->buffer_offset),
node->attrsz, node->prim, node->prim_count,
node->wrap_count, node->vertex_size);
 
_glapi_set_dispatch(dispatch);
}
 
/* Decide whether the storage structs are full, or can be used for
* the next vertex lists as well.
*/
if (save->vertex_store->used >
VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
 
/* Unmap old store:
*/
vbo_save_unmap_vertex_store(ctx, save->vertex_store);
 
/* Release old reference:
*/
save->vertex_store->refcount--;
assert(save->vertex_store->refcount != 0);
save->vertex_store = NULL;
 
/* Allocate and map new store:
*/
save->vertex_store = alloc_vertex_store(ctx);
save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
save->out_of_memory = save->buffer_ptr == NULL;
}
 
if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
save->prim_store->refcount--;
assert(save->prim_store->refcount != 0);
save->prim_store = alloc_prim_store(ctx);
}
 
/* Reset our structures for the next run of vertices:
*/
_save_reset_counters(ctx);
}
 
 
/**
* This is called when we fill a vertex buffer before we hit a glEnd().
* We
* TODO -- If no new vertices have been stored, don't bother saving it.
*/
static void
_save_wrap_buffers(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLint i = save->prim_count - 1;
GLenum mode;
GLboolean weak;
GLboolean no_current_update;
 
assert(i < (GLint) save->prim_max);
assert(i >= 0);
 
/* Close off in-progress primitive.
*/
save->prim[i].count = (save->vert_count - save->prim[i].start);
mode = save->prim[i].mode;
weak = save->prim[i].weak;
no_current_update = save->prim[i].no_current_update;
 
/* store the copied vertices, and allocate a new list.
*/
_save_compile_vertex_list(ctx);
 
/* Restart interrupted primitive
*/
save->prim[0].mode = mode;
save->prim[0].weak = weak;
save->prim[0].no_current_update = no_current_update;
save->prim[0].begin = 0;
save->prim[0].end = 0;
save->prim[0].pad = 0;
save->prim[0].start = 0;
save->prim[0].count = 0;
save->prim[0].num_instances = 1;
save->prim[0].base_instance = 0;
save->prim_count = 1;
}
 
 
/**
* Called only when buffers are wrapped as the result of filling the
* vertex_store struct.
*/
static void
_save_wrap_filled_vertex(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLfloat *data = save->copied.buffer;
GLuint i;
 
/* Emit a glEnd to close off the last vertex list.
*/
_save_wrap_buffers(ctx);
 
/* Copy stored stored vertices to start of new list.
*/
assert(save->max_vert - save->vert_count > save->copied.nr);
 
for (i = 0; i < save->copied.nr; i++) {
memcpy(save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat));
data += save->vertex_size;
save->buffer_ptr += save->vertex_size;
save->vert_count++;
}
}
 
 
static void
_save_copy_to_current(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLuint i;
 
for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
if (save->attrsz[i]) {
save->currentsz[i][0] = save->attrsz[i];
COPY_CLEAN_4V_TYPE_AS_FLOAT(save->current[i], save->attrsz[i],
save->attrptr[i], save->attrtype[i]);
}
}
}
 
 
static void
_save_copy_from_current(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLint i;
 
for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
switch (save->attrsz[i]) {
case 4:
save->attrptr[i][3] = save->current[i][3];
case 3:
save->attrptr[i][2] = save->current[i][2];
case 2:
save->attrptr[i][1] = save->current[i][1];
case 1:
save->attrptr[i][0] = save->current[i][0];
case 0:
break;
}
}
}
 
 
/**
* Called when we increase the size of a vertex attribute. For example,
* if we've seen one or more glTexCoord2f() calls and now we get a
* glTexCoord3f() call.
* Flush existing data, set new attrib size, replay copied vertices.
*/
static void
_save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLuint oldsz;
GLuint i;
GLfloat *tmp;
 
/* Store the current run of vertices, and emit a GL_END. Emit a
* BEGIN in the new buffer.
*/
if (save->vert_count)
_save_wrap_buffers(ctx);
else
assert(save->copied.nr == 0);
 
/* Do a COPY_TO_CURRENT to ensure back-copying works for the case
* when the attribute already exists in the vertex and is having
* its size increased.
*/
_save_copy_to_current(ctx);
 
/* Fix up sizes:
*/
oldsz = save->attrsz[attr];
save->attrsz[attr] = newsz;
 
save->vertex_size += newsz - oldsz;
save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
save->vertex_size);
save->vert_count = 0;
 
/* Recalculate all the attrptr[] values:
*/
for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) {
if (save->attrsz[i]) {
save->attrptr[i] = tmp;
tmp += save->attrsz[i];
}
else {
save->attrptr[i] = NULL; /* will not be dereferenced. */
}
}
 
/* Copy from current to repopulate the vertex with correct values.
*/
_save_copy_from_current(ctx);
 
/* Replay stored vertices to translate them to new format here.
*
* If there are copied vertices and the new (upgraded) attribute
* has not been defined before, this list is somewhat degenerate,
* and will need fixup at runtime.
*/
if (save->copied.nr) {
const GLfloat *data = save->copied.buffer;
GLfloat *dest = save->buffer;
GLuint j;
 
/* Need to note this and fix up at runtime (or loopback):
*/
if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
assert(oldsz == 0);
save->dangling_attr_ref = GL_TRUE;
}
 
for (i = 0; i < save->copied.nr; i++) {
for (j = 0; j < VBO_ATTRIB_MAX; j++) {
if (save->attrsz[j]) {
if (j == attr) {
if (oldsz) {
COPY_CLEAN_4V_TYPE_AS_FLOAT(dest, oldsz, data,
save->attrtype[j]);
data += oldsz;
dest += newsz;
}
else {
COPY_SZ_4V(dest, newsz, save->current[attr]);
dest += newsz;
}
}
else {
GLint sz = save->attrsz[j];
COPY_SZ_4V(dest, sz, data);
data += sz;
dest += sz;
}
}
}
}
 
save->buffer_ptr = dest;
save->vert_count += save->copied.nr;
}
}
 
 
/**
* This is called when the size of a vertex attribute changes.
* For example, after seeing one or more glTexCoord2f() calls we
* get a glTexCoord4f() or glTexCoord1f() call.
*/
static void
save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
 
if (sz > save->attrsz[attr]) {
/* New size is larger. Need to flush existing vertices and get
* an enlarged vertex format.
*/
_save_upgrade_vertex(ctx, attr, sz);
}
else if (sz < save->active_sz[attr]) {
GLuint i;
const GLfloat *id = vbo_get_default_vals_as_float(save->attrtype[attr]);
 
/* New size is equal or smaller - just need to fill in some
* zeros.
*/
for (i = sz; i <= save->attrsz[attr]; i++)
save->attrptr[attr][i - 1] = id[i - 1];
}
 
save->active_sz[attr] = sz;
}
 
 
/**
* Reset the current size of all vertex attributes to the default
* value of 0. This signals that we haven't yet seen any per-vertex
* commands such as glNormal3f() or glTexCoord2f().
*/
static void
_save_reset_vertex(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLuint i;
 
for (i = 0; i < VBO_ATTRIB_MAX; i++) {
save->attrsz[i] = 0;
save->active_sz[i] = 0;
}
 
save->vertex_size = 0;
}
 
 
 
#define ERROR(err) _mesa_compile_error(ctx, err, __FUNCTION__);
 
 
/* Only one size for each attribute may be active at once. Eg. if
* Color3f is installed/active, then Color4f may not be, even if the
* vertex actually contains 4 color coordinates. This is because the
* 3f version won't otherwise set color[3] to 1.0 -- this is the job
* of the chooser function when switching between Color4f and Color3f.
*/
#define ATTR(A, N, T, V0, V1, V2, V3) \
do { \
struct vbo_save_context *save = &vbo_context(ctx)->save; \
\
if (save->active_sz[A] != N) \
save_fixup_vertex(ctx, A, N); \
\
{ \
GLfloat *dest = save->attrptr[A]; \
if (N>0) dest[0] = V0; \
if (N>1) dest[1] = V1; \
if (N>2) dest[2] = V2; \
if (N>3) dest[3] = V3; \
save->attrtype[A] = T; \
} \
\
if ((A) == 0) { \
GLuint i; \
\
for (i = 0; i < save->vertex_size; i++) \
save->buffer_ptr[i] = save->vertex[i]; \
\
save->buffer_ptr += save->vertex_size; \
\
if (++save->vert_count >= save->max_vert) \
_save_wrap_filled_vertex(ctx); \
} \
} while (0)
 
#define TAG(x) _save_##x
 
#include "vbo_attrib_tmp.h"
 
 
 
#define MAT( ATTR, N, face, params ) \
do { \
if (face != GL_BACK) \
MAT_ATTR( ATTR, N, params ); /* front */ \
if (face != GL_FRONT) \
MAT_ATTR( ATTR + 1, N, params ); /* back */ \
} while (0)
 
 
/**
* Save a glMaterial call found between glBegin/End.
* glMaterial calls outside Begin/End are handled in dlist.c.
*/
static void GLAPIENTRY
_save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
{
GET_CURRENT_CONTEXT(ctx);
 
if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
_mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
return;
}
 
switch (pname) {
case GL_EMISSION:
MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
break;
case GL_AMBIENT:
MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
break;
case GL_DIFFUSE:
MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
break;
case GL_SPECULAR:
MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
break;
case GL_SHININESS:
if (*params < 0 || *params > ctx->Const.MaxShininess) {
_mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
}
else {
MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
}
break;
case GL_COLOR_INDEXES:
MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
break;
case GL_AMBIENT_AND_DIFFUSE:
MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
break;
default:
_mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
return;
}
}
 
 
/* Cope with EvalCoord/CallList called within a begin/end object:
* -- Flush current buffer
* -- Fallback to opcodes for the rest of the begin/end object.
*/
static void
dlist_fallback(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
 
if (save->vert_count || save->prim_count) {
if (save->prim_count > 0) {
/* Close off in-progress primitive. */
GLint i = save->prim_count - 1;
save->prim[i].count = save->vert_count - save->prim[i].start;
}
 
/* Need to replay this display list with loopback,
* unfortunately, otherwise this primitive won't be handled
* properly:
*/
save->dangling_attr_ref = 1;
 
_save_compile_vertex_list(ctx);
}
 
_save_copy_to_current(ctx);
_save_reset_vertex(ctx);
_save_reset_counters(ctx);
if (save->out_of_memory) {
_mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
}
else {
_mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
}
ctx->Driver.SaveNeedFlush = GL_FALSE;
}
 
 
static void GLAPIENTRY
_save_EvalCoord1f(GLfloat u)
{
GET_CURRENT_CONTEXT(ctx);
dlist_fallback(ctx);
CALL_EvalCoord1f(ctx->Save, (u));
}
 
static void GLAPIENTRY
_save_EvalCoord1fv(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
dlist_fallback(ctx);
CALL_EvalCoord1fv(ctx->Save, (v));
}
 
static void GLAPIENTRY
_save_EvalCoord2f(GLfloat u, GLfloat v)
{
GET_CURRENT_CONTEXT(ctx);
dlist_fallback(ctx);
CALL_EvalCoord2f(ctx->Save, (u, v));
}
 
static void GLAPIENTRY
_save_EvalCoord2fv(const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
dlist_fallback(ctx);
CALL_EvalCoord2fv(ctx->Save, (v));
}
 
static void GLAPIENTRY
_save_EvalPoint1(GLint i)
{
GET_CURRENT_CONTEXT(ctx);
dlist_fallback(ctx);
CALL_EvalPoint1(ctx->Save, (i));
}
 
static void GLAPIENTRY
_save_EvalPoint2(GLint i, GLint j)
{
GET_CURRENT_CONTEXT(ctx);
dlist_fallback(ctx);
CALL_EvalPoint2(ctx->Save, (i, j));
}
 
static void GLAPIENTRY
_save_CallList(GLuint l)
{
GET_CURRENT_CONTEXT(ctx);
dlist_fallback(ctx);
CALL_CallList(ctx->Save, (l));
}
 
static void GLAPIENTRY
_save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
{
GET_CURRENT_CONTEXT(ctx);
dlist_fallback(ctx);
CALL_CallLists(ctx->Save, (n, type, v));
}
 
 
 
/**
* Called via ctx->Driver.NotifySaveBegin() when a glBegin is getting
* compiled into a display list.
* Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
*/
GLboolean
vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
const GLuint i = save->prim_count++;
 
assert(i < save->prim_max);
save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
save->prim[i].begin = 1;
save->prim[i].end = 0;
save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
save->prim[i].no_current_update =
(mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0;
save->prim[i].pad = 0;
save->prim[i].start = save->vert_count;
save->prim[i].count = 0;
save->prim[i].num_instances = 1;
save->prim[i].base_instance = 0;
 
if (save->out_of_memory) {
_mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
}
else {
_mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
}
 
/* We need to call SaveFlushVertices() if there's state change */
ctx->Driver.SaveNeedFlush = GL_TRUE;
 
/* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN
* opcode into the display list.
*/
return GL_TRUE;
}
 
 
static void GLAPIENTRY
_save_End(void)
{
GET_CURRENT_CONTEXT(ctx);
struct vbo_save_context *save = &vbo_context(ctx)->save;
const GLint i = save->prim_count - 1;
 
ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
save->prim[i].end = 1;
save->prim[i].count = (save->vert_count - save->prim[i].start);
 
if (i == (GLint) save->prim_max - 1) {
_save_compile_vertex_list(ctx);
assert(save->copied.nr == 0);
}
 
/* Swap out this vertex format while outside begin/end. Any color,
* etc. received between here and the next begin will be compiled
* as opcodes.
*/
if (save->out_of_memory) {
_mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
}
else {
_mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
}
}
 
 
static void GLAPIENTRY
_save_Begin(GLenum mode)
{
GET_CURRENT_CONTEXT(ctx);
(void) mode;
_mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
}
 
 
static void GLAPIENTRY
_save_PrimitiveRestartNV(void)
{
GLenum curPrim;
GET_CURRENT_CONTEXT(ctx);
 
curPrim = ctx->Driver.CurrentSavePrimitive;
 
_save_End();
_save_Begin(curPrim);
}
 
 
/* Unlike the functions above, these are to be hooked into the vtxfmt
* maintained in ctx->ListState, active when the list is known or
* suspected to be outside any begin/end primitive.
* Note: OBE = Outside Begin/End
*/
static void GLAPIENTRY
_save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
{
GET_CURRENT_CONTEXT(ctx);
vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK);
CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
CALL_End(GET_DISPATCH(), ());
}
 
 
static void GLAPIENTRY
_save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
{
GET_CURRENT_CONTEXT(ctx);
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLint i;
 
if (!_mesa_is_valid_prim_mode(ctx, mode)) {
_mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
return;
}
if (count < 0) {
_mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
return;
}
 
if (save->out_of_memory)
return;
 
_ae_map_vbos(ctx);
 
vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK
| VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
 
for (i = 0; i < count; i++)
CALL_ArrayElement(GET_DISPATCH(), (start + i));
CALL_End(GET_DISPATCH(), ());
 
_ae_unmap_vbos(ctx);
}
 
 
/* Could do better by copying the arrays and element list intact and
* then emitting an indexed prim at runtime.
*/
static void GLAPIENTRY
_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
const GLvoid * indices)
{
GET_CURRENT_CONTEXT(ctx);
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLint i;
 
if (!_mesa_is_valid_prim_mode(ctx, mode)) {
_mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
return;
}
if (count < 0) {
_mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
return;
}
if (type != GL_UNSIGNED_BYTE &&
type != GL_UNSIGNED_SHORT &&
type != GL_UNSIGNED_INT) {
_mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
return;
}
 
if (save->out_of_memory)
return;
 
_ae_map_vbos(ctx);
 
if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj))
indices =
ADD_POINTERS(ctx->Array.ArrayObj->ElementArrayBufferObj->Pointer, indices);
 
vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK |
VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
 
switch (type) {
case GL_UNSIGNED_BYTE:
for (i = 0; i < count; i++)
CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i]));
break;
case GL_UNSIGNED_SHORT:
for (i = 0; i < count; i++)
CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i]));
break;
case GL_UNSIGNED_INT:
for (i = 0; i < count; i++)
CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i]));
break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
break;
}
 
CALL_End(GET_DISPATCH(), ());
 
_ae_unmap_vbos(ctx);
}
 
 
static void GLAPIENTRY
_save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
GLsizei count, GLenum type,
const GLvoid * indices)
{
GET_CURRENT_CONTEXT(ctx);
struct vbo_save_context *save = &vbo_context(ctx)->save;
 
if (!_mesa_is_valid_prim_mode(ctx, mode)) {
_mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
return;
}
if (count < 0) {
_mesa_compile_error(ctx, GL_INVALID_VALUE,
"glDrawRangeElements(count<0)");
return;
}
if (type != GL_UNSIGNED_BYTE &&
type != GL_UNSIGNED_SHORT &&
type != GL_UNSIGNED_INT) {
_mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
return;
}
if (end < start) {
_mesa_compile_error(ctx, GL_INVALID_VALUE,
"glDrawRangeElements(end < start)");
return;
}
 
if (save->out_of_memory)
return;
 
_save_OBE_DrawElements(mode, count, type, indices);
}
 
 
static void GLAPIENTRY
_save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
const GLvoid * const *indices, GLsizei primcount)
{
GLsizei i;
 
for (i = 0; i < primcount; i++) {
if (count[i] > 0) {
CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i]));
}
}
}
 
 
static void GLAPIENTRY
_save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
GLenum type,
const GLvoid * const *indices,
GLsizei primcount,
const GLint *basevertex)
{
GLsizei i;
 
for (i = 0; i < primcount; i++) {
if (count[i] > 0) {
CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
indices[i],
basevertex[i]));
}
}
}
 
 
static void
_save_vtxfmt_init(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLvertexformat *vfmt = &save->vtxfmt;
 
vfmt->ArrayElement = _ae_ArrayElement;
 
vfmt->Color3f = _save_Color3f;
vfmt->Color3fv = _save_Color3fv;
vfmt->Color4f = _save_Color4f;
vfmt->Color4fv = _save_Color4fv;
vfmt->EdgeFlag = _save_EdgeFlag;
vfmt->End = _save_End;
vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
vfmt->FogCoordfEXT = _save_FogCoordfEXT;
vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
vfmt->Indexf = _save_Indexf;
vfmt->Indexfv = _save_Indexfv;
vfmt->Materialfv = _save_Materialfv;
vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
vfmt->Normal3f = _save_Normal3f;
vfmt->Normal3fv = _save_Normal3fv;
vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
vfmt->TexCoord1f = _save_TexCoord1f;
vfmt->TexCoord1fv = _save_TexCoord1fv;
vfmt->TexCoord2f = _save_TexCoord2f;
vfmt->TexCoord2fv = _save_TexCoord2fv;
vfmt->TexCoord3f = _save_TexCoord3f;
vfmt->TexCoord3fv = _save_TexCoord3fv;
vfmt->TexCoord4f = _save_TexCoord4f;
vfmt->TexCoord4fv = _save_TexCoord4fv;
vfmt->Vertex2f = _save_Vertex2f;
vfmt->Vertex2fv = _save_Vertex2fv;
vfmt->Vertex3f = _save_Vertex3f;
vfmt->Vertex3fv = _save_Vertex3fv;
vfmt->Vertex4f = _save_Vertex4f;
vfmt->Vertex4fv = _save_Vertex4fv;
vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
 
vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
 
/* integer-valued */
vfmt->VertexAttribI1i = _save_VertexAttribI1i;
vfmt->VertexAttribI2i = _save_VertexAttribI2i;
vfmt->VertexAttribI3i = _save_VertexAttribI3i;
vfmt->VertexAttribI4i = _save_VertexAttribI4i;
vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
 
/* unsigned integer-valued */
vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
 
vfmt->VertexP2ui = _save_VertexP2ui;
vfmt->VertexP3ui = _save_VertexP3ui;
vfmt->VertexP4ui = _save_VertexP4ui;
vfmt->VertexP2uiv = _save_VertexP2uiv;
vfmt->VertexP3uiv = _save_VertexP3uiv;
vfmt->VertexP4uiv = _save_VertexP4uiv;
 
vfmt->TexCoordP1ui = _save_TexCoordP1ui;
vfmt->TexCoordP2ui = _save_TexCoordP2ui;
vfmt->TexCoordP3ui = _save_TexCoordP3ui;
vfmt->TexCoordP4ui = _save_TexCoordP4ui;
vfmt->TexCoordP1uiv = _save_TexCoordP1uiv;
vfmt->TexCoordP2uiv = _save_TexCoordP2uiv;
vfmt->TexCoordP3uiv = _save_TexCoordP3uiv;
vfmt->TexCoordP4uiv = _save_TexCoordP4uiv;
 
vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui;
vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui;
vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui;
vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui;
vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv;
vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv;
vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv;
vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv;
 
vfmt->NormalP3ui = _save_NormalP3ui;
vfmt->NormalP3uiv = _save_NormalP3uiv;
 
vfmt->ColorP3ui = _save_ColorP3ui;
vfmt->ColorP4ui = _save_ColorP4ui;
vfmt->ColorP3uiv = _save_ColorP3uiv;
vfmt->ColorP4uiv = _save_ColorP4uiv;
 
vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui;
vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv;
 
vfmt->VertexAttribP1ui = _save_VertexAttribP1ui;
vfmt->VertexAttribP2ui = _save_VertexAttribP2ui;
vfmt->VertexAttribP3ui = _save_VertexAttribP3ui;
vfmt->VertexAttribP4ui = _save_VertexAttribP4ui;
 
vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv;
vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv;
vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv;
vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv;
 
/* This will all require us to fallback to saving the list as opcodes:
*/
vfmt->CallList = _save_CallList;
vfmt->CallLists = _save_CallLists;
 
vfmt->EvalCoord1f = _save_EvalCoord1f;
vfmt->EvalCoord1fv = _save_EvalCoord1fv;
vfmt->EvalCoord2f = _save_EvalCoord2f;
vfmt->EvalCoord2fv = _save_EvalCoord2fv;
vfmt->EvalPoint1 = _save_EvalPoint1;
vfmt->EvalPoint2 = _save_EvalPoint2;
 
/* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
* only used when we're inside a glBegin/End pair.
*/
vfmt->Begin = _save_Begin;
}
 
 
/**
* Initialize the dispatch table with the VBO functions for display
* list compilation.
*/
void
vbo_initialize_save_dispatch(const struct gl_context *ctx,
struct _glapi_table *exec)
{
SET_DrawArrays(exec, _save_OBE_DrawArrays);
SET_DrawElements(exec, _save_OBE_DrawElements);
SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
SET_Rectf(exec, _save_OBE_Rectf);
/* Note: other glDraw functins aren't compiled into display lists */
}
 
 
 
void
vbo_save_SaveFlushVertices(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
 
/* Noop when we are actually active:
*/
if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
return;
 
if (save->vert_count || save->prim_count)
_save_compile_vertex_list(ctx);
 
_save_copy_to_current(ctx);
_save_reset_vertex(ctx);
_save_reset_counters(ctx);
ctx->Driver.SaveNeedFlush = GL_FALSE;
}
 
 
void
vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
 
(void) list;
(void) mode;
 
if (!save->prim_store)
save->prim_store = alloc_prim_store(ctx);
 
if (!save->vertex_store)
save->vertex_store = alloc_vertex_store(ctx);
 
save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
 
_save_reset_vertex(ctx);
_save_reset_counters(ctx);
ctx->Driver.SaveNeedFlush = GL_FALSE;
}
 
 
void
vbo_save_EndList(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
 
/* EndList called inside a (saved) Begin/End pair?
*/
if (_mesa_inside_dlist_begin_end(ctx)) {
if (save->prim_count > 0) {
GLint i = save->prim_count - 1;
ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
save->prim[i].end = 0;
save->prim[i].count = (save->vert_count - save->prim[i].start);
}
 
/* Make sure this vertex list gets replayed by the "loopback"
* mechanism:
*/
save->dangling_attr_ref = 1;
vbo_save_SaveFlushVertices(ctx);
 
/* Swap out this vertex format while outside begin/end. Any color,
* etc. received between here and the next begin will be compiled
* as opcodes.
*/
_mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
}
 
vbo_save_unmap_vertex_store(ctx, save->vertex_store);
 
assert(save->vertex_size == 0);
}
 
 
void
vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
save->replay_flags |= dlist->Flags;
}
 
 
void
vbo_save_EndCallList(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
 
if (ctx->ListState.CallDepth == 1) {
/* This is correct: want to keep only the VBO_SAVE_FALLBACK
* flag, if it is set:
*/
save->replay_flags &= VBO_SAVE_FALLBACK;
}
}
 
 
static void
vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
{
struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
(void) ctx;
 
if (--node->vertex_store->refcount == 0)
free_vertex_store(ctx, node->vertex_store);
 
if (--node->prim_store->refcount == 0)
free(node->prim_store);
 
free(node->current_data);
node->current_data = NULL;
}
 
 
static void
vbo_print_vertex_list(struct gl_context *ctx, void *data)
{
struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
GLuint i;
(void) ctx;
 
printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
node->count, node->prim_count, node->vertex_size);
 
for (i = 0; i < node->prim_count; i++) {
struct _mesa_prim *prim = &node->prim[i];
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)");
}
}
 
 
/**
* Called during context creation/init.
*/
static void
_save_current_init(struct gl_context *ctx)
{
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLint i;
 
for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
const GLuint j = i - VBO_ATTRIB_POS;
ASSERT(j < VERT_ATTRIB_MAX);
save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
save->current[i] = ctx->ListState.CurrentAttrib[j];
}
 
for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
ASSERT(j < MAT_ATTRIB_MAX);
save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
save->current[i] = ctx->ListState.CurrentMaterial[j];
}
}
 
 
/**
* Initialize the display list compiler. Called during context creation.
*/
void
vbo_save_api_init(struct vbo_save_context *save)
{
struct gl_context *ctx = save->ctx;
GLuint i;
 
save->opcode_vertex_list =
_mesa_dlist_alloc_opcode(ctx,
sizeof(struct vbo_save_vertex_list),
vbo_save_playback_vertex_list,
vbo_destroy_vertex_list,
vbo_print_vertex_list);
 
ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
 
_save_vtxfmt_init(ctx);
_save_current_init(ctx);
_mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
 
/* These will actually get set again when binding/drawing */
for (i = 0; i < VBO_ATTRIB_MAX; i++)
save->inputs[i] = &save->arrays[i];
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_save_draw.c
0,0 → 1,328
/*
* Mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
/* Author:
* Keith Whitwell <keith@tungstengraphics.com>
*/
 
#include "main/glheader.h"
#include "main/bufferobj.h"
#include "main/context.h"
#include "main/imports.h"
#include "main/mtypes.h"
#include "main/macros.h"
#include "main/light.h"
#include "main/state.h"
 
#include "vbo_context.h"
 
 
/**
* 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, 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_TYPE_AS_FLOAT(tmp,
node->attrsz[i],
data,
node->attrtype[i]);
if (node->attrtype[i] != vbo->currval[i].Type ||
memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) {
memcpy(current, tmp, 4 * sizeof(GLfloat));
 
vbo->currval[i].Size = node->attrsz[i];
vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
vbo->currval[i].Type = node->attrtype[i];
vbo->currval[i].Integer =
vbo_attrtype_to_integer_flag(node->attrtype[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[] */
GLenum node_attrtype[VBO_ATTRIB_MAX]; /* copy of node->attrtype[] */
GLbitfield64 varying_inputs = 0x0;
 
memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz));
memcpy(node_attrtype, node->attrtype, sizeof(node->attrtype));
 
/* Install the default (ie Current) attributes first, then overlay
* all active ones.
*/
switch (get_program_mode(ctx)) {
case VP_NONE:
for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
save->inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
}
for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
save->inputs[VERT_ATTRIB_GENERIC(attr)] =
&vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr];
}
map = vbo->map_vp_none;
break;
case VP_ARB:
for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
save->inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
}
for (attr = 0; attr < VERT_ATTRIB_GENERIC_MAX; attr++) {
save->inputs[VERT_ATTRIB_GENERIC(attr)] =
&vbo->currval[VBO_ATTRIB_GENERIC0+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[VERT_ATTRIB_GENERIC0] = save->inputs[0];
node_attrsz[VERT_ATTRIB_GENERIC0] = node_attrsz[0];
node_attrtype[VERT_ATTRIB_GENERIC0] = node_attrtype[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 = node_attrtype[src];
arrays[attr].Integer =
vbo_attrtype_to_integer_flag(node_attrtype[src]);
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 |= VERT_BIT(attr);
}
}
 
_mesa_set_varying_vp_inputs( ctx, varying_inputs );
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
}
 
 
static void
vbo_save_loopback_vertex_list(struct gl_context *ctx,
const struct vbo_save_vertex_list *list)
{
const char *buffer =
ctx->Driver.MapBufferRange(ctx, 0,
list->vertex_store->bufferobj->Size,
GL_MAP_READ_BIT, /* ? */
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, 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;
GLboolean remap_vertex_store = GL_FALSE;
 
if (save->vertex_store && save->vertex_store->buffer) {
/* The vertex store is currently mapped but we're about to replay
* a display list. This can happen when a nested display list is
* being build with GL_COMPILE_AND_EXECUTE.
* We never want to have mapped vertex buffers when we're drawing.
* Unmap the vertex store, execute the list, then remap the vertex
* store.
*/
vbo_save_unmap_vertex_store(ctx, save->vertex_store);
remap_vertex_store = GL_TRUE;
}
 
FLUSH_CURRENT(ctx, 0);
 
if (node->prim_count > 0) {
 
if (_mesa_inside_begin_end(ctx) && node->prim[0].begin) {
/* Error: we're about to begin a new primitive but we're already
* inside a glBegin/End pair.
*/
_mesa_error(ctx, GL_INVALID_OPERATION,
"draw operation inside glBegin/End");
goto end;
}
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 );
 
goto end;
}
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 );
 
vbo_draw_method(vbo_context(ctx), DRAW_DISPLAY_LIST);
 
/* Again...
*/
if (ctx->NewState)
_mesa_update_state( ctx );
 
if (node->count > 0) {
vbo_context(ctx)->draw_prims(ctx,
node->prim,
node->prim_count,
NULL,
GL_TRUE,
0, /* Node is a VBO, so this is ok */
node->count - 1,
NULL);
}
}
 
/* Copy to current?
*/
_playback_copy_to_current( ctx, node );
 
end:
if (remap_vertex_store) {
save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
}
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_save_loopback.c
0,0 → 1,189
/**************************************************************************
*
* Copyright 2005 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
 
#include "main/context.h"
#include "main/glheader.h"
#include "main/enums.h"
#include "main/imports.h"
#include "main/mtypes.h"
#include "main/dispatch.h"
#include "glapi/glapi.h"
 
#include "vbo_context.h"
 
 
typedef void (*attr_func)( struct gl_context *ctx, GLint target, const GLfloat * );
 
 
/* This file makes heavy use of the aliasing of NV vertex attributes
* with the legacy attributes, and also with ARB and Material
* attributes as currently implemented.
*/
static void VertexAttrib1fvNV(struct gl_context *ctx, GLint target, const GLfloat *v)
{
CALL_VertexAttrib1fvNV(ctx->Exec, (target, v));
}
 
static void VertexAttrib2fvNV(struct gl_context *ctx, GLint target, const GLfloat *v)
{
CALL_VertexAttrib2fvNV(ctx->Exec, (target, v));
}
 
static void VertexAttrib3fvNV(struct gl_context *ctx, GLint target, const GLfloat *v)
{
CALL_VertexAttrib3fvNV(ctx->Exec, (target, v));
}
 
static void VertexAttrib4fvNV(struct gl_context *ctx, GLint target, const GLfloat *v)
{
CALL_VertexAttrib4fvNV(ctx->Exec, (target, v));
}
 
static attr_func vert_attrfunc[4] = {
VertexAttrib1fvNV,
VertexAttrib2fvNV,
VertexAttrib3fvNV,
VertexAttrib4fvNV
};
 
struct loopback_attr {
GLint target;
GLint sz;
attr_func func;
};
 
/* Don't emit ends and begins on wrapped primitives. Don't replay
* wrapped vertices. If we get here, it's probably because the
* precalculated wrapping is wrong.
*/
static void loopback_prim( struct gl_context *ctx,
const GLfloat *buffer,
const struct _mesa_prim *prim,
GLuint wrap_count,
GLuint vertex_size,
const struct loopback_attr *la, GLuint nr )
{
GLint start = prim->start;
GLint end = start + prim->count;
const GLfloat *data;
GLint j;
GLuint k;
 
if (0)
printf("loopback prim %s(%s,%s) verts %d..%d\n",
_mesa_lookup_prim_by_nr(prim->mode),
prim->begin ? "begin" : "..",
prim->end ? "end" : "..",
start,
end);
 
if (prim->begin) {
CALL_Begin(GET_DISPATCH(), ( prim->mode ));
}
else {
assert(start == 0);
start += wrap_count;
}
 
data = buffer + start * vertex_size;
 
for (j = start ; j < end ; j++) {
const GLfloat *tmp = data + la[0].sz;
 
for (k = 1 ; k < nr ; k++) {
la[k].func( ctx, la[k].target, tmp );
tmp += la[k].sz;
}
/* Fire the vertex
*/
la[0].func( ctx, VBO_ATTRIB_POS, data );
data = tmp;
}
 
if (prim->end) {
CALL_End(GET_DISPATCH(), ());
}
}
 
/* Primitives generated by DrawArrays/DrawElements/Rectf may be
* caught here. If there is no primitive in progress, execute them
* normally, otherwise need to track and discard the generated
* primitives.
*/
static void loopback_weak_prim( struct gl_context *ctx,
const struct _mesa_prim *prim )
{
/* Use the prim_weak flag to ensure that if this primitive
* wraps, we don't mistake future vertex_lists for part of the
* surrounding primitive.
*
* While this flag is set, we are simply disposing of data
* generated by an operation now known to be a noop.
*/
if (prim->begin)
ctx->Driver.CurrentExecPrimitive |= VBO_SAVE_PRIM_WEAK;
if (prim->end)
ctx->Driver.CurrentExecPrimitive &= ~VBO_SAVE_PRIM_WEAK;
}
 
 
void vbo_loopback_vertex_list( struct gl_context *ctx,
const GLfloat *buffer,
const GLubyte *attrsz,
const struct _mesa_prim *prim,
GLuint prim_count,
GLuint wrap_count,
GLuint vertex_size)
{
struct loopback_attr la[VBO_ATTRIB_MAX];
GLuint i, nr = 0;
 
/* All Legacy, NV, ARB and Material attributes are routed through
* the NV attributes entrypoints:
*/
for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
if (attrsz[i]) {
la[nr].target = i;
la[nr].sz = attrsz[i];
la[nr].func = vert_attrfunc[attrsz[i]-1];
nr++;
}
}
 
for (i = 0 ; i < prim_count ; i++) {
if ((prim[i].mode & VBO_SAVE_PRIM_WEAK) &&
_mesa_inside_begin_end(ctx))
{
loopback_weak_prim( ctx, &prim[i] );
}
else
{
loopback_prim( ctx, buffer, &prim[i], wrap_count, vertex_size, la, nr );
}
}
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_split.c
0,0 → 1,168
 
/*
* Mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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>
*/
 
/* Deal with hardware and/or swtnl maximums:
* - maximum number of vertices in buffer
* - maximum number of elements (maybe zero)
*
* The maximums may vary with opengl state (eg if a larger hardware
* vertex is required in this state, the maximum number of vertices
* may be smaller than in another state).
*
* We want buffer splitting to be a convenience function for the code
* actually drawing the primitives rather than a system-wide maximum,
* otherwise it is hard to avoid pessimism.
*
* For instance, if a driver has no hardware limits on vertex buffer
* dimensions, it would not ordinarily want to split vbos. But if
* there is an unexpected fallback, eg memory manager fails to upload
* textures, it will want to pass the drawing commands onto swtnl,
* which does have limitations. A convenience function allows swtnl
* to split the drawing and vbos internally without imposing its
* limitations on drivers which want to use it as a fallback path.
*/
 
#include "main/glheader.h"
#include "main/imports.h"
#include "main/mtypes.h"
#include "main/macros.h"
 
#include "vbo_split.h"
#include "vbo.h"
 
/* True if a primitive can be split without copying of vertices, false
* otherwise.
*/
GLboolean split_prim_inplace(GLenum mode, GLuint *first, GLuint *incr)
{
switch (mode) {
case GL_POINTS:
*first = 1;
*incr = 1;
return GL_TRUE;
case GL_LINES:
*first = 2;
*incr = 2;
return GL_TRUE;
case GL_LINE_STRIP:
*first = 2;
*incr = 1;
return GL_TRUE;
case GL_TRIANGLES:
*first = 3;
*incr = 3;
return GL_TRUE;
case GL_TRIANGLE_STRIP:
*first = 3;
*incr = 1;
return GL_TRUE;
case GL_QUADS:
*first = 4;
*incr = 4;
return GL_TRUE;
case GL_QUAD_STRIP:
*first = 4;
*incr = 2;
return GL_TRUE;
default:
*first = 0;
*incr = 1; /* so that count % incr works */
return GL_FALSE;
}
}
 
 
 
void vbo_split_prims( struct gl_context *ctx,
const struct gl_client_array *arrays[],
const struct _mesa_prim *prim,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index,
vbo_draw_func draw,
const struct split_limits *limits )
{
GLint max_basevertex = prim->basevertex;
GLuint i;
 
for (i = 1; i < nr_prims; i++)
max_basevertex = MAX2(max_basevertex, prim[i].basevertex);
 
/* XXX max_basevertex is computed but not used, why? */
 
if (ib) {
if (limits->max_indices == 0) {
/* Could traverse the indices, re-emitting vertices in turn.
* But it's hard to see why this case would be needed - for
* software tnl, it is better to convert to non-indexed
* rendering after transformation is complete. Are there any devices
* with hardware tnl that cannot do indexed rendering?
*
* For now, this path is disabled.
*/
assert(0);
}
else if (max_index - min_index >= limits->max_verts) {
/* The vertex buffers are too large for hardware (or the
* swtnl module). Traverse the indices, re-emitting vertices
* in turn. Use a vertex cache to preserve some of the
* sharing from the original index list.
*/
vbo_split_copy(ctx, arrays, prim, nr_prims, ib,
draw, limits );
}
else if (ib->count > limits->max_indices) {
/* The index buffer is too large for hardware. Try to split
* on whole-primitive boundaries, otherwise try to split the
* individual primitives.
*/
vbo_split_inplace(ctx, arrays, prim, nr_prims, ib,
min_index, max_index, draw, limits );
}
else {
/* Why were we called? */
assert(0);
}
}
else {
if (max_index - min_index >= limits->max_verts) {
/* The vertex buffer is too large for hardware (or the swtnl
* module). Try to split on whole-primitive boundaries,
* otherwise try to split the individual primitives.
*/
vbo_split_inplace(ctx, arrays, prim, nr_prims, ib,
min_index, max_index, draw, limits );
}
else {
/* Why were we called? */
assert(0);
}
}
}
 
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_split.h
0,0 → 1,72
/*
* mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
/**
* \file vbo_context.h
* \brief VBO builder module datatypes and definitions.
* \author Keith Whitwell
*/
 
 
/**
* \mainpage The VBO splitter
*
* This is the private data used internally to the vbo_split_prims()
* helper function. Nobody outside the vbo_split* files needs to
* include or know about this structure.
*/
 
 
#ifndef _VBO_SPLIT_H
#define _VBO_SPLIT_H
 
#include "vbo.h"
 
 
/* True if a primitive can be split without copying of vertices, false
* otherwise.
*/
GLboolean split_prim_inplace(GLenum mode, GLuint *first, GLuint *incr);
 
void vbo_split_inplace( struct gl_context *ctx,
const struct gl_client_array *arrays[],
const struct _mesa_prim *prim,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index,
vbo_draw_func draw,
const struct split_limits *limits );
 
/* Requires ib != NULL:
*/
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 );
 
#endif
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_split_copy.c
0,0 → 1,636
 
/*
* Mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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/glformats.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 )
{
struct gl_context *ctx = copy->ctx;
const struct gl_client_array **saved_arrays = ctx->Array._DrawArrays;
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
 
ctx->Array._DrawArrays = copy->dstarray_ptr;
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
 
copy->draw( ctx,
copy->dstprim,
copy->dstprim_nr,
&copy->dstib,
GL_TRUE,
0,
copy->dstbuf_nr - 1,
NULL );
 
ctx->Array._DrawArrays = saved_arrays;
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
 
/* 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.MapBufferRange(ctx, 0, vbo->Size, GL_MAP_READ_BIT, 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.MapBufferRange(ctx, 0, copy->ib->obj->Size, GL_MAP_READ_BIT,
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->Integer = src->Integer;
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, vbo);
}
 
/* Unmap index buffer:
*/
if (_mesa_is_bufferobj(copy->ib->obj) &&
_mesa_bufferobj_mapped(copy->ib->obj)) {
ctx->Driver.UnmapBuffer(ctx, 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);
}
}
/contrib/sdk/sources/Mesa/src/mesa/vbo/vbo_split_inplace.c
0,0 → 1,295
 
/*
* Mesa 3-D graphics library
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
 
 
#include "main/mtypes.h"
#include "main/macros.h"
#include "main/enums.h"
#include "main/glformats.h"
#include "vbo_split.h"
 
 
#define MAX_PRIM 32
 
/* Used for splitting without copying. No attempt is made to handle
* too large indexed vertex buffers: In general you need to copy to do
* that.
*/
struct split_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;
GLuint min_index;
GLuint max_index;
vbo_draw_func draw;
 
const struct split_limits *limits;
GLuint limit;
 
struct _mesa_prim dstprim[MAX_PRIM];
GLuint dstprim_nr;
};
 
 
 
 
static void flush_vertex( struct split_context *split )
{
struct gl_context *ctx = split->ctx;
const struct gl_client_array **saved_arrays = ctx->Array._DrawArrays;
struct _mesa_index_buffer ib;
GLuint i;
 
if (!split->dstprim_nr)
return;
 
if (split->ib) {
ib = *split->ib;
 
ib.count = split->max_index - split->min_index + 1;
ib.ptr = (const void *)((const char *)ib.ptr +
split->min_index * _mesa_sizeof_type(ib.type));
 
/* Rebase the primitives to save index buffer entries. */
for (i = 0; i < split->dstprim_nr; i++)
split->dstprim[i].start -= split->min_index;
}
 
assert(split->max_index >= split->min_index);
 
ctx->Array._DrawArrays = split->array;
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
 
split->draw(ctx,
split->dstprim,
split->dstprim_nr,
split->ib ? &ib : NULL,
!split->ib,
split->min_index,
split->max_index,
NULL);
 
ctx->Array._DrawArrays = saved_arrays;
ctx->NewDriverState |= ctx->DriverFlags.NewArray;
 
split->dstprim_nr = 0;
split->min_index = ~0;
split->max_index = 0;
}
 
 
static struct _mesa_prim *next_outprim( struct split_context *split )
{
if (split->dstprim_nr == MAX_PRIM-1) {
flush_vertex(split);
}
 
{
struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
memset(prim, 0, sizeof(*prim));
return prim;
}
}
 
static void update_index_bounds(struct split_context *split,
const struct _mesa_prim *prim)
{
split->min_index = MIN2(split->min_index, prim->start);
split->max_index = MAX2(split->max_index, prim->start + prim->count - 1);
}
 
/* Return the maximum amount of vertices that can be emitted for a
* primitive starting at 'prim->start', depending on the previous
* index bounds.
*/
static GLuint get_max_vertices(struct split_context *split,
const struct _mesa_prim *prim)
{
if ((prim->start > split->min_index &&
prim->start - split->min_index >= split->limit) ||
(prim->start < split->max_index &&
split->max_index - prim->start >= split->limit))
/* "prim" starts too far away from the old range. */
return 0;
 
return MIN2(split->min_index, prim->start) + split->limit - prim->start;
}
 
/* Break large primitives into smaller ones. If not possible, convert
* the primitive to indexed and pass to split_elts().
*/
static void split_prims( struct split_context *split)
{
GLuint i;
 
for (i = 0; i < split->nr_prims; i++) {
const struct _mesa_prim *prim = &split->prim[i];
GLuint first, incr;
GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
GLuint available = get_max_vertices(split, prim);
GLuint count = prim->count - (prim->count - first) % incr;
 
if (prim->count < first)
continue;
 
if ((available < count && !split_inplace) ||
(available < first && split_inplace)) {
flush_vertex(split);
available = get_max_vertices(split, prim);
}
if (available >= count) {
struct _mesa_prim *outprim = next_outprim(split);
 
*outprim = *prim;
update_index_bounds(split, outprim);
}
else if (split_inplace) {
GLuint j, nr;
 
for (j = 0 ; j < count ; ) {
GLuint remaining = count - j;
struct _mesa_prim *outprim = next_outprim(split);
 
nr = MIN2( available, remaining );
nr -= (nr - first) % incr;
 
outprim->mode = prim->mode;
outprim->begin = (j == 0 && prim->begin);
outprim->end = (nr == remaining && prim->end);
outprim->start = prim->start + j;
outprim->count = nr;
outprim->num_instances = prim->num_instances;
outprim->base_instance = prim->base_instance;
 
update_index_bounds(split, outprim);
 
if (nr == remaining) {
/* Finished.
*/
j += nr;
}
else {
/* Wrapped the primitive:
*/
j += nr - (first - incr);
flush_vertex(split);
available = get_max_vertices(split, prim);
}
}
}
else if (split->ib == NULL) {
/* XXX: could at least send the first max_verts off from the
* inplace buffers.
*/
 
/* else convert to indexed primitive and pass to split_elts,
* which will do the necessary copying and turn it back into a
* vertex primitive for rendering...
*/
struct _mesa_index_buffer ib;
struct _mesa_prim tmpprim;
GLuint *elts = malloc(count * sizeof(GLuint));
GLuint j;
for (j = 0; j < count; j++)
elts[j] = prim->start + j;
 
ib.count = count;
ib.type = GL_UNSIGNED_INT;
ib.obj = split->ctx->Shared->NullBufferObj;
ib.ptr = elts;
 
tmpprim = *prim;
tmpprim.indexed = 1;
tmpprim.start = 0;
tmpprim.count = count;
tmpprim.num_instances = 1;
tmpprim.base_instance = 0;
 
flush_vertex(split);
 
vbo_split_copy(split->ctx,
split->array,
&tmpprim, 1,
&ib,
split->draw,
split->limits);
free(elts);
}
else {
flush_vertex(split);
 
vbo_split_copy(split->ctx,
split->array,
prim, 1,
split->ib,
split->draw,
split->limits);
}
}
 
flush_vertex(split);
}
 
 
void vbo_split_inplace( struct gl_context *ctx,
const struct gl_client_array *arrays[],
const struct _mesa_prim *prim,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index,
vbo_draw_func draw,
const struct split_limits *limits )
{
struct split_context split;
 
memset(&split, 0, sizeof(split));
 
split.ctx = ctx;
split.array = arrays;
split.prim = prim;
split.nr_prims = nr_prims;
split.ib = ib;
 
/* Empty interval, makes calculations simpler. */
split.min_index = ~0;
split.max_index = 0;
 
split.draw = draw;
split.limits = limits;
split.limit = ib ? limits->max_indices : limits->max_verts;
 
split_prims( &split );
}