Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / tnl_dd / t_dd_dmatmp.h
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@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