vbo_split_inplace.c [plain text]
#include "mtypes.h"
#include "macros.h"
#include "enums.h"
#include "vbo_split.h"
#define MAX_PRIM 32
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;
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) {
assert(split->max_index - split->min_index < split->limits->max_verts);
min_index = split->min_index;
max_index = split->max_index;
}
else {
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);
}
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;
GLuint available = align(split->limits->max_verts - csr - 1, 2);
assert(split->limits->max_verts >= csr);
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);
}
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 (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) {
j += nr;
csr += nr;
available = align(split->limits->max_verts - csr - 1, 2);
}
else {
j += nr - (first - incr);
flush_vertex(split);
csr = 0;
available = align(split->limits->max_verts - csr - 1, 2);
}
}
}
else if (split->ib == NULL) {
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;
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 );
}