diff options
-rw-r--r-- | src/gallium/auxiliary/draw/Makefile | 1 | ||||
-rw-r--r-- | src/gallium/auxiliary/draw/draw_private.h | 1 | ||||
-rw-r--r-- | src/gallium/auxiliary/draw/draw_pt.c | 30 | ||||
-rw-r--r-- | src/gallium/auxiliary/draw/draw_pt.h | 1 | ||||
-rw-r--r-- | src/gallium/auxiliary/draw/draw_pt_varray.c | 251 | ||||
-rw-r--r-- | src/gallium/auxiliary/draw/draw_pt_varray_tmp.h | 144 |
6 files changed, 421 insertions, 7 deletions
diff --git a/src/gallium/auxiliary/draw/Makefile b/src/gallium/auxiliary/draw/Makefile index bc6acfe4589..da7eded21f6 100644 --- a/src/gallium/auxiliary/draw/Makefile +++ b/src/gallium/auxiliary/draw/Makefile @@ -28,6 +28,7 @@ C_SOURCES = \ draw_pt_fetch_emit.c \ draw_pt_fetch_shade_pipeline.c \ draw_pt_post_vs.c \ + draw_pt_varray.c \ draw_pt_vcache.c \ draw_vertex.c \ draw_vs.c \ diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h index 49593c8fada..cee58bbf73e 100644 --- a/src/gallium/auxiliary/draw/draw_private.h +++ b/src/gallium/auxiliary/draw/draw_private.h @@ -129,6 +129,7 @@ struct draw_context struct { struct draw_pt_front_end *vcache; + struct draw_pt_front_end *varray; } front; struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS]; diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c index f5a3bf390e8..d6585bbfd0d 100644 --- a/src/gallium/auxiliary/draw/draw_pt.c +++ b/src/gallium/auxiliary/draw/draw_pt.c @@ -53,12 +53,14 @@ draw_pt_arrays(struct draw_context *draw, struct draw_pt_front_end *frontend = NULL; struct draw_pt_middle_end *middle = NULL; unsigned opt = 0; + pt_elt_func get_elt = 0; + void *elts = 0; if (!draw->render) { opt |= PT_PIPELINE; } - if (draw_need_pipeline(draw, + if (draw_need_pipeline(draw, draw->rasterizer, prim)) { opt |= PT_PIPELINE; @@ -78,16 +80,21 @@ draw_pt_arrays(struct draw_context *draw, middle = draw->pt.middle.fetch_emit; - /* May create a short-circuited version of this for small primitives: + /* Pick the right frontend */ - frontend = draw->pt.front.vcache; + if (draw->pt.user.elts || + count >= 256) { + frontend = draw->pt.front.vcache; + get_elt = draw_pt_elt_func(draw); + elts = draw_pt_elt_ptr(draw, start); + } else { + frontend = draw->pt.front.varray; + elts = start; + } frontend->prepare( frontend, prim, middle, opt ); - frontend->run( frontend, - draw_pt_elt_func( draw ), - draw_pt_elt_ptr( draw, start ), - count ); + frontend->run(frontend, get_elt, elts, count); frontend->finish( frontend ); @@ -101,6 +108,10 @@ boolean draw_pt_init( struct draw_context *draw ) if (!draw->pt.front.vcache) return FALSE; + draw->pt.front.varray = draw_pt_varray(draw); + if (!draw->pt.front.varray) + return FALSE; + draw->pt.middle.fetch_emit = draw_pt_fetch_emit( draw ); if (!draw->pt.middle.fetch_emit) return FALSE; @@ -129,6 +140,11 @@ void draw_pt_destroy( struct draw_context *draw ) draw->pt.front.vcache->destroy( draw->pt.front.vcache ); draw->pt.front.vcache = NULL; } + + if (draw->pt.front.varray) { + draw->pt.front.varray->destroy( draw->pt.front.varray ); + draw->pt.front.varray = NULL; + } } diff --git a/src/gallium/auxiliary/draw/draw_pt.h b/src/gallium/auxiliary/draw/draw_pt.h index df5c29fc364..2dec376ceee 100644 --- a/src/gallium/auxiliary/draw/draw_pt.h +++ b/src/gallium/auxiliary/draw/draw_pt.h @@ -115,6 +115,7 @@ const void *draw_pt_elt_ptr( struct draw_context *draw, * a special case for tiny vertex buffers. */ struct draw_pt_front_end *draw_pt_vcache( struct draw_context *draw ); +struct draw_pt_front_end *draw_pt_varray(struct draw_context *draw); /* Middle-ends: * diff --git a/src/gallium/auxiliary/draw/draw_pt_varray.c b/src/gallium/auxiliary/draw/draw_pt_varray.c new file mode 100644 index 00000000000..022098a314f --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_pt_varray.c @@ -0,0 +1,251 @@ +/************************************************************************** + * + * Copyright 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 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 "pipe/p_util.h" +#include "draw/draw_context.h" +#include "draw/draw_private.h" +#include "draw/draw_pt.h" + +#define FETCH_MAX 256 +#define DRAW_MAX (16*FETCH_MAX) + +struct varray_frontend { + struct draw_pt_front_end base; + struct draw_context *draw; + + ushort draw_elts[DRAW_MAX]; + unsigned fetch_elts[FETCH_MAX]; + + unsigned draw_count; + unsigned fetch_count; + + struct draw_pt_middle_end *middle; + + unsigned input_prim; + unsigned output_prim; +}; + +static void varray_flush(struct varray_frontend *varray) +{ + if (varray->draw_count) { +#if 0 + debug_printf("FLUSH fc = %d, dc = %d\n", + varray->fetch_count, + varray->draw_count); +#endif + varray->middle->run(varray->middle, + varray->fetch_elts, + varray->fetch_count, + varray->draw_elts, + varray->draw_count); + } + + varray->fetch_count = 0; + varray->draw_count = 0; +} + +#if 0 +static void varray_check_flush(struct varray_frontend *varray) +{ + if (varray->draw_count + 6 >= DRAW_MAX/* || + varray->fetch_count + 4 >= FETCH_MAX*/) { + varray_flush(varray); + } +} +#endif + +static INLINE void add_draw_el(struct varray_frontend *varray, + int idx, ushort flags) +{ + varray->draw_elts[varray->draw_count++] = idx | flags; +} + + +static INLINE void varray_triangle( struct varray_frontend *varray, + unsigned i0, + unsigned i1, + unsigned i2 ) +{ + add_draw_el(varray, i0, 0); + add_draw_el(varray, i1, 0); + add_draw_el(varray, i2, 0); +} + +static INLINE void varray_triangle_flags( struct varray_frontend *varray, + ushort flags, + unsigned i0, + unsigned i1, + unsigned i2 ) +{ + add_draw_el(varray, i0, flags); + add_draw_el(varray, i1, 0); + add_draw_el(varray, i2, 0); +} + +static INLINE void varray_line( struct varray_frontend *varray, + unsigned i0, + unsigned i1 ) +{ + add_draw_el(varray, i0, 0); + add_draw_el(varray, i1, 0); +} + + +static INLINE void varray_line_flags( struct varray_frontend *varray, + ushort flags, + unsigned i0, + unsigned i1 ) +{ + add_draw_el(varray, i0, flags); + add_draw_el(varray, i1, 0); +} + + +static INLINE void varray_point( struct varray_frontend *varray, + unsigned i0 ) +{ + add_draw_el(varray, i0, 0); +} + +static INLINE void varray_quad( struct varray_frontend *varray, + unsigned i0, + unsigned i1, + unsigned i2, + unsigned i3 ) +{ + varray_triangle( varray, i0, i1, i3 ); + varray_triangle( varray, i1, i2, i3 ); +} + +static INLINE void varray_ef_quad( struct varray_frontend *varray, + unsigned i0, + unsigned i1, + unsigned i2, + unsigned i3 ) +{ + const unsigned omitEdge1 = DRAW_PIPE_EDGE_FLAG_0 | DRAW_PIPE_EDGE_FLAG_2; + const unsigned omitEdge2 = DRAW_PIPE_EDGE_FLAG_0 | DRAW_PIPE_EDGE_FLAG_1; + + varray_triangle_flags( varray, + DRAW_PIPE_RESET_STIPPLE | omitEdge1, + i0, i1, i3 ); + + varray_triangle_flags( varray, + omitEdge2, + i1, i2, i3 ); +} + +/* At least for now, we're back to using a template include file for + * this. The two paths aren't too different though - it may be + * possible to reunify them. + */ +#define TRIANGLE(vc,flags,i0,i1,i2) varray_triangle_flags(vc,flags,i0,i1,i2) +#define QUAD(vc,i0,i1,i2,i3) varray_ef_quad(vc,i0,i1,i2,i3) +#define LINE(vc,flags,i0,i1) varray_line_flags(vc,flags,i0,i1) +#define POINT(vc,i0) varray_point(vc,i0) +#define FUNC varray_run_extras +#include "draw_pt_varray_tmp.h" + +#define TRIANGLE(vc,flags,i0,i1,i2) varray_triangle(vc,i0,i1,i2) +#define QUAD(vc,i0,i1,i2,i3) varray_quad(vc,i0,i1,i2,i3) +#define LINE(vc,flags,i0,i1) varray_line(vc,i0,i1) +#define POINT(vc,i0) varray_point(vc,i0) +#define FUNC varray_run +#include "draw_pt_varray_tmp.h" + + + +static unsigned reduced_prim[PIPE_PRIM_POLYGON + 1] = { + PIPE_PRIM_POINTS, + PIPE_PRIM_LINES, + PIPE_PRIM_LINES, + PIPE_PRIM_LINES, + PIPE_PRIM_TRIANGLES, + PIPE_PRIM_TRIANGLES, + PIPE_PRIM_TRIANGLES, + PIPE_PRIM_TRIANGLES, + PIPE_PRIM_TRIANGLES, + PIPE_PRIM_TRIANGLES +}; + + + +static void varray_prepare(struct draw_pt_front_end *frontend, + unsigned prim, + struct draw_pt_middle_end *middle, + unsigned opt) +{ + struct varray_frontend *varray = (struct varray_frontend *)frontend; + const struct pipe_rasterizer_state *rasterizer = varray->draw->rasterizer; + + if (rasterizer->fill_cw != PIPE_POLYGON_MODE_FILL || + rasterizer->fill_ccw != PIPE_POLYGON_MODE_FILL || + rasterizer->line_stipple_enable) + { + assert(opt & PT_PIPELINE); + varray->base.run = varray_run_extras; + } else { + varray->base.run = varray_run; + } + + varray->input_prim = prim; + varray->output_prim = reduced_prim[prim]; + + varray->middle = middle; + middle->prepare(middle, varray->output_prim, opt); +} + + + + +static void varray_finish(struct draw_pt_front_end *frontend) +{ + struct varray_frontend *varray = (struct varray_frontend *)frontend; + varray->middle->finish(varray->middle); + varray->middle = NULL; +} + +static void varray_destroy(struct draw_pt_front_end *frontend) +{ + FREE(frontend); +} + + +struct draw_pt_front_end *draw_pt_varray(struct draw_context *draw) +{ + struct varray_frontend *varray = CALLOC_STRUCT(varray_frontend); + if (varray == NULL) + return NULL; + + varray->base.prepare = varray_prepare; + varray->base.run = NULL; + varray->base.finish = varray_finish; + varray->base.destroy = varray_destroy; + varray->draw = draw; + + return &varray->base; +} diff --git a/src/gallium/auxiliary/draw/draw_pt_varray_tmp.h b/src/gallium/auxiliary/draw/draw_pt_varray_tmp.h new file mode 100644 index 00000000000..b9a319b2535 --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_pt_varray_tmp.h @@ -0,0 +1,144 @@ + +static void FUNC(struct draw_pt_front_end *frontend, + pt_elt_func get_elt, + const void *elts, + unsigned count) +{ + struct varray_frontend *varray = (struct varray_frontend *)frontend; + struct draw_context *draw = varray->draw; + unsigned start = (unsigned)elts; + + boolean flatfirst = (draw->rasterizer->flatshade && + draw->rasterizer->flatshade_first); + unsigned i, flags; + +#if 0 + debug_printf("%s (%d) %d/%d\n", __FUNCTION__, draw->prim, start, count); +#endif +#if 0 + debug_printf("INPUT PRIM = %d (start = %d, count = %d)\n", varray->input_prim, + start, count); +#endif + + for (i = 0; i < count; ++i) { + varray->fetch_elts[i] = start + i; + } + varray->fetch_count = count; + + switch (varray->input_prim) { + case PIPE_PRIM_POINTS: + for (i = 0; i < count; i ++) { + POINT(varray, i + 0); + } + break; + + case PIPE_PRIM_LINES: + for (i = 0; i+1 < count; i += 2) { + LINE(varray, DRAW_PIPE_RESET_STIPPLE, + i + 0, i + 1); + } + break; + + case PIPE_PRIM_LINE_LOOP: + if (count >= 2) { + flags = DRAW_PIPE_RESET_STIPPLE; + + for (i = 1; i < count; i++, flags = 0) { + LINE(varray, flags, i - 1, i); + } + LINE(varray, flags, i - 1, 0); + } + break; + + case PIPE_PRIM_LINE_STRIP: + flags = DRAW_PIPE_RESET_STIPPLE; + for (i = 1; i < count; i++, flags = 0) { + LINE(varray, flags, i - 1, i); + } + break; + + case PIPE_PRIM_TRIANGLES: + for (i = 0; i+2 < count; i += 3) { + TRIANGLE(varray, DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL, + i + 0, i + 1, i + 2); + } + break; + + case PIPE_PRIM_TRIANGLE_STRIP: + if (flatfirst) { + for (i = 0; i+2 < count; i++) { + TRIANGLE(varray, DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL, + i + 0, i + 1 + (i&1), i + 2 - (i&1)); + } + } + else { + for (i = 0; i+2 < count; i++) { + TRIANGLE(varray, DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL, + i + 0 + (i&1), i + 1 - (i&1), i + 2); + } + } + break; + + case PIPE_PRIM_TRIANGLE_FAN: + if (count >= 3) { + if (flatfirst) { + flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL; + for (i = 0; i+2 < count; i++) { + TRIANGLE(varray, flags, i + 1, i + 2, 0); + } + } + else { + flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL; + for (i = 0; i+2 < count; i++) { + TRIANGLE(varray, flags, 0, i + 1, i + 2); + } + } + } + break; + + case PIPE_PRIM_QUADS: + for (i = 0; i+3 < count; i += 4) { + QUAD(varray, i + 0, i + 1, i + 2, i + 3); + } + break; + + case PIPE_PRIM_QUAD_STRIP: + for (i = 0; i+3 < count; i += 2) { + QUAD(varray, i + 2, i + 0, i + 1, i + 3); + } + break; + + case PIPE_PRIM_POLYGON: + { + /* These bitflags look a little odd because we submit the + * vertices as (1,2,0) to satisfy flatshade requirements. + */ + const unsigned edge_first = DRAW_PIPE_EDGE_FLAG_2; + const unsigned edge_middle = DRAW_PIPE_EDGE_FLAG_0; + const unsigned edge_last = DRAW_PIPE_EDGE_FLAG_1; + + flags = DRAW_PIPE_RESET_STIPPLE | edge_first | edge_middle; + + for (i = 0; i+2 < count; i++, flags = edge_middle) { + + if (i + 3 == count) + flags |= edge_last; + + TRIANGLE(varray, flags, i + 1, i + 2, 0); + } + } + break; + + default: + assert(0); + break; + } + + varray_flush(varray); +} + +#undef TRIANGLE +#undef QUAD +#undef POINT +#undef LINE +#undef FUNC |