/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, |
©->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, |
©->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 = ©->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 = ©->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 = ©->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] = ©->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 = ©->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(©, 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(©); |
replay_elts(©); |
replay_finish(©); |
} |
} |
/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 ); |
} |