diff options
Diffstat (limited to 'src/mesa/pipe/draw/draw_vb.c')
-rw-r--r-- | src/mesa/pipe/draw/draw_vb.c | 621 |
1 files changed, 325 insertions, 296 deletions
diff --git a/src/mesa/pipe/draw/draw_vb.c b/src/mesa/pipe/draw/draw_vb.c index f9c10e5f970..ef32f02ec10 100644 --- a/src/mesa/pipe/draw/draw_vb.c +++ b/src/mesa/pipe/draw/draw_vb.c @@ -40,356 +40,377 @@ #include "draw_context.h" -/* This file is a temporary set of hooks to allow us to use the tnl/ - * and vf/ modules until we have replacements in pipe. - */ +#define RP_NONE 0 +#define RP_POINT 1 +#define RP_LINE 2 +#define RP_TRI 3 + +static unsigned reduced_prim[GL_POLYGON + 1] = { + RP_POINT, + RP_LINE, + RP_LINE, + RP_LINE, + RP_TRI, + RP_TRI, + RP_TRI, + RP_TRI, + RP_TRI, + RP_TRI +}; -static struct vertex_header *get_vertex( struct draw_context *pipe, - GLuint i ) -{ - return (struct vertex_header *)(pipe->verts + i * pipe->vertex_size); -} +/* This file is a temporary set of hooks to allow us to use the tnl/ + * and vf/ modules until we have replacements in pipe. + */ -static void draw_allocate_vertices( struct draw_context *draw, - GLuint nr_vertices ) +static void vs_flush( struct draw_context *draw ) { - draw->nr_vertices = nr_vertices; - draw->verts = (GLubyte *) malloc( nr_vertices * draw->vertex_size ); + unsigned i; - draw->pipeline.first->begin( draw->pipeline.first ); + /* We're not really running a vertex shader yet, so flushing the vs + * queue is just a matter of building the vertices and returning. + */ + /* Actually, I'm cheating even more and pre-building them still + * with the mesa/vf module. So it's very easy... + */ + for (i = 0; i < draw->vs.queue_nr; i++) { + /* Would do the following steps here: + * + * 1) Loop over vertex element descriptors, fetch data from each + * to build the pre-tnl vertex. This might require a new struct + * to represent the pre-tnl vertex. + * + * 2) Bundle groups of upto 4 pre-tnl vertices together and pass + * to vertex shader. + * + * 3) Do any necessary unswizzling, make sure vertex headers are + * correctly populated, store resulting post-transformed + * vertices in vcache. + * + * In this version, just do the last step: + */ + unsigned elt = draw->vs.queue[i].elt; + struct vertex_header *dest = draw->vs.queue[i].dest; + + /* Magic: + */ + memcpy(dest, + draw->verts + elt * draw->vertex_size, + draw->vertex_size); + + } + draw->vs.queue_nr = 0; } -static void draw_set_prim( struct draw_context *draw, - GLenum prim ) + +static void draw_flush( struct draw_context *draw ) { - draw->prim = prim; + struct draw_stage *first = draw->pipeline.first; + unsigned i; - /* Not done yet - need to force edgeflags to 1 in strip/fan - * primitives. + /* Make sure all vertices are available: */ -#if 0 - switch (prim) { - case GL_TRIANGLES: - case GL_POLYGON: - case GL_QUADS: - case GL_QUAD_STRIP: /* yes, we need this */ - respect_edgeflags( pipe, GL_TRUE ); + vs_flush( draw ); + + + switch (draw->reduced_prim) { + case RP_TRI: + for (i = 0; i < draw->pq.queue_nr; i++) { + if (draw->pq.queue[i].reset_line_stipple) + first->reset_stipple_counter( first ); + + first->tri( first, &draw->pq.queue[i] ); + } break; + case RP_LINE: + for (i = 0; i < draw->pq.queue_nr; i++) { + if (draw->pq.queue[i].reset_line_stipple) + first->reset_stipple_counter( first ); - default: - respect_edgeflags( pipe, GL_FALSE ); + first->line( first, &draw->pq.queue[i] ); + } + break; + case RP_POINT: + first->reset_stipple_counter( first ); + for (i = 0; i < draw->pq.queue_nr; i++) + first->point( first, &draw->pq.queue[i] ); break; } -#endif -} - + draw->pq.queue_nr = 0; + draw->vcache.referenced = 0; + draw->vcache.overflow = 0; +} -static void do_quad( struct draw_stage *first, - struct vertex_header *v0, - struct vertex_header *v1, - struct vertex_header *v2, - struct vertex_header *v3 ) +static void draw_invalidate_vcache( struct draw_context *draw ) { - struct prim_header prim; - - { - GLuint tmp = v1->edgeflag; - v1->edgeflag = 0; - - prim.v[0] = v0; - prim.v[1] = v1; - prim.v[2] = v3; - first->tri( first, &prim ); + unsigned i; + + assert(draw->pq.queue_nr == 0); + assert(draw->vs.queue_nr == 0); + assert(draw->vcache.referenced == 0); + + for (i = 0; i < Elements( draw->vcache.idx ); i++) + draw->vcache.idx[i] = ~0; +} - v1->edgeflag = tmp; - } - { - GLuint tmp = v3->edgeflag; - v3->edgeflag = 0; +/* Return a pointer to a freshly queued primitive header. Ensure that + * there is room in the vertex cache for a maximum of "nr_verts" new + * vertices. Flush primitive and/or vertex queues if necessary to + * make space. + */ +static struct prim_header *get_queued_prim( struct draw_context *draw, + GLuint nr_verts ) +{ + if (draw->pq.queue_nr + 1 >= PRIM_QUEUE_LENGTH || + draw->vcache.overflow + nr_verts >= VCACHE_OVERFLOW) + draw_flush( draw ); - prim.v[0] = v1; - prim.v[1] = v2; - prim.v[2] = v3; - first->tri( first, &prim ); + /* The vs queue is sized so that this can never happen: + */ + assert(draw->vs.queue_nr + nr_verts < VS_QUEUE_LENGTH); - v3->edgeflag = tmp; - } + return &draw->pq.queue[draw->pq.queue_nr++]; } - - -static void draw_indexed_prim( struct draw_context *draw, - const GLuint *elts, - GLuint count ) +/* Check if vertex is in cache, otherwise add it. It won't go through + * VS yet, not until there is a flush operation or the VS queue fills up. + */ +static struct vertex_header *get_vertex( struct draw_context *draw, + GLuint i ) { - struct draw_stage * const first = draw->pipeline.first; - struct prim_header prim; - GLuint i; + unsigned slot = (i + (i>>5)) & 31; + + /* Cache miss? + */ + if (draw->vcache.idx[slot] != i) { - prim.det = 0; /* valid from cull stage onwards */ - prim.v[0] = 0; - prim.v[1] = 0; - prim.v[2] = 0; + /* If slot is in use, use the overflow area: + */ + if (draw->vcache.referenced & (1<<slot)) + slot = draw->vcache.overflow++; - switch (draw->prim) { - case GL_POINTS: - for (i = 0; i < count; i ++) { - prim.v[0] = get_vertex( draw, elts[i] ); + draw->vcache.idx[slot] = i; - first->point( first, &prim ); - } - break; + /* Add to vertex shader queue: + */ + draw->vs.queue[draw->vs.queue_nr].dest = draw->vcache.vertex[slot]; + draw->vs.queue[draw->vs.queue_nr].elt = i; + draw->vs.queue_nr++; + } - case GL_LINES: - for (i = 0; i+1 < count; i += 2) { - prim.v[0] = get_vertex( draw, elts[i + 0] ); - prim.v[1] = get_vertex( draw, elts[i + 1] ); - - first->reset_stipple_counter( first ); - first->line( first, &prim ); - } - break; + /* Mark slot as in-use: + */ + draw->vcache.referenced |= (1<<slot); + return draw->vcache.vertex[slot]; +} - case GL_LINE_LOOP: - if (count >= 2) { - first->reset_stipple_counter( first ); - for (i = 1; i < count; i++) { - prim.v[0] = get_vertex( draw, elts[i-1] ); - prim.v[1] = get_vertex( draw, elts[i] ); - first->line( first, &prim ); - } - prim.v[0] = get_vertex( draw, elts[count-1] ); - prim.v[1] = get_vertex( draw, elts[0] ); - first->line( first, &prim ); - } - break; +static struct vertex_header *get_uint_elt_vertex( struct draw_context *draw, + GLuint i ) +{ + const GLuint *elts = (const GLuint *)draw->elts; + return get_vertex( draw, elts[i] ); +} - case GL_LINE_STRIP: - /* I'm guessing it will be necessary to have something like a - * render->reset_line_stipple() method to properly support - * splitting strips into primitives like this. Alternately we - * could just scan ahead to find individual clipped lines and - * otherwise leave the strip intact - that might be better, but - * require more complex code here. - */ - if (count >= 2) { - first->reset_stipple_counter( first ); - prim.v[0] = 0; - prim.v[1] = get_vertex( draw, elts[0] ); - - for (i = 1; i < count; i++) { - prim.v[0] = prim.v[1]; - prim.v[1] = get_vertex( draw, elts[i] ); - - first->line( first, &prim ); - } - } - break; +#if 0 +static struct vertex_header *get_ushort_elt_vertex( struct draw_context *draw, + const void *elts, + GLuint i ) +{ + const GLushort *elts = (const GLushort *)draw->elts; + return get_vertex( draw, elts[i] ); +} - case GL_TRIANGLES: - for (i = 0; i+2 < count; i += 3) { - prim.v[0] = get_vertex( draw, elts[i + 0] ); - prim.v[1] = get_vertex( draw, elts[i + 1] ); - prim.v[2] = get_vertex( draw, elts[i + 2] ); - - first->tri( first, &prim ); - } - break; +static struct vertex_header *get_ubyte_elt_vertex( struct draw_context *draw, + const void *elts, + GLuint i ) +{ + const GLubyte *elts = (const GLubyte *)draw->elts; + return get_vertex( draw, elts[i] ); +} +#endif - case GL_TRIANGLE_STRIP: - for (i = 0; i+2 < count; i++) { - if (i & 1) { - prim.v[0] = get_vertex( draw, elts[i + 1] ); - prim.v[1] = get_vertex( draw, elts[i + 0] ); - prim.v[2] = get_vertex( draw, elts[i + 2] ); - } - else { - prim.v[0] = get_vertex( draw, elts[i + 0] ); - prim.v[1] = get_vertex( draw, elts[i + 1] ); - prim.v[2] = get_vertex( draw, elts[i + 2] ); - } - - first->tri( first, &prim ); - } - break; - case GL_TRIANGLE_FAN: - if (count >= 3) { - prim.v[0] = get_vertex( draw, elts[0] ); - prim.v[1] = 0; - prim.v[2] = get_vertex( draw, elts[1] ); - - for (i = 0; i+2 < count; i++) { - prim.v[1] = prim.v[2]; - prim.v[2] = get_vertex( draw, elts[i+2] ); - - first->tri( first, &prim ); - } - } - break; +static void draw_set_prim( struct draw_context *draw, + GLenum prim ) +{ + if (reduced_prim[prim] != draw->reduced_prim) { + draw_flush( draw ); + draw->reduced_prim = reduced_prim[prim]; + } - case GL_QUADS: - for (i = 0; i+3 < count; i += 4) { - do_quad( first, - get_vertex( draw, elts[i + 0] ), - get_vertex( draw, elts[i + 1] ), - get_vertex( draw, elts[i + 2] ), - get_vertex( draw, elts[i + 3] )); - } - break; + draw->prim = prim; +} - case GL_QUAD_STRIP: - for (i = 0; i+3 < count; i += 2) { - do_quad( first, - get_vertex( draw, elts[i + 2] ), - get_vertex( draw, elts[i + 0] ), - get_vertex( draw, elts[i + 1] ), - get_vertex( draw, elts[i + 3] )); - } - break; +static void do_point( struct draw_context *draw, + GLuint i0 ) +{ + struct prim_header *prim = get_queued_prim( draw, 1 ); + + prim->reset_line_stipple = 0; + prim->edgeflags = 1; + prim->pad = 0; + prim->v[0] = draw->get_vertex( draw, i0 ); +} - case GL_POLYGON: - if (count >= 3) { - int e1save, e2save; - prim.v[0] = 0; - prim.v[1] = get_vertex( draw, elts[1] ); - prim.v[2] = get_vertex( draw, elts[0] ); - e2save = prim.v[2]->edgeflag; - - for (i = 0; i+2 < count; i++) { - prim.v[0] = prim.v[1]; - prim.v[1] = get_vertex( draw, elts[i+2] ); - - /* save v1 edge flag, and clear if not last triangle */ - e1save = prim.v[1]->edgeflag; - if (i + 3 < count) - prim.v[1]->edgeflag = 0; - /* draw */ - first->tri( first, &prim ); +static void do_line( struct draw_context *draw, + GLboolean reset_stipple, + GLuint i0, + GLuint i1 ) +{ + struct prim_header *prim = get_queued_prim( draw, 2 ); + + prim->reset_line_stipple = reset_stipple; + prim->edgeflags = 1; + prim->pad = 0; + prim->v[0] = draw->get_vertex( draw, i0 ); + prim->v[1] = draw->get_vertex( draw, i1 ); +} - prim.v[1]->edgeflag = e1save; /* restore */ - prim.v[2]->edgeflag = 0; /* disable edge after 1st tri */ - } - prim.v[2]->edgeflag = e2save; - } - break; +static void do_triangle( struct draw_context *draw, + GLuint i0, + GLuint i1, + GLuint i2 ) +{ + struct prim_header *prim = get_queued_prim( draw, 3 ); + + prim->reset_line_stipple = 1; + prim->edgeflags = ~0; + prim->pad = 0; + prim->v[0] = draw->get_vertex( draw, i0 ); + prim->v[1] = draw->get_vertex( draw, i1 ); + prim->v[2] = draw->get_vertex( draw, i2 ); +} + +static void do_ef_triangle( struct draw_context *draw, + GLboolean reset_stipple, + GLuint ef_mask, + GLuint i0, + GLuint i1, + GLuint i2 ) +{ + struct prim_header *prim = get_queued_prim( draw, 3 ); + struct vertex_header *v0 = draw->get_vertex( draw, i0 ); + struct vertex_header *v1 = draw->get_vertex( draw, i1 ); + struct vertex_header *v2 = draw->get_vertex( draw, i2 ); + + prim->reset_line_stipple = reset_stipple; + + prim->edgeflags = ef_mask & ((v0->edgeflag << 0) | + (v1->edgeflag << 1) | + (v2->edgeflag << 2)); + prim->pad = 0; + prim->v[0] = v0; + prim->v[1] = v1; + prim->v[2] = v2; +} - default: - assert(0); - break; - } + +static void do_quad( struct draw_context *draw, + unsigned v0, + unsigned v1, + unsigned v2, + unsigned v3 ) +{ + do_ef_triangle( draw, 1, ~(1<<0), v0, v1, v3 ); + do_ef_triangle( draw, 0, ~(1<<1), v1, v2, v3 ); } + static void draw_prim( struct draw_context *draw, GLuint start, GLuint count ) { - struct draw_stage * const first = draw->pipeline.first; - struct prim_header prim; GLuint i; // _mesa_printf("%s (%d) %d/%d\n", __FUNCTION__, draw->prim, start, count ); - prim.det = 0; /* valid from cull stage onwards */ - prim.v[0] = 0; - prim.v[1] = 0; - prim.v[2] = 0; - switch (draw->prim) { case GL_POINTS: for (i = 0; i < count; i ++) { - prim.v[0] = get_vertex( draw, start + i ); - first->point( first, &prim ); + do_point( draw, + start + i ); } break; case GL_LINES: for (i = 0; i+1 < count; i += 2) { - prim.v[0] = get_vertex( draw, start + i + 0 ); - prim.v[1] = get_vertex( draw, start + i + 1 ); - - first->reset_stipple_counter( first ); - first->line( first, &prim ); + do_line( draw, + TRUE, + start + i + 0, + start + i + 1); } break; case GL_LINE_LOOP: if (count >= 2) { - first->reset_stipple_counter( first ); for (i = 1; i < count; i++) { - prim.v[0] = get_vertex( draw, start + i - 1 ); - prim.v[1] = get_vertex( draw, start + i ); - first->line( first, &prim ); + do_line( draw, + i == 1, /* XXX: only if vb not split */ + start + i - 1, + start + i ); } - prim.v[0] = get_vertex( draw, start + count - 1 ); - prim.v[1] = get_vertex( draw, start + 0 ); - first->line( first, &prim ); + do_line( draw, + 0, + start + count - 1, + start + 0 ); } break; case GL_LINE_STRIP: if (count >= 2) { - first->reset_stipple_counter( first ); - prim.v[0] = 0; - prim.v[1] = get_vertex( draw, start + 0 ); - for (i = 1; i < count; i++) { - prim.v[0] = prim.v[1]; - prim.v[1] = get_vertex( draw, start + i ); - - first->line( first, &prim ); + do_line( draw, + i == 1, + start + i - 1, + start + i ); } } break; case GL_TRIANGLES: for (i = 0; i+2 < count; i += 3) { - prim.v[0] = get_vertex( draw, start + i + 0 ); - prim.v[1] = get_vertex( draw, start + i + 1 ); - prim.v[2] = get_vertex( draw, start + i + 2 ); - - first->tri( first, &prim ); + do_ef_triangle( draw, + 1, + ~0, + start + i + 0, + start + i + 1, + start + i + 2 ); } break; case GL_TRIANGLE_STRIP: for (i = 0; i+2 < count; i++) { if (i & 1) { - prim.v[0] = get_vertex( draw, start + i + 1 ); - prim.v[1] = get_vertex( draw, start + i + 0 ); - prim.v[2] = get_vertex( draw, start + i + 2 ); + do_triangle( draw, + start + i + 1, + start + i + 0, + start + i + 2 ); } else { - prim.v[0] = get_vertex( draw, start + i + 0 ); - prim.v[1] = get_vertex( draw, start + i + 1 ); - prim.v[2] = get_vertex( draw, start + i + 2 ); + do_triangle( draw, + start + i + 0, + start + i + 1, + start + i + 2 ); } - - first->tri( first, &prim ); } break; case GL_TRIANGLE_FAN: if (count >= 3) { - prim.v[0] = get_vertex( draw, start + 0 ); - prim.v[1] = 0; - prim.v[2] = get_vertex( draw, start + 1 ); - for (i = 0; i+2 < count; i++) { - prim.v[1] = prim.v[2]; - prim.v[2] = get_vertex( draw, start + i + 2 ); - - first->tri( first, &prim ); + do_triangle( draw, + start + 0, + start + i + 1, + start + i + 2 ); } } break; @@ -397,48 +418,42 @@ static void draw_prim( struct draw_context *draw, case GL_QUADS: for (i = 0; i+3 < count; i += 4) { - do_quad( first, - get_vertex( draw, start + i + 0 ), - get_vertex( draw, start + i + 1 ), - get_vertex( draw, start + i + 2 ), - get_vertex( draw, start + i + 3 )); + do_quad( draw, + start + i + 0, + start + i + 1, + start + i + 2, + start + i + 3); } break; case GL_QUAD_STRIP: for (i = 0; i+3 < count; i += 2) { - do_quad( first, - get_vertex( draw, start + i + 2 ), - get_vertex( draw, start + i + 0 ), - get_vertex( draw, start + i + 1 ), - get_vertex( draw, start + i + 3 )); + do_quad( draw, + start + i + 2, + start + i + 0, + start + i + 1, + start + i + 3); } break; case GL_POLYGON: if (count >= 3) { - int e1save, e2save; - prim.v[0] = 0; - prim.v[1] = get_vertex( draw, start + 1 ); - prim.v[2] = get_vertex( draw, start + 0 ); - e2save = prim.v[2]->edgeflag; + unsigned ef_mask = (1<<2) | (1<<0); for (i = 0; i+2 < count; i++) { - prim.v[0] = prim.v[1]; - prim.v[1] = get_vertex( draw, start + i + 2 ); - /* save v1 edge flag, and clear if not last triangle */ - e1save = prim.v[1]->edgeflag; - if (i + 3 < count) - prim.v[1]->edgeflag = 0; + if (i + 3 >= count) + ef_mask |= (1<<1); - /* draw */ - first->tri( first, &prim ); + do_ef_triangle( draw, + i == 0, + ef_mask, + start + i + 1, + start + i + 2, + start + i + 0); - prim.v[1]->edgeflag = e1save; /* restore */ - prim.v[2]->edgeflag = 0; /* disable edge after 1st tri */ + ef_mask &= ~(1<<2); } - prim.v[2]->edgeflag = e2save; } break; @@ -449,10 +464,18 @@ static void draw_prim( struct draw_context *draw, } -static void draw_release_vertices( struct draw_context *draw ) +static void draw_allocate_vertices( struct draw_context *draw, + GLuint nr_vertices ) { - draw->pipeline.first->end( draw->pipeline.first ); + draw->nr_vertices = nr_vertices; + draw->verts = (GLubyte *) malloc( nr_vertices * draw->vertex_size ); + draw_invalidate_vcache( draw ); +} + + +static void draw_release_vertices( struct draw_context *draw ) +{ free(draw->verts); draw->verts = NULL; } @@ -598,6 +621,8 @@ void draw_vb(struct draw_context *draw, draw->in_vb = 1; + draw->pipeline.first->begin( draw->pipeline.first ); + /* Allocate the vertices: */ draw_allocate_vertices( draw, VB->Count ); @@ -605,11 +630,14 @@ void draw_vb(struct draw_context *draw, /* Bind the vb outputs: */ vf_set_sources( draw->vf, VB->AttribPtr, 0 ); - - /* Build the hardware or prim-pipe vertices: - */ vf_emit_vertices( draw->vf, VB->Count, draw->verts ); + draw->elts = VB->Elts; + + if (VB->Elts) + draw->get_vertex = get_uint_elt_vertex; + else + draw->get_vertex = get_vertex; for (i = 0; i < VB->PrimitiveCount; i++) { @@ -628,21 +656,15 @@ void draw_vb(struct draw_context *draw, if (draw->prim != mode) draw_set_prim( draw, mode ); - if (VB->Elts) { - draw_indexed_prim( draw, - VB->Elts + start, - length ); - } - else { - draw_prim( draw, - start, - length ); - } + draw_prim( draw, start, length ); } + draw_flush(draw); + draw->pipeline.first->end( draw->pipeline.first ); draw_release_vertices( draw ); draw->verts = NULL; draw->in_vb = 0; + draw->elts = NULL; } @@ -661,11 +683,17 @@ draw_vertices(struct draw_context *draw, assert(mode <= GL_POLYGON); + draw->get_vertex = get_vertex; draw->vertex_size = sizeof(struct vertex_header) + numAttrs * 4 * sizeof(GLfloat); + + + /*draw_prim_info(mode, &first, &incr);*/ draw_allocate_vertices( draw, numVerts ); + draw->pipeline.first->begin( draw->pipeline.first ); + if (draw->prim != mode) draw_set_prim( draw, mode ); @@ -694,6 +722,9 @@ draw_vertices(struct draw_context *draw, /* draw */ draw_prim(draw, 0, numVerts); + draw_flush(draw); + draw->pipeline.first->end( draw->pipeline.first ); + /* clean up */ draw_release_vertices( draw ); @@ -759,8 +790,6 @@ void draw_set_vertex_attributes( struct draw_context *draw, } -#define MAX_VERTEX_SIZE ((2 + FRAG_ATTRIB_MAX) * 4 * sizeof(GLfloat)) - void draw_alloc_tmps( struct draw_stage *stage, GLuint nr ) { stage->nr_tmps = nr; |