/programs/develop/libraries/Mesa/src/mesa/vbo/descrip.mms |
---|
0,0 → 1,62 |
# Makefile for core library for VMS |
# contributed by Jouk Jansen joukj@hrem.nano.tudelft.nl |
# Last revision : 3 October 2007 |
.first |
define gl [---.include.gl] |
define math [-.math] |
define vbo [-.vbo] |
define tnl [-.tnl] |
define shader [-.shader] |
define swrast [-.swrast] |
define swrast_setup [-.swrast_setup] |
define main [-.main] |
define glapi [-.glapi] |
.include [---]mms-config. |
##### MACROS ##### |
VPATH = RCS |
INCDIR = [---.include],[-.main],[-.glapi],[-.shader],[-.shader.slang] |
LIBDIR = [---.lib] |
CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)/float=ieee/ieee=denorm |
SOURCES =vbo_context.c,vbo_exec.c,vbo_exec_api.c,vbo_exec_array.c,\ |
vbo_exec_draw.c,vbo_exec_eval.c,vbo_rebase.c,vbo_save.c,\ |
vbo_save_api.c,vbo_save_draw.c,vbo_save_loopback.c,\ |
vbo_split.c,vbo_split_copy.c,vbo_split_inplace.c |
OBJECTS =vbo_context.obj,vbo_exec.obj,vbo_exec_api.obj,vbo_exec_array.obj,\ |
vbo_exec_draw.obj,vbo_exec_eval.obj,vbo_rebase.obj,vbo_save.obj,\ |
vbo_save_api.obj,vbo_save_draw.obj,vbo_save_loopback.obj,\ |
vbo_split.obj,vbo_split_copy.obj,vbo_split_inplace.obj |
##### RULES ##### |
VERSION=Mesa V3.4 |
##### TARGETS ##### |
# Make the library |
$(LIBDIR)$(GL_LIB) : $(OBJECTS) |
@ library $(LIBDIR)$(GL_LIB) $(OBJECTS) |
clean : |
purge |
delete *.obj;* |
vbo_context.obj : vbo_context.c |
vbo_exec.obj : vbo_exec.c |
vbo_exec_api.obj : vbo_exec_api.c |
vbo_exec_array.obj : vbo_exec_array.c |
vbo_exec_draw.obj : vbo_exec_draw.c |
vbo_exec_eval.obj : vbo_exec_eval.c |
vbo_rebase.obj : vbo_rebase.c |
vbo_save.obj : vbo_save.c |
vbo_save_api.obj : vbo_save_api.c |
vbo_save_draw.obj : vbo_save_draw.c |
vbo_save_loopback.obj : vbo_save_loopback.c |
vbo_split.obj : vbo_split.c |
vbo_split_copy.obj : vbo_split_copy.c |
vbo_split_inplace.obj : vbo_split_inplace.c |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo.h |
---|
0,0 → 1,169 |
/* |
* mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
*/ |
/** |
* \file vbo_context.h |
* \brief VBO builder module datatypes and definitions. |
* \author Keith Whitwell |
*/ |
#ifndef _VBO_H |
#define _VBO_H |
#include "main/mtypes.h" |
struct _mesa_prim { |
GLuint mode:8; |
GLuint indexed:1; |
GLuint begin:1; |
GLuint end:1; |
GLuint weak:1; |
GLuint pad:20; |
GLuint start; |
GLuint count; |
GLint basevertex; |
GLsizei num_instances; |
}; |
/* Would like to call this a "vbo_index_buffer", but this would be |
* confusing as the indices are not neccessarily yet in a non-null |
* buffer object. |
*/ |
struct _mesa_index_buffer { |
GLuint count; |
GLenum type; |
struct gl_buffer_object *obj; |
const void *ptr; |
}; |
GLboolean _vbo_CreateContext( struct gl_context *ctx ); |
void _vbo_DestroyContext( struct gl_context *ctx ); |
void _vbo_InvalidateState( struct gl_context *ctx, GLuint new_state ); |
typedef void (*vbo_draw_func)( struct gl_context *ctx, |
const struct gl_client_array **arrays, |
const struct _mesa_prim *prims, |
GLuint nr_prims, |
const struct _mesa_index_buffer *ib, |
GLboolean index_bounds_valid, |
GLuint min_index, |
GLuint max_index ); |
/* Utility function to cope with various constraints on tnl modules or |
* hardware. This can be used to split an incoming set of arrays and |
* primitives against the following constraints: |
* - Maximum number of indices in index buffer. |
* - Maximum number of vertices referenced by index buffer. |
* - Maximum hardware vertex buffer size. |
*/ |
struct split_limits { |
GLuint max_verts; |
GLuint max_indices; |
GLuint max_vb_size; /* bytes */ |
}; |
void vbo_split_prims( struct gl_context *ctx, |
const struct gl_client_array *arrays[], |
const struct _mesa_prim *prim, |
GLuint nr_prims, |
const struct _mesa_index_buffer *ib, |
GLuint min_index, |
GLuint max_index, |
vbo_draw_func draw, |
const struct split_limits *limits ); |
/* Helpers for dealing translating away non-zero min_index. |
*/ |
GLboolean vbo_all_varyings_in_vbos( const struct gl_client_array *arrays[] ); |
GLboolean vbo_any_varyings_in_vbos( const struct gl_client_array *arrays[] ); |
void vbo_rebase_prims( struct gl_context *ctx, |
const struct gl_client_array *arrays[], |
const struct _mesa_prim *prim, |
GLuint nr_prims, |
const struct _mesa_index_buffer *ib, |
GLuint min_index, |
GLuint max_index, |
vbo_draw_func draw ); |
void |
vbo_get_minmax_index(struct gl_context *ctx, const struct _mesa_prim *prim, |
const struct _mesa_index_buffer *ib, |
GLuint *min_index, GLuint *max_index); |
void vbo_use_buffer_objects(struct gl_context *ctx); |
void vbo_set_draw_func(struct gl_context *ctx, vbo_draw_func func); |
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 |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_attrib.h |
---|
0,0 → 1,107 |
/* |
Copyright (C) Intel Corp. 2006. All Rights Reserved. |
Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to |
develop this 3D driver. |
Permission is hereby granted, free of charge, to any person obtaining |
a copy of this software and associated documentation files (the |
"Software"), to deal in the Software without restriction, including |
without limitation the rights to use, copy, modify, merge, publish, |
distribute, sublicense, and/or sell copies of the Software, and to |
permit persons to whom the Software is furnished to do so, subject to |
the following conditions: |
The above copyright notice and this permission notice (including the |
next paragraph) shall be included in all copies or substantial |
portions of the Software. |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE |
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
**********************************************************************/ |
/* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#ifndef 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_GENERIC0 = 16, /* Not used? */ |
VBO_ATTRIB_GENERIC1 = 17, |
VBO_ATTRIB_GENERIC2 = 18, |
VBO_ATTRIB_GENERIC3 = 19, |
VBO_ATTRIB_GENERIC4 = 20, |
VBO_ATTRIB_GENERIC5 = 21, |
VBO_ATTRIB_GENERIC6 = 22, |
VBO_ATTRIB_GENERIC7 = 23, |
VBO_ATTRIB_GENERIC8 = 24, |
VBO_ATTRIB_GENERIC9 = 25, |
VBO_ATTRIB_GENERIC10 = 26, |
VBO_ATTRIB_GENERIC11 = 27, |
VBO_ATTRIB_GENERIC12 = 28, |
VBO_ATTRIB_GENERIC13 = 29, |
VBO_ATTRIB_GENERIC14 = 30, |
VBO_ATTRIB_GENERIC15 = 31, |
/* XXX: in the vertex program InputsRead flag, we alias |
* materials and generics and use knowledge about the program |
* (whether it is a fixed-function emulation) to |
* differentiate. Here we must keep them apart instead. |
*/ |
VBO_ATTRIB_MAT_FRONT_AMBIENT = 32, |
VBO_ATTRIB_MAT_BACK_AMBIENT = 33, |
VBO_ATTRIB_MAT_FRONT_DIFFUSE = 34, |
VBO_ATTRIB_MAT_BACK_DIFFUSE = 35, |
VBO_ATTRIB_MAT_FRONT_SPECULAR = 36, |
VBO_ATTRIB_MAT_BACK_SPECULAR = 37, |
VBO_ATTRIB_MAT_FRONT_EMISSION = 38, |
VBO_ATTRIB_MAT_BACK_EMISSION = 39, |
VBO_ATTRIB_MAT_FRONT_SHININESS = 40, |
VBO_ATTRIB_MAT_BACK_SHININESS = 41, |
VBO_ATTRIB_MAT_FRONT_INDEXES = 42, |
VBO_ATTRIB_MAT_BACK_INDEXES = 43, |
VBO_ATTRIB_MAX = 44 |
}; |
#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 |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_attrib_tmp.h |
---|
0,0 → 1,740 |
/************************************************************************** |
Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas. |
All Rights Reserved. |
Permission is hereby granted, free of charge, to any person obtaining a |
copy of this software and associated documentation files (the "Software"), |
to deal in the Software without restriction, including without limitation |
on the rights to use, copy, modify, merge, publish, distribute, sub |
license, and/or sell copies of the Software, and to permit persons to whom |
the Software is furnished to do so, subject to the following conditions: |
The above copyright notice and this permission notice (including the next |
paragraph) shall be included in all copies or substantial portions of the |
Software. |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, |
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
USE OR OTHER DEALINGS IN THE SOFTWARE. |
**************************************************************************/ |
/* float */ |
#define ATTR1FV( A, V ) ATTR( A, 1, (V)[0], 0, 0, 1 ) |
#define ATTR2FV( A, V ) ATTR( A, 2, (V)[0], (V)[1], 0, 1 ) |
#define ATTR3FV( A, V ) ATTR( A, 3, (V)[0], (V)[1], (V)[2], 1 ) |
#define ATTR4FV( A, V ) ATTR( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] ) |
#define ATTR1F( A, X ) ATTR( A, 1, X, 0, 0, 1 ) |
#define ATTR2F( A, X, Y ) ATTR( A, 2, X, Y, 0, 1 ) |
#define ATTR3F( A, X, Y, Z ) ATTR( A, 3, X, Y, Z, 1 ) |
#define ATTR4F( A, X, Y, Z, W ) ATTR( A, 4, X, Y, Z, W ) |
/* int */ |
#define ATTR2IV( A, V ) ATTR( A, 2, (V)[0], (V)[1], 0, 1 ) |
#define ATTR3IV( A, V ) ATTR( A, 3, (V)[0], (V)[1], (V)[2], 1 ) |
#define ATTR4IV( A, V ) ATTR( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] ) |
#define ATTR1I( A, X ) ATTR( A, 1, X, 0, 0, 1 ) |
#define ATTR2I( A, X, Y ) ATTR( A, 2, X, Y, 0, 1 ) |
#define ATTR3I( A, X, Y, Z ) ATTR( A, 3, X, Y, Z, 1 ) |
#define ATTR4I( A, X, Y, Z, W ) ATTR( A, 4, X, Y, Z, W ) |
/* uint */ |
#define ATTR2UIV( A, V ) ATTR( A, 2, (V)[0], (V)[1], 0, 1 ) |
#define ATTR3UIV( A, V ) ATTR( A, 3, (V)[0], (V)[1], (V)[2], 1 ) |
#define ATTR4UIV( A, V ) ATTR( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] ) |
#define ATTR1UI( A, X ) ATTR( A, 1, X, 0, 0, 1 ) |
#define ATTR2UI( A, X, Y ) ATTR( A, 2, X, Y, 0, 1 ) |
#define ATTR3UI( A, X, Y, Z ) ATTR( A, 3, X, Y, Z, 1 ) |
#define ATTR4UI( A, X, Y, Z, W ) ATTR( A, 4, X, Y, Z, W ) |
#define MAT_ATTR( A, N, V ) ATTR( A, N, (V)[0], (V)[1], (V)[2], (V)[3] ) |
static void GLAPIENTRY |
TAG(Vertex2f)(GLfloat x, GLfloat y) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR2F(VBO_ATTRIB_POS, x, y); |
} |
static void GLAPIENTRY |
TAG(Vertex2fv)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR2FV(VBO_ATTRIB_POS, v); |
} |
static void GLAPIENTRY |
TAG(Vertex3f)(GLfloat x, GLfloat y, GLfloat z) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR3F(VBO_ATTRIB_POS, x, y, z); |
} |
static void GLAPIENTRY |
TAG(Vertex3fv)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR3FV(VBO_ATTRIB_POS, v); |
} |
static void GLAPIENTRY |
TAG(Vertex4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR4F(VBO_ATTRIB_POS, x, y, z, w); |
} |
static void GLAPIENTRY |
TAG(Vertex4fv)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR4FV(VBO_ATTRIB_POS, v); |
} |
static void GLAPIENTRY |
TAG(TexCoord1f)(GLfloat x) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR1F(VBO_ATTRIB_TEX0, x); |
} |
static void GLAPIENTRY |
TAG(TexCoord1fv)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR1FV(VBO_ATTRIB_TEX0, v); |
} |
static void GLAPIENTRY |
TAG(TexCoord2f)(GLfloat x, GLfloat y) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR2F(VBO_ATTRIB_TEX0, x, y); |
} |
static void GLAPIENTRY |
TAG(TexCoord2fv)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR2FV(VBO_ATTRIB_TEX0, v); |
} |
static void GLAPIENTRY |
TAG(TexCoord3f)(GLfloat x, GLfloat y, GLfloat z) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR3F(VBO_ATTRIB_TEX0, x, y, z); |
} |
static void GLAPIENTRY |
TAG(TexCoord3fv)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR3FV(VBO_ATTRIB_TEX0, v); |
} |
static void GLAPIENTRY |
TAG(TexCoord4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR4F(VBO_ATTRIB_TEX0, x, y, z, w); |
} |
static void GLAPIENTRY |
TAG(TexCoord4fv)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR4FV(VBO_ATTRIB_TEX0, v); |
} |
static void GLAPIENTRY |
TAG(Normal3f)(GLfloat x, GLfloat y, GLfloat z) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR3F(VBO_ATTRIB_NORMAL, x, y, z); |
} |
static void GLAPIENTRY |
TAG(Normal3fv)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR3FV(VBO_ATTRIB_NORMAL, v); |
} |
static void GLAPIENTRY |
TAG(FogCoordfEXT)(GLfloat x) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR1F(VBO_ATTRIB_FOG, x); |
} |
static void GLAPIENTRY |
TAG(FogCoordfvEXT)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR1FV(VBO_ATTRIB_FOG, v); |
} |
static void GLAPIENTRY |
TAG(Color3f)(GLfloat x, GLfloat y, GLfloat z) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR3F(VBO_ATTRIB_COLOR0, x, y, z); |
} |
static void GLAPIENTRY |
TAG(Color3fv)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR3FV(VBO_ATTRIB_COLOR0, v); |
} |
static void GLAPIENTRY |
TAG(Color4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR4F(VBO_ATTRIB_COLOR0, x, y, z, w); |
} |
static void GLAPIENTRY |
TAG(Color4fv)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR4FV(VBO_ATTRIB_COLOR0, v); |
} |
static void GLAPIENTRY |
TAG(SecondaryColor3fEXT)(GLfloat x, GLfloat y, GLfloat z) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR3F(VBO_ATTRIB_COLOR1, x, y, z); |
} |
static void GLAPIENTRY |
TAG(SecondaryColor3fvEXT)(const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR3FV(VBO_ATTRIB_COLOR1, v); |
} |
static void GLAPIENTRY |
TAG(EdgeFlag)(GLboolean b) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR1F(VBO_ATTRIB_EDGEFLAG, (GLfloat) b); |
} |
static void GLAPIENTRY |
TAG(Indexf)(GLfloat f) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR1F(VBO_ATTRIB_INDEX, f); |
} |
static void GLAPIENTRY |
TAG(Indexfv)(const GLfloat * f) |
{ |
GET_CURRENT_CONTEXT(ctx); |
ATTR1FV(VBO_ATTRIB_INDEX, f); |
} |
static void GLAPIENTRY |
TAG(MultiTexCoord1f)(GLenum target, GLfloat x) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0; |
ATTR1F(attr, x); |
} |
static void GLAPIENTRY |
TAG(MultiTexCoord1fv)(GLenum target, const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0; |
ATTR1FV(attr, v); |
} |
static void GLAPIENTRY |
TAG(MultiTexCoord2f)(GLenum target, GLfloat x, GLfloat y) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0; |
ATTR2F(attr, x, y); |
} |
static void GLAPIENTRY |
TAG(MultiTexCoord2fv)(GLenum target, const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0; |
ATTR2FV(attr, v); |
} |
static void GLAPIENTRY |
TAG(MultiTexCoord3f)(GLenum target, GLfloat x, GLfloat y, GLfloat z) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0; |
ATTR3F(attr, x, y, z); |
} |
static void GLAPIENTRY |
TAG(MultiTexCoord3fv)(GLenum target, const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0; |
ATTR3FV(attr, v); |
} |
static void GLAPIENTRY |
TAG(MultiTexCoord4f)(GLenum target, GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0; |
ATTR4F(attr, x, y, z, w); |
} |
static void GLAPIENTRY |
TAG(MultiTexCoord4fv)(GLenum target, const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLuint attr = (target & 0x7) + VBO_ATTRIB_TEX0; |
ATTR4FV(attr, v); |
} |
static void GLAPIENTRY |
TAG(VertexAttrib1fARB)(GLuint index, GLfloat x) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (index == 0) |
ATTR1F(0, x); |
else if (index < MAX_VERTEX_GENERIC_ATTRIBS) |
ATTR1F(VBO_ATTRIB_GENERIC0 + index, x); |
else |
ERROR(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
/* 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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
/* 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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
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(); |
} |
/* In addition to supporting NV_vertex_program, these entrypoints are |
* used by the display list and other code specifically because of |
* their property of aliasing with other attributes. (See |
* vbo_save_loopback.c) |
*/ |
static void GLAPIENTRY |
TAG(VertexAttrib1fNV)(GLuint index, GLfloat x) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (index < VBO_ATTRIB_MAX) |
ATTR1F(index, x); |
} |
static void GLAPIENTRY |
TAG(VertexAttrib1fvNV)(GLuint index, const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (index < VBO_ATTRIB_MAX) |
ATTR1FV(index, v); |
} |
static void GLAPIENTRY |
TAG(VertexAttrib2fNV)(GLuint index, GLfloat x, GLfloat y) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (index < VBO_ATTRIB_MAX) |
ATTR2F(index, x, y); |
} |
static void GLAPIENTRY |
TAG(VertexAttrib2fvNV)(GLuint index, const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (index < VBO_ATTRIB_MAX) |
ATTR2FV(index, v); |
} |
static void GLAPIENTRY |
TAG(VertexAttrib3fNV)(GLuint index, GLfloat x, GLfloat y, GLfloat z) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (index < VBO_ATTRIB_MAX) |
ATTR3F(index, x, y, z); |
} |
static void GLAPIENTRY |
TAG(VertexAttrib3fvNV)(GLuint index, |
const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (index < VBO_ATTRIB_MAX) |
ATTR3FV(index, v); |
} |
static void GLAPIENTRY |
TAG(VertexAttrib4fNV)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (index < VBO_ATTRIB_MAX) |
ATTR4F(index, x, y, z, w); |
} |
static void GLAPIENTRY |
TAG(VertexAttrib4fvNV)(GLuint index, const GLfloat * v) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (index < VBO_ATTRIB_MAX) |
ATTR4FV(index, v); |
} |
#define MAT( ATTR, N, face, params ) \ |
do { \ |
if (face != GL_BACK) \ |
MAT_ATTR( ATTR, N, params ); /* front */ \ |
if (face != GL_FRONT) \ |
MAT_ATTR( ATTR + 1, N, params ); /* back */ \ |
} while (0) |
/* Colormaterial conflicts are dealt with later. |
*/ |
static void GLAPIENTRY |
TAG(Materialfv)(GLenum face, GLenum pname, |
const GLfloat * params) |
{ |
GET_CURRENT_CONTEXT(ctx); |
switch (pname) { |
case GL_EMISSION: |
MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params); |
break; |
case GL_AMBIENT: |
MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params); |
break; |
case GL_DIFFUSE: |
MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params); |
break; |
case GL_SPECULAR: |
MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params); |
break; |
case GL_SHININESS: |
MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params); |
break; |
case GL_COLOR_INDEXES: |
MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params); |
break; |
case GL_AMBIENT_AND_DIFFUSE: |
MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params); |
MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params); |
break; |
default: |
ERROR(); |
return; |
} |
} |
#undef ATTR1FV |
#undef ATTR2FV |
#undef ATTR3FV |
#undef ATTR4FV |
#undef ATTR1F |
#undef ATTR2F |
#undef ATTR3F |
#undef ATTR4F |
#undef MAT |
#undef MAT_ATTR |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_context.c |
---|
0,0 → 1,247 |
/* |
* Mesa 3-D graphics library |
* Version: 6.3 |
* |
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/imports.h" |
#include "main/mtypes.h" |
#include "main/api_arrayelt.h" |
#include "main/bufferobj.h" |
#include "math/m_eval.h" |
#include "vbo.h" |
#include "vbo_context.h" |
#define NR_LEGACY_ATTRIBS 16 |
#define NR_GENERIC_ATTRIBS 16 |
#define NR_MAT_ATTRIBS 12 |
static GLuint check_size( const GLfloat *attr ) |
{ |
if (attr[3] != 1.0) return 4; |
if (attr[2] != 0.0) return 3; |
if (attr[1] != 0.0) return 2; |
return 1; |
} |
static void init_legacy_currval(struct gl_context *ctx) |
{ |
struct vbo_context *vbo = vbo_context(ctx); |
struct gl_client_array *arrays = vbo->legacy_currval; |
GLuint i; |
memset(arrays, 0, sizeof(*arrays) * NR_LEGACY_ATTRIBS); |
/* Set up a constant (StrideB == 0) array for each current |
* attribute: |
*/ |
for (i = 0; i < NR_LEGACY_ATTRIBS; i++) { |
struct gl_client_array *cl = &arrays[i]; |
/* Size will have to be determined at runtime: |
*/ |
cl->Size = check_size(ctx->Current.Attrib[i]); |
cl->Stride = 0; |
cl->StrideB = 0; |
cl->Enabled = 1; |
cl->Type = GL_FLOAT; |
cl->Format = GL_RGBA; |
cl->Ptr = (const void *)ctx->Current.Attrib[i]; |
_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->generic_currval; |
GLuint i; |
memset(arrays, 0, sizeof(*arrays) * NR_GENERIC_ATTRIBS); |
for (i = 0; i < NR_GENERIC_ATTRIBS; i++) { |
struct gl_client_array *cl = &arrays[i]; |
/* This will have to be determined at runtime: |
*/ |
cl->Size = 1; |
cl->Type = GL_FLOAT; |
cl->Format = GL_RGBA; |
cl->Ptr = (const void *)ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + i]; |
cl->Stride = 0; |
cl->StrideB = 0; |
cl->Enabled = 1; |
_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->mat_currval; |
GLuint i; |
ASSERT(NR_MAT_ATTRIBS == MAT_ATTRIB_MAX); |
memset(arrays, 0, sizeof(*arrays) * NR_MAT_ATTRIBS); |
/* Set up a constant (StrideB == 0) array for each current |
* attribute: |
*/ |
for (i = 0; i < NR_MAT_ATTRIBS; i++) { |
struct gl_client_array *cl = &arrays[i]; |
/* Size is fixed for the material attributes, for others will |
* be determined at runtime: |
*/ |
switch (i - VERT_ATTRIB_GENERIC0) { |
case MAT_ATTRIB_FRONT_SHININESS: |
case MAT_ATTRIB_BACK_SHININESS: |
cl->Size = 1; |
break; |
case MAT_ATTRIB_FRONT_INDEXES: |
case MAT_ATTRIB_BACK_INDEXES: |
cl->Size = 3; |
break; |
default: |
cl->Size = 4; |
break; |
} |
cl->Ptr = (const void *)ctx->Light.Material.Attrib[i]; |
cl->Type = GL_FLOAT; |
cl->Format = GL_RGBA; |
cl->Stride = 0; |
cl->StrideB = 0; |
cl->Enabled = 1; |
_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; |
} |
/* TODO: remove these pointers. |
*/ |
vbo->legacy_currval = &vbo->currval[VBO_ATTRIB_POS]; |
vbo->generic_currval = &vbo->currval[VBO_ATTRIB_GENERIC0]; |
vbo->mat_currval = &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT]; |
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; |
/* When no vertex program, pull in the material attributes in |
* the 16..32 generic range. |
*/ |
for (i = 0; i < 16; i++) |
vbo->map_vp_none[i] = i; |
for (i = 0; i < 12; i++) |
vbo->map_vp_none[16+i] = VBO_ATTRIB_MAT_FRONT_AMBIENT + i; |
for (i = 0; i < 4; i++) |
vbo->map_vp_none[28+i] = 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) |
vbo_save_init( ctx ); |
_math_init_eval(); |
return GL_TRUE; |
} |
void _vbo_InvalidateState( struct gl_context *ctx, GLuint new_state ) |
{ |
_ae_invalidate_state(ctx, 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) |
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; |
} |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_context.h |
---|
0,0 → 1,112 |
/* |
* mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
*/ |
/** |
* \file 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" |
struct vbo_context { |
struct gl_client_array currval[VBO_ATTRIB_MAX]; |
/* These point into the above. TODO: remove. |
*/ |
struct gl_client_array *legacy_currval; |
struct gl_client_array *generic_currval; |
struct gl_client_array *mat_currval; |
GLuint map_vp_none[VERT_ATTRIB_MAX]; |
GLuint map_vp_arb[VERT_ATTRIB_MAX]; |
GLfloat *current[VBO_ATTRIB_MAX]; /* points into ctx->Current, ctx->Light.Material */ |
GLfloat CurrentFloatEdgeFlag; |
struct vbo_exec_context exec; |
#if FEATURE_dlist |
struct vbo_save_context save; |
#endif |
/* Callback into the driver. This must always succeed, the driver |
* is responsible for initiating any fallback actions required: |
*/ |
vbo_draw_func draw_prims; |
}; |
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 if (ctx->VertexProgram._Current->IsNVProgram) |
return VP_NV; |
else |
return VP_ARB; |
} |
#endif |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_exec.c |
---|
0,0 → 1,92 |
/* |
* Mesa 3-D graphics library |
* Version: 6.3 |
* |
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/api_arrayelt.h" |
#include "main/glheader.h" |
#include "main/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 ); |
vbo_exec_array_init( exec ); |
/* Hook our functions into exec and compile dispatch tables. |
*/ |
_mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt ); |
ctx->Driver.NeedFlush = 0; |
ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; |
ctx->Driver.BeginVertices = 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 ); |
vbo_exec_array_destroy( exec ); |
} |
/** |
* Really want to install these callbacks to a central facility to be |
* invoked according to the state flags. That will have to wait for a |
* mesa rework: |
*/ |
void vbo_exec_invalidate_state( struct gl_context *ctx, GLuint new_state ) |
{ |
struct vbo_exec_context *exec = &vbo_context(ctx)->exec; |
if (new_state & (_NEW_PROGRAM|_NEW_EVAL)) |
exec->eval.recalculate_maps = 1; |
_ae_invalidate_state(ctx, new_state); |
} |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_exec.h |
---|
0,0 → 1,198 |
/************************************************************************** |
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" |
#define VBO_MAX_PRIM 64 |
/* Wierd implementation stuff: |
*/ |
#define VBO_VERT_BUFFER_SIZE (1024*64) /* bytes */ |
#define VBO_MAX_ATTR_CODEGEN 16 |
#define ERROR_ATTRIB 16 |
/** Current vertex program mode */ |
enum vp_mode { |
VP_NONE, /**< fixed function */ |
VP_NV, /**< NV vertex program */ |
VP_ARB /**< ARB vertex program or GLSL vertex shader */ |
}; |
struct vbo_exec_eval1_map { |
struct gl_1d_map *map; |
GLuint sz; |
}; |
struct vbo_exec_eval2_map { |
struct gl_2d_map *map; |
GLuint sz; |
}; |
struct vbo_exec_copied_vtx { |
GLfloat buffer[VBO_ATTRIB_MAX * 4 * VBO_MAX_COPIED_VERTS]; |
GLuint nr; |
}; |
typedef void (*vbo_attrfv_func)( const GLfloat * ); |
struct vbo_exec_context |
{ |
struct gl_context *ctx; |
GLvertexformat vtxfmt; |
struct { |
struct gl_buffer_object *bufferobj; |
GLuint vertex_size; /* in dwords */ |
struct _mesa_prim prim[VBO_MAX_PRIM]; |
GLuint prim_count; |
GLfloat *buffer_map; |
GLfloat *buffer_ptr; /* cursor, points into buffer */ |
GLuint buffer_used; /* in bytes */ |
GLfloat vertex[VBO_ATTRIB_MAX*4]; /* current vertex */ |
GLuint vert_count; |
GLuint max_vert; |
struct vbo_exec_copied_vtx copied; |
GLubyte attrsz[VBO_ATTRIB_MAX]; |
GLubyte active_sz[VBO_ATTRIB_MAX]; |
GLfloat *attrptr[VBO_ATTRIB_MAX]; |
struct gl_client_array arrays[VERT_ATTRIB_MAX]; |
/* According to program mode, the values above plus current |
* values are squashed down to the 32 attributes passed to the |
* vertex program below: |
*/ |
enum vp_mode program_mode; |
GLuint enabled_flags; |
const struct gl_client_array *inputs[VERT_ATTRIB_MAX]; |
} vtx; |
struct { |
GLboolean recalculate_maps; |
struct vbo_exec_eval1_map map1[VERT_ATTRIB_MAX]; |
struct vbo_exec_eval2_map map2[VERT_ATTRIB_MAX]; |
} eval; |
struct { |
enum vp_mode program_mode; |
GLuint enabled_flags; |
GLuint array_obj; |
/* These just mirror the current arrayobj (todo: make arrayobj |
* look like this and remove the mirror): |
*/ |
const struct gl_client_array *legacy_array[16]; |
const struct gl_client_array *generic_array[16]; |
/* Arrays and current values manipulated according to program |
* mode, etc. These are the attributes as seen by vertex |
* programs: |
*/ |
const struct gl_client_array *inputs[VERT_ATTRIB_MAX]; |
} array; |
#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_FlushVertices_internal( struct gl_context *ctx, GLboolean unmap ); |
void vbo_exec_BeginVertices( struct gl_context *ctx ); |
void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags ); |
/* Internal functions: |
*/ |
void vbo_exec_array_init( struct vbo_exec_context *exec ); |
void vbo_exec_array_destroy( struct vbo_exec_context *exec ); |
void vbo_exec_vtx_init( struct vbo_exec_context *exec ); |
void vbo_exec_vtx_destroy( struct vbo_exec_context *exec ); |
#if FEATURE_beginend |
void vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap ); |
void vbo_exec_vtx_map( struct vbo_exec_context *exec ); |
#else /* FEATURE_beginend */ |
static INLINE void |
vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap ) |
{ |
} |
static INLINE void |
vbo_exec_vtx_map( struct vbo_exec_context *exec ) |
{ |
} |
#endif /* FEATURE_beginend */ |
void vbo_exec_vtx_wrap( struct vbo_exec_context *exec ); |
void vbo_exec_eval_update( struct vbo_exec_context *exec ); |
void vbo_exec_do_EvalCoord2f( struct vbo_exec_context *exec, |
GLfloat u, GLfloat v ); |
void vbo_exec_do_EvalCoord1f( struct vbo_exec_context *exec, |
GLfloat u); |
#endif |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_exec_api.c |
---|
0,0 → 1,1079 |
/************************************************************************** |
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_noop.h" |
#include "main/dispatch.h" |
#include "vbo_context.h" |
#ifdef ERROR |
#undef ERROR |
#endif |
/** ID/name for immediate-mode VBO */ |
#define IMM_BUFFER_NAME 0xaabbccdd |
static void reset_attrfv( struct vbo_exec_context *exec ); |
/** |
* Close off the last primitive, execute the buffer, restart the |
* primitive. |
*/ |
static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec ) |
{ |
if (exec->vtx.prim_count == 0) { |
exec->vtx.copied.nr = 0; |
exec->vtx.vert_count = 0; |
exec->vtx.buffer_ptr = exec->vtx.buffer_map; |
} |
else { |
GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin; |
GLuint last_count; |
if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { |
GLint i = exec->vtx.prim_count - 1; |
assert(i >= 0); |
exec->vtx.prim[i].count = (exec->vtx.vert_count - |
exec->vtx.prim[i].start); |
} |
last_count = exec->vtx.prim[exec->vtx.prim_count-1].count; |
/* Execute the buffer and save copied vertices. |
*/ |
if (exec->vtx.vert_count) |
vbo_exec_vtx_flush( exec, GL_FALSE ); |
else { |
exec->vtx.prim_count = 0; |
exec->vtx.copied.nr = 0; |
} |
/* Emit a glBegin to start the new list. |
*/ |
assert(exec->vtx.prim_count == 0); |
if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { |
exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive; |
exec->vtx.prim[0].start = 0; |
exec->vtx.prim[0].count = 0; |
exec->vtx.prim_count++; |
if (exec->vtx.copied.nr == last_count) |
exec->vtx.prim[0].begin = last_begin; |
} |
} |
} |
/** |
* Deal with buffer wrapping where provoked by the vertex buffer |
* filling up, as opposed to upgrade_vertex(). |
*/ |
void vbo_exec_vtx_wrap( struct vbo_exec_context *exec ) |
{ |
GLfloat *data = exec->vtx.copied.buffer; |
GLuint i; |
/* Run pipeline on current vertices, copy wrapped vertices |
* to exec->vtx.copied. |
*/ |
vbo_exec_wrap_buffers( exec ); |
/* Copy stored stored vertices to start of new list. |
*/ |
assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr); |
for (i = 0 ; i < exec->vtx.copied.nr ; i++) { |
memcpy( exec->vtx.buffer_ptr, data, |
exec->vtx.vertex_size * sizeof(GLfloat)); |
exec->vtx.buffer_ptr += exec->vtx.vertex_size; |
data += exec->vtx.vertex_size; |
exec->vtx.vert_count++; |
} |
exec->vtx.copied.nr = 0; |
} |
/** |
* Copy the active vertex's values to the ctx->Current fields. |
*/ |
static void vbo_exec_copy_to_current( struct vbo_exec_context *exec ) |
{ |
struct gl_context *ctx = exec->ctx; |
struct vbo_context *vbo = vbo_context(ctx); |
GLuint i; |
for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { |
if (exec->vtx.attrsz[i]) { |
/* Note: the exec->vtx.current[i] pointers point into the |
* ctx->Current.Attrib and ctx->Light.Material.Attrib arrays. |
*/ |
GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; |
GLfloat tmp[4]; |
COPY_CLEAN_4V(tmp, |
exec->vtx.attrsz[i], |
exec->vtx.attrptr[i]); |
if (memcmp(current, tmp, sizeof(tmp)) != 0) |
{ |
memcpy(current, tmp, sizeof(tmp)); |
/* Given that we explicitly state size here, there is no need |
* for the COPY_CLEAN above, could just copy 16 bytes and be |
* done. The only problem is when Mesa accesses ctx->Current |
* directly. |
*/ |
vbo->currval[i].Size = exec->vtx.attrsz[i]; |
/* This triggers rather too much recalculation of Mesa state |
* that doesn't get used (eg light positions). |
*/ |
if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT && |
i <= VBO_ATTRIB_MAT_BACK_INDEXES) |
ctx->NewState |= _NEW_LIGHT; |
ctx->NewState |= _NEW_CURRENT_ATTRIB; |
} |
} |
} |
/* Colormaterial -- this kindof sucks. |
*/ |
if (ctx->Light.ColorMaterialEnabled && |
exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) { |
_mesa_update_color_material(ctx, |
ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); |
} |
} |
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. |
*/ |
static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec, |
GLuint attr, |
GLuint newsz ) |
{ |
struct gl_context *ctx = exec->ctx; |
struct vbo_context *vbo = vbo_context(ctx); |
GLint lastcount = exec->vtx.vert_count; |
GLfloat *old_attrptr[VBO_ATTRIB_MAX]; |
GLuint old_vtx_size = exec->vtx.vertex_size; |
GLuint oldsz = 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(oldsz)) { |
/* Do a COPY_TO_CURRENT to ensure back-copying works for the |
* case when the attribute already exists in the vertex and is |
* having its size increased. |
*/ |
vbo_exec_copy_to_current( exec ); |
} |
/* Heuristic: Attempt to isolate attributes received outside |
* begin/end so that they don't bloat the vertices. |
*/ |
if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END && |
!oldsz && lastcount > 8 && exec->vtx.vertex_size) { |
vbo_exec_copy_to_current( exec ); |
reset_attrfv( exec ); |
} |
/* Fix up sizes: |
*/ |
exec->vtx.attrsz[attr] = newsz; |
exec->vtx.vertex_size += newsz - oldsz; |
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(oldsz)) { |
/* 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 - newsz; |
} |
/* 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 (oldsz) { |
GLfloat tmp[4]; |
COPY_CLEAN_4V(tmp, oldsz, data + old_offset); |
COPY_SZ_4V(dest + new_offset, newsz, 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; |
} |
} |
static void vbo_exec_fixup_vertex( struct gl_context *ctx, |
GLuint attr, GLuint sz ) |
{ |
struct vbo_exec_context *exec = &vbo_context(ctx)->exec; |
int i; |
if (sz > 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, sz ); |
} |
else if (sz < exec->vtx.active_sz[attr]) { |
static const GLfloat id[4] = { 0, 0, 0, 1 }; |
/* New size is smaller - just need to fill in some |
* zeros. Don't need to flush or wrap. |
*/ |
for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++) |
exec->vtx.attrptr[attr][i-1] = id[i-1]; |
} |
exec->vtx.active_sz[attr] = sz; |
/* Does setting NeedFlush belong here? Necessitates resetting |
* vtxfmt on each flush (otherwise flags won't get reset |
* afterwards). |
*/ |
if (attr == 0) |
exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; |
} |
/* |
*/ |
#define ATTR( A, N, V0, V1, V2, V3 ) \ |
do { \ |
struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \ |
\ |
if (unlikely(!(exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \ |
ctx->Driver.BeginVertices( ctx ); \ |
if (unlikely(exec->vtx.active_sz[A] != N)) \ |
vbo_exec_fixup_vertex(ctx, A, N); \ |
\ |
{ \ |
GLfloat *dest = exec->vtx.attrptr[A]; \ |
if (N>0) dest[0] = V0; \ |
if (N>1) dest[1] = V1; \ |
if (N>2) dest[2] = V2; \ |
if (N>3) dest[3] = V3; \ |
} \ |
\ |
if ((A) == 0) { \ |
GLuint i; \ |
\ |
for (i = 0; i < exec->vtx.vertex_size; i++) \ |
exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \ |
\ |
exec->vtx.buffer_ptr += exec->vtx.vertex_size; \ |
exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \ |
\ |
if (++exec->vtx.vert_count >= exec->vtx.max_vert) \ |
vbo_exec_vtx_wrap( exec ); \ |
} \ |
} while (0) |
#define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ ) |
#define TAG(x) vbo_##x |
#include "vbo_attrib_tmp.h" |
#if FEATURE_beginend |
#if FEATURE_evaluators |
static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u ) |
{ |
GET_CURRENT_CONTEXT( ctx ); |
struct vbo_exec_context *exec = &vbo_context(ctx)->exec; |
{ |
GLint i; |
if (exec->eval.recalculate_maps) |
vbo_exec_eval_update( exec ); |
for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { |
if (exec->eval.map1[i].map) |
if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz) |
vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz ); |
} |
} |
memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, |
exec->vtx.vertex_size * sizeof(GLfloat)); |
vbo_exec_do_EvalCoord1f( exec, u ); |
memcpy( exec->vtx.vertex, exec->vtx.copied.buffer, |
exec->vtx.vertex_size * sizeof(GLfloat)); |
} |
static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v ) |
{ |
GET_CURRENT_CONTEXT( ctx ); |
struct vbo_exec_context *exec = &vbo_context(ctx)->exec; |
{ |
GLint i; |
if (exec->eval.recalculate_maps) |
vbo_exec_eval_update( exec ); |
for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { |
if (exec->eval.map2[i].map) |
if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz) |
vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz ); |
} |
if (ctx->Eval.AutoNormal) |
if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3) |
vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 ); |
} |
memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, |
exec->vtx.vertex_size * sizeof(GLfloat)); |
vbo_exec_do_EvalCoord2f( exec, u, v ); |
memcpy( exec->vtx.vertex, exec->vtx.copied.buffer, |
exec->vtx.vertex_size * sizeof(GLfloat)); |
} |
static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u ) |
{ |
vbo_exec_EvalCoord1f( u[0] ); |
} |
static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u ) |
{ |
vbo_exec_EvalCoord2f( u[0], u[1] ); |
} |
static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i ) |
{ |
GET_CURRENT_CONTEXT( ctx ); |
GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) / |
(GLfloat) ctx->Eval.MapGrid1un); |
GLfloat u = i * du + ctx->Eval.MapGrid1u1; |
vbo_exec_EvalCoord1f( u ); |
} |
static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j ) |
{ |
GET_CURRENT_CONTEXT( ctx ); |
GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) / |
(GLfloat) ctx->Eval.MapGrid2un); |
GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) / |
(GLfloat) ctx->Eval.MapGrid2vn); |
GLfloat u = i * du + ctx->Eval.MapGrid2u1; |
GLfloat v = j * dv + ctx->Eval.MapGrid2v1; |
vbo_exec_EvalCoord2f( u, v ); |
} |
/* use noop eval mesh */ |
#define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1 |
#define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2 |
#endif /* FEATURE_evaluators */ |
/** |
* Called via glBegin. |
*/ |
static void GLAPIENTRY vbo_exec_Begin( GLenum mode ) |
{ |
GET_CURRENT_CONTEXT( ctx ); |
if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) { |
struct vbo_exec_context *exec = &vbo_context(ctx)->exec; |
int i; |
if (ctx->NewState) { |
_mesa_update_state( ctx ); |
CALL_Begin(ctx->Exec, (mode)); |
return; |
} |
if (!_mesa_valid_to_render(ctx, "glBegin")) { |
return; |
} |
/* Heuristic: attempt to isolate attributes occuring outside |
* begin/end pairs. |
*/ |
if (exec->vtx.vertex_size && !exec->vtx.attrsz[0]) |
vbo_exec_FlushVertices_internal( ctx, GL_FALSE ); |
i = exec->vtx.prim_count++; |
exec->vtx.prim[i].mode = mode; |
exec->vtx.prim[i].begin = 1; |
exec->vtx.prim[i].end = 0; |
exec->vtx.prim[i].indexed = 0; |
exec->vtx.prim[i].weak = 0; |
exec->vtx.prim[i].pad = 0; |
exec->vtx.prim[i].start = exec->vtx.vert_count; |
exec->vtx.prim[i].count = 0; |
exec->vtx.prim[i].num_instances = 1; |
ctx->Driver.CurrentExecPrimitive = mode; |
} |
else |
_mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); |
} |
/** |
* Called via glEnd. |
*/ |
static void GLAPIENTRY vbo_exec_End( void ) |
{ |
GET_CURRENT_CONTEXT( ctx ); |
if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { |
struct vbo_exec_context *exec = &vbo_context(ctx)->exec; |
int idx = exec->vtx.vert_count; |
int i = exec->vtx.prim_count - 1; |
exec->vtx.prim[i].end = 1; |
exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start; |
ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; |
if (exec->vtx.prim_count == VBO_MAX_PRIM) |
vbo_exec_vtx_flush( exec, GL_FALSE ); |
} |
else |
_mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" ); |
} |
/** |
* Called via glPrimitiveRestartNV() |
*/ |
static void GLAPIENTRY |
vbo_exec_PrimitiveRestartNV(void) |
{ |
GLenum curPrim; |
GET_CURRENT_CONTEXT( ctx ); |
curPrim = ctx->Driver.CurrentExecPrimitive; |
if (curPrim == PRIM_OUTSIDE_BEGIN_END) { |
_mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" ); |
} |
else { |
vbo_exec_End(); |
vbo_exec_Begin(curPrim); |
} |
} |
static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec ) |
{ |
GLvertexformat *vfmt = &exec->vtxfmt; |
_MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_); |
vfmt->Begin = vbo_exec_Begin; |
vfmt->End = vbo_exec_End; |
vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV; |
_MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_); |
_MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_); |
vfmt->Rectf = _mesa_noop_Rectf; |
/* from attrib_tmp.h: |
*/ |
vfmt->Color3f = vbo_Color3f; |
vfmt->Color3fv = vbo_Color3fv; |
vfmt->Color4f = vbo_Color4f; |
vfmt->Color4fv = vbo_Color4fv; |
vfmt->FogCoordfEXT = vbo_FogCoordfEXT; |
vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT; |
vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f; |
vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv; |
vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f; |
vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv; |
vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f; |
vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv; |
vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f; |
vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv; |
vfmt->Normal3f = vbo_Normal3f; |
vfmt->Normal3fv = vbo_Normal3fv; |
vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT; |
vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT; |
vfmt->TexCoord1f = vbo_TexCoord1f; |
vfmt->TexCoord1fv = vbo_TexCoord1fv; |
vfmt->TexCoord2f = vbo_TexCoord2f; |
vfmt->TexCoord2fv = vbo_TexCoord2fv; |
vfmt->TexCoord3f = vbo_TexCoord3f; |
vfmt->TexCoord3fv = vbo_TexCoord3fv; |
vfmt->TexCoord4f = vbo_TexCoord4f; |
vfmt->TexCoord4fv = vbo_TexCoord4fv; |
vfmt->Vertex2f = vbo_Vertex2f; |
vfmt->Vertex2fv = vbo_Vertex2fv; |
vfmt->Vertex3f = vbo_Vertex3f; |
vfmt->Vertex3fv = vbo_Vertex3fv; |
vfmt->Vertex4f = vbo_Vertex4f; |
vfmt->Vertex4fv = vbo_Vertex4fv; |
vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB; |
vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB; |
vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB; |
vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB; |
vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB; |
vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB; |
vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB; |
vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB; |
vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV; |
vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV; |
vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV; |
vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV; |
vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV; |
vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV; |
vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV; |
vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV; |
/* integer-valued */ |
vfmt->VertexAttribI1i = vbo_VertexAttribI1i; |
vfmt->VertexAttribI2i = vbo_VertexAttribI2i; |
vfmt->VertexAttribI3i = vbo_VertexAttribI3i; |
vfmt->VertexAttribI4i = vbo_VertexAttribI4i; |
vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv; |
vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv; |
vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv; |
/* unsigned integer-valued */ |
vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui; |
vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui; |
vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui; |
vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui; |
vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv; |
vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv; |
vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv; |
vfmt->Materialfv = vbo_Materialfv; |
vfmt->EdgeFlag = vbo_EdgeFlag; |
vfmt->Indexf = vbo_Indexf; |
vfmt->Indexfv = vbo_Indexfv; |
} |
#else /* FEATURE_beginend */ |
static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec ) |
{ |
/* silence warnings */ |
(void) vbo_Color3f; |
(void) vbo_Color3fv; |
(void) vbo_Color4f; |
(void) vbo_Color4fv; |
(void) vbo_FogCoordfEXT; |
(void) vbo_FogCoordfvEXT; |
(void) vbo_MultiTexCoord1f; |
(void) vbo_MultiTexCoord1fv; |
(void) vbo_MultiTexCoord2f; |
(void) vbo_MultiTexCoord2fv; |
(void) vbo_MultiTexCoord3f; |
(void) vbo_MultiTexCoord3fv; |
(void) vbo_MultiTexCoord4f; |
(void) vbo_MultiTexCoord4fv; |
(void) vbo_Normal3f; |
(void) vbo_Normal3fv; |
(void) vbo_SecondaryColor3fEXT; |
(void) vbo_SecondaryColor3fvEXT; |
(void) vbo_TexCoord1f; |
(void) vbo_TexCoord1fv; |
(void) vbo_TexCoord2f; |
(void) vbo_TexCoord2fv; |
(void) vbo_TexCoord3f; |
(void) vbo_TexCoord3fv; |
(void) vbo_TexCoord4f; |
(void) vbo_TexCoord4fv; |
(void) vbo_Vertex2f; |
(void) vbo_Vertex2fv; |
(void) vbo_Vertex3f; |
(void) vbo_Vertex3fv; |
(void) vbo_Vertex4f; |
(void) vbo_Vertex4fv; |
(void) vbo_VertexAttrib1fARB; |
(void) vbo_VertexAttrib1fvARB; |
(void) vbo_VertexAttrib2fARB; |
(void) vbo_VertexAttrib2fvARB; |
(void) vbo_VertexAttrib3fARB; |
(void) vbo_VertexAttrib3fvARB; |
(void) vbo_VertexAttrib4fARB; |
(void) vbo_VertexAttrib4fvARB; |
(void) vbo_VertexAttrib1fNV; |
(void) vbo_VertexAttrib1fvNV; |
(void) vbo_VertexAttrib2fNV; |
(void) vbo_VertexAttrib2fvNV; |
(void) vbo_VertexAttrib3fNV; |
(void) vbo_VertexAttrib3fvNV; |
(void) vbo_VertexAttrib4fNV; |
(void) vbo_VertexAttrib4fvNV; |
(void) vbo_Materialfv; |
(void) vbo_EdgeFlag; |
(void) vbo_Indexf; |
(void) vbo_Indexfv; |
} |
#endif /* FEATURE_beginend */ |
/** |
* Tell the VBO module to use a real OpenGL vertex buffer object to |
* store accumulated immediate-mode vertex data. |
* This replaces the malloced buffer which was created in |
* vb_exec_vtx_init() below. |
*/ |
void vbo_use_buffer_objects(struct gl_context *ctx) |
{ |
struct vbo_exec_context *exec = &vbo_context(ctx)->exec; |
/* Any buffer name but 0 can be used here since this bufferobj won't |
* go into the bufferobj hashtable. |
*/ |
GLuint bufName = IMM_BUFFER_NAME; |
GLenum target = GL_ARRAY_BUFFER_ARB; |
GLenum usage = GL_STREAM_DRAW_ARB; |
GLsizei size = VBO_VERT_BUFFER_SIZE; |
/* Make sure this func is only used once */ |
assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj); |
if (exec->vtx.buffer_map) { |
_mesa_align_free(exec->vtx.buffer_map); |
exec->vtx.buffer_map = NULL; |
exec->vtx.buffer_ptr = NULL; |
} |
/* Allocate a real buffer object now */ |
_mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); |
exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target); |
ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj); |
} |
void vbo_exec_vtx_init( struct vbo_exec_context *exec ) |
{ |
struct gl_context *ctx = exec->ctx; |
struct vbo_context *vbo = vbo_context(ctx); |
GLuint i; |
/* Allocate a buffer object. Will just reuse this object |
* continuously, unless vbo_use_buffer_objects() is called to enable |
* use of real VBOs. |
*/ |
_mesa_reference_buffer_object(ctx, |
&exec->vtx.bufferobj, |
ctx->Shared->NullBufferObj); |
ASSERT(!exec->vtx.buffer_map); |
exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64); |
exec->vtx.buffer_ptr = exec->vtx.buffer_map; |
vbo_exec_vtxfmt_init( exec ); |
/* Hook our functions into the dispatch table. |
*/ |
_mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt ); |
for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { |
ASSERT(i < Elements(exec->vtx.attrsz)); |
exec->vtx.attrsz[i] = 0; |
ASSERT(i < Elements(exec->vtx.active_sz)); |
exec->vtx.active_sz[i] = 0; |
} |
for (i = 0 ; i < VERT_ATTRIB_MAX; i++) { |
ASSERT(i < Elements(exec->vtx.inputs)); |
ASSERT(i < Elements(exec->vtx.arrays)); |
exec->vtx.inputs[i] = &exec->vtx.arrays[i]; |
} |
{ |
struct gl_client_array *arrays = exec->vtx.arrays; |
unsigned i; |
memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0])); |
memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0])); |
for (i = 0; i < 16; ++i) { |
arrays[i ].BufferObj = NULL; |
arrays[i + 16].BufferObj = NULL; |
_mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj, |
vbo->legacy_currval[i].BufferObj); |
_mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj, |
vbo->generic_currval[i].BufferObj); |
} |
} |
exec->vtx.vertex_size = 0; |
} |
void vbo_exec_vtx_destroy( struct vbo_exec_context *exec ) |
{ |
/* using a real VBO for vertex data */ |
struct gl_context *ctx = exec->ctx; |
unsigned i; |
/* True VBOs should already be unmapped |
*/ |
if (exec->vtx.buffer_map) { |
ASSERT(exec->vtx.bufferobj->Name == 0 || |
exec->vtx.bufferobj->Name == IMM_BUFFER_NAME); |
if (exec->vtx.bufferobj->Name == 0) { |
_mesa_align_free(exec->vtx.buffer_map); |
exec->vtx.buffer_map = NULL; |
exec->vtx.buffer_ptr = NULL; |
} |
} |
/* Drop any outstanding reference to the vertex buffer |
*/ |
for (i = 0; i < Elements(exec->vtx.arrays); i++) { |
_mesa_reference_buffer_object(ctx, |
&exec->vtx.arrays[i].BufferObj, |
NULL); |
} |
/* Free the vertex buffer. Unmap first if needed. |
*/ |
if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) { |
ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj); |
} |
_mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); |
} |
void vbo_exec_BeginVertices( struct gl_context *ctx ) |
{ |
struct vbo_exec_context *exec = &vbo_context(ctx)->exec; |
if (0) printf("%s\n", __FUNCTION__); |
vbo_exec_vtx_map( exec ); |
assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0); |
exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; |
} |
void vbo_exec_FlushVertices_internal( struct gl_context *ctx, GLboolean unmap ) |
{ |
struct vbo_exec_context *exec = &vbo_context(ctx)->exec; |
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 ); |
} |
} |
/** |
* \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 (0) printf("%s\n", __FUNCTION__); |
if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) { |
if (0) printf("%s - inside begin/end\n", __FUNCTION__); |
#ifdef DEBUG |
exec->flush_call_depth--; |
assert(exec->flush_call_depth == 0); |
#endif |
return; |
} |
vbo_exec_FlushVertices_internal( ctx, GL_TRUE ); |
/* Need to do this to ensure BeginVertices gets called again: |
*/ |
if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) |
exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT; |
exec->ctx->Driver.NeedFlush &= ~flags; |
#ifdef DEBUG |
exec->flush_call_depth--; |
assert(exec->flush_call_depth == 0); |
#endif |
} |
static void reset_attrfv( struct vbo_exec_context *exec ) |
{ |
GLuint i; |
for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { |
exec->vtx.attrsz[i] = 0; |
exec->vtx.active_sz[i] = 0; |
} |
exec->vtx.vertex_size = 0; |
} |
void GLAPIENTRY |
_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) |
{ |
vbo_Color4f(r, g, b, a); |
} |
void GLAPIENTRY |
_es_Normal3f(GLfloat x, GLfloat y, GLfloat z) |
{ |
vbo_Normal3f(x, y, z); |
} |
void GLAPIENTRY |
_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) |
{ |
vbo_MultiTexCoord4f(target, s, t, r, q); |
} |
void GLAPIENTRY |
_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params) |
{ |
vbo_Materialfv(face, pname, params); |
} |
void GLAPIENTRY |
_es_Materialf(GLenum face, GLenum pname, GLfloat param) |
{ |
GLfloat p[4]; |
p[0] = param; |
p[1] = p[2] = p[3] = 0.0F; |
vbo_Materialfv(face, pname, p); |
} |
/** |
* A special version of glVertexAttrib4f that does not treat index 0 as |
* VBO_ATTRIB_POS. |
*/ |
static void |
VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (index < MAX_VERTEX_GENERIC_ATTRIBS) |
ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w); |
else |
ERROR(); |
} |
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]); |
} |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_exec_array.c |
---|
0,0 → 1,1277 |
/************************************************************************** |
* |
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. |
* Copyright 2009 VMware, Inc. |
* All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the |
* "Software"), to deal in the Software without restriction, including |
* without limitation the rights to use, copy, modify, merge, publish, |
* distribute, sub license, and/or sell copies of the Software, and to |
* permit persons to whom the Software is furnished to do so, subject to |
* the following conditions: |
* |
* The above copyright notice and this permission notice (including the |
* next paragraph) shall be included in all copies or substantial portions |
* of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
**************************************************************************/ |
#include "main/glheader.h" |
#include "main/context.h" |
#include "main/state.h" |
#include "main/api_validate.h" |
#include "main/varray.h" |
#include "main/bufferobj.h" |
#include "main/enums.h" |
#include "main/macros.h" |
#include "vbo_context.h" |
/** |
* Compute min and max elements by scanning the index buffer for |
* glDraw[Range]Elements() calls. |
* If primitive restart is enabled, we need to ignore restart |
* indexes when computing min/max. |
*/ |
void |
vbo_get_minmax_index(struct gl_context *ctx, |
const struct _mesa_prim *prim, |
const struct _mesa_index_buffer *ib, |
GLuint *min_index, GLuint *max_index) |
{ |
const GLboolean restart = ctx->Array.PrimitiveRestart; |
const GLuint restartIndex = ctx->Array.RestartIndex; |
const GLuint count = prim->count; |
const void *indices; |
GLuint i; |
if (_mesa_is_bufferobj(ib->obj)) { |
const GLvoid *map = |
ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, |
GL_READ_ONLY, ib->obj); |
indices = ADD_POINTERS(map, ib->ptr); |
} else { |
indices = ib->ptr; |
} |
switch (ib->type) { |
case GL_UNSIGNED_INT: { |
const GLuint *ui_indices = (const GLuint *)indices; |
GLuint max_ui = 0; |
GLuint min_ui = ~0U; |
if (restart) { |
for (i = 0; i < count; i++) { |
if (ui_indices[i] != restartIndex) { |
if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; |
if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; |
} |
} |
} |
else { |
for (i = 0; i < count; i++) { |
if (ui_indices[i] > max_ui) max_ui = ui_indices[i]; |
if (ui_indices[i] < min_ui) min_ui = ui_indices[i]; |
} |
} |
*min_index = min_ui; |
*max_index = max_ui; |
break; |
} |
case GL_UNSIGNED_SHORT: { |
const GLushort *us_indices = (const GLushort *)indices; |
GLuint max_us = 0; |
GLuint min_us = ~0U; |
if (restart) { |
for (i = 0; i < count; i++) { |
if (us_indices[i] != restartIndex) { |
if (us_indices[i] > max_us) max_us = us_indices[i]; |
if (us_indices[i] < min_us) min_us = us_indices[i]; |
} |
} |
} |
else { |
for (i = 0; i < count; i++) { |
if (us_indices[i] > max_us) max_us = us_indices[i]; |
if (us_indices[i] < min_us) min_us = us_indices[i]; |
} |
} |
*min_index = min_us; |
*max_index = max_us; |
break; |
} |
case GL_UNSIGNED_BYTE: { |
const GLubyte *ub_indices = (const GLubyte *)indices; |
GLuint max_ub = 0; |
GLuint min_ub = ~0U; |
if (restart) { |
for (i = 0; i < count; i++) { |
if (ub_indices[i] != restartIndex) { |
if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; |
if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; |
} |
} |
} |
else { |
for (i = 0; i < count; i++) { |
if (ub_indices[i] > max_ub) max_ub = ub_indices[i]; |
if (ub_indices[i] < min_ub) min_ub = ub_indices[i]; |
} |
} |
*min_index = min_ub; |
*max_index = max_ub; |
break; |
} |
default: |
assert(0); |
break; |
} |
if (_mesa_is_bufferobj(ib->obj)) { |
ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, ib->obj); |
} |
} |
/** |
* Check that element 'j' of the array has reasonable data. |
* Map VBO if needed. |
* For debugging purposes; not normally used. |
*/ |
static void |
check_array_data(struct gl_context *ctx, struct gl_client_array *array, |
GLuint attrib, GLuint j) |
{ |
if (array->Enabled) { |
const void *data = array->Ptr; |
if (_mesa_is_bufferobj(array->BufferObj)) { |
if (!array->BufferObj->Pointer) { |
/* need to map now */ |
array->BufferObj->Pointer = |
ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB, |
GL_READ_ONLY, array->BufferObj); |
} |
data = ADD_POINTERS(data, array->BufferObj->Pointer); |
} |
switch (array->Type) { |
case GL_FLOAT: |
{ |
GLfloat *f = (GLfloat *) ((GLubyte *) data + array->StrideB * j); |
GLint k; |
for (k = 0; k < array->Size; k++) { |
if (IS_INF_OR_NAN(f[k]) || |
f[k] >= 1.0e20 || f[k] <= -1.0e10) { |
printf("Bad array data:\n"); |
printf(" Element[%u].%u = %f\n", j, k, f[k]); |
printf(" Array %u at %p\n", attrib, (void* ) array); |
printf(" Type 0x%x, Size %d, Stride %d\n", |
array->Type, array->Size, array->Stride); |
printf(" Address/offset %p in Buffer Object %u\n", |
array->Ptr, array->BufferObj->Name); |
f[k] = 1.0; /* XXX replace the bad value! */ |
} |
/*assert(!IS_INF_OR_NAN(f[k]));*/ |
} |
} |
break; |
default: |
; |
} |
} |
} |
/** |
* Unmap the buffer object referenced by given array, if mapped. |
*/ |
static void |
unmap_array_buffer(struct gl_context *ctx, struct gl_client_array *array) |
{ |
if (array->Enabled && |
_mesa_is_bufferobj(array->BufferObj) && |
_mesa_bufferobj_mapped(array->BufferObj)) { |
ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, array->BufferObj); |
} |
} |
/** |
* Examine the array's data for NaNs, etc. |
* For debug purposes; not normally used. |
*/ |
static void |
check_draw_elements_data(struct gl_context *ctx, GLsizei count, GLenum elemType, |
const void *elements, GLint basevertex) |
{ |
struct gl_array_object *arrayObj = ctx->Array.ArrayObj; |
const void *elemMap; |
GLint i, k; |
if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { |
elemMap = ctx->Driver.MapBuffer(ctx, |
GL_ELEMENT_ARRAY_BUFFER_ARB, |
GL_READ_ONLY, |
ctx->Array.ElementArrayBufferObj); |
elements = ADD_POINTERS(elements, elemMap); |
} |
for (i = 0; i < count; i++) { |
GLuint j; |
/* j = element[i] */ |
switch (elemType) { |
case GL_UNSIGNED_BYTE: |
j = ((const GLubyte *) elements)[i]; |
break; |
case GL_UNSIGNED_SHORT: |
j = ((const GLushort *) elements)[i]; |
break; |
case GL_UNSIGNED_INT: |
j = ((const GLuint *) elements)[i]; |
break; |
default: |
assert(0); |
} |
/* check element j of each enabled array */ |
check_array_data(ctx, &arrayObj->Vertex, VERT_ATTRIB_POS, j); |
check_array_data(ctx, &arrayObj->Normal, VERT_ATTRIB_NORMAL, j); |
check_array_data(ctx, &arrayObj->Color, VERT_ATTRIB_COLOR0, j); |
check_array_data(ctx, &arrayObj->SecondaryColor, VERT_ATTRIB_COLOR1, j); |
for (k = 0; k < Elements(arrayObj->TexCoord); k++) { |
check_array_data(ctx, &arrayObj->TexCoord[k], VERT_ATTRIB_TEX0 + k, j); |
} |
for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { |
check_array_data(ctx, &arrayObj->VertexAttrib[k], |
VERT_ATTRIB_GENERIC0 + k, j); |
} |
} |
if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { |
ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, |
ctx->Array.ElementArrayBufferObj); |
} |
unmap_array_buffer(ctx, &arrayObj->Vertex); |
unmap_array_buffer(ctx, &arrayObj->Normal); |
unmap_array_buffer(ctx, &arrayObj->Color); |
for (k = 0; k < Elements(arrayObj->TexCoord); k++) { |
unmap_array_buffer(ctx, &arrayObj->TexCoord[k]); |
} |
for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) { |
unmap_array_buffer(ctx, &arrayObj->VertexAttrib[k]); |
} |
} |
/** |
* Check array data, looking for NaNs, etc. |
*/ |
static void |
check_draw_arrays_data(struct gl_context *ctx, GLint start, GLsizei count) |
{ |
/* TO DO */ |
} |
/** |
* Print info/data for glDrawArrays(), for debugging. |
*/ |
static void |
print_draw_arrays(struct gl_context *ctx, |
GLenum mode, GLint start, GLsizei count) |
{ |
struct vbo_context *vbo = vbo_context(ctx); |
struct vbo_exec_context *exec = &vbo->exec; |
int i; |
printf("vbo_exec_DrawArrays(mode 0x%x, start %d, count %d):\n", |
mode, start, count); |
for (i = 0; i < 32; i++) { |
GLuint bufName = exec->array.inputs[i]->BufferObj->Name; |
GLint stride = exec->array.inputs[i]->Stride; |
printf("attr %2d: size %d stride %d enabled %d " |
"ptr %p Bufobj %u\n", |
i, |
exec->array.inputs[i]->Size, |
stride, |
/*exec->array.inputs[i]->Enabled,*/ |
exec->array.legacy_array[i]->Enabled, |
exec->array.inputs[i]->Ptr, |
bufName); |
if (bufName) { |
struct gl_buffer_object *buf = _mesa_lookup_bufferobj(ctx, bufName); |
GLubyte *p = ctx->Driver.MapBuffer(ctx, GL_ARRAY_BUFFER_ARB, |
GL_READ_ONLY_ARB, buf); |
int offset = (int) (GLintptr) exec->array.inputs[i]->Ptr; |
float *f = (float *) (p + offset); |
int *k = (int *) f; |
int i; |
int n = (count * stride) / 4; |
if (n > 32) |
n = 32; |
printf(" Data at offset %d:\n", offset); |
for (i = 0; i < n; i++) { |
printf(" float[%d] = 0x%08x %f\n", i, k[i], f[i]); |
} |
ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, buf); |
} |
} |
} |
/** |
* Bind the VBO executor to the current vertex array object prior |
* to drawing. |
* |
* Just translate the arrayobj into a sane layout. |
*/ |
static void |
bind_array_obj(struct gl_context *ctx) |
{ |
struct vbo_context *vbo = vbo_context(ctx); |
struct vbo_exec_context *exec = &vbo->exec; |
struct gl_array_object *arrayObj = ctx->Array.ArrayObj; |
GLuint i; |
/* TODO: Fix the ArrayObj struct to keep legacy arrays in an array |
* rather than as individual named arrays. Then this function can |
* go away. |
*/ |
exec->array.legacy_array[VERT_ATTRIB_POS] = &arrayObj->Vertex; |
exec->array.legacy_array[VERT_ATTRIB_WEIGHT] = &arrayObj->Weight; |
exec->array.legacy_array[VERT_ATTRIB_NORMAL] = &arrayObj->Normal; |
exec->array.legacy_array[VERT_ATTRIB_COLOR0] = &arrayObj->Color; |
exec->array.legacy_array[VERT_ATTRIB_COLOR1] = &arrayObj->SecondaryColor; |
exec->array.legacy_array[VERT_ATTRIB_FOG] = &arrayObj->FogCoord; |
exec->array.legacy_array[VERT_ATTRIB_COLOR_INDEX] = &arrayObj->Index; |
if (arrayObj->PointSize.Enabled) { |
/* this aliases COLOR_INDEX */ |
exec->array.legacy_array[VERT_ATTRIB_POINT_SIZE] = &arrayObj->PointSize; |
} |
exec->array.legacy_array[VERT_ATTRIB_EDGEFLAG] = &arrayObj->EdgeFlag; |
for (i = 0; i < Elements(arrayObj->TexCoord); i++) |
exec->array.legacy_array[VERT_ATTRIB_TEX0 + i] = &arrayObj->TexCoord[i]; |
for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) { |
assert(i < Elements(exec->array.generic_array)); |
exec->array.generic_array[i] = &arrayObj->VertexAttrib[i]; |
} |
exec->array.array_obj = arrayObj->Name; |
} |
/** |
* Set the vbo->exec->inputs[] pointers to point to the enabled |
* vertex arrays. This depends on the current vertex program/shader |
* being executed because of whether or not generic vertex arrays |
* alias the conventional vertex arrays. |
* For arrays that aren't enabled, we set the input[attrib] pointer |
* to point at a zero-stride current value "array". |
*/ |
static void |
recalculate_input_bindings(struct gl_context *ctx) |
{ |
struct vbo_context *vbo = vbo_context(ctx); |
struct vbo_exec_context *exec = &vbo->exec; |
const struct gl_client_array **inputs = &exec->array.inputs[0]; |
GLbitfield const_inputs = 0x0; |
GLuint i; |
exec->array.program_mode = get_program_mode(ctx); |
exec->array.enabled_flags = ctx->Array.ArrayObj->_Enabled; |
switch (exec->array.program_mode) { |
case VP_NONE: |
/* When no vertex program is active (or the vertex program is generated |
* from fixed-function state). We put the material values into the |
* generic slots. This is the only situation where material values |
* are available as per-vertex attributes. |
*/ |
for (i = 0; i <= VERT_ATTRIB_TEX7; i++) { |
if (exec->array.legacy_array[i]->Enabled) |
inputs[i] = exec->array.legacy_array[i]; |
else { |
inputs[i] = &vbo->legacy_currval[i]; |
const_inputs |= 1 << i; |
} |
} |
for (i = 0; i < MAT_ATTRIB_MAX; i++) { |
inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->mat_currval[i]; |
const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); |
} |
/* Could use just about anything, just to fill in the empty |
* slots: |
*/ |
for (i = MAT_ATTRIB_MAX; i < VERT_ATTRIB_MAX - VERT_ATTRIB_GENERIC0; i++) { |
inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; |
const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); |
} |
break; |
case VP_NV: |
/* NV_vertex_program - attribute arrays alias and override |
* conventional, legacy arrays. No materials, and the generic |
* slots are vacant. |
*/ |
for (i = 0; i <= VERT_ATTRIB_TEX7; i++) { |
if (exec->array.generic_array[i]->Enabled) |
inputs[i] = exec->array.generic_array[i]; |
else if (exec->array.legacy_array[i]->Enabled) |
inputs[i] = exec->array.legacy_array[i]; |
else { |
inputs[i] = &vbo->legacy_currval[i]; |
const_inputs |= 1 << i; |
} |
} |
/* Could use just about anything, just to fill in the empty |
* slots: |
*/ |
for (i = VERT_ATTRIB_GENERIC0; i < VERT_ATTRIB_MAX; i++) { |
inputs[i] = &vbo->generic_currval[i - VERT_ATTRIB_GENERIC0]; |
const_inputs |= 1 << i; |
} |
break; |
case VP_ARB: |
/* GL_ARB_vertex_program or GLSL vertex shader - Only the generic[0] |
* attribute array aliases and overrides the legacy position array. |
* |
* Otherwise, legacy attributes available in the legacy slots, |
* generic attributes in the generic slots and materials are not |
* available as per-vertex attributes. |
*/ |
if (exec->array.generic_array[0]->Enabled) |
inputs[0] = exec->array.generic_array[0]; |
else if (exec->array.legacy_array[0]->Enabled) |
inputs[0] = exec->array.legacy_array[0]; |
else { |
inputs[0] = &vbo->legacy_currval[0]; |
const_inputs |= 1 << 0; |
} |
for (i = 1; i <= VERT_ATTRIB_TEX7; i++) { |
if (exec->array.legacy_array[i]->Enabled) |
inputs[i] = exec->array.legacy_array[i]; |
else { |
inputs[i] = &vbo->legacy_currval[i]; |
const_inputs |= 1 << i; |
} |
} |
for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) { |
if (exec->array.generic_array[i]->Enabled) |
inputs[VERT_ATTRIB_GENERIC0 + i] = exec->array.generic_array[i]; |
else { |
inputs[VERT_ATTRIB_GENERIC0 + i] = &vbo->generic_currval[i]; |
const_inputs |= 1 << (VERT_ATTRIB_GENERIC0 + i); |
} |
} |
break; |
} |
_mesa_set_varying_vp_inputs( ctx, ~const_inputs ); |
} |
/** |
* Examine the enabled vertex arrays to set the exec->array.inputs[] values. |
* These will point to the arrays to actually use for drawing. Some will |
* be user-provided arrays, other will be zero-stride const-valued arrays. |
* Note that this might set the _NEW_ARRAY dirty flag so state validation |
* must be done after this call. |
*/ |
static void |
bind_arrays(struct gl_context *ctx) |
{ |
bind_array_obj(ctx); |
recalculate_input_bindings(ctx); |
} |
/** |
* Helper function called by the other DrawArrays() functions below. |
* This is where we handle primitive restart for drawing non-indexed |
* arrays. If primitive restart is enabled, it typically means |
* splitting one DrawArrays() into two. |
*/ |
static void |
vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, |
GLsizei count, GLuint numInstances) |
{ |
struct vbo_context *vbo = vbo_context(ctx); |
struct vbo_exec_context *exec = &vbo->exec; |
struct _mesa_prim prim[2]; |
bind_arrays(ctx); |
/* Again... because we may have changed the bitmask of per-vertex varying |
* attributes. If we regenerate the fixed-function vertex program now |
* we may be able to prune down the number of vertex attributes which we |
* need in the shader. |
*/ |
if (ctx->NewState) |
_mesa_update_state(ctx); |
prim[0].begin = 1; |
prim[0].end = 1; |
prim[0].weak = 0; |
prim[0].pad = 0; |
prim[0].mode = mode; |
prim[0].start = 0; /* filled in below */ |
prim[0].count = 0; /* filled in below */ |
prim[0].indexed = 0; |
prim[0].basevertex = 0; |
prim[0].num_instances = numInstances; |
/* Implement the primitive restart index */ |
if (ctx->Array.PrimitiveRestart && ctx->Array.RestartIndex < count) { |
GLuint primCount = 0; |
if (ctx->Array.RestartIndex == start) { |
/* special case: RestartIndex at beginning */ |
if (count > 1) { |
prim[0].start = start + 1; |
prim[0].count = count - 1; |
primCount = 1; |
} |
} |
else if (ctx->Array.RestartIndex == start + count - 1) { |
/* special case: RestartIndex at end */ |
if (count > 1) { |
prim[0].start = start; |
prim[0].count = count - 1; |
primCount = 1; |
} |
} |
else { |
/* general case: RestartIndex in middle, split into two prims */ |
prim[0].start = start; |
prim[0].count = ctx->Array.RestartIndex - start; |
prim[1] = prim[0]; |
prim[1].start = ctx->Array.RestartIndex + 1; |
prim[1].count = count - prim[1].start; |
primCount = 2; |
} |
if (primCount > 0) { |
/* draw one or two prims */ |
vbo->draw_prims(ctx, exec->array.inputs, prim, primCount, NULL, |
GL_TRUE, start, start + count - 1); |
} |
} |
else { |
/* no prim restart */ |
prim[0].start = start; |
prim[0].count = count; |
vbo->draw_prims(ctx, exec->array.inputs, prim, 1, NULL, |
GL_TRUE, start, start + count - 1); |
} |
} |
/** |
* Called from glDrawArrays when in immediate mode (not display list mode). |
*/ |
static void GLAPIENTRY |
vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (MESA_VERBOSE & VERBOSE_DRAW) |
_mesa_debug(ctx, "glDrawArrays(%s, %d, %d)\n", |
_mesa_lookup_enum_by_nr(mode), start, count); |
if (!_mesa_validate_DrawArrays( ctx, mode, start, count )) |
return; |
FLUSH_CURRENT( ctx, 0 ); |
if (!_mesa_valid_to_render(ctx, "glDrawArrays")) { |
return; |
} |
if (0) |
check_draw_arrays_data(ctx, start, count); |
vbo_draw_arrays(ctx, mode, start, count, 1); |
if (0) |
print_draw_arrays(ctx, mode, start, count); |
} |
/** |
* Called from glDrawArraysInstanced when in immediate mode (not |
* display list mode). |
*/ |
static void GLAPIENTRY |
vbo_exec_DrawArraysInstanced(GLenum mode, GLint start, GLsizei count, |
GLsizei primcount) |
{ |
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, primcount); |
if (!_mesa_validate_DrawArraysInstanced(ctx, mode, start, count, primcount)) |
return; |
FLUSH_CURRENT( ctx, 0 ); |
if (!_mesa_valid_to_render(ctx, "glDrawArraysInstanced")) { |
return; |
} |
if (0) |
check_draw_arrays_data(ctx, start, count); |
vbo_draw_arrays(ctx, mode, start, count, primcount); |
if (0) |
print_draw_arrays(ctx, mode, start, count); |
} |
/** |
* Map GL_ELEMENT_ARRAY_BUFFER and print contents. |
* For debugging. |
*/ |
static void |
dump_element_buffer(struct gl_context *ctx, GLenum type) |
{ |
const GLvoid *map = ctx->Driver.MapBuffer(ctx, |
GL_ELEMENT_ARRAY_BUFFER_ARB, |
GL_READ_ONLY, |
ctx->Array.ElementArrayBufferObj); |
switch (type) { |
case GL_UNSIGNED_BYTE: |
{ |
const GLubyte *us = (const GLubyte *) map; |
GLint i; |
for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size; i++) { |
printf("%02x ", us[i]); |
if (i % 32 == 31) |
printf("\n"); |
} |
printf("\n"); |
} |
break; |
case GL_UNSIGNED_SHORT: |
{ |
const GLushort *us = (const GLushort *) map; |
GLint i; |
for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 2; i++) { |
printf("%04x ", us[i]); |
if (i % 16 == 15) |
printf("\n"); |
} |
printf("\n"); |
} |
break; |
case GL_UNSIGNED_INT: |
{ |
const GLuint *us = (const GLuint *) map; |
GLint i; |
for (i = 0; i < ctx->Array.ElementArrayBufferObj->Size / 4; i++) { |
printf("%08x ", us[i]); |
if (i % 8 == 7) |
printf("\n"); |
} |
printf("\n"); |
} |
break; |
default: |
; |
} |
ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, |
ctx->Array.ElementArrayBufferObj); |
} |
/** |
* Inner support for both _mesa_DrawElements and _mesa_DrawRangeElements. |
* Do the rendering for a glDrawElements or glDrawRangeElements call after |
* we've validated buffer bounds, etc. |
*/ |
static void |
vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode, |
GLboolean index_bounds_valid, |
GLuint start, GLuint end, |
GLsizei count, GLenum type, |
const GLvoid *indices, |
GLint basevertex, GLint primcount) |
{ |
struct vbo_context *vbo = vbo_context(ctx); |
struct vbo_exec_context *exec = &vbo->exec; |
struct _mesa_index_buffer ib; |
struct _mesa_prim prim[1]; |
FLUSH_CURRENT( ctx, 0 ); |
if (!_mesa_valid_to_render(ctx, "glDraw[Range]Elements")) { |
return; |
} |
bind_arrays( ctx ); |
/* check for dirty state again */ |
if (ctx->NewState) |
_mesa_update_state( ctx ); |
ib.count = count; |
ib.type = type; |
ib.obj = ctx->Array.ElementArrayBufferObj; |
ib.ptr = indices; |
prim[0].begin = 1; |
prim[0].end = 1; |
prim[0].weak = 0; |
prim[0].pad = 0; |
prim[0].mode = mode; |
prim[0].start = 0; |
prim[0].count = count; |
prim[0].indexed = 1; |
prim[0].basevertex = basevertex; |
prim[0].num_instances = primcount; |
/* 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. |
*/ |
vbo->draw_prims( ctx, exec->array.inputs, prim, 1, &ib, |
index_bounds_valid, start, end ); |
} |
/** |
* Called by glDrawRangeElementsBaseVertex() in immediate mode. |
*/ |
static void GLAPIENTRY |
vbo_exec_DrawRangeElementsBaseVertex(GLenum mode, |
GLuint start, GLuint end, |
GLsizei count, GLenum type, |
const GLvoid *indices, |
GLint basevertex) |
{ |
static GLuint warnCount = 0; |
GET_CURRENT_CONTEXT(ctx); |
if (MESA_VERBOSE & VERBOSE_DRAW) |
_mesa_debug(ctx, |
"glDrawRangeElementsBaseVertex(%s, %u, %u, %d, %s, %p, %d)\n", |
_mesa_lookup_enum_by_nr(mode), start, end, count, |
_mesa_lookup_enum_by_nr(type), indices, basevertex); |
if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count, |
type, indices, basevertex )) |
return; |
/* NOTE: It's important that 'end' is a reasonable value. |
* in _tnl_draw_prims(), we use end to determine how many vertices |
* to transform. If it's too large, we can unnecessarily split prims |
* or we can read/write out of memory in several different places! |
*/ |
/* Catch/fix some potential user errors */ |
if (type == GL_UNSIGNED_BYTE) { |
start = MIN2(start, 0xff); |
end = MIN2(end, 0xff); |
} |
else if (type == GL_UNSIGNED_SHORT) { |
start = MIN2(start, 0xffff); |
end = MIN2(end, 0xffff); |
} |
if (end >= ctx->Array.ArrayObj->_MaxElement) { |
/* the max element is out of bounds of one or more enabled arrays */ |
warnCount++; |
if (warnCount < 10) { |
_mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, count %d, " |
"type 0x%x, indices=%p)\n" |
"\tend is out of bounds (max=%u) " |
"Element Buffer %u (size %d)\n" |
"\tThis should probably be fixed in the application.", |
start, end, count, type, indices, |
ctx->Array.ArrayObj->_MaxElement - 1, |
ctx->Array.ElementArrayBufferObj->Name, |
(int) ctx->Array.ElementArrayBufferObj->Size); |
} |
if (0) |
dump_element_buffer(ctx, type); |
if (0) |
_mesa_print_arrays(ctx); |
#ifdef DEBUG |
/* 'end' was out of bounds, but now let's check the actual array |
* indexes to see if any of them are out of bounds. |
*/ |
{ |
GLuint max = _mesa_max_buffer_index(ctx, count, type, indices, |
ctx->Array.ElementArrayBufferObj); |
if (max >= ctx->Array.ArrayObj->_MaxElement) { |
if (warnCount < 10) { |
_mesa_warning(ctx, "glDraw[Range]Elements(start %u, end %u, " |
"count %d, type 0x%x, indices=%p)\n" |
"\tindex=%u is out of bounds (max=%u) " |
"Element Buffer %u (size %d)\n" |
"\tSkipping the glDrawRangeElements() call", |
start, end, count, type, indices, max, |
ctx->Array.ArrayObj->_MaxElement - 1, |
ctx->Array.ElementArrayBufferObj->Name, |
(int) ctx->Array.ElementArrayBufferObj->Size); |
} |
} |
/* XXX we could also find the min index and compare to 'start' |
* to see if start is correct. But it's more likely to get the |
* upper bound wrong. |
*/ |
} |
#endif |
/* Set 'end' to the max possible legal value */ |
assert(ctx->Array.ArrayObj->_MaxElement >= 1); |
end = ctx->Array.ArrayObj->_MaxElement - 1; |
} |
else if (0) { |
printf("glDraw[Range]Elements{,BaseVertex}" |
"(start %u, end %u, type 0x%x, count %d) ElemBuf %u, " |
"base %d\n", |
start, end, type, count, |
ctx->Array.ElementArrayBufferObj->Name, |
basevertex); |
} |
#if 0 |
check_draw_elements_data(ctx, count, type, indices); |
#else |
(void) check_draw_elements_data; |
#endif |
vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end, |
count, type, indices, basevertex, 1); |
} |
/** |
* Called by glDrawRangeElements() in immediate mode. |
*/ |
static void GLAPIENTRY |
vbo_exec_DrawRangeElements(GLenum mode, GLuint start, GLuint end, |
GLsizei count, GLenum type, const GLvoid *indices) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (MESA_VERBOSE & VERBOSE_DRAW) |
_mesa_debug(ctx, |
"glDrawRangeElements(%s, %u, %u, %d, %s, %p)\n", |
_mesa_lookup_enum_by_nr(mode), start, end, count, |
_mesa_lookup_enum_by_nr(type), indices); |
vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, |
indices, 0); |
} |
/** |
* Called by glDrawElements() in immediate mode. |
*/ |
static void GLAPIENTRY |
vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type, |
const GLvoid *indices) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (MESA_VERBOSE & VERBOSE_DRAW) |
_mesa_debug(ctx, "glDrawElements(%s, %u, %s, %p)\n", |
_mesa_lookup_enum_by_nr(mode), count, |
_mesa_lookup_enum_by_nr(type), indices); |
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) |
return; |
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, |
count, type, indices, 0, 1); |
} |
/** |
* Called by glDrawElementsBaseVertex() in immediate mode. |
*/ |
static void GLAPIENTRY |
vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, |
const GLvoid *indices, GLint basevertex) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (MESA_VERBOSE & VERBOSE_DRAW) |
_mesa_debug(ctx, "glDrawElementsBaseVertex(%s, %d, %s, %p, %d)\n", |
_mesa_lookup_enum_by_nr(mode), count, |
_mesa_lookup_enum_by_nr(type), indices, basevertex); |
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, |
basevertex )) |
return; |
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, |
count, type, indices, basevertex, 1); |
} |
/** |
* Called by glDrawElementsInstanced() in immediate mode. |
*/ |
static void GLAPIENTRY |
vbo_exec_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, |
const GLvoid *indices, GLsizei primcount) |
{ |
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, primcount); |
if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices, |
primcount)) |
return; |
vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0, |
count, type, indices, 0, primcount); |
} |
/** |
* Inner support for both _mesa_MultiDrawElements() and |
* _mesa_MultiDrawRangeElements(). |
* This does the actual rendering after we've checked array indexes, etc. |
*/ |
static void |
vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, |
const GLsizei *count, GLenum type, |
const GLvoid **indices, GLsizei primcount, |
const GLint *basevertex) |
{ |
struct vbo_context *vbo = vbo_context(ctx); |
struct vbo_exec_context *exec = &vbo->exec; |
struct _mesa_index_buffer ib; |
struct _mesa_prim *prim; |
unsigned int index_type_size = 0; |
uintptr_t min_index_ptr, max_index_ptr; |
GLboolean fallback = GL_FALSE; |
int i; |
if (primcount == 0) |
return; |
FLUSH_CURRENT( ctx, 0 ); |
if (!_mesa_valid_to_render(ctx, "glMultiDrawElements")) { |
return; |
} |
prim = calloc(1, primcount * sizeof(*prim)); |
if (prim == NULL) { |
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElements"); |
return; |
} |
/* Decide if we can do this all as one set of primitives sharing the |
* same index buffer, or if we have to reset the index pointer per |
* primitive. |
*/ |
bind_arrays( ctx ); |
/* check for dirty state again */ |
if (ctx->NewState) |
_mesa_update_state( ctx ); |
switch (type) { |
case GL_UNSIGNED_INT: |
index_type_size = 4; |
break; |
case GL_UNSIGNED_SHORT: |
index_type_size = 2; |
break; |
case GL_UNSIGNED_BYTE: |
index_type_size = 1; |
break; |
default: |
assert(0); |
} |
min_index_ptr = (uintptr_t)indices[0]; |
max_index_ptr = 0; |
for (i = 0; i < primcount; i++) { |
min_index_ptr = MIN2(min_index_ptr, (uintptr_t)indices[i]); |
max_index_ptr = MAX2(max_index_ptr, (uintptr_t)indices[i] + |
index_type_size * count[i]); |
} |
/* Check if we can handle this thing as a bunch of index offsets from the |
* same index pointer. If we can't, then we have to fall back to doing |
* a draw_prims per primitive. |
* Check that the difference between each prim's indexes is a multiple of |
* the index/element size. |
*/ |
if (index_type_size != 1) { |
for (i = 0; i < primcount; i++) { |
if ((((uintptr_t)indices[i] - min_index_ptr) % index_type_size) != 0) { |
fallback = GL_TRUE; |
break; |
} |
} |
} |
/* If the index buffer isn't in a VBO, then treating the application's |
* subranges of the index buffer as one large index buffer may lead to |
* us reading unmapped memory. |
*/ |
if (!_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) |
fallback = GL_TRUE; |
if (!fallback) { |
ib.count = (max_index_ptr - min_index_ptr) / index_type_size; |
ib.type = type; |
ib.obj = ctx->Array.ElementArrayBufferObj; |
ib.ptr = (void *)min_index_ptr; |
for (i = 0; i < primcount; i++) { |
prim[i].begin = (i == 0); |
prim[i].end = (i == primcount - 1); |
prim[i].weak = 0; |
prim[i].pad = 0; |
prim[i].mode = mode; |
prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size; |
prim[i].count = count[i]; |
prim[i].indexed = 1; |
prim[i].num_instances = 1; |
if (basevertex != NULL) |
prim[i].basevertex = basevertex[i]; |
else |
prim[i].basevertex = 0; |
} |
vbo->draw_prims(ctx, exec->array.inputs, prim, primcount, &ib, |
GL_FALSE, ~0, ~0); |
} else { |
/* render one prim at a time */ |
for (i = 0; i < primcount; i++) { |
ib.count = count[i]; |
ib.type = type; |
ib.obj = ctx->Array.ElementArrayBufferObj; |
ib.ptr = indices[i]; |
prim[0].begin = 1; |
prim[0].end = 1; |
prim[0].weak = 0; |
prim[0].pad = 0; |
prim[0].mode = mode; |
prim[0].start = 0; |
prim[0].count = count[i]; |
prim[0].indexed = 1; |
prim[0].num_instances = 1; |
if (basevertex != NULL) |
prim[0].basevertex = basevertex[i]; |
else |
prim[0].basevertex = 0; |
vbo->draw_prims(ctx, exec->array.inputs, prim, 1, &ib, |
GL_FALSE, ~0, ~0); |
} |
} |
free(prim); |
} |
static void GLAPIENTRY |
vbo_exec_MultiDrawElements(GLenum mode, |
const GLsizei *count, GLenum type, |
const GLvoid **indices, |
GLsizei primcount) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLint i; |
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); |
for (i = 0; i < primcount; i++) { |
if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], |
0)) |
return; |
} |
vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, |
NULL); |
} |
static void GLAPIENTRY |
vbo_exec_MultiDrawElementsBaseVertex(GLenum mode, |
const GLsizei *count, GLenum type, |
const GLvoid **indices, |
GLsizei primcount, |
const GLsizei *basevertex) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLint i; |
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); |
for (i = 0; i < primcount; i++) { |
if (!_mesa_validate_DrawElements(ctx, mode, count[i], type, indices[i], |
basevertex[i])) |
return; |
} |
vbo_validated_multidrawelements(ctx, mode, count, type, indices, primcount, |
basevertex); |
} |
/** |
* Plug in the immediate-mode vertex array drawing commands into the |
* givven vbo_exec_context object. |
*/ |
void |
vbo_exec_array_init( struct vbo_exec_context *exec ) |
{ |
exec->vtxfmt.DrawArrays = vbo_exec_DrawArrays; |
exec->vtxfmt.DrawElements = vbo_exec_DrawElements; |
exec->vtxfmt.DrawRangeElements = vbo_exec_DrawRangeElements; |
exec->vtxfmt.MultiDrawElementsEXT = vbo_exec_MultiDrawElements; |
exec->vtxfmt.DrawElementsBaseVertex = vbo_exec_DrawElementsBaseVertex; |
exec->vtxfmt.DrawRangeElementsBaseVertex = vbo_exec_DrawRangeElementsBaseVertex; |
exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex; |
exec->vtxfmt.DrawArraysInstanced = vbo_exec_DrawArraysInstanced; |
exec->vtxfmt.DrawElementsInstanced = vbo_exec_DrawElementsInstanced; |
} |
void |
vbo_exec_array_destroy( struct vbo_exec_context *exec ) |
{ |
/* nothing to do */ |
} |
/** |
* The following functions are only used for OpenGL ES 1/2 support. |
* And some aren't even supported (yet) in ES 1/2. |
*/ |
void GLAPIENTRY |
_mesa_DrawArrays(GLenum mode, GLint first, GLsizei count) |
{ |
vbo_exec_DrawArrays(mode, first, count); |
} |
void GLAPIENTRY |
_mesa_DrawElements(GLenum mode, GLsizei count, GLenum type, |
const GLvoid *indices) |
{ |
vbo_exec_DrawElements(mode, count, type, indices); |
} |
void GLAPIENTRY |
_mesa_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, |
const GLvoid *indices, GLint basevertex) |
{ |
vbo_exec_DrawElementsBaseVertex(mode, count, type, indices, basevertex); |
} |
void GLAPIENTRY |
_mesa_DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, |
GLenum type, const GLvoid *indices) |
{ |
vbo_exec_DrawRangeElements(mode, start, end, count, type, indices); |
} |
void GLAPIENTRY |
_mesa_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, |
GLsizei count, GLenum type, |
const GLvoid *indices, GLint basevertex) |
{ |
vbo_exec_DrawRangeElementsBaseVertex(mode, start, end, count, type, |
indices, basevertex); |
} |
void GLAPIENTRY |
_mesa_MultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type, |
const GLvoid **indices, GLsizei primcount) |
{ |
vbo_exec_MultiDrawElements(mode, count, type, indices, primcount); |
} |
void GLAPIENTRY |
_mesa_MultiDrawElementsBaseVertex(GLenum mode, |
const GLsizei *count, GLenum type, |
const GLvoid **indices, GLsizei primcount, |
const GLint *basevertex) |
{ |
vbo_exec_MultiDrawElementsBaseVertex(mode, count, type, indices, |
primcount, basevertex); |
} |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_exec_draw.c |
---|
0,0 → 1,419 |
/* |
* Mesa 3-D graphics library |
* Version: 7.2 |
* |
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/bufferobj.h" |
#include "main/compiler.h" |
#include "main/enums.h" |
#include "main/state.h" |
#include "vbo_context.h" |
#if FEATURE_beginend |
static void |
vbo_exec_debug_verts( struct vbo_exec_context *exec ) |
{ |
GLuint count = exec->vtx.vert_count; |
GLuint i; |
printf("%s: %u vertices %d primitives, %d vertsize\n", |
__FUNCTION__, |
count, |
exec->vtx.prim_count, |
exec->vtx.vertex_size); |
for (i = 0 ; i < exec->vtx.prim_count ; i++) { |
struct _mesa_prim *prim = &exec->vtx.prim[i]; |
printf(" prim %d: %s%s %d..%d %s %s\n", |
i, |
_mesa_lookup_prim_by_nr(prim->mode), |
prim->weak ? " (weak)" : "", |
prim->start, |
prim->start + prim->count, |
prim->begin ? "BEGIN" : "(wrap)", |
prim->end ? "END" : "(wrap)"); |
} |
} |
/* |
* NOTE: Need to have calculated primitives by this point -- do it on the fly. |
* NOTE: Old 'parity' issue is gone. |
*/ |
static GLuint |
vbo_copy_vertices( struct vbo_exec_context *exec ) |
{ |
GLuint nr = exec->vtx.prim[exec->vtx.prim_count-1].count; |
GLuint ovf, i; |
GLuint sz = exec->vtx.vertex_size; |
GLfloat *dst = exec->vtx.copied.buffer; |
const GLfloat *src = (exec->vtx.buffer_map + |
exec->vtx.prim[exec->vtx.prim_count-1].start * |
exec->vtx.vertex_size); |
switch (exec->ctx->Driver.CurrentExecPrimitive) { |
case GL_POINTS: |
return 0; |
case GL_LINES: |
ovf = nr&1; |
for (i = 0 ; i < ovf ; i++) |
memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); |
return i; |
case GL_TRIANGLES: |
ovf = nr%3; |
for (i = 0 ; i < ovf ; i++) |
memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); |
return i; |
case GL_QUADS: |
ovf = nr&3; |
for (i = 0 ; i < ovf ; i++) |
memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); |
return i; |
case GL_LINE_STRIP: |
if (nr == 0) { |
return 0; |
} |
else { |
memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) ); |
return 1; |
} |
case GL_LINE_LOOP: |
case GL_TRIANGLE_FAN: |
case GL_POLYGON: |
if (nr == 0) { |
return 0; |
} |
else if (nr == 1) { |
memcpy( dst, src+0, sz * sizeof(GLfloat) ); |
return 1; |
} |
else { |
memcpy( dst, src+0, sz * sizeof(GLfloat) ); |
memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) ); |
return 2; |
} |
case GL_TRIANGLE_STRIP: |
/* no parity issue, but need to make sure the tri is not drawn twice */ |
if (nr & 1) { |
exec->vtx.prim[exec->vtx.prim_count-1].count--; |
} |
/* fallthrough */ |
case GL_QUAD_STRIP: |
switch (nr) { |
case 0: |
ovf = 0; |
break; |
case 1: |
ovf = 1; |
break; |
default: |
ovf = 2 + (nr & 1); |
break; |
} |
for (i = 0 ; i < ovf ; i++) |
memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) ); |
return i; |
case PRIM_OUTSIDE_BEGIN_END: |
return 0; |
default: |
assert(0); |
return 0; |
} |
} |
/* TODO: populate these as the vertex is defined: |
*/ |
static void |
vbo_exec_bind_arrays( struct gl_context *ctx ) |
{ |
struct vbo_context *vbo = vbo_context(ctx); |
struct vbo_exec_context *exec = &vbo->exec; |
struct gl_client_array *arrays = exec->vtx.arrays; |
const GLuint count = exec->vtx.vert_count; |
const GLuint *map; |
GLuint attr; |
GLbitfield varying_inputs = 0x0; |
/* Install the default (ie Current) attributes first, then overlay |
* all active ones. |
*/ |
switch (get_program_mode(exec->ctx)) { |
case VP_NONE: |
for (attr = 0; attr < 16; attr++) { |
exec->vtx.inputs[attr] = &vbo->legacy_currval[attr]; |
} |
for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) { |
ASSERT(attr + 16 < Elements(exec->vtx.inputs)); |
exec->vtx.inputs[attr + 16] = &vbo->mat_currval[attr]; |
} |
map = vbo->map_vp_none; |
break; |
case VP_NV: |
case VP_ARB: |
/* The aliasing of attributes for NV vertex programs has already |
* occurred. NV vertex programs cannot access material values, |
* nor attributes greater than VERT_ATTRIB_TEX7. |
*/ |
for (attr = 0; attr < 16; attr++) { |
exec->vtx.inputs[attr] = &vbo->legacy_currval[attr]; |
ASSERT(attr + 16 < Elements(exec->vtx.inputs)); |
exec->vtx.inputs[attr + 16] = &vbo->generic_currval[attr]; |
} |
map = vbo->map_vp_arb; |
/* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read. |
* In that case we effectively need to route the data from |
* glVertexAttrib(0, val) calls to feed into the GENERIC0 input. |
*/ |
if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 && |
(ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) { |
exec->vtx.inputs[16] = exec->vtx.inputs[0]; |
exec->vtx.attrsz[16] = exec->vtx.attrsz[0]; |
exec->vtx.attrptr[16] = exec->vtx.attrptr[0]; |
exec->vtx.attrsz[0] = 0; |
} |
break; |
default: |
assert(0); |
} |
/* Make all active attributes (including edgeflag) available as |
* arrays of floats. |
*/ |
for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) { |
const GLuint src = map[attr]; |
if (exec->vtx.attrsz[src]) { |
GLsizeiptr offset = (GLbyte *)exec->vtx.attrptr[src] - |
(GLbyte *)exec->vtx.vertex; |
/* override the default array set above */ |
ASSERT(attr < Elements(exec->vtx.inputs)); |
ASSERT(attr < Elements(exec->vtx.arrays)); /* arrays[] */ |
exec->vtx.inputs[attr] = &arrays[attr]; |
if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { |
/* a real buffer obj: Ptr is an offset, not a pointer*/ |
assert(exec->vtx.bufferobj->Pointer); /* buf should be mapped */ |
assert(offset >= 0); |
arrays[attr].Ptr = (GLubyte *)exec->vtx.bufferobj->Offset + offset; |
} |
else { |
/* Ptr into ordinary app memory */ |
arrays[attr].Ptr = (GLubyte *)exec->vtx.buffer_map + offset; |
} |
arrays[attr].Size = exec->vtx.attrsz[src]; |
arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat); |
arrays[attr].Stride = exec->vtx.vertex_size * sizeof(GLfloat); |
arrays[attr].Type = GL_FLOAT; |
arrays[attr].Format = GL_RGBA; |
arrays[attr].Enabled = 1; |
_mesa_reference_buffer_object(ctx, |
&arrays[attr].BufferObj, |
exec->vtx.bufferobj); |
arrays[attr]._MaxElement = count; /* ??? */ |
varying_inputs |= 1 << attr; |
} |
} |
_mesa_set_varying_vp_inputs( ctx, varying_inputs ); |
} |
static void |
vbo_exec_vtx_unmap( struct vbo_exec_context *exec ) |
{ |
GLenum target = GL_ARRAY_BUFFER_ARB; |
if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { |
struct gl_context *ctx = exec->ctx; |
if (ctx->Driver.FlushMappedBufferRange) { |
GLintptr offset = exec->vtx.buffer_used - exec->vtx.bufferobj->Offset; |
GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) * sizeof(float); |
if (length) |
ctx->Driver.FlushMappedBufferRange(ctx, target, |
offset, length, |
exec->vtx.bufferobj); |
} |
exec->vtx.buffer_used += (exec->vtx.buffer_ptr - |
exec->vtx.buffer_map) * sizeof(float); |
assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE); |
assert(exec->vtx.buffer_ptr != NULL); |
ctx->Driver.UnmapBuffer(ctx, target, exec->vtx.bufferobj); |
exec->vtx.buffer_map = NULL; |
exec->vtx.buffer_ptr = NULL; |
exec->vtx.max_vert = 0; |
} |
} |
void |
vbo_exec_vtx_map( struct vbo_exec_context *exec ) |
{ |
struct gl_context *ctx = exec->ctx; |
const GLenum target = GL_ARRAY_BUFFER_ARB; |
const GLenum access = GL_READ_WRITE_ARB; /* for MapBuffer */ |
const GLenum accessRange = GL_MAP_WRITE_BIT | /* for MapBufferRange */ |
GL_MAP_INVALIDATE_RANGE_BIT | |
GL_MAP_UNSYNCHRONIZED_BIT | |
GL_MAP_FLUSH_EXPLICIT_BIT | |
MESA_MAP_NOWAIT_BIT; |
const GLenum usage = GL_STREAM_DRAW_ARB; |
if (!_mesa_is_bufferobj(exec->vtx.bufferobj)) |
return; |
if (exec->vtx.buffer_map != NULL) { |
assert(0); |
exec->vtx.buffer_map = NULL; |
exec->vtx.buffer_ptr = NULL; |
} |
if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024 && |
ctx->Driver.MapBufferRange) { |
exec->vtx.buffer_map = |
(GLfloat *)ctx->Driver.MapBufferRange(ctx, |
target, |
exec->vtx.buffer_used, |
(VBO_VERT_BUFFER_SIZE - |
exec->vtx.buffer_used), |
accessRange, |
exec->vtx.bufferobj); |
exec->vtx.buffer_ptr = exec->vtx.buffer_map; |
} |
if (!exec->vtx.buffer_map) { |
exec->vtx.buffer_used = 0; |
ctx->Driver.BufferData(ctx, target, |
VBO_VERT_BUFFER_SIZE, |
NULL, usage, exec->vtx.bufferobj); |
if (ctx->Driver.MapBufferRange) |
exec->vtx.buffer_map = |
(GLfloat *)ctx->Driver.MapBufferRange(ctx, target, |
0, VBO_VERT_BUFFER_SIZE, |
accessRange, |
exec->vtx.bufferobj); |
if (!exec->vtx.buffer_map) |
exec->vtx.buffer_map = |
(GLfloat *)ctx->Driver.MapBuffer(ctx, target, access, exec->vtx.bufferobj); |
assert(exec->vtx.buffer_map); |
exec->vtx.buffer_ptr = exec->vtx.buffer_map; |
} |
if (0) |
printf("map %d..\n", exec->vtx.buffer_used); |
} |
/** |
* Execute the buffer and save copied verts. |
*/ |
void |
vbo_exec_vtx_flush( struct vbo_exec_context *exec, GLboolean unmap ) |
{ |
if (0) |
vbo_exec_debug_verts( exec ); |
if (exec->vtx.prim_count && |
exec->vtx.vert_count) { |
exec->vtx.copied.nr = vbo_copy_vertices( exec ); |
if (exec->vtx.copied.nr != exec->vtx.vert_count) { |
struct gl_context *ctx = exec->ctx; |
/* Before the update_state() as this may raise _NEW_ARRAY |
* from _mesa_set_varying_vp_inputs(). |
*/ |
vbo_exec_bind_arrays( ctx ); |
if (ctx->NewState) |
_mesa_update_state( ctx ); |
if (_mesa_is_bufferobj(exec->vtx.bufferobj)) { |
vbo_exec_vtx_unmap( exec ); |
} |
if (0) |
printf("%s %d %d\n", __FUNCTION__, exec->vtx.prim_count, |
exec->vtx.vert_count); |
vbo_context(ctx)->draw_prims( ctx, |
exec->vtx.inputs, |
exec->vtx.prim, |
exec->vtx.prim_count, |
NULL, |
GL_TRUE, |
0, |
exec->vtx.vert_count - 1); |
/* If using a real VBO, get new storage -- unless asked not to. |
*/ |
if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !unmap) { |
vbo_exec_vtx_map( exec ); |
} |
} |
} |
/* May have to unmap explicitly if we didn't draw: |
*/ |
if (unmap && |
_mesa_is_bufferobj(exec->vtx.bufferobj) && |
exec->vtx.buffer_map) { |
vbo_exec_vtx_unmap( exec ); |
} |
if (unmap || exec->vtx.vertex_size == 0) |
exec->vtx.max_vert = 0; |
else |
exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) / |
(exec->vtx.vertex_size * sizeof(GLfloat))); |
exec->vtx.buffer_ptr = exec->vtx.buffer_map; |
exec->vtx.prim_count = 0; |
exec->vtx.vert_count = 0; |
} |
#endif /* FEATURE_beginend */ |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_exec_eval.c |
---|
0,0 → 1,263 |
/* |
* Mesa 3-D graphics library |
* Version: 6.1 |
* |
* Copyright (C) 1999-2004 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/context.h" |
#include "main/macros.h" |
#include "math/m_eval.h" |
#include "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 ); |
/* _NEW_PROGRAM */ |
if (ctx->VertexProgram._Enabled) { |
/* These are the 16 evaluators which GL_NV_vertex_program defines. |
* They alias and override the conventional vertex attributs. |
*/ |
for (attr = 0; attr < 16; attr++) { |
/* _NEW_EVAL */ |
assert(attr < Elements(ctx->Eval.Map1Attrib)); |
if (ctx->Eval.Map1Attrib[attr]) |
set_active_eval1( exec, attr, 4, &ctx->EvalMap.Map1Attrib[attr] ); |
assert(attr < Elements(ctx->Eval.Map2Attrib)); |
if (ctx->Eval.Map2Attrib[attr]) |
set_active_eval2( exec, attr, 4, &ctx->EvalMap.Map2Attrib[attr] ); |
} |
} |
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 )); |
} |
} |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_rebase.c |
---|
0,0 → 1,251 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
/* 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]->StrideB && |
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; |
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 = (struct _mesa_prim *)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.MapBuffer(ctx, |
GL_ELEMENT_ARRAY_BUFFER, |
GL_READ_ONLY_ARB, |
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, |
GL_ELEMENT_ARRAY_BUFFER, |
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 = (struct _mesa_prim *)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. |
*/ |
draw( ctx, |
tmp_array_pointers, |
prim, |
nr_prims, |
ib, |
GL_TRUE, |
0, |
max_index - min_index ); |
if (tmp_indices) |
free(tmp_indices); |
if (tmp_prims) |
free(tmp_prims); |
} |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_save.c |
---|
0,0 → 1,122 |
/* |
* Mesa 3-D graphics library |
* Version: 7.2 |
* |
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/mtypes.h" |
#include "main/bufferobj.h" |
#include "main/imports.h" |
#include "vbo_context.h" |
#if FEATURE_dlist |
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; |
} |
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->legacy_currval, 16 * sizeof(arrays[0])); |
memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0])); |
for (i = 0; i < 16; ++i) { |
arrays[i ].BufferObj = NULL; |
arrays[i + 16].BufferObj = NULL; |
_mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj, |
vbo->legacy_currval[i].BufferObj); |
_mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj, |
vbo->generic_currval[i].BufferObj); |
} |
} |
ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN; |
} |
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; |
} |
#endif /* FEATURE_dlist */ |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_save.h |
---|
0,0 → 1,199 |
/************************************************************************** |
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]; |
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; |
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_WEAK 0x40 |
#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; |
struct gl_client_array arrays[VBO_ATTRIB_MAX]; |
const struct gl_client_array *inputs[VBO_ATTRIB_MAX]; |
GLubyte attrsz[VBO_ATTRIB_MAX]; |
GLubyte active_sz[VBO_ATTRIB_MAX]; |
GLuint vertex_size; |
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; |
GLboolean have_materials; |
GLuint opcode_vertex_list; |
struct vbo_save_copied_vtx copied; |
GLfloat *current[VBO_ATTRIB_MAX]; /* points into ctx->ListState */ |
GLubyte *currentsz[VBO_ATTRIB_MAX]; |
}; |
#if FEATURE_dlist |
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 ); |
#else /* FEATURE_dlist */ |
static INLINE void |
vbo_save_init( struct gl_context *ctx ) |
{ |
} |
static INLINE void |
vbo_save_destroy( struct gl_context *ctx ) |
{ |
} |
#endif /* FEATURE_dlist */ |
#endif /* VBO_SAVE_H */ |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_save_api.c |
---|
0,0 → 1,1301 |
/************************************************************************** |
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_noop.h" |
#include "main/api_validate.h" |
#include "main/api_arrayelt.h" |
#include "main/vtxfmt.h" |
#include "main/dispatch.h" |
#include "vbo_context.h" |
#if FEATURE_dlist |
#ifdef ERROR |
#undef ERROR |
#endif |
/* An interesting VBO number/name to help with debugging */ |
#define VBO_BUF_ID 12345 |
/* |
* NOTE: Old 'parity' issue is gone, but copying can still be |
* wrong-footed on replay. |
*/ |
static GLuint _save_copy_vertices( struct gl_context *ctx, |
const struct vbo_save_vertex_list *node, |
const GLfloat *src_buffer) |
{ |
struct vbo_save_context *save = &vbo_context( ctx )->save; |
const struct _mesa_prim *prim = &node->prim[node->prim_count-1]; |
GLuint nr = prim->count; |
GLuint sz = save->vertex_size; |
const GLfloat *src = src_buffer + prim->start * sz; |
GLfloat *dst = save->copied.buffer; |
GLuint ovf, i; |
if (prim->end) |
return 0; |
switch( prim->mode ) |
{ |
case GL_POINTS: |
return 0; |
case GL_LINES: |
ovf = nr&1; |
for (i = 0 ; i < ovf ; i++) |
memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); |
return i; |
case GL_TRIANGLES: |
ovf = nr%3; |
for (i = 0 ; i < ovf ; i++) |
memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); |
return i; |
case GL_QUADS: |
ovf = nr&3; |
for (i = 0 ; i < ovf ; i++) |
memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); |
return i; |
case GL_LINE_STRIP: |
if (nr == 0) |
return 0; |
else { |
memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) ); |
return 1; |
} |
case GL_LINE_LOOP: |
case GL_TRIANGLE_FAN: |
case GL_POLYGON: |
if (nr == 0) |
return 0; |
else if (nr == 1) { |
memcpy( dst, src+0, sz*sizeof(GLfloat) ); |
return 1; |
} else { |
memcpy( dst, src+0, sz*sizeof(GLfloat) ); |
memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) ); |
return 2; |
} |
case GL_TRIANGLE_STRIP: |
case GL_QUAD_STRIP: |
switch (nr) { |
case 0: ovf = 0; break; |
case 1: ovf = 1; break; |
default: ovf = 2 + (nr&1); break; |
} |
for (i = 0 ; i < ovf ; i++) |
memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) ); |
return i; |
default: |
assert(0); |
return 0; |
} |
} |
static struct vbo_save_vertex_store *alloc_vertex_store( struct gl_context *ctx ) |
{ |
struct vbo_save_vertex_store *vertex_store = CALLOC_STRUCT(vbo_save_vertex_store); |
/* obj->Name needs to be non-zero, but won't ever be examined more |
* closely than that. In particular these buffers won't be entered |
* into the hash and can never be confused with ones visible to the |
* user. Perhaps there could be a special number for internal |
* buffers: |
*/ |
vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, |
VBO_BUF_ID, |
GL_ARRAY_BUFFER_ARB); |
ctx->Driver.BufferData( ctx, |
GL_ARRAY_BUFFER_ARB, |
VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat), |
NULL, |
GL_STATIC_DRAW_ARB, |
vertex_store->bufferobj); |
vertex_store->buffer = NULL; |
vertex_store->used = 0; |
vertex_store->refcount = 1; |
return vertex_store; |
} |
static void free_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store ) |
{ |
assert(!vertex_store->buffer); |
if (vertex_store->bufferobj) { |
_mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL); |
} |
FREE( vertex_store ); |
} |
static GLfloat *map_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store ) |
{ |
assert(vertex_store->bufferobj); |
assert(!vertex_store->buffer); |
vertex_store->buffer = (GLfloat *)ctx->Driver.MapBuffer(ctx, |
GL_ARRAY_BUFFER_ARB, /* not used */ |
GL_WRITE_ONLY, /* not used */ |
vertex_store->bufferobj); |
assert(vertex_store->buffer); |
return vertex_store->buffer + vertex_store->used; |
} |
static void unmap_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store ) |
{ |
ctx->Driver.UnmapBuffer( ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj ); |
vertex_store->buffer = NULL; |
} |
static struct vbo_save_primitive_store *alloc_prim_store( struct gl_context *ctx ) |
{ |
struct vbo_save_primitive_store *store = CALLOC_STRUCT(vbo_save_primitive_store); |
(void) ctx; |
store->used = 0; |
store->refcount = 1; |
return store; |
} |
static void _save_reset_counters( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
save->prim = save->prim_store->buffer + save->prim_store->used; |
save->buffer = (save->vertex_store->buffer + |
save->vertex_store->used); |
assert(save->buffer == save->buffer_ptr); |
if (save->vertex_size) |
save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / |
save->vertex_size); |
else |
save->max_vert = 0; |
save->vert_count = 0; |
save->prim_count = 0; |
save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used; |
save->dangling_attr_ref = 0; |
} |
/* Insert the active immediate struct onto the display list currently |
* being built. |
*/ |
static void _save_compile_vertex_list( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
struct vbo_save_vertex_list *node; |
/* Allocate space for this structure in the display list currently |
* being compiled. |
*/ |
node = (struct vbo_save_vertex_list *) |
_mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node)); |
if (!node) |
return; |
/* Duplicate our template, increment refcounts to the storage structs: |
*/ |
memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz)); |
node->vertex_size = save->vertex_size; |
node->buffer_offset = (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat); |
node->count = save->vert_count; |
node->wrap_count = save->copied.nr; |
node->dangling_attr_ref = save->dangling_attr_ref; |
node->prim = save->prim; |
node->prim_count = save->prim_count; |
node->vertex_store = save->vertex_store; |
node->prim_store = save->prim_store; |
node->vertex_store->refcount++; |
node->prim_store->refcount++; |
node->current_size = node->vertex_size - node->attrsz[0]; |
node->current_data = NULL; |
if (node->current_size) { |
/* If the malloc fails, we just pull the data out of the VBO |
* later instead. |
*/ |
node->current_data = MALLOC( node->current_size * sizeof(GLfloat) ); |
if (node->current_data) { |
const char *buffer = (const char *)save->vertex_store->buffer; |
unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat); |
unsigned vertex_offset = 0; |
if (node->count) |
vertex_offset = (node->count-1) * node->vertex_size * sizeof(GLfloat); |
memcpy( node->current_data, |
buffer + node->buffer_offset + vertex_offset + attr_offset, |
node->current_size * sizeof(GLfloat) ); |
} |
} |
assert(node->attrsz[VBO_ATTRIB_POS] != 0 || |
node->count == 0); |
if (save->dangling_attr_ref) |
ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS; |
save->vertex_store->used += save->vertex_size * node->count; |
save->prim_store->used += node->prim_count; |
/* Copy duplicated vertices |
*/ |
save->copied.nr = _save_copy_vertices( ctx, node, save->buffer ); |
/* Deal with GL_COMPILE_AND_EXECUTE: |
*/ |
if (ctx->ExecuteFlag) { |
struct _glapi_table *dispatch = GET_DISPATCH(); |
_glapi_set_dispatch(ctx->Exec); |
vbo_loopback_vertex_list( ctx, |
(const GLfloat *)((const char *)save->vertex_store->buffer + |
node->buffer_offset), |
node->attrsz, |
node->prim, |
node->prim_count, |
node->wrap_count, |
node->vertex_size); |
_glapi_set_dispatch(dispatch); |
} |
/* Decide whether the storage structs are full, or can be used for |
* the next vertex lists as well. |
*/ |
if (save->vertex_store->used > |
VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) { |
/* Unmap old store: |
*/ |
unmap_vertex_store( ctx, save->vertex_store ); |
/* Release old reference: |
*/ |
save->vertex_store->refcount--; |
assert(save->vertex_store->refcount != 0); |
save->vertex_store = NULL; |
/* Allocate and map new store: |
*/ |
save->vertex_store = alloc_vertex_store( ctx ); |
save->buffer_ptr = map_vertex_store( ctx, save->vertex_store ); |
} |
if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) { |
save->prim_store->refcount--; |
assert(save->prim_store->refcount != 0); |
save->prim_store = alloc_prim_store( ctx ); |
} |
/* Reset our structures for the next run of vertices: |
*/ |
_save_reset_counters( ctx ); |
} |
/* TODO -- If no new vertices have been stored, don't bother saving |
* it. |
*/ |
static void _save_wrap_buffers( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
GLint i = save->prim_count - 1; |
GLenum mode; |
GLboolean weak; |
assert(i < (GLint) save->prim_max); |
assert(i >= 0); |
/* Close off in-progress primitive. |
*/ |
save->prim[i].count = (save->vert_count - |
save->prim[i].start); |
mode = save->prim[i].mode; |
weak = save->prim[i].weak; |
/* store the copied vertices, and allocate a new list. |
*/ |
_save_compile_vertex_list( ctx ); |
/* Restart interrupted primitive |
*/ |
save->prim[0].mode = mode; |
save->prim[0].weak = weak; |
save->prim[0].begin = 0; |
save->prim[0].end = 0; |
save->prim[0].pad = 0; |
save->prim[0].start = 0; |
save->prim[0].count = 0; |
save->prim[0].num_instances = 1; |
save->prim_count = 1; |
} |
/* Called only when buffers are wrapped as the result of filling the |
* vertex_store struct. |
*/ |
static void _save_wrap_filled_vertex( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
GLfloat *data = save->copied.buffer; |
GLuint i; |
/* Emit a glEnd to close off the last vertex list. |
*/ |
_save_wrap_buffers( ctx ); |
/* Copy stored stored vertices to start of new list. |
*/ |
assert(save->max_vert - save->vert_count > save->copied.nr); |
for (i = 0 ; i < save->copied.nr ; i++) { |
memcpy( save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat)); |
data += save->vertex_size; |
save->buffer_ptr += save->vertex_size; |
save->vert_count++; |
} |
} |
static void _save_copy_to_current( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
GLuint i; |
for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { |
if (save->attrsz[i]) { |
save->currentsz[i][0] = save->attrsz[i]; |
COPY_CLEAN_4V(save->current[i], |
save->attrsz[i], |
save->attrptr[i]); |
} |
} |
} |
static void _save_copy_from_current( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
GLint i; |
for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { |
switch (save->attrsz[i]) { |
case 4: save->attrptr[i][3] = save->current[i][3]; |
case 3: save->attrptr[i][2] = save->current[i][2]; |
case 2: save->attrptr[i][1] = save->current[i][1]; |
case 1: save->attrptr[i][0] = save->current[i][0]; |
case 0: break; |
} |
} |
} |
/* Flush existing data, set new attrib size, replay copied vertices. |
*/ |
static void _save_upgrade_vertex( struct gl_context *ctx, |
GLuint attr, |
GLuint newsz ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
GLuint oldsz; |
GLuint i; |
GLfloat *tmp; |
/* Store the current run of vertices, and emit a GL_END. Emit a |
* BEGIN in the new buffer. |
*/ |
if (save->vert_count) |
_save_wrap_buffers( ctx ); |
else |
assert( save->copied.nr == 0 ); |
/* Do a COPY_TO_CURRENT to ensure back-copying works for the case |
* when the attribute already exists in the vertex and is having |
* its size increased. |
*/ |
_save_copy_to_current( ctx ); |
/* Fix up sizes: |
*/ |
oldsz = save->attrsz[attr]; |
save->attrsz[attr] = newsz; |
save->vertex_size += newsz - oldsz; |
save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / |
save->vertex_size); |
save->vert_count = 0; |
/* Recalculate all the attrptr[] values: |
*/ |
for (i = 0, tmp = save->vertex ; i < VBO_ATTRIB_MAX ; i++) { |
if (save->attrsz[i]) { |
save->attrptr[i] = tmp; |
tmp += save->attrsz[i]; |
} |
else |
save->attrptr[i] = NULL; /* will not be dereferenced. */ |
} |
/* Copy from current to repopulate the vertex with correct values. |
*/ |
_save_copy_from_current( ctx ); |
/* Replay stored vertices to translate them to new format here. |
* |
* If there are copied vertices and the new (upgraded) attribute |
* has not been defined before, this list is somewhat degenerate, |
* and will need fixup at runtime. |
*/ |
if (save->copied.nr) |
{ |
GLfloat *data = save->copied.buffer; |
GLfloat *dest = save->buffer; |
GLuint j; |
/* Need to note this and fix up at runtime (or loopback): |
*/ |
if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) { |
assert(oldsz == 0); |
save->dangling_attr_ref = GL_TRUE; |
} |
for (i = 0 ; i < save->copied.nr ; i++) { |
for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) { |
if (save->attrsz[j]) { |
if (j == attr) { |
if (oldsz) { |
COPY_CLEAN_4V( dest, oldsz, data ); |
data += oldsz; |
dest += newsz; |
} |
else { |
COPY_SZ_4V( dest, newsz, save->current[attr] ); |
dest += newsz; |
} |
} |
else { |
GLint sz = save->attrsz[j]; |
COPY_SZ_4V( dest, sz, data ); |
data += sz; |
dest += sz; |
} |
} |
} |
} |
save->buffer_ptr = dest; |
save->vert_count += save->copied.nr; |
} |
} |
static void save_fixup_vertex( struct gl_context *ctx, GLuint attr, GLuint sz ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
if (sz > save->attrsz[attr]) { |
/* New size is larger. Need to flush existing vertices and get |
* an enlarged vertex format. |
*/ |
_save_upgrade_vertex( ctx, attr, sz ); |
} |
else if (sz < save->active_sz[attr]) { |
static GLfloat id[4] = { 0, 0, 0, 1 }; |
GLuint i; |
/* New size is equal or smaller - just need to fill in some |
* zeros. |
*/ |
for (i = sz ; i <= save->attrsz[attr] ; i++) |
save->attrptr[attr][i-1] = id[i-1]; |
} |
save->active_sz[attr] = sz; |
} |
static void _save_reset_vertex( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
GLuint i; |
for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) { |
save->attrsz[i] = 0; |
save->active_sz[i] = 0; |
} |
save->vertex_size = 0; |
} |
#define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ ); |
/* Only one size for each attribute may be active at once. Eg. if |
* Color3f is installed/active, then Color4f may not be, even if the |
* vertex actually contains 4 color coordinates. This is because the |
* 3f version won't otherwise set color[3] to 1.0 -- this is the job |
* of the chooser function when switching between Color4f and Color3f. |
*/ |
#define ATTR( A, N, V0, V1, V2, V3 ) \ |
do { \ |
struct vbo_save_context *save = &vbo_context(ctx)->save; \ |
\ |
if (save->active_sz[A] != N) \ |
save_fixup_vertex(ctx, A, N); \ |
\ |
{ \ |
GLfloat *dest = save->attrptr[A]; \ |
if (N>0) dest[0] = V0; \ |
if (N>1) dest[1] = V1; \ |
if (N>2) dest[2] = V2; \ |
if (N>3) dest[3] = V3; \ |
} \ |
\ |
if ((A) == 0) { \ |
GLuint i; \ |
\ |
for (i = 0; i < save->vertex_size; i++) \ |
save->buffer_ptr[i] = save->vertex[i]; \ |
\ |
save->buffer_ptr += save->vertex_size; \ |
\ |
if (++save->vert_count >= save->max_vert) \ |
_save_wrap_filled_vertex( ctx ); \ |
} \ |
} while (0) |
#define TAG(x) _save_##x |
#include "vbo_attrib_tmp.h" |
/* Cope with EvalCoord/CallList called within a begin/end object: |
* -- Flush current buffer |
* -- Fallback to opcodes for the rest of the begin/end object. |
*/ |
static void DO_FALLBACK( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
if (save->vert_count || save->prim_count) { |
GLint i = save->prim_count - 1; |
/* Close off in-progress primitive. |
*/ |
save->prim[i].count = (save->vert_count - |
save->prim[i].start); |
/* Need to replay this display list with loopback, |
* unfortunately, otherwise this primitive won't be handled |
* properly: |
*/ |
save->dangling_attr_ref = 1; |
_save_compile_vertex_list( ctx ); |
} |
_save_copy_to_current( ctx ); |
_save_reset_vertex( ctx ); |
_save_reset_counters( ctx ); |
_mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); |
ctx->Driver.SaveNeedFlush = 0; |
} |
static void GLAPIENTRY _save_EvalCoord1f( GLfloat u ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
DO_FALLBACK(ctx); |
CALL_EvalCoord1f(ctx->Save, (u)); |
} |
static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
DO_FALLBACK(ctx); |
CALL_EvalCoord1fv(ctx->Save, (v)); |
} |
static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
DO_FALLBACK(ctx); |
CALL_EvalCoord2f(ctx->Save, (u, v)); |
} |
static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
DO_FALLBACK(ctx); |
CALL_EvalCoord2fv(ctx->Save, (v)); |
} |
static void GLAPIENTRY _save_EvalPoint1( GLint i ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
DO_FALLBACK(ctx); |
CALL_EvalPoint1(ctx->Save, (i)); |
} |
static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
DO_FALLBACK(ctx); |
CALL_EvalPoint2(ctx->Save, (i, j)); |
} |
static void GLAPIENTRY _save_CallList( GLuint l ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
DO_FALLBACK(ctx); |
CALL_CallList(ctx->Save, (l)); |
} |
static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
DO_FALLBACK(ctx); |
CALL_CallLists(ctx->Save, (n, type, v)); |
} |
/* This begin is hooked into ... Updating of |
* ctx->Driver.CurrentSavePrimitive is already taken care of. |
*/ |
GLboolean vbo_save_NotifyBegin( struct gl_context *ctx, GLenum mode ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
GLuint i = save->prim_count++; |
assert(i < save->prim_max); |
save->prim[i].mode = mode & ~VBO_SAVE_PRIM_WEAK; |
save->prim[i].begin = 1; |
save->prim[i].end = 0; |
save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0; |
save->prim[i].pad = 0; |
save->prim[i].start = save->vert_count; |
save->prim[i].count = 0; |
save->prim[i].num_instances = 1; |
_mesa_install_save_vtxfmt( ctx, &save->vtxfmt ); |
ctx->Driver.SaveNeedFlush = 1; |
return GL_TRUE; |
} |
static void GLAPIENTRY _save_End( void ) |
{ |
GET_CURRENT_CONTEXT( ctx ); |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
GLint i = save->prim_count - 1; |
ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; |
save->prim[i].end = 1; |
save->prim[i].count = (save->vert_count - |
save->prim[i].start); |
if (i == (GLint) save->prim_max - 1) { |
_save_compile_vertex_list( ctx ); |
assert(save->copied.nr == 0); |
} |
/* Swap out this vertex format while outside begin/end. Any color, |
* etc. received between here and the next begin will be compiled |
* as opcodes. |
*/ |
_mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); |
} |
/* These are all errors as this vtxfmt is only installed inside |
* begin/end pairs. |
*/ |
static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type, |
const GLvoid *indices) |
{ |
GET_CURRENT_CONTEXT(ctx); |
(void) mode; (void) count; (void) type; (void) indices; |
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" ); |
} |
static void GLAPIENTRY _save_DrawRangeElements(GLenum mode, |
GLuint start, GLuint end, |
GLsizei count, GLenum type, |
const GLvoid *indices) |
{ |
GET_CURRENT_CONTEXT(ctx); |
(void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices; |
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" ); |
} |
static void GLAPIENTRY _save_DrawElementsBaseVertex(GLenum mode, |
GLsizei count, |
GLenum type, |
const GLvoid *indices, |
GLint basevertex) |
{ |
GET_CURRENT_CONTEXT(ctx); |
(void) mode; (void) count; (void) type; (void) indices; (void)basevertex; |
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" ); |
} |
static void GLAPIENTRY _save_DrawRangeElementsBaseVertex(GLenum mode, |
GLuint start, |
GLuint end, |
GLsizei count, |
GLenum type, |
const GLvoid *indices, |
GLint basevertex) |
{ |
GET_CURRENT_CONTEXT(ctx); |
(void) mode; (void) start; (void) end; (void) count; (void) type; |
(void) indices; (void)basevertex; |
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" ); |
} |
static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count) |
{ |
GET_CURRENT_CONTEXT(ctx); |
(void) mode; (void) start; (void) count; |
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" ); |
} |
static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
(void) x1; (void) y1; (void) x2; (void) y2; |
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" ); |
} |
static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
(void) mode; (void) i1; (void) i2; |
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" ); |
} |
static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2, |
GLint j1, GLint j2 ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
(void) mode; (void) i1; (void) i2; (void) j1; (void) j2; |
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" ); |
} |
static void GLAPIENTRY _save_Begin( GLenum mode ) |
{ |
GET_CURRENT_CONTEXT( ctx ); |
(void) mode; |
_mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" ); |
} |
static void GLAPIENTRY _save_PrimitiveRestartNV( void ) |
{ |
GLenum curPrim; |
GET_CURRENT_CONTEXT( ctx ); |
curPrim = ctx->Driver.CurrentSavePrimitive; |
_save_End(); |
_save_Begin(curPrim); |
} |
/* Unlike the functions above, these are to be hooked into the vtxfmt |
* maintained in ctx->ListState, active when the list is known or |
* suspected to be outside any begin/end primitive. |
*/ |
static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 ) |
{ |
GET_CURRENT_CONTEXT(ctx); |
vbo_save_NotifyBegin( ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK ); |
CALL_Vertex2f(GET_DISPATCH(), ( x1, y1 )); |
CALL_Vertex2f(GET_DISPATCH(), ( x2, y1 )); |
CALL_Vertex2f(GET_DISPATCH(), ( x2, y2 )); |
CALL_Vertex2f(GET_DISPATCH(), ( x1, y2 )); |
CALL_End(GET_DISPATCH(), ()); |
} |
static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLint i; |
if (!_mesa_validate_DrawArrays( ctx, mode, start, count )) |
return; |
_ae_map_vbos( ctx ); |
vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK ); |
for (i = 0; i < count; i++) |
CALL_ArrayElement(GET_DISPATCH(), (start + i)); |
CALL_End(GET_DISPATCH(), ()); |
_ae_unmap_vbos( ctx ); |
} |
/* Could do better by copying the arrays and element list intact and |
* then emitting an indexed prim at runtime. |
*/ |
static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, |
const GLvoid *indices) |
{ |
GET_CURRENT_CONTEXT(ctx); |
GLint i; |
if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 )) |
return; |
_ae_map_vbos( ctx ); |
if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) |
indices = ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Pointer, indices); |
vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK ); |
switch (type) { |
case GL_UNSIGNED_BYTE: |
for (i = 0 ; i < count ; i++) |
CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] )); |
break; |
case GL_UNSIGNED_SHORT: |
for (i = 0 ; i < count ; i++) |
CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] )); |
break; |
case GL_UNSIGNED_INT: |
for (i = 0 ; i < count ; i++) |
CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] )); |
break; |
default: |
_mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); |
break; |
} |
CALL_End(GET_DISPATCH(), ()); |
_ae_unmap_vbos( ctx ); |
} |
static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode, |
GLuint start, GLuint end, |
GLsizei count, GLenum type, |
const GLvoid *indices) |
{ |
GET_CURRENT_CONTEXT(ctx); |
if (_mesa_validate_DrawRangeElements( ctx, mode, |
start, end, |
count, type, indices, 0 )) |
_save_OBE_DrawElements( mode, count, type, indices ); |
} |
static void _save_vtxfmt_init( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
GLvertexformat *vfmt = &save->vtxfmt; |
_MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_); |
vfmt->Begin = _save_Begin; |
vfmt->Color3f = _save_Color3f; |
vfmt->Color3fv = _save_Color3fv; |
vfmt->Color4f = _save_Color4f; |
vfmt->Color4fv = _save_Color4fv; |
vfmt->EdgeFlag = _save_EdgeFlag; |
vfmt->End = _save_End; |
vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV; |
vfmt->FogCoordfEXT = _save_FogCoordfEXT; |
vfmt->FogCoordfvEXT = _save_FogCoordfvEXT; |
vfmt->Indexf = _save_Indexf; |
vfmt->Indexfv = _save_Indexfv; |
vfmt->Materialfv = _save_Materialfv; |
vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f; |
vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv; |
vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f; |
vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv; |
vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f; |
vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv; |
vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f; |
vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv; |
vfmt->Normal3f = _save_Normal3f; |
vfmt->Normal3fv = _save_Normal3fv; |
vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT; |
vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT; |
vfmt->TexCoord1f = _save_TexCoord1f; |
vfmt->TexCoord1fv = _save_TexCoord1fv; |
vfmt->TexCoord2f = _save_TexCoord2f; |
vfmt->TexCoord2fv = _save_TexCoord2fv; |
vfmt->TexCoord3f = _save_TexCoord3f; |
vfmt->TexCoord3fv = _save_TexCoord3fv; |
vfmt->TexCoord4f = _save_TexCoord4f; |
vfmt->TexCoord4fv = _save_TexCoord4fv; |
vfmt->Vertex2f = _save_Vertex2f; |
vfmt->Vertex2fv = _save_Vertex2fv; |
vfmt->Vertex3f = _save_Vertex3f; |
vfmt->Vertex3fv = _save_Vertex3fv; |
vfmt->Vertex4f = _save_Vertex4f; |
vfmt->Vertex4fv = _save_Vertex4fv; |
vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB; |
vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB; |
vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB; |
vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB; |
vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB; |
vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB; |
vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB; |
vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB; |
vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV; |
vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV; |
vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV; |
vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV; |
vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV; |
vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV; |
vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV; |
vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV; |
/* integer-valued */ |
vfmt->VertexAttribI1i = _save_VertexAttribI1i; |
vfmt->VertexAttribI2i = _save_VertexAttribI2i; |
vfmt->VertexAttribI3i = _save_VertexAttribI3i; |
vfmt->VertexAttribI4i = _save_VertexAttribI4i; |
vfmt->VertexAttribI2iv = _save_VertexAttribI2iv; |
vfmt->VertexAttribI3iv = _save_VertexAttribI3iv; |
vfmt->VertexAttribI4iv = _save_VertexAttribI4iv; |
/* unsigned integer-valued */ |
vfmt->VertexAttribI1ui = _save_VertexAttribI1ui; |
vfmt->VertexAttribI2ui = _save_VertexAttribI2ui; |
vfmt->VertexAttribI3ui = _save_VertexAttribI3ui; |
vfmt->VertexAttribI4ui = _save_VertexAttribI4ui; |
vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv; |
vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv; |
vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv; |
/* This will all require us to fallback to saving the list as opcodes: |
*/ |
_MESA_INIT_DLIST_VTXFMT(vfmt, _save_); /* inside begin/end */ |
_MESA_INIT_EVAL_VTXFMT(vfmt, _save_); |
/* These are all errors as we at least know we are in some sort of |
* begin/end pair: |
*/ |
vfmt->Begin = _save_Begin; |
vfmt->Rectf = _save_Rectf; |
vfmt->DrawArrays = _save_DrawArrays; |
vfmt->DrawElements = _save_DrawElements; |
vfmt->DrawRangeElements = _save_DrawRangeElements; |
vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex; |
vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex; |
/* Loops back into vfmt->DrawElements */ |
vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; |
vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; |
} |
void vbo_save_SaveFlushVertices( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
/* Noop when we are actually active: |
*/ |
if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM || |
ctx->Driver.CurrentSavePrimitive <= GL_POLYGON) |
return; |
if (save->vert_count || |
save->prim_count) |
_save_compile_vertex_list( ctx ); |
_save_copy_to_current( ctx ); |
_save_reset_vertex( ctx ); |
_save_reset_counters( ctx ); |
ctx->Driver.SaveNeedFlush = 0; |
} |
void vbo_save_NewList( struct gl_context *ctx, GLuint list, GLenum mode ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
(void) list; (void) mode; |
if (!save->prim_store) |
save->prim_store = alloc_prim_store( ctx ); |
if (!save->vertex_store) |
save->vertex_store = alloc_vertex_store( ctx ); |
save->buffer_ptr = map_vertex_store( ctx, save->vertex_store ); |
_save_reset_vertex( ctx ); |
_save_reset_counters( ctx ); |
ctx->Driver.SaveNeedFlush = 0; |
} |
void vbo_save_EndList( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
/* EndList called inside a (saved) Begin/End pair? |
*/ |
if (ctx->Driver.CurrentSavePrimitive != PRIM_OUTSIDE_BEGIN_END) { |
if (save->prim_count > 0) { |
GLint i = save->prim_count - 1; |
ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; |
save->prim[i].end = 0; |
save->prim[i].count = (save->vert_count - |
save->prim[i].start); |
} |
/* Make sure this vertex list gets replayed by the "loopback" |
* mechanism: |
*/ |
save->dangling_attr_ref = 1; |
vbo_save_SaveFlushVertices( ctx ); |
/* Swap out this vertex format while outside begin/end. Any color, |
* etc. received between here and the next begin will be compiled |
* as opcodes. |
*/ |
_mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); |
} |
unmap_vertex_store( ctx, save->vertex_store ); |
assert(save->vertex_size == 0); |
} |
void vbo_save_BeginCallList( struct gl_context *ctx, struct gl_display_list *dlist ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
save->replay_flags |= dlist->Flags; |
} |
void vbo_save_EndCallList( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
if (ctx->ListState.CallDepth == 1) { |
/* This is correct: want to keep only the VBO_SAVE_FALLBACK |
* flag, if it is set: |
*/ |
save->replay_flags &= VBO_SAVE_FALLBACK; |
} |
} |
static void vbo_destroy_vertex_list( struct gl_context *ctx, void *data ) |
{ |
struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data; |
(void) ctx; |
if ( --node->vertex_store->refcount == 0 ) |
free_vertex_store( ctx, node->vertex_store ); |
if ( --node->prim_store->refcount == 0 ) |
FREE( node->prim_store ); |
if (node->current_data) { |
FREE(node->current_data); |
node->current_data = NULL; |
} |
} |
static void vbo_print_vertex_list( struct gl_context *ctx, void *data ) |
{ |
struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data; |
GLuint i; |
(void) ctx; |
printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n", |
node->count, |
node->prim_count, |
node->vertex_size); |
for (i = 0 ; i < node->prim_count ; i++) { |
struct _mesa_prim *prim = &node->prim[i]; |
_mesa_debug(NULL, " prim %d: %s%s %d..%d %s %s\n", |
i, |
_mesa_lookup_prim_by_nr(prim->mode), |
prim->weak ? " (weak)" : "", |
prim->start, |
prim->start + prim->count, |
(prim->begin) ? "BEGIN" : "(wrap)", |
(prim->end) ? "END" : "(wrap)"); |
} |
} |
static void _save_current_init( struct gl_context *ctx ) |
{ |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
GLint i; |
for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) { |
const GLuint j = i - VBO_ATTRIB_POS; |
ASSERT(j < VERT_ATTRIB_MAX); |
save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j]; |
save->current[i] = ctx->ListState.CurrentAttrib[j]; |
} |
for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) { |
const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL; |
ASSERT(j < MAT_ATTRIB_MAX); |
save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j]; |
save->current[i] = ctx->ListState.CurrentMaterial[j]; |
} |
} |
/** |
* Initialize the display list compiler |
*/ |
void vbo_save_api_init( struct vbo_save_context *save ) |
{ |
struct gl_context *ctx = save->ctx; |
GLuint i; |
save->opcode_vertex_list = |
_mesa_dlist_alloc_opcode( ctx, |
sizeof(struct vbo_save_vertex_list), |
vbo_save_playback_vertex_list, |
vbo_destroy_vertex_list, |
vbo_print_vertex_list ); |
ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin; |
_save_vtxfmt_init( ctx ); |
_save_current_init( ctx ); |
/* These will actually get set again when binding/drawing */ |
for (i = 0; i < VBO_ATTRIB_MAX; i++) |
save->inputs[i] = &save->arrays[i]; |
/* Hook our array functions into the outside-begin-end vtxfmt in |
* ctx->ListState. |
*/ |
ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf; |
ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays; |
ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements; |
ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements; |
/* loops back into _save_OBE_DrawElements */ |
ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements; |
ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex; |
_mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); |
} |
#endif /* FEATURE_dlist */ |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_save_draw.c |
---|
0,0 → 1,303 |
/* |
* Mesa 3-D graphics library |
* Version: 7.2 |
* |
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
*/ |
/* Author: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/glheader.h" |
#include "main/bufferobj.h" |
#include "main/context.h" |
#include "main/imports.h" |
#include "main/mtypes.h" |
#include "main/macros.h" |
#include "main/light.h" |
#include "main/state.h" |
#include "vbo_context.h" |
#if FEATURE_dlist |
/** |
* After playback, copy everything but the position from the |
* last vertex to the saved state |
*/ |
static void |
_playback_copy_to_current(struct gl_context *ctx, |
const struct vbo_save_vertex_list *node) |
{ |
struct vbo_context *vbo = vbo_context(ctx); |
GLfloat vertex[VBO_ATTRIB_MAX * 4]; |
GLfloat *data; |
GLuint i, offset; |
if (node->current_size == 0) |
return; |
if (node->current_data) { |
data = node->current_data; |
} |
else { |
data = vertex; |
if (node->count) |
offset = (node->buffer_offset + |
(node->count-1) * node->vertex_size * sizeof(GLfloat)); |
else |
offset = node->buffer_offset; |
ctx->Driver.GetBufferSubData( ctx, 0, offset, |
node->vertex_size * sizeof(GLfloat), |
data, node->vertex_store->bufferobj ); |
data += node->attrsz[0]; /* skip vertex position */ |
} |
for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) { |
if (node->attrsz[i]) { |
GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; |
GLfloat tmp[4]; |
COPY_CLEAN_4V(tmp, |
node->attrsz[i], |
data); |
if (memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) { |
memcpy(current, tmp, 4 * sizeof(GLfloat)); |
vbo->currval[i].Size = node->attrsz[i]; |
if (i >= VBO_ATTRIB_FIRST_MATERIAL && |
i <= VBO_ATTRIB_LAST_MATERIAL) |
ctx->NewState |= _NEW_LIGHT; |
ctx->NewState |= _NEW_CURRENT_ATTRIB; |
} |
data += node->attrsz[i]; |
} |
} |
/* Colormaterial -- this kindof sucks. |
*/ |
if (ctx->Light.ColorMaterialEnabled) { |
_mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); |
} |
/* CurrentExecPrimitive |
*/ |
if (node->prim_count) { |
const struct _mesa_prim *prim = &node->prim[node->prim_count - 1]; |
if (prim->end) |
ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; |
else |
ctx->Driver.CurrentExecPrimitive = prim->mode; |
} |
} |
/** |
* Treat the vertex storage as a VBO, define vertex arrays pointing |
* into it: |
*/ |
static void vbo_bind_vertex_list(struct gl_context *ctx, |
const struct vbo_save_vertex_list *node) |
{ |
struct vbo_context *vbo = vbo_context(ctx); |
struct vbo_save_context *save = &vbo->save; |
struct gl_client_array *arrays = save->arrays; |
GLuint buffer_offset = node->buffer_offset; |
const GLuint *map; |
GLuint attr; |
GLubyte node_attrsz[VBO_ATTRIB_MAX]; /* copy of node->attrsz[] */ |
GLbitfield varying_inputs = 0x0; |
memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz)); |
/* Install the default (ie Current) attributes first, then overlay |
* all active ones. |
*/ |
switch (get_program_mode(ctx)) { |
case VP_NONE: |
for (attr = 0; attr < 16; attr++) { |
save->inputs[attr] = &vbo->legacy_currval[attr]; |
} |
for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) { |
save->inputs[attr + 16] = &vbo->mat_currval[attr]; |
} |
map = vbo->map_vp_none; |
break; |
case VP_NV: |
case VP_ARB: |
/* The aliasing of attributes for NV vertex programs has already |
* occurred. NV vertex programs cannot access material values, |
* nor attributes greater than VERT_ATTRIB_TEX7. |
*/ |
for (attr = 0; attr < 16; attr++) { |
save->inputs[attr] = &vbo->legacy_currval[attr]; |
save->inputs[attr + 16] = &vbo->generic_currval[attr]; |
} |
map = vbo->map_vp_arb; |
/* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read. |
* In that case we effectively need to route the data from |
* glVertexAttrib(0, val) calls to feed into the GENERIC0 input. |
*/ |
if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 && |
(ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) { |
save->inputs[16] = save->inputs[0]; |
node_attrsz[16] = node_attrsz[0]; |
node_attrsz[0] = 0; |
} |
break; |
default: |
assert(0); |
} |
for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { |
const GLuint src = map[attr]; |
if (node_attrsz[src]) { |
/* override the default array set above */ |
save->inputs[attr] = &arrays[attr]; |
arrays[attr].Ptr = (const GLubyte *) NULL + buffer_offset; |
arrays[attr].Size = node->attrsz[src]; |
arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat); |
arrays[attr].Stride = node->vertex_size * sizeof(GLfloat); |
arrays[attr].Type = GL_FLOAT; |
arrays[attr].Format = GL_RGBA; |
arrays[attr].Enabled = 1; |
_mesa_reference_buffer_object(ctx, |
&arrays[attr].BufferObj, |
node->vertex_store->bufferobj); |
arrays[attr]._MaxElement = node->count; /* ??? */ |
assert(arrays[attr].BufferObj->Name); |
buffer_offset += node->attrsz[src] * sizeof(GLfloat); |
varying_inputs |= 1<<attr; |
} |
} |
_mesa_set_varying_vp_inputs( ctx, varying_inputs ); |
} |
static void |
vbo_save_loopback_vertex_list(struct gl_context *ctx, |
const struct vbo_save_vertex_list *list) |
{ |
const char *buffer = ctx->Driver.MapBuffer(ctx, |
GL_ARRAY_BUFFER_ARB, |
GL_READ_ONLY, /* ? */ |
list->vertex_store->bufferobj); |
vbo_loopback_vertex_list(ctx, |
(const GLfloat *)(buffer + list->buffer_offset), |
list->attrsz, |
list->prim, |
list->prim_count, |
list->wrap_count, |
list->vertex_size); |
ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, |
list->vertex_store->bufferobj); |
} |
/** |
* Execute the buffer and save copied verts. |
* This is called from the display list code when executing |
* a drawing command. |
*/ |
void |
vbo_save_playback_vertex_list(struct gl_context *ctx, void *data) |
{ |
const struct vbo_save_vertex_list *node = |
(const struct vbo_save_vertex_list *) data; |
struct vbo_save_context *save = &vbo_context(ctx)->save; |
FLUSH_CURRENT(ctx, 0); |
if (node->prim_count > 0 && node->count > 0) { |
if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END && |
node->prim[0].begin) { |
/* Degenerate case: list is called inside begin/end pair and |
* includes operations such as glBegin or glDrawArrays. |
*/ |
if (0) |
printf("displaylist recursive begin"); |
vbo_save_loopback_vertex_list( ctx, node ); |
return; |
} |
else if (save->replay_flags) { |
/* Various degnerate cases: translate into immediate mode |
* calls rather than trying to execute in place. |
*/ |
vbo_save_loopback_vertex_list( ctx, node ); |
return; |
} |
if (ctx->NewState) |
_mesa_update_state( ctx ); |
/* XXX also need to check if shader enabled, but invalid */ |
if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) || |
(ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) { |
_mesa_error(ctx, GL_INVALID_OPERATION, |
"glBegin (invalid vertex/fragment program)"); |
return; |
} |
vbo_bind_vertex_list( ctx, node ); |
/* Again... |
*/ |
if (ctx->NewState) |
_mesa_update_state( ctx ); |
vbo_context(ctx)->draw_prims(ctx, |
save->inputs, |
node->prim, |
node->prim_count, |
NULL, |
GL_TRUE, |
0, /* Node is a VBO, so this is ok */ |
node->count - 1); |
} |
/* Copy to current? |
*/ |
_playback_copy_to_current( ctx, node ); |
} |
#endif /* FEATURE_dlist */ |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_save_loopback.c |
---|
0,0 → 1,195 |
/************************************************************************** |
* |
* 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" |
#if FEATURE_dlist |
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) && |
(ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)) |
{ |
loopback_weak_prim( ctx, &prim[i] ); |
} |
else |
{ |
loopback_prim( ctx, buffer, &prim[i], wrap_count, vertex_size, la, nr ); |
} |
} |
} |
#endif /* FEATURE_dlist */ |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_split.c |
---|
0,0 → 1,169 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
/* 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, as is done in |
* the t_dd_rendertmp.h templates. 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); |
} |
} |
} |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_split.h |
---|
0,0 → 1,72 |
/* |
* mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
*/ |
/** |
* \file vbo_context.h |
* \brief VBO builder module datatypes and definitions. |
* \author Keith Whitwell |
*/ |
/** |
* \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 |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_split_copy.c |
---|
0,0 → 1,625 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
/* Split indexed primitives with per-vertex copying. |
*/ |
#include "main/glheader.h" |
#include "main/bufferobj.h" |
#include "main/imports.h" |
#include "main/image.h" |
#include "main/macros.h" |
#include "main/mtypes.h" |
#include "vbo_split.h" |
#include "vbo.h" |
#define ELT_TABLE_SIZE 16 |
/** |
* Used for vertex-level splitting of indexed buffers. Note that |
* non-indexed primitives may be converted to indexed in some cases |
* (eg loops, fans) in order to use this splitting path. |
*/ |
struct copy_context { |
struct gl_context *ctx; |
const struct gl_client_array **array; |
const struct _mesa_prim *prim; |
GLuint nr_prims; |
const struct _mesa_index_buffer *ib; |
vbo_draw_func draw; |
const struct split_limits *limits; |
struct { |
GLuint attr; |
GLuint size; |
const struct gl_client_array *array; |
const GLubyte *src_ptr; |
struct gl_client_array dstarray; |
} varying[VERT_ATTRIB_MAX]; |
GLuint nr_varying; |
const struct gl_client_array *dstarray_ptr[VERT_ATTRIB_MAX]; |
struct _mesa_index_buffer dstib; |
GLuint *translated_elt_buf; |
const GLuint *srcelt; |
/** A baby hash table to avoid re-emitting (some) duplicate |
* vertices when splitting indexed primitives. |
*/ |
struct { |
GLuint in; |
GLuint out; |
} vert_cache[ELT_TABLE_SIZE]; |
GLuint vertex_size; |
GLubyte *dstbuf; |
GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */ |
GLuint dstbuf_size; /**< in vertices */ |
GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value |
* in dstelt. Our MaxIndex. |
*/ |
GLuint *dstelt; |
GLuint dstelt_nr; |
GLuint dstelt_size; |
#define MAX_PRIM 32 |
struct _mesa_prim dstprim[MAX_PRIM]; |
GLuint dstprim_nr; |
}; |
static GLuint attr_size( const struct gl_client_array *array ) |
{ |
return array->Size * _mesa_sizeof_type(array->Type); |
} |
/** |
* Starts returning true slightly before the buffer fills, to ensure |
* that there is sufficient room for any remaining vertices to finish |
* off the prim: |
*/ |
static GLboolean |
check_flush( struct copy_context *copy ) |
{ |
GLenum mode = copy->dstprim[copy->dstprim_nr].mode; |
if (GL_TRIANGLE_STRIP == mode && |
copy->dstelt_nr & 1) { /* see bug9962 */ |
return GL_FALSE; |
} |
if (copy->dstbuf_nr + 4 > copy->dstbuf_size) |
return GL_TRUE; |
if (copy->dstelt_nr + 4 > copy->dstelt_size) |
return GL_TRUE; |
return GL_FALSE; |
} |
/** |
* Dump the parameters/info for a vbo->draw() call. |
*/ |
static void |
dump_draw_info(struct gl_context *ctx, |
const struct gl_client_array **arrays, |
const struct _mesa_prim *prims, |
GLuint nr_prims, |
const struct _mesa_index_buffer *ib, |
GLuint min_index, |
GLuint max_index) |
{ |
GLuint i, j; |
printf("VBO Draw:\n"); |
for (i = 0; i < nr_prims; i++) { |
printf("Prim %u of %u\n", i, nr_prims); |
printf(" Prim mode 0x%x\n", prims[i].mode); |
printf(" IB: %p\n", (void*) ib); |
for (j = 0; j < VERT_ATTRIB_MAX; j++) { |
printf(" array %d at %p:\n", j, (void*) arrays[j]); |
printf(" enabled %d, ptr %p, size %d, type 0x%x, stride %d\n", |
arrays[j]->Enabled, arrays[j]->Ptr, |
arrays[j]->Size, arrays[j]->Type, arrays[j]->StrideB); |
if (0) { |
GLint k = prims[i].start + prims[i].count - 1; |
GLfloat *last = (GLfloat *) (arrays[j]->Ptr + arrays[j]->Stride * k); |
printf(" last: %f %f %f\n", |
last[0], last[1], last[2]); |
} |
} |
} |
} |
static void |
flush( struct copy_context *copy ) |
{ |
GLuint i; |
/* Set some counters: |
*/ |
copy->dstib.count = copy->dstelt_nr; |
#if 0 |
dump_draw_info(copy->ctx, |
copy->dstarray_ptr, |
copy->dstprim, |
copy->dstprim_nr, |
©->dstib, |
0, |
copy->dstbuf_nr); |
#else |
(void) dump_draw_info; |
#endif |
copy->draw( copy->ctx, |
copy->dstarray_ptr, |
copy->dstprim, |
copy->dstprim_nr, |
©->dstib, |
GL_TRUE, |
0, |
copy->dstbuf_nr - 1 ); |
/* Reset all pointers: |
*/ |
copy->dstprim_nr = 0; |
copy->dstelt_nr = 0; |
copy->dstbuf_nr = 0; |
copy->dstptr = copy->dstbuf; |
/* Clear the vertex cache: |
*/ |
for (i = 0; i < ELT_TABLE_SIZE; i++) |
copy->vert_cache[i].in = ~0; |
} |
/** |
* Called at begin of each primitive during replay. |
*/ |
static void |
begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag ) |
{ |
struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr]; |
prim->mode = mode; |
prim->begin = begin_flag; |
} |
/** |
* 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.MapBuffer(ctx, GL_ARRAY_BUFFER, GL_READ_ONLY, vbo); |
copy->varying[j].src_ptr = ADD_POINTERS(vbo->Pointer, |
copy->array[i]->Ptr); |
copy->dstarray_ptr[i] = ©->varying[j].dstarray; |
} |
} |
/* There must always be an index buffer. Currently require the |
* caller convert non-indexed prims to indexed. Could alternately |
* do it internally. |
*/ |
if (_mesa_is_bufferobj(copy->ib->obj) && |
!_mesa_bufferobj_mapped(copy->ib->obj)) |
ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY, |
copy->ib->obj); |
srcptr = (const GLubyte *) ADD_POINTERS(copy->ib->obj->Pointer, |
copy->ib->ptr); |
switch (copy->ib->type) { |
case GL_UNSIGNED_BYTE: |
copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count); |
copy->srcelt = copy->translated_elt_buf; |
for (i = 0; i < copy->ib->count; i++) |
copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i]; |
break; |
case GL_UNSIGNED_SHORT: |
copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count); |
copy->srcelt = copy->translated_elt_buf; |
for (i = 0; i < copy->ib->count; i++) |
copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i]; |
break; |
case GL_UNSIGNED_INT: |
copy->translated_elt_buf = NULL; |
copy->srcelt = (const GLuint *)srcptr; |
break; |
} |
/* Figure out the maximum allowed vertex buffer size: |
*/ |
if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) { |
copy->dstbuf_size = copy->limits->max_verts; |
} |
else { |
copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size; |
} |
/* Allocate an output vertex buffer: |
* |
* XXX: This should be a VBO! |
*/ |
copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size); |
copy->dstptr = copy->dstbuf; |
/* Setup new vertex arrays to point into the output buffer: |
*/ |
for (offset = 0, i = 0; i < copy->nr_varying; i++) { |
const struct gl_client_array *src = copy->varying[i].array; |
struct gl_client_array *dst = ©->varying[i].dstarray; |
dst->Size = src->Size; |
dst->Type = src->Type; |
dst->Format = GL_RGBA; |
dst->Stride = copy->vertex_size; |
dst->StrideB = copy->vertex_size; |
dst->Ptr = copy->dstbuf + offset; |
dst->Enabled = GL_TRUE; |
dst->Normalized = src->Normalized; |
dst->BufferObj = ctx->Shared->NullBufferObj; |
dst->_MaxElement = copy->dstbuf_size; /* may be less! */ |
offset += copy->varying[i].size; |
} |
/* Allocate an output element list: |
*/ |
copy->dstelt_size = MIN2(65536, |
copy->ib->count * 2 + 3); |
copy->dstelt_size = MIN2(copy->dstelt_size, |
copy->limits->max_indices); |
copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size); |
copy->dstelt_nr = 0; |
/* Setup the new index buffer to point to the allocated element |
* list: |
*/ |
copy->dstib.count = 0; /* duplicates dstelt_nr */ |
copy->dstib.type = GL_UNSIGNED_INT; |
copy->dstib.obj = ctx->Shared->NullBufferObj; |
copy->dstib.ptr = copy->dstelt; |
} |
/** |
* Free up everything allocated during split/replay. |
*/ |
static void |
replay_finish( struct copy_context *copy ) |
{ |
struct gl_context *ctx = copy->ctx; |
GLuint i; |
/* Free our vertex and index buffers: |
*/ |
free(copy->translated_elt_buf); |
free(copy->dstbuf); |
free(copy->dstelt); |
/* Unmap VBO's |
*/ |
for (i = 0; i < copy->nr_varying; i++) { |
struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj; |
if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo)) |
ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, vbo); |
} |
/* Unmap index buffer: |
*/ |
if (_mesa_is_bufferobj(copy->ib->obj) && |
_mesa_bufferobj_mapped(copy->ib->obj)) { |
ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, copy->ib->obj); |
} |
} |
/** |
* Split VBO into smaller pieces, draw the pieces. |
*/ |
void vbo_split_copy( struct gl_context *ctx, |
const struct gl_client_array *arrays[], |
const struct _mesa_prim *prim, |
GLuint nr_prims, |
const struct _mesa_index_buffer *ib, |
vbo_draw_func draw, |
const struct split_limits *limits ) |
{ |
struct copy_context copy; |
GLuint i, this_nr_prims; |
for (i = 0; i < nr_prims;) { |
/* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices |
* will rebase the elements to the basevertex, and we'll only |
* emit strings of prims with the same basevertex in one draw call. |
*/ |
for (this_nr_prims = 1; i + this_nr_prims < nr_prims; |
this_nr_prims++) { |
if (prim[i].basevertex != prim[i + this_nr_prims].basevertex) |
break; |
} |
memset(©, 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(©); |
} |
} |
/programs/develop/libraries/Mesa/src/mesa/vbo/vbo_split_inplace.c |
---|
0,0 → 1,283 |
/* |
* Mesa 3-D graphics library |
* Version: 6.5 |
* |
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved. |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included |
* in all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
* |
* Authors: |
* Keith Whitwell <keith@tungstengraphics.com> |
*/ |
#include "main/mtypes.h" |
#include "main/macros.h" |
#include "main/enums.h" |
#include "main/image.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 _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); |
split->draw(split->ctx, |
split->array, |
split->dstprim, |
split->dstprim_nr, |
split->ib ? &ib : NULL, |
!split->ib, |
split->min_index, |
split->max_index); |
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; |
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; |
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 ); |
} |
/programs/develop/libraries/Mesa/src/mesa/vbo/. |
---|
Property changes: |
Added: tsvn:logminsize |
+5 |
\ No newline at end of property |