Home | History | Annotate | Download | only in tnl_dd
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  6.5.1
      4  *
      5  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Keith Whitwell <keith (at) tungstengraphics.com>
     26  */
     27 
     28 
     29 /**
     30  * \file t_dd_dmatmp.h
     31  * Template for render stages which build and emit vertices directly
     32  * to fixed-size dma buffers.  Useful for rendering strips and other
     33  * native primitives where clipping and per-vertex tweaks such as
     34  * those in t_dd_tritmp.h are not required.
     35  *
     36  * Produces code for both inline triangles and indexed triangles.
     37  * Where various primitive types are unaccelerated by hardware, the
     38  * code attempts to fallback to other primitive types (quadstrips to
     39  * tristrips, lineloops to linestrips), or to indexed vertices.
     40  */
     41 
     42 #if !defined(HAVE_TRIANGLES)
     43 #error "must have at least triangles to use render template"
     44 #endif
     45 
     46 #if !HAVE_ELTS
     47 #define ELTS_VARS(buf)
     48 #define ALLOC_ELTS(nr) 0
     49 #define EMIT_ELT( offset, elt )
     50 #define EMIT_TWO_ELTS( offset, elt0, elt1 )
     51 #define INCR_ELTS( nr )
     52 #define ELT_INIT(prim)
     53 #define GET_CURRENT_VB_MAX_ELTS() 0
     54 #define GET_SUBSEQUENT_VB_MAX_ELTS() 0
     55 #define RELEASE_ELT_VERTS()
     56 #define EMIT_INDEXED_VERTS( ctx, start, count )
     57 #endif
     58 
     59 #ifndef EMIT_TWO_ELTS
     60 #define EMIT_TWO_ELTS( offset, elt0, elt1 )	\
     61 do { 						\
     62    EMIT_ELT( offset, elt0 ); 			\
     63    EMIT_ELT( offset+1, elt1 ); 			\
     64 } while (0)
     65 #endif
     66 
     67 
     68 /**********************************************************************/
     69 /*                  Render whole begin/end objects                    */
     70 /**********************************************************************/
     71 
     72 
     73 
     74 
     75 #if (HAVE_ELTS)
     76 static void *TAG(emit_elts)( struct gl_context *ctx, GLuint *elts, GLuint nr,
     77 			     void *buf)
     78 {
     79    GLint i;
     80    LOCAL_VARS;
     81    ELTS_VARS(buf);
     82 
     83    for ( i = 0 ; i+1 < nr ; i+=2, elts += 2 ) {
     84       EMIT_TWO_ELTS( 0, elts[0], elts[1] );
     85       INCR_ELTS( 2 );
     86    }
     87 
     88    if (i < nr) {
     89       EMIT_ELT( 0, elts[0] );
     90       INCR_ELTS( 1 );
     91    }
     92 
     93    return (void *)ELTPTR;
     94 }
     95 #endif
     96 
     97 static __inline void *TAG(emit_verts)( struct gl_context *ctx, GLuint start,
     98 				     GLuint count, void *buf )
     99 {
    100    return EMIT_VERTS(ctx, start, count, buf);
    101 }
    102 
    103 /***********************************************************************
    104  *                    Render non-indexed primitives.
    105  ***********************************************************************/
    106 
    107 static void TAG(render_points_verts)( struct gl_context *ctx,
    108 				      GLuint start,
    109 				      GLuint count,
    110 				      GLuint flags )
    111 {
    112    if (HAVE_POINTS) {
    113       LOCAL_VARS;
    114       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    115       int currentsz;
    116       GLuint j, nr;
    117 
    118       INIT( GL_POINTS );
    119 
    120       currentsz = GET_CURRENT_VB_MAX_VERTS();
    121       if (currentsz < 8)
    122 	 currentsz = dmasz;
    123 
    124       for (j = start; j < count; j += nr ) {
    125 	 nr = MIN2( currentsz, count - j );
    126 	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
    127 	 currentsz = dmasz;
    128       }
    129 
    130    } else {
    131       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    132       return;
    133    }
    134 }
    135 
    136 static void TAG(render_lines_verts)( struct gl_context *ctx,
    137 				     GLuint start,
    138 				     GLuint count,
    139 				     GLuint flags )
    140 {
    141    if (HAVE_LINES) {
    142       LOCAL_VARS;
    143       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    144       int currentsz;
    145       GLuint j, nr;
    146 
    147       INIT( GL_LINES );
    148 
    149       /* Emit whole number of lines in total and in each buffer:
    150        */
    151       count -= (count-start) & 1;
    152       currentsz = GET_CURRENT_VB_MAX_VERTS();
    153       currentsz -= currentsz & 1;
    154       dmasz -= dmasz & 1;
    155 
    156       if (currentsz < 8)
    157 	 currentsz = dmasz;
    158 
    159       for (j = start; j < count; j += nr ) {
    160 	 nr = MIN2( currentsz, count - j );
    161 	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
    162 	 currentsz = dmasz;
    163       }
    164 
    165    } else {
    166       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    167       return;
    168    }
    169 }
    170 
    171 
    172 static void TAG(render_line_strip_verts)( struct gl_context *ctx,
    173 					  GLuint start,
    174 					  GLuint count,
    175 					  GLuint flags )
    176 {
    177    if (HAVE_LINE_STRIPS) {
    178       LOCAL_VARS;
    179       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    180       int currentsz;
    181       GLuint j, nr;
    182 
    183       INIT( GL_LINE_STRIP );
    184 
    185       currentsz = GET_CURRENT_VB_MAX_VERTS();
    186       if (currentsz < 8)
    187 	 currentsz = dmasz;
    188 
    189       for (j = start; j + 1 < count; j += nr - 1 ) {
    190 	 nr = MIN2( currentsz, count - j );
    191 	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
    192 	 currentsz = dmasz;
    193       }
    194 
    195       FLUSH();
    196 
    197    } else {
    198       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    199       return;
    200    }
    201 }
    202 
    203 
    204 static void TAG(render_line_loop_verts)( struct gl_context *ctx,
    205 					 GLuint start,
    206 					 GLuint count,
    207 					 GLuint flags )
    208 {
    209    if (HAVE_LINE_STRIPS) {
    210       LOCAL_VARS;
    211       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    212       int currentsz;
    213       GLuint j, nr;
    214 
    215       INIT( GL_LINE_STRIP );
    216 
    217       if (flags & PRIM_BEGIN)
    218 	 j = start;
    219       else
    220 	 j = start + 1;
    221 
    222       /* Ensure last vertex won't wrap buffers:
    223        */
    224       currentsz = GET_CURRENT_VB_MAX_VERTS();
    225       currentsz--;
    226       dmasz--;
    227 
    228       if (currentsz < 8) {
    229 	 currentsz = dmasz;
    230       }
    231 
    232       if (j + 1 < count) {
    233 	 for ( ; j + 1 < count; j += nr - 1 ) {
    234 	    nr = MIN2( currentsz, count - j );
    235 
    236 	    if (j + nr >= count &&
    237 		start < count - 1 &&
    238 		(flags & PRIM_END))
    239 	    {
    240 	       void *tmp;
    241 	       tmp = ALLOC_VERTS(nr+1);
    242 	       tmp = TAG(emit_verts)( ctx, j, nr, tmp );
    243 	       tmp = TAG(emit_verts)( ctx, start, 1, tmp );
    244 	       (void) tmp;
    245 	    }
    246 	    else {
    247 	       TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
    248 	       currentsz = dmasz;
    249 	    }
    250 	 }
    251 
    252       }
    253       else if (start + 1 < count && (flags & PRIM_END)) {
    254 	 void *tmp;
    255 	 tmp = ALLOC_VERTS(2);
    256 	 tmp = TAG(emit_verts)( ctx, start+1, 1, tmp );
    257 	 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
    258 	 (void) tmp;
    259       }
    260 
    261       FLUSH();
    262 
    263    } else {
    264       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    265       return;
    266    }
    267 }
    268 
    269 
    270 static void TAG(render_triangles_verts)( struct gl_context *ctx,
    271 					 GLuint start,
    272 					 GLuint count,
    273 					 GLuint flags )
    274 {
    275    LOCAL_VARS;
    276    int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/3) * 3;
    277    int currentsz;
    278    GLuint j, nr;
    279 
    280    INIT(GL_TRIANGLES);
    281 
    282    currentsz = (GET_CURRENT_VB_MAX_VERTS()/3) * 3;
    283 
    284    /* Emit whole number of tris in total.  dmasz is already a multiple
    285     * of 3.
    286     */
    287    count -= (count-start)%3;
    288 
    289    if (currentsz < 8)
    290       currentsz = dmasz;
    291 
    292    for (j = start; j < count; j += nr) {
    293       nr = MIN2( currentsz, count - j );
    294       TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
    295       currentsz = dmasz;
    296    }
    297 }
    298 
    299 
    300 
    301 static void TAG(render_tri_strip_verts)( struct gl_context *ctx,
    302 					 GLuint start,
    303 					 GLuint count,
    304 					 GLuint flags )
    305 {
    306    if (HAVE_TRI_STRIPS) {
    307       LOCAL_VARS;
    308       GLuint j, nr;
    309       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    310       int currentsz;
    311 
    312       INIT(GL_TRIANGLE_STRIP);
    313 
    314       currentsz = GET_CURRENT_VB_MAX_VERTS();
    315 
    316       if (currentsz < 8) {
    317 	 currentsz = dmasz;
    318       }
    319 
    320       /* From here on emit even numbers of tris when wrapping over buffers:
    321        */
    322       dmasz -= (dmasz & 1);
    323       currentsz -= (currentsz & 1);
    324 
    325       for (j = start ; j + 2 < count; j += nr - 2 ) {
    326 	 nr = MIN2( currentsz, count - j );
    327 	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
    328 	 currentsz = dmasz;
    329       }
    330 
    331       FLUSH();
    332 
    333    } else {
    334       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    335       return;
    336    }
    337 }
    338 
    339 static void TAG(render_tri_fan_verts)( struct gl_context *ctx,
    340 				       GLuint start,
    341 				       GLuint count,
    342 				       GLuint flags )
    343 {
    344    if (HAVE_TRI_FANS) {
    345       LOCAL_VARS;
    346       GLuint j, nr;
    347       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    348       int currentsz;
    349 
    350       INIT(GL_TRIANGLE_FAN);
    351 
    352       currentsz = GET_CURRENT_VB_MAX_VERTS();
    353       if (currentsz < 8) {
    354 	 currentsz = dmasz;
    355       }
    356 
    357       for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
    358 	 void *tmp;
    359 	 nr = MIN2( currentsz, count - j + 1 );
    360 	 tmp = ALLOC_VERTS( nr );
    361 	 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
    362 	 tmp = TAG(emit_verts)( ctx, j, nr - 1, tmp );
    363 	 (void) tmp;
    364 	 currentsz = dmasz;
    365       }
    366 
    367       FLUSH();
    368    }
    369    else {
    370       /* Could write code to emit these as indexed vertices (for the
    371        * g400, for instance).
    372        */
    373       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    374       return;
    375    }
    376 }
    377 
    378 
    379 static void TAG(render_poly_verts)( struct gl_context *ctx,
    380 				    GLuint start,
    381 				    GLuint count,
    382 				    GLuint flags )
    383 {
    384    if (HAVE_POLYGONS) {
    385       LOCAL_VARS;
    386       GLuint j, nr;
    387       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    388       int currentsz;
    389 
    390       INIT(GL_POLYGON);
    391 
    392       currentsz = GET_CURRENT_VB_MAX_VERTS();
    393       if (currentsz < 8) {
    394 	 currentsz = dmasz;
    395       }
    396 
    397       for (j = start + 1 ; j + 1 < count ; j += nr - 2 ) {
    398 	 void *tmp;
    399 	 nr = MIN2( currentsz, count - j + 1 );
    400 	 tmp = ALLOC_VERTS( nr );
    401 	 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
    402 	 tmp = TAG(emit_verts)( ctx, j, nr - 1, tmp );
    403 	 (void) tmp;
    404 	 currentsz = dmasz;
    405       }
    406 
    407       FLUSH();
    408    }
    409    else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
    410       TAG(render_tri_fan_verts)( ctx, start, count, flags );
    411    } else {
    412       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    413       return;
    414    }
    415 }
    416 
    417 static void TAG(render_quad_strip_verts)( struct gl_context *ctx,
    418 					  GLuint start,
    419 					  GLuint count,
    420 					  GLuint flags )
    421 {
    422    GLuint j, nr;
    423 
    424    if (HAVE_QUAD_STRIPS) {
    425       LOCAL_VARS;
    426       GLuint j, nr;
    427       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    428       int currentsz;
    429 
    430       INIT(GL_QUAD_STRIP);
    431 
    432       currentsz = GET_CURRENT_VB_MAX_VERTS();
    433       if (currentsz < 8) {
    434 	 currentsz = dmasz;
    435       }
    436 
    437       dmasz -= (dmasz & 2);
    438       currentsz -= (currentsz & 2);
    439 
    440       for (j = start ; j + 3 < count; j += nr - 2 ) {
    441 	 nr = MIN2( currentsz, count - j );
    442 	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
    443 	 currentsz = dmasz;
    444       }
    445 
    446       FLUSH();
    447 
    448    } else if (HAVE_TRI_STRIPS &&
    449 	      ctx->Light.ShadeModel == GL_FLAT &&
    450 	      TNL_CONTEXT(ctx)->vb.AttribPtr[_TNL_ATTRIB_COLOR0]->stride) {
    451       if (HAVE_ELTS) {
    452 	 LOCAL_VARS;
    453 	 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
    454 	 int currentsz;
    455 	 GLuint j, nr;
    456 
    457          EMIT_INDEXED_VERTS( ctx, start, count );
    458 
    459 	 /* Simulate flat-shaded quadstrips using indexed vertices:
    460 	  */
    461 	 ELT_INIT( GL_TRIANGLES );
    462 
    463 	 currentsz = GET_CURRENT_VB_MAX_ELTS();
    464 
    465 	 /* Emit whole number of quads in total, and in each buffer.
    466 	  */
    467 	 dmasz -= dmasz & 1;
    468 	 count -= (count-start) & 1;
    469 	 currentsz -= currentsz & 1;
    470 
    471 	 if (currentsz < 12)
    472 	    currentsz = dmasz;
    473 
    474 	 currentsz = currentsz/6*2;
    475 	 dmasz = dmasz/6*2;
    476 
    477 	 for (j = start; j + 3 < count; j += nr - 2 ) {
    478 	    nr = MIN2( currentsz, count - j );
    479 	    if (nr >= 4) {
    480 	       GLint quads = (nr/2)-1;
    481 	       GLint i;
    482 	       ELTS_VARS( ALLOC_ELTS( quads*6 ) );
    483 
    484 	       for ( i = j-start ; i < j-start+quads*2 ; i+=2 ) {
    485 		  EMIT_TWO_ELTS( 0, (i+0), (i+1) );
    486 		  EMIT_TWO_ELTS( 2, (i+2), (i+1) );
    487 		  EMIT_TWO_ELTS( 4, (i+3), (i+2) );
    488 		  INCR_ELTS( 6 );
    489 	       }
    490 
    491 	       FLUSH();
    492 	    }
    493 	    currentsz = dmasz;
    494 	 }
    495 
    496 	 RELEASE_ELT_VERTS();
    497 	 FLUSH();
    498       }
    499       else {
    500 	 /* Vertices won't fit in a single buffer or elts not
    501 	  * available - should never happen.
    502 	  */
    503 	 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    504 	 return;
    505       }
    506    }
    507    else if (HAVE_TRI_STRIPS) {
    508       LOCAL_VARS;
    509       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
    510       int currentsz;
    511 
    512       /* Emit smooth-shaded quadstrips as tristrips:
    513        */
    514       FLUSH();
    515       INIT( GL_TRIANGLE_STRIP );
    516 
    517       /* Emit whole number of quads in total, and in each buffer.
    518        */
    519       dmasz -= dmasz & 1;
    520       currentsz = GET_CURRENT_VB_MAX_VERTS();
    521       currentsz -= currentsz & 1;
    522       count -= (count-start) & 1;
    523 
    524       if (currentsz < 8) {
    525 	 currentsz = dmasz;
    526       }
    527 
    528       for (j = start; j + 3 < count; j += nr - 2 ) {
    529 	 nr = MIN2( currentsz, count - j );
    530 	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
    531 	 currentsz = dmasz;
    532       }
    533 
    534       FLUSH();
    535 
    536    } else {
    537       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    538       return;
    539    }
    540 }
    541 
    542 
    543 static void TAG(render_quads_verts)( struct gl_context *ctx,
    544 				     GLuint start,
    545 				     GLuint count,
    546 				     GLuint flags )
    547 {
    548    if (HAVE_QUADS) {
    549       LOCAL_VARS;
    550       int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/4) * 4;
    551       int currentsz;
    552       GLuint j, nr;
    553 
    554       INIT(GL_QUADS);
    555 
    556       /* Emit whole number of quads in total.  dmasz is already a multiple
    557        * of 4.
    558        */
    559       count -= (count-start)%4;
    560 
    561       currentsz = (GET_CURRENT_VB_MAX_VERTS()/4) * 4;
    562       if (currentsz < 8)
    563          currentsz = dmasz;
    564 
    565       for (j = start; j < count; j += nr) {
    566          nr = MIN2( currentsz, count - j );
    567          TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
    568          currentsz = dmasz;
    569       }
    570    }
    571    else if (HAVE_ELTS) {
    572       /* Hardware doesn't have a quad primitive type -- try to
    573        * simulate it using indexed vertices and the triangle
    574        * primitive:
    575        */
    576       LOCAL_VARS;
    577       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
    578       int currentsz;
    579       GLuint j, nr;
    580 
    581       EMIT_INDEXED_VERTS( ctx, start, count );
    582 
    583       FLUSH();
    584       ELT_INIT( GL_TRIANGLES );
    585       currentsz = GET_CURRENT_VB_MAX_ELTS();
    586 
    587       /* Emit whole number of quads in total, and in each buffer.
    588        */
    589       dmasz -= dmasz & 3;
    590       count -= (count-start) & 3;
    591       currentsz -= currentsz & 3;
    592 
    593       /* Adjust for rendering as triangles:
    594        */
    595       currentsz = currentsz/6*4;
    596       dmasz = dmasz/6*4;
    597 
    598       if (currentsz < 8)
    599 	 currentsz = dmasz;
    600 
    601       for (j = start; j < count; j += nr ) {
    602 	 nr = MIN2( currentsz, count - j );
    603 	 if (nr >= 4) {
    604 	    GLint quads = nr/4;
    605 	    GLint i;
    606 	    ELTS_VARS( ALLOC_ELTS( quads*6 ) );
    607 
    608 	    for ( i = j-start ; i < j-start+quads*4 ; i+=4 ) {
    609 	       EMIT_TWO_ELTS( 0, (i+0), (i+1) );
    610 	       EMIT_TWO_ELTS( 2, (i+3), (i+1) );
    611 	       EMIT_TWO_ELTS( 4, (i+2), (i+3) );
    612 	       INCR_ELTS( 6 );
    613 	    }
    614 
    615 	    FLUSH();
    616 	 }
    617 	 currentsz = dmasz;
    618       }
    619 
    620       RELEASE_ELT_VERTS();
    621    }
    622    else if (HAVE_TRIANGLES) {
    623       /* Hardware doesn't have a quad primitive type -- try to
    624        * simulate it using triangle primitive.  This is a win for
    625        * gears, but is it useful in the broader world?
    626        */
    627       LOCAL_VARS;
    628       GLuint j;
    629 
    630       INIT(GL_TRIANGLES);
    631 
    632       for (j = start; j < count-3; j += 4) {
    633 	 void *tmp = ALLOC_VERTS( 6 );
    634 	 /* Send v0, v1, v3
    635 	  */
    636 	 tmp = EMIT_VERTS(ctx, j,     2, tmp);
    637 	 tmp = EMIT_VERTS(ctx, j + 3, 1, tmp);
    638 	 /* Send v1, v2, v3
    639 	  */
    640 	 tmp = EMIT_VERTS(ctx, j + 1, 3, tmp);
    641 	 (void) tmp;
    642       }
    643    }
    644    else {
    645       /* Vertices won't fit in a single buffer, should never happen.
    646        */
    647       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    648       return;
    649    }
    650 }
    651 
    652 static void TAG(render_noop)( struct gl_context *ctx,
    653 			      GLuint start,
    654 			      GLuint count,
    655 			      GLuint flags )
    656 {
    657 }
    658 
    659 
    660 
    661 
    662 static tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] =
    663 {
    664    TAG(render_points_verts),
    665    TAG(render_lines_verts),
    666    TAG(render_line_loop_verts),
    667    TAG(render_line_strip_verts),
    668    TAG(render_triangles_verts),
    669    TAG(render_tri_strip_verts),
    670    TAG(render_tri_fan_verts),
    671    TAG(render_quads_verts),
    672    TAG(render_quad_strip_verts),
    673    TAG(render_poly_verts),
    674    TAG(render_noop),
    675 };
    676 
    677 
    678 /****************************************************************************
    679  *                 Render elts using hardware indexed verts                 *
    680  ****************************************************************************/
    681 
    682 #if (HAVE_ELTS)
    683 static void TAG(render_points_elts)( struct gl_context *ctx,
    684 				     GLuint start,
    685 				     GLuint count,
    686 				     GLuint flags )
    687 {
    688    if (HAVE_POINTS) {
    689       LOCAL_VARS;
    690       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
    691       int currentsz;
    692       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
    693       GLuint j, nr;
    694 
    695       ELT_INIT( GL_POINTS );
    696 
    697       currentsz = GET_CURRENT_VB_MAX_ELTS();
    698       if (currentsz < 8)
    699 	 currentsz = dmasz;
    700 
    701       for (j = start; j < count; j += nr ) {
    702 	 nr = MIN2( currentsz, count - j );
    703 	 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
    704 	 FLUSH();
    705 	 currentsz = dmasz;
    706       }
    707    } else {
    708       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    709       return;
    710    }
    711 }
    712 
    713 
    714 
    715 static void TAG(render_lines_elts)( struct gl_context *ctx,
    716 				    GLuint start,
    717 				    GLuint count,
    718 				    GLuint flags )
    719 {
    720    if (HAVE_LINES) {
    721       LOCAL_VARS;
    722       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
    723       int currentsz;
    724       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
    725       GLuint j, nr;
    726 
    727       ELT_INIT( GL_LINES );
    728 
    729       /* Emit whole number of lines in total and in each buffer:
    730        */
    731       count -= (count-start) & 1;
    732       currentsz -= currentsz & 1;
    733       dmasz -= dmasz & 1;
    734 
    735       currentsz = GET_CURRENT_VB_MAX_ELTS();
    736       if (currentsz < 8)
    737 	 currentsz = dmasz;
    738 
    739       for (j = start; j < count; j += nr ) {
    740 	 nr = MIN2( currentsz, count - j );
    741 	 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
    742 	 FLUSH();
    743 	 currentsz = dmasz;
    744       }
    745    } else {
    746       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    747       return;
    748    }
    749 }
    750 
    751 
    752 static void TAG(render_line_strip_elts)( struct gl_context *ctx,
    753 					 GLuint start,
    754 					 GLuint count,
    755 					 GLuint flags )
    756 {
    757    if (HAVE_LINE_STRIPS) {
    758       LOCAL_VARS;
    759       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
    760       int currentsz;
    761       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
    762       GLuint j, nr;
    763 
    764       FLUSH(); /* always a new primitive */
    765       ELT_INIT( GL_LINE_STRIP );
    766 
    767       currentsz = GET_CURRENT_VB_MAX_ELTS();
    768       if (currentsz < 8)
    769 	 currentsz = dmasz;
    770 
    771       for (j = start; j + 1 < count; j += nr - 1 ) {
    772 	 nr = MIN2( currentsz, count - j );
    773 	 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
    774 	 FLUSH();
    775 	 currentsz = dmasz;
    776       }
    777    } else {
    778       /* TODO: Try to emit as indexed lines.
    779        */
    780       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    781       return;
    782    }
    783 }
    784 
    785 
    786 static void TAG(render_line_loop_elts)( struct gl_context *ctx,
    787 					GLuint start,
    788 					GLuint count,
    789 					GLuint flags )
    790 {
    791    if (HAVE_LINE_STRIPS) {
    792       LOCAL_VARS;
    793       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
    794       int currentsz;
    795       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
    796       GLuint j, nr;
    797 
    798       FLUSH();
    799       ELT_INIT( GL_LINE_STRIP );
    800 
    801       if (flags & PRIM_BEGIN)
    802 	 j = start;
    803       else
    804 	 j = start + 1;
    805 
    806       currentsz = GET_CURRENT_VB_MAX_ELTS();
    807       if (currentsz < 8) {
    808 	 currentsz = dmasz;
    809       }
    810 
    811       /* Ensure last vertex doesn't wrap:
    812        */
    813       currentsz--;
    814       dmasz--;
    815 
    816       if (j + 1 < count) {
    817 	 for ( ; j + 1 < count; j += nr - 1 ) {
    818 	    nr = MIN2( currentsz, count - j );
    819 
    820 	    if (j + nr >= count &&
    821 		start < count - 1 &&
    822 		(flags & PRIM_END))
    823 	    {
    824 	       void *tmp;
    825 	       tmp = ALLOC_ELTS(nr+1);
    826 	       tmp = TAG(emit_elts)( ctx, elts+j, nr, tmp );
    827 	       tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
    828 	       (void) tmp;
    829 	    }
    830 	    else {
    831 	       TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
    832 	       currentsz = dmasz;
    833 	    }
    834 	 }
    835 
    836       }
    837       else if (start + 1 < count && (flags & PRIM_END)) {
    838 	 void *tmp;
    839 	 tmp = ALLOC_ELTS(2);
    840 	 tmp = TAG(emit_elts)( ctx, elts+start+1, 1, tmp );
    841 	 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
    842 	 (void) tmp;
    843       }
    844 
    845       FLUSH();
    846    } else {
    847       /* TODO: Try to emit as indexed lines */
    848       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    849       return;
    850    }
    851 }
    852 
    853 
    854 /* For verts, we still eliminate the copy from main memory to dma
    855  * buffers.  For elts, this is probably no better (worse?) than the
    856  * standard path.
    857  */
    858 static void TAG(render_triangles_elts)( struct gl_context *ctx,
    859 					GLuint start,
    860 					GLuint count,
    861 					GLuint flags )
    862 {
    863    LOCAL_VARS;
    864    GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
    865    int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/3*3;
    866    int currentsz;
    867    GLuint j, nr;
    868 
    869    FLUSH();
    870    ELT_INIT( GL_TRIANGLES );
    871 
    872    currentsz = GET_CURRENT_VB_MAX_ELTS();
    873 
    874    /* Emit whole number of tris in total.  dmasz is already a multiple
    875     * of 3.
    876     */
    877    count -= (count-start)%3;
    878    currentsz -= currentsz%3;
    879    if (currentsz < 8)
    880       currentsz = dmasz;
    881 
    882    for (j = start; j < count; j += nr) {
    883       nr = MIN2( currentsz, count - j );
    884       TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
    885       FLUSH();
    886       currentsz = dmasz;
    887    }
    888 }
    889 
    890 
    891 
    892 static void TAG(render_tri_strip_elts)( struct gl_context *ctx,
    893 					GLuint start,
    894 					GLuint count,
    895 					GLuint flags )
    896 {
    897    if (HAVE_TRI_STRIPS) {
    898       LOCAL_VARS;
    899       GLuint j, nr;
    900       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
    901       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
    902       int currentsz;
    903 
    904       FLUSH();
    905       ELT_INIT( GL_TRIANGLE_STRIP );
    906 
    907       currentsz = GET_CURRENT_VB_MAX_ELTS();
    908       if (currentsz < 8) {
    909 	 currentsz = dmasz;
    910       }
    911 
    912       /* Keep the same winding over multiple buffers:
    913        */
    914       dmasz -= (dmasz & 1);
    915       currentsz -= (currentsz & 1);
    916 
    917       for (j = start ; j + 2 < count; j += nr - 2 ) {
    918 	 nr = MIN2( currentsz, count - j );
    919 	 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
    920 	 FLUSH();
    921 	 currentsz = dmasz;
    922       }
    923    } else {
    924       /* TODO: try to emit as indexed triangles */
    925       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    926       return;
    927    }
    928 }
    929 
    930 static void TAG(render_tri_fan_elts)( struct gl_context *ctx,
    931 				      GLuint start,
    932 				      GLuint count,
    933 				      GLuint flags )
    934 {
    935    if (HAVE_TRI_FANS) {
    936       LOCAL_VARS;
    937       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
    938       GLuint j, nr;
    939       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
    940       int currentsz;
    941 
    942       FLUSH();
    943       ELT_INIT( GL_TRIANGLE_FAN );
    944 
    945       currentsz = GET_CURRENT_VB_MAX_ELTS();
    946       if (currentsz < 8) {
    947 	 currentsz = dmasz;
    948       }
    949 
    950       for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
    951 	 void *tmp;
    952 	 nr = MIN2( currentsz, count - j + 1 );
    953 	 tmp = ALLOC_ELTS( nr );
    954 	 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
    955 	 tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp );
    956 	 (void) tmp;
    957 	 FLUSH();
    958 	 currentsz = dmasz;
    959       }
    960    } else {
    961       /* TODO: try to emit as indexed triangles */
    962       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
    963       return;
    964    }
    965 }
    966 
    967 
    968 static void TAG(render_poly_elts)( struct gl_context *ctx,
    969 				   GLuint start,
    970 				   GLuint count,
    971 				   GLuint flags )
    972 {
    973    if (HAVE_POLYGONS) {
    974       LOCAL_VARS;
    975       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
    976       GLuint j, nr;
    977       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
    978       int currentsz;
    979 
    980       FLUSH();
    981       ELT_INIT( GL_POLYGON );
    982 
    983       currentsz = GET_CURRENT_VB_MAX_ELTS();
    984       if (currentsz < 8) {
    985 	 currentsz = dmasz;
    986       }
    987 
    988       for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
    989 	 void *tmp;
    990 	 nr = MIN2( currentsz, count - j + 1 );
    991 	 tmp = ALLOC_ELTS( nr );
    992 	 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
    993 	 tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp );
    994 	 (void) tmp;
    995 	 FLUSH();
    996 	 currentsz = dmasz;
    997       }
    998    } else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
    999       TAG(render_tri_fan_verts)( ctx, start, count, flags );
   1000    } else {
   1001       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
   1002       return;
   1003    }
   1004 }
   1005 
   1006 static void TAG(render_quad_strip_elts)( struct gl_context *ctx,
   1007 					 GLuint start,
   1008 					 GLuint count,
   1009 					 GLuint flags )
   1010 {
   1011    if (HAVE_QUAD_STRIPS && 0) {
   1012    }
   1013    else if (HAVE_TRI_STRIPS) {
   1014       LOCAL_VARS;
   1015       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
   1016       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
   1017       int currentsz;
   1018       GLuint j, nr;
   1019 
   1020       FLUSH();
   1021       currentsz = GET_CURRENT_VB_MAX_ELTS();
   1022 
   1023       /* Emit whole number of quads in total, and in each buffer.
   1024        */
   1025       dmasz -= dmasz & 1;
   1026       count -= (count-start) & 1;
   1027       currentsz -= currentsz & 1;
   1028 
   1029       if (currentsz < 12)
   1030 	 currentsz = dmasz;
   1031 
   1032       if (ctx->Light.ShadeModel == GL_FLAT) {
   1033 	 ELT_INIT( GL_TRIANGLES );
   1034 
   1035 	 currentsz = currentsz/6*2;
   1036 	 dmasz = dmasz/6*2;
   1037 
   1038 	 for (j = start; j + 3 < count; j += nr - 2 ) {
   1039 	    nr = MIN2( currentsz, count - j );
   1040 
   1041 	    if (nr >= 4)
   1042 	    {
   1043 	       GLint i;
   1044 	       GLint quads = (nr/2)-1;
   1045 	       ELTS_VARS( ALLOC_ELTS( quads*6 ) );
   1046 
   1047 	       for ( i = j-start ; i < j-start+quads ; i++, elts += 2 ) {
   1048 		  EMIT_TWO_ELTS( 0, elts[0], elts[1] );
   1049 		  EMIT_TWO_ELTS( 2, elts[2], elts[1] );
   1050 		  EMIT_TWO_ELTS( 4, elts[3], elts[2] );
   1051 		  INCR_ELTS( 6 );
   1052 	       }
   1053 
   1054 	       FLUSH();
   1055 	    }
   1056 
   1057 	    currentsz = dmasz;
   1058 	 }
   1059       }
   1060       else {
   1061 	 ELT_INIT( GL_TRIANGLE_STRIP );
   1062 
   1063 	 for (j = start; j + 3 < count; j += nr - 2 ) {
   1064 	    nr = MIN2( currentsz, count - j );
   1065 	    TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
   1066 	    FLUSH();
   1067 	    currentsz = dmasz;
   1068 	 }
   1069       }
   1070    }
   1071 }
   1072 
   1073 
   1074 static void TAG(render_quads_elts)( struct gl_context *ctx,
   1075 				    GLuint start,
   1076 				    GLuint count,
   1077 				    GLuint flags )
   1078 {
   1079    if (HAVE_QUADS) {
   1080       LOCAL_VARS;
   1081       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
   1082       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/4*4;
   1083       int currentsz;
   1084       GLuint j, nr;
   1085 
   1086       FLUSH();
   1087       ELT_INIT( GL_TRIANGLES );
   1088 
   1089       currentsz = GET_CURRENT_VB_MAX_ELTS()/4*4;
   1090 
   1091       count -= (count-start)%4;
   1092 
   1093       if (currentsz < 8)
   1094 	 currentsz = dmasz;
   1095 
   1096       for (j = start; j < count; j += nr) {
   1097 	 nr = MIN2( currentsz, count - j );
   1098 	 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
   1099 	 FLUSH();
   1100 	 currentsz = dmasz;
   1101       }
   1102    } else {
   1103       LOCAL_VARS;
   1104       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
   1105       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
   1106       int currentsz;
   1107       GLuint j, nr;
   1108 
   1109       ELT_INIT( GL_TRIANGLES );
   1110       currentsz = GET_CURRENT_VB_MAX_ELTS();
   1111 
   1112       /* Emit whole number of quads in total, and in each buffer.
   1113        */
   1114       dmasz -= dmasz & 3;
   1115       count -= (count-start) & 3;
   1116       currentsz -= currentsz & 3;
   1117 
   1118       /* Adjust for rendering as triangles:
   1119        */
   1120       currentsz = currentsz/6*4;
   1121       dmasz = dmasz/6*4;
   1122 
   1123       if (currentsz < 8)
   1124 	 currentsz = dmasz;
   1125 
   1126       for (j = start; j + 3 < count; j += nr - 2 ) {
   1127 	 nr = MIN2( currentsz, count - j );
   1128 
   1129 	 if (nr >= 4)
   1130 	 {
   1131 	    GLint quads = nr/4;
   1132 	    GLint i;
   1133 	    ELTS_VARS( ALLOC_ELTS( quads * 6 ) );
   1134 
   1135 	    for ( i = j-start ; i < j-start+quads ; i++, elts += 4 ) {
   1136 	       EMIT_TWO_ELTS( 0, elts[0], elts[1] );
   1137 	       EMIT_TWO_ELTS( 2, elts[3], elts[1] );
   1138 	       EMIT_TWO_ELTS( 4, elts[2], elts[3] );
   1139 	       INCR_ELTS( 6 );
   1140 	    }
   1141 
   1142 	    FLUSH();
   1143 	 }
   1144 
   1145 	 currentsz = dmasz;
   1146       }
   1147    }
   1148 }
   1149 
   1150 
   1151 
   1152 static tnl_render_func TAG(render_tab_elts)[GL_POLYGON+2] =
   1153 {
   1154    TAG(render_points_elts),
   1155    TAG(render_lines_elts),
   1156    TAG(render_line_loop_elts),
   1157    TAG(render_line_strip_elts),
   1158    TAG(render_triangles_elts),
   1159    TAG(render_tri_strip_elts),
   1160    TAG(render_tri_fan_elts),
   1161    TAG(render_quads_elts),
   1162    TAG(render_quad_strip_elts),
   1163    TAG(render_poly_elts),
   1164    TAG(render_noop),
   1165 };
   1166 
   1167 
   1168 
   1169 #endif
   1170 
   1171 
   1172 
   1173 /* Pre-check the primitives in the VB to prevent the need for
   1174  * fallbacks later on.
   1175  */
   1176 static GLboolean TAG(validate_render)( struct gl_context *ctx,
   1177 				       struct vertex_buffer *VB )
   1178 {
   1179    GLint i;
   1180 
   1181    if (VB->ClipOrMask & ~CLIP_CULL_BIT)
   1182       return GL_FALSE;
   1183 
   1184    if (VB->Elts && !HAVE_ELTS)
   1185       return GL_FALSE;
   1186 
   1187    for (i = 0 ; i < VB->PrimitiveCount ; i++) {
   1188       GLuint prim = VB->Primitive[i].mode;
   1189       GLuint count = VB->Primitive[i].count;
   1190       GLboolean ok = GL_FALSE;
   1191 
   1192       if (!count)
   1193 	 continue;
   1194 
   1195       switch (prim & PRIM_MODE_MASK) {
   1196       case GL_POINTS:
   1197 	 ok = HAVE_POINTS;
   1198 	 break;
   1199       case GL_LINES:
   1200 	 ok = HAVE_LINES && !ctx->Line.StippleFlag;
   1201 	 break;
   1202       case GL_LINE_STRIP:
   1203 	 ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
   1204 	 break;
   1205       case GL_LINE_LOOP:
   1206 	 ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
   1207 	 break;
   1208       case GL_TRIANGLES:
   1209 	 ok = HAVE_TRIANGLES;
   1210 	 break;
   1211       case GL_TRIANGLE_STRIP:
   1212 	 ok = HAVE_TRI_STRIPS;
   1213 	 break;
   1214       case GL_TRIANGLE_FAN:
   1215 	 ok = HAVE_TRI_FANS;
   1216 	 break;
   1217       case GL_POLYGON:
   1218 	 if (HAVE_POLYGONS) {
   1219 	    ok = GL_TRUE;
   1220 	 }
   1221 	 else {
   1222 	    ok = (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH);
   1223          }
   1224 	 break;
   1225       case GL_QUAD_STRIP:
   1226 	 if (VB->Elts) {
   1227 	    ok = HAVE_TRI_STRIPS;
   1228 	 }
   1229 	 else if (HAVE_QUAD_STRIPS) {
   1230 	    ok = GL_TRUE;
   1231 	 } else if (HAVE_TRI_STRIPS &&
   1232 		    ctx->Light.ShadeModel == GL_FLAT &&
   1233 		    VB->AttribPtr[_TNL_ATTRIB_COLOR0]->stride != 0) {
   1234 	    if (HAVE_ELTS) {
   1235 	       ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
   1236 	    }
   1237 	    else {
   1238 	       ok = GL_FALSE;
   1239 	    }
   1240 	 }
   1241 	 else
   1242 	    ok = HAVE_TRI_STRIPS;
   1243 	 break;
   1244       case GL_QUADS:
   1245 	 if (HAVE_QUADS) {
   1246 	    ok = GL_TRUE;
   1247 	 } else if (HAVE_ELTS) {
   1248 	    ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
   1249 	 }
   1250 	 else {
   1251 	    ok = HAVE_TRIANGLES; /* flatshading is ok. */
   1252 	 }
   1253 	 break;
   1254       default:
   1255 	 break;
   1256       }
   1257 
   1258       if (!ok) {
   1259 /* 	 fprintf(stderr, "not ok %s\n", _mesa_lookup_enum_by_nr(prim & PRIM_MODE_MASK)); */
   1260 	 return GL_FALSE;
   1261       }
   1262    }
   1263 
   1264    return GL_TRUE;
   1265 }
   1266 
   1267