mesa: Branch 'vbo_0_1_branch' - 8 commits
Keith Whitwell
keithw at kemper.freedesktop.org
Mon Jan 15 14:35:06 UTC 2007
src/mesa/main/context.c | 1
src/mesa/sources | 3
src/mesa/tnl/t_draw.c | 128 +++++++--
src/mesa/vbo/vbo.h | 36 ++
src/mesa/vbo/vbo_attrib_tmp.h | 5
src/mesa/vbo/vbo_context.c | 11
src/mesa/vbo/vbo_context.h | 8
src/mesa/vbo/vbo_exec_array.c | 6
src/mesa/vbo/vbo_save.h | 2
src/mesa/vbo/vbo_save_api.c | 42 --
src/mesa/vbo/vbo_save_loopback.c | 149 ----------
src/mesa/vbo/vbo_split.c | 161 +++++++++++
src/mesa/vbo/vbo_split.h | 72 +++++
src/mesa/vbo/vbo_split_copy.c | 549 +++++++++++++++++++++++++++++++++++++++
src/mesa/vbo/vbo_split_inplace.c | 287 ++++++++++++++++++++
15 files changed, 1244 insertions(+), 216 deletions(-)
New commits:
diff-tree 6ff9b48fe2bb2113689e45c89a7c643e44906d67 (from 50f76b9d9b4b17940798b44233b9b5af2f932117)
Author: Keith Whitwell <keith at tungstengraphics.com>
Date: Mon Jan 15 14:30:16 2007 +0000
Don't special-case FOG attribute initialization.
Initial fog value was being set to {0,0,0,0}. This results in vector
size 4, but isn't necessary. The regular {0,0,0,1} works fine.
diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
index 91f3af3..94d0ff6 100644
--- a/src/mesa/main/context.c
+++ b/src/mesa/main/context.c
@@ -970,7 +970,6 @@ _mesa_init_current( GLcontext *ctx )
ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_NORMAL], 0.0, 0.0, 1.0, 1.0 );
ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR0], 1.0, 1.0, 1.0, 1.0 );
ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR1], 0.0, 0.0, 0.0, 1.0 );
- ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_FOG], 0.0, 0.0, 0.0, 0.0 );
ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_COLOR_INDEX], 1.0, 0.0, 0.0, 1.0 );
ASSIGN_4V( ctx->Current.Attrib[VERT_ATTRIB_EDGEFLAG], 1.0, 0.0, 0.0, 1.0 );
}
diff-tree 50f76b9d9b4b17940798b44233b9b5af2f932117 (from 82152a2a8e1afeb61710318e769b1379be6c02c6)
Author: Keith Whitwell <keith at tungstengraphics.com>
Date: Mon Jan 15 14:20:21 2007 +0000
Correctly initialize current attribute sizes.
Some legacy attributes (eg color) have an initial value other than {0,0,0,1}
which means that their initial size != 1 either.
diff --git a/src/mesa/vbo/vbo_context.c b/src/mesa/vbo/vbo_context.c
index 165e32d..65998e7 100644
--- a/src/mesa/vbo/vbo_context.c
+++ b/src/mesa/vbo/vbo_context.c
@@ -47,6 +47,14 @@ extern void _tnl_draw_prims( GLcontext *
#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(GLcontext *ctx)
{
struct vbo_context *vbo = vbo_context(ctx);
@@ -63,7 +71,7 @@ static void init_legacy_currval(GLcontex
/* Size will have to be determined at runtime:
*/
- cl->Size = 1;
+ cl->Size = check_size(ctx->Current.Attrib[i]);
cl->Stride = 0;
cl->StrideB = 0;
cl->Enabled = 1;
@@ -88,7 +96,6 @@ static void init_generic_currval(GLconte
/* This will have to be determined at runtime:
*/
cl->Size = 1;
-
cl->Type = GL_FLOAT;
cl->Ptr = (const void *)ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + i];
cl->Stride = 0;
diff-tree 82152a2a8e1afeb61710318e769b1379be6c02c6 (from 5464cd0a60f474753abc6af047fd21b0e29b8ac4)
Author: keithw <keithw at keithw-laptop.(none)>
Date: Mon Jan 15 14:10:42 2007 +0000
Remove debug, reenable inplace splitting.
diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c
index 25b8708..0e7c2b6 100644
--- a/src/mesa/tnl/t_draw.c
+++ b/src/mesa/tnl/t_draw.c
@@ -375,7 +375,6 @@ void _tnl_draw_prims( GLcontext *ctx,
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &tnl->vb;
GLint max = VB->Size;
- GLuint i;
#ifdef TEST_SPLIT
max = 8 + MAX_CLIPPED_VERTICES;
@@ -387,12 +386,15 @@ void _tnl_draw_prims( GLcontext *ctx,
VB->Elts = NULL;
#if 0
- _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
- for (i = 0; i < nr_prims; i++)
- _mesa_printf("prim %d: %s start %d count %d\n", i,
- _mesa_lookup_enum_by_nr(prim[i].mode),
- prim[i].start,
- prim[i].count);
+ {
+ GLuint i;
+ _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
+ for (i = 0; i < nr_prims; i++)
+ _mesa_printf("prim %d: %s start %d count %d\n", i,
+ _mesa_lookup_enum_by_nr(prim[i].mode),
+ prim[i].start,
+ prim[i].count);
+ }
#endif
/* The software TNL pipeline has a fixed amount of storage for
diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c
index f339436..ade48d2 100644
--- a/src/mesa/vbo/vbo_save_api.c
+++ b/src/mesa/vbo/vbo_save_api.c
@@ -598,8 +598,6 @@ do { \
if (save->active_sz[A] != N) \
save_fixup_vertex(ctx, A, N); \
\
- _mesa_printf("Attr %d, sz %d: %f %f %f %f\n", A, N, V0, V1, V2, V3 ); \
- \
{ \
GLfloat *dest = save->attrptr[A]; \
if (N>0) dest[0] = V0; \
diff --git a/src/mesa/vbo/vbo_save_loopback.c b/src/mesa/vbo/vbo_save_loopback.c
index 2c28126..430333b 100644
--- a/src/mesa/vbo/vbo_save_loopback.c
+++ b/src/mesa/vbo/vbo_save_loopback.c
@@ -45,7 +45,8 @@ typedef void (*attr_func)( GLcontext *ct
/* This file makes heavy use of the aliasing of NV vertex attributes
- * with the legacy attributes.
+ * with the legacy attributes, and also with ARB and Material
+ * attributes as currently implemented.
*/
static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
{
diff --git a/src/mesa/vbo/vbo_split_inplace.c b/src/mesa/vbo/vbo_split_inplace.c
index 66c94ac..d3649c5 100644
--- a/src/mesa/vbo/vbo_split_inplace.c
+++ b/src/mesa/vbo/vbo_split_inplace.c
@@ -49,9 +49,6 @@ struct split_context {
const struct split_limits *limits;
-/* GLuint out_maxindex; */
-/* GLuint out_minindex; */
-
struct _mesa_prim dstprim[MAX_PRIM];
GLuint dstprim_nr;
};
@@ -151,13 +148,6 @@ static void split_prims( struct split_co
GLuint available = align(split->limits->max_verts - csr - 1, 2);
assert(split->limits->max_verts >= csr);
- _mesa_printf("%s: prim %d: %s %d..%d\n", __FUNCTION__,
- i,
- _mesa_lookup_enum_by_nr(prim->mode),
- prim->start, prim->count);
-
- _mesa_printf("a: available %d\n", available);
-
if (prim->count < first)
continue;
@@ -171,15 +161,13 @@ static void split_prims( struct split_co
available = align(split->limits->max_verts - csr - 1, 2);
}
- _mesa_printf("b: available %d\n", available);
-
if (available >= count) {
struct _mesa_prim *outprim = next_outprim(split);
*outprim = *prim;
csr += prim->count;
available = align(split->limits->max_verts - csr - 1, 2);
}
- else if (0 && split_inplace) {
+ else if (split_inplace) {
GLuint j, nr;
@@ -207,8 +195,6 @@ static void split_prims( struct split_co
else {
/* Wrapped the primitive:
*/
- _mesa_printf("wrap %d %d\n", nr, first-incr);
-
j += nr - (first - incr);
flush_vertex(split);
csr = 0;
diff-tree 5464cd0a60f474753abc6af047fd21b0e29b8ac4 (from 2421b25dd777ebfd614ae45907fd4af8c2713102)
Author: Keith Whitwell <keith at tungstengraphics.com>
Date: Mon Jan 15 13:54:08 2007 +0000
Split too-large draw commands.
Use the vbo_split_ functionality to split incoming drawing command
to fit within the fixed-size buffers used by software t&l module.
diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c
index 0f9615e..25b8708 100644
--- a/src/mesa/tnl/t_draw.c
+++ b/src/mesa/tnl/t_draw.c
@@ -32,6 +32,7 @@
#include "state.h"
#include "mtypes.h"
#include "macros.h"
+#include "enums.h"
#include "t_context.h"
#include "t_pipeline.h"
@@ -182,7 +183,7 @@ static GLboolean *_tnl_import_edgeflag(
static void bind_inputs( GLcontext *ctx,
const struct gl_client_array *inputs[],
- GLint start, GLint end,
+ GLint min_index, GLint max_index,
struct gl_buffer_object **bo,
GLuint *nr_bo )
{
@@ -214,15 +215,20 @@ static void bind_inputs( GLcontext *ctx,
ptr = inputs[i]->Ptr;
/* Just make sure the array is floating point, otherwise convert to
- * temporary storage. Rebase arrays so that 'start' becomes
+ * temporary storage. Rebase arrays so that 'min_index' becomes
* element zero.
*
* XXX: remove the GLvector4f type at some stage and just use
* client arrays.
*/
- _tnl_import_array(ctx, i, start, end, inputs[i], ptr);
+ _tnl_import_array(ctx, i, min_index, max_index, inputs[i], ptr);
}
+ /* We process only the vertices between min & max index:
+ */
+ VB->Count = max_index - min_index;
+
+
/* Legacy pointers -- remove one day.
*/
VB->ObjPtr = VB->AttribPtr[_TNL_ATTRIB_POS];
@@ -256,10 +262,11 @@ static void bind_inputs( GLcontext *ctx,
/* Translate indices to GLuints and store in VB->Elts.
*/
-static void bind_indicies( GLcontext *ctx,
- const struct _mesa_index_buffer *ib,
- struct gl_buffer_object **bo,
- GLuint *nr_bo)
+static void bind_indices( GLcontext *ctx,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ struct gl_buffer_object **bo,
+ GLuint *nr_bo)
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &tnl->vb;
@@ -282,7 +289,7 @@ static void bind_indicies( GLcontext *ct
ptr = ADD_POINTERS(ib->obj->Pointer, ib->ptr);
- if (ib->type == GL_UNSIGNED_INT) {
+ if (ib->type == GL_UNSIGNED_INT && min_index == 0) {
VB->Elts = (GLuint *) ptr;
VB->Elts += ib->rebase;
}
@@ -291,22 +298,54 @@ static void bind_indicies( GLcontext *ct
VB->Elts = elts;
switch (ib->type) {
+ case GL_UNSIGNED_INT: {
+ const GLuint *in = ((GLuint *)ptr) + ib->rebase;
+ for (i = 0; i < ib->count; i++)
+ *elts++ = *in++ - min_index;
+ break;
+ }
case GL_UNSIGNED_SHORT: {
const GLushort *in = ((GLushort *)ptr) + ib->rebase;
for (i = 0; i < ib->count; i++)
- *elts++ = *in++;
+ *elts++ = (GLuint)(*in++) - min_index;
break;
}
case GL_UNSIGNED_BYTE: {
const GLubyte *in = ((GLubyte *)ptr) + ib->rebase;
for (i = 0; i < ib->count; i++)
- *elts++ = *in++;
+ *elts++ = (GLuint)(*in++) - min_index;
break;
}
}
}
}
+static void bind_prims( GLcontext *ctx,
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ GLuint min_index )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint i;
+
+ if (min_index != 0) {
+ struct _mesa_prim *tmp = (struct _mesa_prim *)get_space(ctx, nr_prims * sizeof(*prim));
+
+ for (i = 0; i < nr_prims; i++) {
+ tmp[i] = prim[i];
+ tmp[i].start -= min_index;
+ }
+
+ VB->Primitive = tmp;
+ }
+ else {
+ VB->Primitive = prim;
+ }
+
+ VB->PrimitiveCount = nr_prims;
+}
+
static void unmap_vbos( GLcontext *ctx,
struct gl_buffer_object **bo,
GLuint nr_bo )
@@ -335,26 +374,63 @@ void _tnl_draw_prims( GLcontext *ctx,
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &tnl->vb;
+ GLint max = VB->Size;
+ GLuint i;
- /* May need to map a vertex buffer object for every attribute plus
- * one for the index buffer.
- */
- struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
- GLuint nr_bo = 0;
+#ifdef TEST_SPLIT
+ max = 8 + MAX_CLIPPED_VERTICES;
+#endif
+
+ assert(max_index > min_index);
+ assert(!(max_index & 0x80000000));
- /* Binding inputs may imply mapping some vertex buffer objects.
- * They will need to be unmapped below.
+ VB->Elts = NULL;
+
+#if 0
+ _mesa_printf("%s %d..%d\n", __FUNCTION__, min_index, max_index);
+ for (i = 0; i < nr_prims; i++)
+ _mesa_printf("prim %d: %s start %d count %d\n", i,
+ _mesa_lookup_enum_by_nr(prim[i].mode),
+ prim[i].start,
+ prim[i].count);
+#endif
+
+ /* The software TNL pipeline has a fixed amount of storage for
+ * vertices and it is necessary to split incoming drawing commands
+ * if they exceed that limit.
*/
- bind_inputs(ctx, arrays, min_index, max_index, bo, &nr_bo);
- bind_indicies(ctx, ib, bo, &nr_bo);
+ if (max_index - min_index >= max - MAX_CLIPPED_VERTICES) {
+ struct split_limits limits;
+ limits.max_verts = max - MAX_CLIPPED_VERTICES;
+ limits.max_vb_size = ~0;
+ limits.max_indices = ~0;
- VB->Primitive = prim;
- VB->PrimitiveCount = nr_prims;
- VB->Count = max_index - min_index;
+ /* This will split the buffers one way or another and
+ * recursively call back into this function.
+ */
+ vbo_split_prims( ctx, arrays, prim, nr_prims, ib,
+ min_index, max_index,
+ _tnl_draw_prims,
+ &limits );
+ }
+ else {
+ /* May need to map a vertex buffer object for every attribute plus
+ * one for the index buffer.
+ */
+ struct gl_buffer_object *bo[VERT_ATTRIB_MAX + 1];
+ GLuint nr_bo = 0;
+
+ /* Binding inputs may imply mapping some vertex buffer objects.
+ * They will need to be unmapped below.
+ */
+ bind_inputs(ctx, arrays, min_index, max_index+1, bo, &nr_bo);
+ bind_indices(ctx, ib, min_index, bo, &nr_bo);
+ bind_prims(ctx, prim, nr_prims, VB->Elts ? 0 : min_index );
- TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
+ TNL_CONTEXT(ctx)->Driver.RunPipeline(ctx);
- unmap_vbos(ctx, bo, nr_bo);
- free_space(ctx);
+ unmap_vbos(ctx, bo, nr_bo);
+ free_space(ctx);
+ }
}
diff-tree 2421b25dd777ebfd614ae45907fd4af8c2713102 (from 1b7c24c33c43e2c0db391735b2f2ca0026459cc9)
Author: Keith Whitwell <keith at tungstengraphics.com>
Date: Mon Jan 15 13:40:38 2007 +0000
Remove special-case handling for index and edgeflag
This isn't required with the changes to core mesa and the new
attribute layout.
diff --git a/src/mesa/vbo/vbo_attrib_tmp.h b/src/mesa/vbo/vbo_attrib_tmp.h
index 72a8b04..ff11c7d 100644
--- a/src/mesa/vbo/vbo_attrib_tmp.h
+++ b/src/mesa/vbo/vbo_attrib_tmp.h
@@ -357,9 +357,10 @@ static void GLAPIENTRY TAG(VertexAttrib4
}
-/* Although we don't export NV_vertex_program, these entrypoints are
+/* 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.
+ * their property of aliasing with other attributes. (See
+ * vbo_save_loopback.c)
*/
static void GLAPIENTRY TAG(VertexAttrib1fNV)( GLuint index, GLfloat x )
{
diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c
index 803e58c..15fbdcf 100644
--- a/src/mesa/vbo/vbo_exec_array.c
+++ b/src/mesa/vbo/vbo_exec_array.c
@@ -96,10 +96,10 @@ static void bind_array_obj( GLcontext *c
exec->array.legacy_array[VERT_ATTRIB_COLOR1] = &ctx->Array.ArrayObj->SecondaryColor;
exec->array.legacy_array[VERT_ATTRIB_FOG] = &ctx->Array.ArrayObj->FogCoord;
exec->array.legacy_array[VERT_ATTRIB_COLOR_INDEX] = &ctx->Array.ArrayObj->Index;
- exec->array.legacy_array[VBO_ATTRIB_EDGEFLAG] = &ctx->Array.ArrayObj->EdgeFlag;
+ exec->array.legacy_array[VERT_ATTRIB_EDGEFLAG] = &ctx->Array.ArrayObj->EdgeFlag;
for (i = 0; i < 8; i++)
- exec->array.legacy_array[VBO_ATTRIB_TEX0 + i] = &ctx->Array.ArrayObj->TexCoord[i];
+ exec->array.legacy_array[VERT_ATTRIB_TEX0 + i] = &ctx->Array.ArrayObj->TexCoord[i];
for (i = 0; i < VERT_ATTRIB_MAX; i++)
exec->array.generic_array[i] = &ctx->Array.ArrayObj->VertexAttrib[i];
@@ -117,8 +117,6 @@ static void recalculate_input_bindings(
exec->array.program_mode = get_program_mode(ctx);
exec->array.enabled_flags = ctx->Array.ArrayObj->_Enabled;
- /* TODO: Get rid of NV_program (please!).
- */
switch (exec->array.program_mode) {
case VP_NONE:
/* When no vertex program is active, we put the material values
diff --git a/src/mesa/vbo/vbo_save.h b/src/mesa/vbo/vbo_save.h
index 3051f5c..b81f275 100644
--- a/src/mesa/vbo/vbo_save.h
+++ b/src/mesa/vbo/vbo_save.h
@@ -142,8 +142,6 @@ struct vbo_save_context {
struct vbo_save_copied_vtx copied;
- GLfloat CurrentFloatEdgeFlag;
-
GLfloat *current[VBO_ATTRIB_MAX]; /* points into ctx->ListState */
GLubyte *currentsz[VBO_ATTRIB_MAX];
};
diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c
index efe018b..f339436 100644
--- a/src/mesa/vbo/vbo_save_api.c
+++ b/src/mesa/vbo/vbo_save_api.c
@@ -415,26 +415,14 @@ static void _save_copy_to_current( GLcon
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLuint i;
- for (i = VBO_ATTRIB_POS+1 ; i <= VBO_ATTRIB_INDEX ; 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]);
+ save->attrsz[i],
+ save->attrptr[i]);
}
}
-
- /* Edgeflag requires special treatment:
- *
- * TODO: change edgeflag to GLfloat in Mesa.
- */
- if (save->attrsz[VBO_ATTRIB_EDGEFLAG]) {
- ctx->ListState.ActiveEdgeFlag = 1;
- save->CurrentFloatEdgeFlag =
- save->attrptr[VBO_ATTRIB_EDGEFLAG][0];
- ctx->ListState.CurrentEdgeFlag =
- (save->CurrentFloatEdgeFlag == 1.0);
- }
}
@@ -443,7 +431,7 @@ static void _save_copy_from_current( GLc
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLint i;
- for (i = VBO_ATTRIB_POS+1 ; i <= VBO_ATTRIB_INDEX ; 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];
@@ -451,12 +439,6 @@ static void _save_copy_from_current( GLc
case 1: save->attrptr[i][0] = save->current[i][0];
case 0: break;
}
-
- /* Edgeflag requires special treatment:
- */
- if (save->attrsz[VBO_ATTRIB_EDGEFLAG]) {
- save->CurrentFloatEdgeFlag = (GLfloat)ctx->ListState.CurrentEdgeFlag;
- save->attrptr[VBO_ATTRIB_EDGEFLAG][0] = save->CurrentFloatEdgeFlag;
}
}
@@ -616,6 +598,8 @@ do { \
if (save->active_sz[A] != N) \
save_fixup_vertex(ctx, A, N); \
\
+ _mesa_printf("Attr %d, sz %d: %f %f %f %f\n", A, N, V0, V1, V2, V3 ); \
+ \
{ \
GLfloat *dest = save->attrptr[A]; \
if (N>0) dest[0] = V0; \
@@ -1106,23 +1090,19 @@ static void _save_current_init( GLcontex
struct vbo_save_context *save = &vbo_context(ctx)->save;
GLint i;
- for (i = 0; i < VBO_ATTRIB_FIRST_MATERIAL; i++) {
- save->currentsz[i] = &ctx->ListState.ActiveAttribSize[i];
- save->current[i] = ctx->ListState.CurrentAttrib[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_INDEX; i++) {
+ for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_MAT_FRONT_AMBIENT; 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];
}
-
- save->currentsz[VBO_ATTRIB_INDEX] = &ctx->ListState.ActiveIndex;
- save->current[VBO_ATTRIB_INDEX] = &ctx->ListState.CurrentIndex;
-
- save->currentsz[VBO_ATTRIB_EDGEFLAG] = &ctx->ListState.ActiveEdgeFlag;
- save->current[VBO_ATTRIB_EDGEFLAG] = &save->CurrentFloatEdgeFlag;
}
/**
diff --git a/src/mesa/vbo/vbo_save_loopback.c b/src/mesa/vbo/vbo_save_loopback.c
index 941c4be..2c28126 100644
--- a/src/mesa/vbo/vbo_save_loopback.c
+++ b/src/mesa/vbo/vbo_save_loopback.c
@@ -44,7 +44,9 @@
typedef void (*attr_func)( GLcontext *ctx, GLint target, const GLfloat * );
-/* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */
+/* This file makes heavy use of the aliasing of NV vertex attributes
+ * with the legacy attributes.
+ */
static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
{
CALL_VertexAttrib1fvNV(ctx->Exec, (target, v));
@@ -72,118 +74,6 @@ static attr_func vert_attrfunc[4] = {
VertexAttrib4fvNV
};
-#if 0
-static void VertexAttrib1fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
-{
- CALL_VertexAttrib1fvARB(ctx->Exec, (target, v));
-}
-
-static void VertexAttrib2fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
-{
- CALL_VertexAttrib2fvARB(ctx->Exec, (target, v));
-}
-
-static void VertexAttrib3fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
-{
- CALL_VertexAttrib3fvARB(ctx->Exec, (target, v));
-}
-
-static void VertexAttrib4fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
-{
- CALL_VertexAttrib4fvARB(ctx->Exec, (target, v));
-}
-
-
-static attr_func vert_attrfunc_arb[4] = {
- VertexAttrib1fvARB,
- VertexAttrib2fvARB,
- VertexAttrib3fvARB,
- VertexAttrib4fvARB
-};
-#endif
-
-
-
-
-
-
-static void mat_attr1fv( GLcontext *ctx, GLint target, const GLfloat *v )
-{
- switch (target) {
- case VBO_ATTRIB_MAT_FRONT_SHININESS:
- CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_SHININESS, v ));
- break;
- case VBO_ATTRIB_MAT_BACK_SHININESS:
- CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_SHININESS, v ));
- break;
- }
-}
-
-
-static void mat_attr3fv( GLcontext *ctx, GLint target, const GLfloat *v )
-{
- switch (target) {
- case VBO_ATTRIB_MAT_FRONT_INDEXES:
- CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_COLOR_INDEXES, v ));
- break;
- case VBO_ATTRIB_MAT_BACK_INDEXES:
- CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_COLOR_INDEXES, v ));
- break;
- }
-}
-
-
-static void mat_attr4fv( GLcontext *ctx, GLint target, const GLfloat *v )
-{
- switch (target) {
- case VBO_ATTRIB_MAT_FRONT_EMISSION:
- CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_EMISSION, v ));
- break;
- case VBO_ATTRIB_MAT_BACK_EMISSION:
- CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_EMISSION, v ));
- break;
- case VBO_ATTRIB_MAT_FRONT_AMBIENT:
- CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_AMBIENT, v ));
- break;
- case VBO_ATTRIB_MAT_BACK_AMBIENT:
- CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_AMBIENT, v ));
- break;
- case VBO_ATTRIB_MAT_FRONT_DIFFUSE:
- CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_DIFFUSE, v ));
- break;
- case VBO_ATTRIB_MAT_BACK_DIFFUSE:
- CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_DIFFUSE, v ));
- break;
- case VBO_ATTRIB_MAT_FRONT_SPECULAR:
- CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_SPECULAR, v ));
- break;
- case VBO_ATTRIB_MAT_BACK_SPECULAR:
- CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_SPECULAR, v ));
- break;
- }
-}
-
-
-static attr_func mat_attrfunc[4] = {
- mat_attr1fv,
- NULL,
- mat_attr3fv,
- mat_attr4fv
-};
-
-
-static void index_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
-{
- (void) target;
- CALL_Indexf(ctx->Exec, (v[0]));
-}
-
-static void edgeflag_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
-{
- (void) target;
- CALL_EdgeFlag(ctx->Exec, ((GLboolean)(v[0] == 1.0)));
-}
-
struct loopback_attr {
GLint target;
GLint sz;
@@ -277,7 +167,10 @@ void vbo_loopback_vertex_list( GLcontext
struct loopback_attr la[VBO_ATTRIB_MAX];
GLuint i, nr = 0;
- for (i = 0 ; i <= VBO_ATTRIB_TEX7 ; i++) {
+ /* 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];
@@ -286,33 +179,6 @@ void vbo_loopback_vertex_list( GLcontext
}
}
- for (i = VBO_ATTRIB_MAT_FRONT_AMBIENT ;
- i <= VBO_ATTRIB_MAT_BACK_INDEXES ;
- i++) {
- if (attrsz[i]) {
- la[nr].target = i;
- la[nr].sz = attrsz[i];
- la[nr].func = mat_attrfunc[attrsz[i]-1];
- nr++;
- }
- }
-
- if (attrsz[VBO_ATTRIB_EDGEFLAG]) {
- la[nr].target = VBO_ATTRIB_EDGEFLAG;
- la[nr].sz = attrsz[VBO_ATTRIB_EDGEFLAG];
- la[nr].func = edgeflag_attr1fv;
- nr++;
- }
-
- if (attrsz[VBO_ATTRIB_INDEX]) {
- la[nr].target = VBO_ATTRIB_INDEX;
- la[nr].sz = attrsz[VBO_ATTRIB_INDEX];
- la[nr].func = index_attr1fv;
- nr++;
- }
-
- /* XXX ARB vertex attribs */
-
for (i = 0 ; i < prim_count ; i++) {
if ((prim[i].mode & VBO_SAVE_PRIM_WEAK) &&
(ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END))
diff-tree 1b7c24c33c43e2c0db391735b2f2ca0026459cc9 (from 4557dfe13206495916d4ff8557f1633194a12c0f)
Author: keithw <keithw at keithw-laptop.(none)>
Date: Mon Jan 15 11:58:06 2007 +0000
Hook in split functionality
diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h
index 80f7a33..c81d83f 100644
--- a/src/mesa/vbo/vbo.h
+++ b/src/mesa/vbo/vbo.h
@@ -65,4 +65,40 @@ void _vbo_DestroyContext( GLcontext *ctx
void _vbo_InvalidateState( GLcontext *ctx, GLuint new_state );
+typedef void (*vbo_draw_func)( GLcontext *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 );
+
+
+
+
+/* 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( GLcontext *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 );
+
+
#endif
diff --git a/src/mesa/vbo/vbo_context.h b/src/mesa/vbo/vbo_context.h
index 4c5ed96..0dc1019 100644
--- a/src/mesa/vbo/vbo_context.h
+++ b/src/mesa/vbo/vbo_context.h
@@ -79,13 +79,7 @@ struct vbo_context {
/* Callback into the driver. This must always succeed, the driver
* is responsible for initiating any fallback actions required:
*/
- void (*draw_prims)( GLcontext *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 );
+ vbo_draw_func draw_prims;
};
diff-tree 4557dfe13206495916d4ff8557f1633194a12c0f (from a38cb37913b7cd2f9c3c7aa11dcbb9485d623924)
Author: keithw <keithw at keithw-laptop.(none)>
Date: Mon Jan 15 11:54:40 2007 +0000
Add vbo_split files
diff --git a/src/mesa/sources b/src/mesa/sources
index b589111..a32ecaf 100644
--- a/src/mesa/sources
+++ b/src/mesa/sources
@@ -143,6 +143,9 @@ VBO_SOURCES = \
vbo/vbo_exec_array.c \
vbo/vbo_exec_draw.c \
vbo/vbo_exec_eval.c \
+ vbo/vbo_split.c \
+ vbo/vbo_split_copy.c \
+ vbo/vbo_split_inplace.c \
vbo/vbo_save.c \
vbo/vbo_save_api.c \
vbo/vbo_save_draw.c \
diff-tree a38cb37913b7cd2f9c3c7aa11dcbb9485d623924 (from dd60eaa6d9f61735141976db0e83d25176ac73c7)
Author: keithw <keithw at keithw-laptop.(none)>
Date: Mon Jan 15 11:52:58 2007 +0000
New files to manage splitting drawing commands
diff --git a/src/mesa/vbo/vbo_split.c b/src/mesa/vbo/vbo_split.c
new file mode 100644
index 0000000..171859a
--- /dev/null
+++ b/src/mesa/vbo/vbo_split.c
@@ -0,0 +1,161 @@
+
+/*
+ * 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 at 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 "glheader.h"
+#include "imports.h"
+#include "mtypes.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( GLcontext *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 )
+{
+
+ 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);
+ }
+ }
+}
+
diff --git a/src/mesa/vbo/vbo_split.h b/src/mesa/vbo/vbo_split.h
new file mode 100644
index 0000000..05888d0
--- /dev/null
+++ b/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( GLcontext *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( GLcontext *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
diff --git a/src/mesa/vbo/vbo_split_copy.c b/src/mesa/vbo/vbo_split_copy.c
new file mode 100644
index 0000000..0adad71
--- /dev/null
+++ b/src/mesa/vbo/vbo_split_copy.c
@@ -0,0 +1,549 @@
+
+/*
+ * 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 at tungstengraphics.com>
+ */
+
+/* Split indexed primitives with per-vertex copying.
+ */
+
+#include "glheader.h"
+#include "imports.h"
+#include "macros.h"
+#include "enums.h"
+#include "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 {
+
+ GLcontext *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 type_size( GLenum type )
+{
+ switch(type) {
+ case GL_BYTE: return sizeof(GLbyte);
+ case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
+ case GL_SHORT: return sizeof(GLshort);
+ case GL_UNSIGNED_SHORT: return sizeof(GLushort);
+ case GL_INT: return sizeof(GLint);
+ case GL_UNSIGNED_INT: return sizeof(GLuint);
+ case GL_FLOAT: return sizeof(GLfloat);
+ case GL_DOUBLE: return sizeof(GLdouble);
+ default: return 0;
+ }
+}
+
+static GLuint attr_size( const struct gl_client_array *array )
+{
+ return array->Size * type_size(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 )
+{
+ 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;
+}
+
+static void flush( struct copy_context *copy )
+{
+ GLuint i;
+
+ /* Set some counters:
+ */
+ copy->dstib.count = copy->dstelt_nr;
+
+ copy->draw( copy->ctx,
+ copy->dstarray_ptr,
+ copy->dstprim,
+ copy->dstprim_nr,
+ ©->dstib,
+ 0,
+ copy->dstbuf_nr );
+
+ /* 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;
+}
+
+
+
+static void begin( struct copy_context *copy, GLenum mode, GLboolean begin_flag )
+{
+ struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr];
+
+ _mesa_printf("begin %s (%d)\n", _mesa_lookup_enum_by_nr(mode), begin_flag);
+
+ 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);
+
+ _mesa_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;
+
+ _mesa_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;
+
+ {
+ const GLuint *f = (const GLuint *)srcptr;
+ GLuint j;
+ _mesa_printf(" varying %d: ", i);
+ for(j = 0; j < copy->varying[i].size / 4; j++)
+ _mesa_printf("%x ", f[j]);
+ _mesa_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
+ _mesa_printf(" --> reuse vertex\n");
+
+ _mesa_printf(" --> emit %d\n", copy->vert_cache[slot].out);
+ copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
+ return check_flush(copy);
+}
+
+static void end( struct copy_context *copy, GLboolean end_flag )
+{
+ struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr];
+
+ _mesa_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 )
+{
+ GLcontext *ctx = copy->ctx;
+ GLuint i;
+ GLuint offset;
+
+ /* 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 (vbo->Name && !vbo->Pointer)
+ ctx->Driver.MapBuffer(ctx,
+ GL_ARRAY_BUFFER_ARB,
+ GL_DYNAMIC_DRAW_ARB, /* XXX */
+ 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 (copy->ib->obj->Name && !copy->ib->obj->Pointer)
+ ctx->Driver.MapBuffer(ctx,
+ GL_ARRAY_BUFFER_ARB, /* XXX */
+ GL_DYNAMIC_DRAW_ARB, /* XXX */
+ copy->ib->obj);
+
+ switch (copy->ib->type) {
+ case GL_UNSIGNED_BYTE:
+ copy->translated_elt_buf = _mesa_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 *)copy->ib->ptr)[i];
+ break;
+
+ case GL_UNSIGNED_SHORT:
+ copy->translated_elt_buf = _mesa_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 *)copy->ib->ptr)[i];
+ break;
+
+ case GL_UNSIGNED_INT:
+ copy->translated_elt_buf = NULL;
+ copy->srcelt = (const GLuint *)ADD_POINTERS(copy->ib->obj->Pointer,
+ copy->ib->ptr);
+ 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 = _mesa_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->Stride = copy->vertex_size;
+ dst->StrideB = copy->vertex_size;
+ dst->Ptr = copy->dstbuf + offset;
+ dst->Enabled = GL_TRUE;
+ dst->Normalized = GL_TRUE;
+ dst->BufferObj = ctx->Array.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);
+ copy->dstelt_size = MIN2(copy->dstelt_size,
+ copy->limits->max_indices);
+ copy->dstelt = _mesa_malloc(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->Array.NullBufferObj;
+ copy->dstib.ptr = copy->dstelt;
+ copy->dstib.rebase = 0;
+}
+
+
+static void replay_finish( struct copy_context *copy )
+{
+ GLcontext *ctx = copy->ctx;
+ GLuint i;
+
+ /* Free our vertex and index buffers:
+ */
+ _mesa_free(copy->translated_elt_buf);
+ _mesa_free(copy->dstbuf);
+ _mesa_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 (vbo->Name && vbo->Pointer)
+ ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, vbo);
+ }
+
+ /* Unmap index buffer:
+ */
+ if (copy->ib->obj->Name && copy->ib->obj->Pointer) {
+ ctx->Driver.UnmapBuffer(ctx,
+ GL_ARRAY_BUFFER_ARB, /* XXX */
+ copy->ib->obj);
+ }
+}
+
+void vbo_split_copy( GLcontext *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;
+
+ memset(©, 0, sizeof(copy));
+
+ /* Require indexed primitives:
+ */
+ assert(ib);
+
+ copy.ctx = ctx;
+ copy.array = arrays;
+ copy.prim = prim;
+ copy.nr_prims = 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(©);
+}
diff --git a/src/mesa/vbo/vbo_split_inplace.c b/src/mesa/vbo/vbo_split_inplace.c
new file mode 100644
index 0000000..66c94ac
--- /dev/null
+++ b/src/mesa/vbo/vbo_split_inplace.c
@@ -0,0 +1,301 @@
+
+/*
+ * 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 at tungstengraphics.com>
+ */
+
+
+#include "mtypes.h"
+#include "macros.h"
+#include "enums.h"
+#include "vbo_split.h"
+
+
+#define MAX_PRIM 32
+
+/* Used for splitting without copying.
+ */
+struct split_context {
+ GLcontext *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 out_maxindex; */
+/* GLuint out_minindex; */
+
+ struct _mesa_prim dstprim[MAX_PRIM];
+ GLuint dstprim_nr;
+};
+
+
+
+
+static void flush_vertex( struct split_context *split )
+{
+ GLint min_index, max_index;
+
+ if (!split->dstprim_nr)
+ return;
+
+ if (split->ib) {
+ /* This should basically be multipass rendering over the same
+ * unchanging set of VBO's. Would like the driver not to
+ * re-upload the data, or swtnl not to re-transform the
+ * vertices.
+ */
+ assert(split->max_index - split->min_index < split->limits->max_verts);
+ min_index = split->min_index;
+ max_index = split->max_index;
+ }
+ else {
+ /* Non-indexed rendering. Cannot assume that the primitives are
+ * ordered by increasing vertex, because of entrypoints like
+ * MultiDrawArrays.
+ */
+ GLuint i;
+ min_index = split->dstprim[0].start;
+ max_index = min_index + split->dstprim[0].count - 1;
+
+ for (i = 1; i < split->dstprim_nr; i++) {
+ GLuint tmp_min = split->dstprim[i].start;
+ GLuint tmp_max = tmp_min + split->dstprim[i].count - 1;
+
+ if (tmp_min < min_index)
+ min_index = tmp_min;
+
+ if (tmp_max > max_index)
+ max_index = tmp_max;
+ }
+ }
+
+ assert(max_index >= min_index);
+
+ split->draw( split->ctx,
+ split->array,
+ split->dstprim,
+ split->dstprim_nr,
+ NULL,
+ min_index,
+ max_index);
+
+ split->dstprim_nr = 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 int align(int value, int alignment)
+{
+ return (value + alignment - 1) & ~(alignment - 1);
+}
+
+
+
+/* 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 csr = 0;
+ 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 count;
+
+ /* Always wrap on an even numbered vertex to avoid problems with
+ * triangle strips.
+ */
+ GLuint available = align(split->limits->max_verts - csr - 1, 2);
+ assert(split->limits->max_verts >= csr);
+
+ _mesa_printf("%s: prim %d: %s %d..%d\n", __FUNCTION__,
+ i,
+ _mesa_lookup_enum_by_nr(prim->mode),
+ prim->start, prim->count);
+
+ _mesa_printf("a: available %d\n", available);
+
+ if (prim->count < first)
+ continue;
+
+ count = prim->count - (prim->count - first) % incr;
+
+
+ if ((available < count && !split_inplace) ||
+ (available < first && split_inplace)) {
+ flush_vertex(split);
+ csr = 0;
+ available = align(split->limits->max_verts - csr - 1, 2);
+ }
+
+ _mesa_printf("b: available %d\n", available);
+
+ if (available >= count) {
+ struct _mesa_prim *outprim = next_outprim(split);
+ *outprim = *prim;
+ csr += prim->count;
+ available = align(split->limits->max_verts - csr - 1, 2);
+ }
+ else if (0 && 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;
+
+ if (nr == remaining) {
+ /* Finished.
+ */
+ j += nr;
+ csr += nr;
+ available = align(split->limits->max_verts - csr - 1, 2);
+ }
+ else {
+ /* Wrapped the primitive:
+ */
+ _mesa_printf("wrap %d %d\n", nr, first-incr);
+
+ j += nr - (first - incr);
+ flush_vertex(split);
+ csr = 0;
+ available = align(split->limits->max_verts - csr - 1, 2);
+ }
+ }
+ }
+ 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->Array.NullBufferObj;
+ ib.ptr = elts;
+ ib.rebase = 0; /* ? */
+
+ 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( GLcontext *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;
+ split.min_index = min_index;
+ split.max_index = max_index;
+ split.draw = draw;
+ split.limits = limits;
+
+ split_prims( &split );
+}
+
+
More information about the mesa-commit
mailing list