/************************************************************************** * * 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; unsigned fetch_start; 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); debug_printf("\telt0 = %d, eltx = %d, draw0 = %d, drawx = %d\n", varray->fetch_elts[0], varray->fetch_elts[varray->fetch_count-1], varray->draw_elts[0], varray->draw_elts[varray->draw_count-1]); #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; } static void varray_flush_linear(struct varray_frontend *varray) { if (varray->draw_count) { #if 0 debug_printf("FLUSH LINEAR fc = %d, dc = %d\n", varray->fetch_count, varray->draw_count); debug_printf("\telt0 = %d, eltx = %d, draw0 = %d, drawx = %d\n", varray->fetch_elts[0], varray->fetch_elts[varray->fetch_count-1], varray->draw_elts[0], varray->draw_elts[varray->draw_count-1]); #endif assert(varray->middle->run_linear); varray->middle->run_linear(varray->middle, varray->fetch_start, varray->fetch_count, varray->draw_elts, varray->draw_count); } varray->fetch_count = 0; varray->draw_count = 0; } static INLINE void fetch_init(struct varray_frontend *varray, unsigned count) { unsigned idx; #if 0 debug_printf("FETCH INIT c = %d, fs = %d\n", count, varray->fetch_start); #endif for (idx = 0; idx < count; ++idx) { varray->fetch_elts[idx] = varray->fetch_start + idx; } varray->fetch_start += idx; varray->fetch_count = idx; } static boolean split_prim_inplace(unsigned prim, unsigned *first, unsigned *incr) { switch (prim) { case PIPE_PRIM_POINTS: *first = 1; *incr = 1; return TRUE; case PIPE_PRIM_LINES: *first = 2; *incr = 2; return TRUE; case PIPE_PRIM_LINE_STRIP: *first = 2; *incr = 1; return TRUE; case PIPE_PRIM_TRIANGLES: *first = 3; *incr = 3; return TRUE; case PIPE_PRIM_TRIANGLE_STRIP: *first = 3; *incr = 1; return TRUE; case PIPE_PRIM_TRIANGLE_FAN: *first = 3; *incr = 1; return TRUE; case PIPE_PRIM_QUADS: *first = 4; *incr = 4; return TRUE; case PIPE_PRIM_QUAD_STRIP: *first = 4; *incr = 2; return TRUE; case PIPE_PRIM_POLYGON: *first = 3; *incr = 1; return TRUE; default: *first = 0; *incr = 1; /* set to one so that count % incr works */ return FALSE; } } 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; if (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; }