OSDN Git Service

t_dd_dmatmp: Allow flat shaded polygons with tri fans
[android-x86/external-mesa.git] / src / mesa / tnl_dd / t_dd_dmatmp.h
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Keith Whitwell <keithw@vmware.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).
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 &&
410             (ctx->Light.ShadeModel == GL_SMOOTH ||
411              ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION_EXT)) {
412       TAG(render_tri_fan_verts)( ctx, start, count, flags );
413    } else {
414       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
415       return;
416    }
417 }
418
419 static void TAG(render_quad_strip_verts)( struct gl_context *ctx,
420                                           GLuint start,
421                                           GLuint count,
422                                           GLuint flags )
423 {
424    GLuint j, nr;
425
426    if (HAVE_QUAD_STRIPS) {
427       LOCAL_VARS;
428       GLuint j, nr;
429       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
430       int currentsz;
431
432       INIT(GL_QUAD_STRIP);
433
434       currentsz = GET_CURRENT_VB_MAX_VERTS();
435       if (currentsz < 8) {
436          currentsz = dmasz;
437       }
438
439       dmasz -= (dmasz & 2);
440       currentsz -= (currentsz & 2);
441
442       for (j = start ; j + 3 < count; j += nr - 2 ) {
443          nr = MIN2( currentsz, count - j );
444          TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
445          currentsz = dmasz;
446       }
447
448       FLUSH();
449    }
450    else if (HAVE_TRI_STRIPS) {
451       LOCAL_VARS;
452       int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
453       int currentsz;
454
455       /* Emit smooth-shaded quadstrips as tristrips:
456        */
457       FLUSH();
458       INIT( GL_TRIANGLE_STRIP );
459
460       /* Emit whole number of quads in total, and in each buffer.
461        */
462       dmasz -= dmasz & 1;
463       currentsz = GET_CURRENT_VB_MAX_VERTS();
464       currentsz -= currentsz & 1;
465       count -= (count-start) & 1;
466
467       if (currentsz < 8) {
468          currentsz = dmasz;
469       }
470
471       for (j = start; j + 3 < count; j += nr - 2 ) {
472          nr = MIN2( currentsz, count - j );
473          TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
474          currentsz = dmasz;
475       }
476
477       FLUSH();
478
479    } else {
480       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
481       return;
482    }
483 }
484
485
486 static void TAG(render_quads_verts)( struct gl_context *ctx,
487                                      GLuint start,
488                                      GLuint count,
489                                      GLuint flags )
490 {
491    if (HAVE_QUADS) {
492       LOCAL_VARS;
493       int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/4) * 4;
494       int currentsz;
495       GLuint j, nr;
496
497       INIT(GL_QUADS);
498
499       /* Emit whole number of quads in total.  dmasz is already a multiple
500        * of 4.
501        */
502       count -= (count-start)%4;
503
504       currentsz = (GET_CURRENT_VB_MAX_VERTS()/4) * 4;
505       if (currentsz < 8)
506          currentsz = dmasz;
507
508       for (j = start; j < count; j += nr) {
509          nr = MIN2( currentsz, count - j );
510          TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
511          currentsz = dmasz;
512       }
513    }
514    else if (HAVE_TRIANGLES) {
515       /* Hardware doesn't have a quad primitive type -- try to
516        * simulate it using triangle primitive.  This is a win for
517        * gears, but is it useful in the broader world?
518        */
519       LOCAL_VARS;
520       GLuint j;
521
522       INIT(GL_TRIANGLES);
523
524       for (j = start; j < count-3; j += 4) {
525          void *tmp = ALLOC_VERTS( 6 );
526          /* Send v0, v1, v3
527           */
528          tmp = EMIT_VERTS(ctx, j,     2, tmp);
529          tmp = EMIT_VERTS(ctx, j + 3, 1, tmp);
530          /* Send v1, v2, v3
531           */
532          tmp = EMIT_VERTS(ctx, j + 1, 3, tmp);
533          (void) tmp;
534       }
535    }
536    else {
537       /* Vertices won't fit in a single buffer, should never happen.
538        */
539       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
540       return;
541    }
542 }
543
544 static void TAG(render_noop)( struct gl_context *ctx,
545                               GLuint start,
546                               GLuint count,
547                               GLuint flags )
548 {
549 }
550
551
552
553
554 static tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] =
555 {
556    TAG(render_points_verts),
557    TAG(render_lines_verts),
558    TAG(render_line_loop_verts),
559    TAG(render_line_strip_verts),
560    TAG(render_triangles_verts),
561    TAG(render_tri_strip_verts),
562    TAG(render_tri_fan_verts),
563    TAG(render_quads_verts),
564    TAG(render_quad_strip_verts),
565    TAG(render_poly_verts),
566    TAG(render_noop),
567 };
568
569
570 /****************************************************************************
571  *                 Render elts using hardware indexed verts                 *
572  ****************************************************************************/
573
574 #if (HAVE_ELTS)
575 static void TAG(render_points_elts)( struct gl_context *ctx,
576                                      GLuint start,
577                                      GLuint count,
578                                      GLuint flags )
579 {
580    if (HAVE_POINTS) {
581       LOCAL_VARS;
582       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
583       int currentsz;
584       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
585       GLuint j, nr;
586
587       ELT_INIT( GL_POINTS );
588
589       currentsz = GET_CURRENT_VB_MAX_ELTS();
590       if (currentsz < 8)
591          currentsz = dmasz;
592
593       for (j = start; j < count; j += nr ) {
594          nr = MIN2( currentsz, count - j );
595          TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
596          FLUSH();
597          currentsz = dmasz;
598       }
599    } else {
600       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
601       return;
602    }
603 }
604
605
606
607 static void TAG(render_lines_elts)( struct gl_context *ctx,
608                                     GLuint start,
609                                     GLuint count,
610                                     GLuint flags )
611 {
612    if (HAVE_LINES) {
613       LOCAL_VARS;
614       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
615       int currentsz;
616       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
617       GLuint j, nr;
618
619       ELT_INIT( GL_LINES );
620
621       /* Emit whole number of lines in total and in each buffer:
622        */
623       count -= (count-start) & 1;
624       currentsz -= currentsz & 1;
625       dmasz -= dmasz & 1;
626
627       currentsz = GET_CURRENT_VB_MAX_ELTS();
628       if (currentsz < 8)
629          currentsz = dmasz;
630
631       for (j = start; j < count; j += nr ) {
632          nr = MIN2( currentsz, count - j );
633          TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
634          FLUSH();
635          currentsz = dmasz;
636       }
637    } else {
638       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
639       return;
640    }
641 }
642
643
644 static void TAG(render_line_strip_elts)( struct gl_context *ctx,
645                                          GLuint start,
646                                          GLuint count,
647                                          GLuint flags )
648 {
649    if (HAVE_LINE_STRIPS) {
650       LOCAL_VARS;
651       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
652       int currentsz;
653       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
654       GLuint j, nr;
655
656       FLUSH(); /* always a new primitive */
657       ELT_INIT( GL_LINE_STRIP );
658
659       currentsz = GET_CURRENT_VB_MAX_ELTS();
660       if (currentsz < 8)
661          currentsz = dmasz;
662
663       for (j = start; j + 1 < count; j += nr - 1 ) {
664          nr = MIN2( currentsz, count - j );
665          TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
666          FLUSH();
667          currentsz = dmasz;
668       }
669    } else {
670       /* TODO: Try to emit as indexed lines.
671        */
672       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
673       return;
674    }
675 }
676
677
678 static void TAG(render_line_loop_elts)( struct gl_context *ctx,
679                                         GLuint start,
680                                         GLuint count,
681                                         GLuint flags )
682 {
683    if (HAVE_LINE_STRIPS) {
684       LOCAL_VARS;
685       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
686       int currentsz;
687       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
688       GLuint j, nr;
689
690       FLUSH();
691       ELT_INIT( GL_LINE_STRIP );
692
693       if (flags & PRIM_BEGIN)
694          j = start;
695       else
696          j = start + 1;
697
698       currentsz = GET_CURRENT_VB_MAX_ELTS();
699       if (currentsz < 8) {
700          currentsz = dmasz;
701       }
702
703       /* Ensure last vertex doesn't wrap:
704        */
705       currentsz--;
706       dmasz--;
707
708       if (j + 1 < count) {
709          for ( ; j + 1 < count; j += nr - 1 ) {
710             nr = MIN2( currentsz, count - j );
711
712             if (j + nr >= count &&
713                 start < count - 1 && 
714                 (flags & PRIM_END)) 
715             {
716                void *tmp;
717                tmp = ALLOC_ELTS(nr+1);
718                tmp = TAG(emit_elts)( ctx, elts+j, nr, tmp );
719                tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
720                (void) tmp;
721             }
722             else {
723                TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
724                currentsz = dmasz;
725             }
726          }
727
728       }
729       else if (start + 1 < count && (flags & PRIM_END)) {
730          void *tmp;
731          tmp = ALLOC_ELTS(2);
732          tmp = TAG(emit_elts)( ctx, elts+start+1, 1, tmp );
733          tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
734          (void) tmp;
735       }
736
737       FLUSH();
738    } else {
739       /* TODO: Try to emit as indexed lines */
740       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
741       return;
742    }
743 }
744
745
746 /* For verts, we still eliminate the copy from main memory to dma
747  * buffers.  For elts, this is probably no better (worse?) than the
748  * standard path.
749  */
750 static void TAG(render_triangles_elts)( struct gl_context *ctx,
751                                         GLuint start,
752                                         GLuint count,
753                                         GLuint flags )
754 {
755    LOCAL_VARS;
756    GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
757    int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/3*3;
758    int currentsz;
759    GLuint j, nr;
760
761    FLUSH();
762    ELT_INIT( GL_TRIANGLES );
763
764    currentsz = GET_CURRENT_VB_MAX_ELTS();
765
766    /* Emit whole number of tris in total.  dmasz is already a multiple
767     * of 3.
768     */
769    count -= (count-start)%3;
770    currentsz -= currentsz%3;
771    if (currentsz < 8)
772       currentsz = dmasz;
773
774    for (j = start; j < count; j += nr) {
775       nr = MIN2( currentsz, count - j );
776       TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
777       FLUSH();
778       currentsz = dmasz;
779    }
780 }
781
782
783
784 static void TAG(render_tri_strip_elts)( struct gl_context *ctx,
785                                         GLuint start,
786                                         GLuint count,
787                                         GLuint flags )
788 {
789    if (HAVE_TRI_STRIPS) {
790       LOCAL_VARS;
791       GLuint j, nr;
792       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
793       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
794       int currentsz;
795
796       FLUSH();
797       ELT_INIT( GL_TRIANGLE_STRIP );
798
799       currentsz = GET_CURRENT_VB_MAX_ELTS();
800       if (currentsz < 8) {
801          currentsz = dmasz;
802       }
803
804       /* Keep the same winding over multiple buffers:
805        */
806       dmasz -= (dmasz & 1);
807       currentsz -= (currentsz & 1);
808
809       for (j = start ; j + 2 < count; j += nr - 2 ) {
810          nr = MIN2( currentsz, count - j );
811          TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
812          FLUSH();
813          currentsz = dmasz;
814       }
815    } else {
816       /* TODO: try to emit as indexed triangles */
817       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
818       return;
819    }
820 }
821
822 static void TAG(render_tri_fan_elts)( struct gl_context *ctx,
823                                       GLuint start,
824                                       GLuint count,
825                                       GLuint flags )
826 {
827    if (HAVE_TRI_FANS) {
828       LOCAL_VARS;
829       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
830       GLuint j, nr;
831       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
832       int currentsz;
833
834       FLUSH();
835       ELT_INIT( GL_TRIANGLE_FAN );
836
837       currentsz = GET_CURRENT_VB_MAX_ELTS();
838       if (currentsz < 8) {
839          currentsz = dmasz;
840       }
841
842       for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
843          void *tmp;
844          nr = MIN2( currentsz, count - j + 1 );
845          tmp = ALLOC_ELTS( nr );
846          tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
847          tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp );
848          (void) tmp;
849          FLUSH();
850          currentsz = dmasz;
851       }
852    } else {
853       /* TODO: try to emit as indexed triangles */
854       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
855       return;
856    }
857 }
858
859
860 static void TAG(render_poly_elts)( struct gl_context *ctx,
861                                    GLuint start,
862                                    GLuint count,
863                                    GLuint flags )
864 {
865    if (HAVE_POLYGONS) {
866       LOCAL_VARS;
867       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
868       GLuint j, nr;
869       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
870       int currentsz;
871
872       FLUSH();
873       ELT_INIT( GL_POLYGON );
874
875       currentsz = GET_CURRENT_VB_MAX_ELTS();
876       if (currentsz < 8) {
877          currentsz = dmasz;
878       }
879
880       for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
881          void *tmp;
882          nr = MIN2( currentsz, count - j + 1 );
883          tmp = ALLOC_ELTS( nr );
884          tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
885          tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp );
886          (void) tmp;
887          FLUSH();
888          currentsz = dmasz;
889       }
890    } else if (HAVE_TRI_FANS &&
891               (ctx->Light.ShadeModel == GL_SMOOTH ||
892                ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION_EXT)) {
893       TAG(render_tri_fan_verts)( ctx, start, count, flags );
894    } else {
895       fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
896       return;
897    }
898 }
899
900 static void TAG(render_quad_strip_elts)( struct gl_context *ctx,
901                                          GLuint start,
902                                          GLuint count,
903                                          GLuint flags )
904 {
905    if (HAVE_QUAD_STRIPS && 0) {
906    }
907    else if (HAVE_TRI_STRIPS) {
908       LOCAL_VARS;
909       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
910       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
911       int currentsz;
912       GLuint j, nr;
913
914       FLUSH();
915       currentsz = GET_CURRENT_VB_MAX_ELTS();
916
917       /* Emit whole number of quads in total, and in each buffer.
918        */
919       dmasz -= dmasz & 1;
920       count -= (count-start) & 1;
921       currentsz -= currentsz & 1;
922
923       if (currentsz < 12)
924          currentsz = dmasz;
925
926       if (ctx->Light.ShadeModel == GL_FLAT) {
927          ELT_INIT( GL_TRIANGLES );
928
929          currentsz = currentsz/6*2;
930          dmasz = dmasz/6*2;
931
932          for (j = start; j + 3 < count; j += nr - 2 ) {
933             nr = MIN2( currentsz, count - j );
934
935             if (nr >= 4)
936             {
937                GLint i;
938                GLint quads = (nr/2)-1;
939                ELTS_VARS( ALLOC_ELTS( quads*6 ) );
940
941                for ( i = j-start ; i < j-start+quads ; i++, elts += 2 ) {
942                   EMIT_TWO_ELTS( 0, elts[0], elts[1] );
943                   EMIT_TWO_ELTS( 2, elts[2], elts[1] );
944                   EMIT_TWO_ELTS( 4, elts[3], elts[2] );
945                   INCR_ELTS( 6 );
946                }
947
948                FLUSH();
949             }
950
951             currentsz = dmasz;
952          }
953       }
954       else {
955          ELT_INIT( GL_TRIANGLE_STRIP );
956
957          for (j = start; j + 3 < count; j += nr - 2 ) {
958             nr = MIN2( currentsz, count - j );
959             TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
960             FLUSH();
961             currentsz = dmasz;
962          }
963       }
964    }
965 }
966
967
968 static void TAG(render_quads_elts)( struct gl_context *ctx,
969                                     GLuint start,
970                                     GLuint count,
971                                     GLuint flags )
972 {
973    if (HAVE_QUADS) {
974       LOCAL_VARS;
975       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
976       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/4*4;
977       int currentsz;
978       GLuint j, nr;
979
980       FLUSH();
981       ELT_INIT( GL_TRIANGLES );
982
983       currentsz = GET_CURRENT_VB_MAX_ELTS()/4*4;
984
985       count -= (count-start)%4;
986
987       if (currentsz < 8)
988          currentsz = dmasz;
989
990       for (j = start; j < count; j += nr) {
991          nr = MIN2( currentsz, count - j );
992          TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
993          FLUSH();
994          currentsz = dmasz;
995       }
996    } else {
997       LOCAL_VARS;
998       GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
999       int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
1000       int currentsz;
1001       GLuint j, nr;
1002
1003       ELT_INIT( GL_TRIANGLES );
1004       currentsz = GET_CURRENT_VB_MAX_ELTS();
1005
1006       /* Emit whole number of quads in total, and in each buffer.
1007        */
1008       dmasz -= dmasz & 3;
1009       count -= (count-start) & 3;
1010       currentsz -= currentsz & 3;
1011
1012       /* Adjust for rendering as triangles:
1013        */
1014       currentsz = currentsz/6*4;
1015       dmasz = dmasz/6*4;
1016
1017       if (currentsz < 8)
1018          currentsz = dmasz;
1019
1020       for (j = start; j + 3 < count; j += nr - 2 ) {
1021          nr = MIN2( currentsz, count - j );
1022
1023          if (nr >= 4)
1024          {
1025             GLint quads = nr/4;
1026             GLint i;
1027             ELTS_VARS( ALLOC_ELTS( quads * 6 ) );
1028
1029             for ( i = j-start ; i < j-start+quads ; i++, elts += 4 ) {
1030                EMIT_TWO_ELTS( 0, elts[0], elts[1] );
1031                EMIT_TWO_ELTS( 2, elts[3], elts[1] );
1032                EMIT_TWO_ELTS( 4, elts[2], elts[3] );
1033                INCR_ELTS( 6 );
1034             }
1035
1036             FLUSH();
1037          }
1038
1039          currentsz = dmasz;
1040       }
1041    }
1042 }
1043
1044
1045
1046 static tnl_render_func TAG(render_tab_elts)[GL_POLYGON+2] =
1047 {
1048    TAG(render_points_elts),
1049    TAG(render_lines_elts),
1050    TAG(render_line_loop_elts),
1051    TAG(render_line_strip_elts),
1052    TAG(render_triangles_elts),
1053    TAG(render_tri_strip_elts),
1054    TAG(render_tri_fan_elts),
1055    TAG(render_quads_elts),
1056    TAG(render_quad_strip_elts),
1057    TAG(render_poly_elts),
1058    TAG(render_noop),
1059 };
1060
1061
1062
1063 #endif
1064
1065
1066
1067 /* Pre-check the primitives in the VB to prevent the need for
1068  * fallbacks later on.
1069  */
1070 static GLboolean TAG(validate_render)( struct gl_context *ctx,
1071                                        struct vertex_buffer *VB )
1072 {
1073    GLint i;
1074
1075    if (VB->ClipOrMask & ~CLIP_CULL_BIT)
1076       return GL_FALSE;
1077
1078    if (VB->Elts && !HAVE_ELTS)
1079       return GL_FALSE;
1080
1081    for (i = 0 ; i < VB->PrimitiveCount ; i++) {
1082       GLuint prim = VB->Primitive[i].mode;
1083       GLuint count = VB->Primitive[i].count;
1084       GLboolean ok = GL_FALSE;
1085
1086       if (!count)
1087          continue;
1088
1089       switch (prim & PRIM_MODE_MASK) {
1090       case GL_POINTS:
1091          ok = HAVE_POINTS;
1092          break;
1093       case GL_LINES:
1094          ok = HAVE_LINES && !ctx->Line.StippleFlag;
1095          break;
1096       case GL_LINE_STRIP:
1097          ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
1098          break;
1099       case GL_LINE_LOOP:
1100          ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
1101          break;
1102       case GL_TRIANGLES:
1103          ok = HAVE_TRIANGLES;
1104          break;
1105       case GL_TRIANGLE_STRIP:
1106          ok = HAVE_TRI_STRIPS;
1107          break;
1108       case GL_TRIANGLE_FAN:
1109          ok = HAVE_TRI_FANS;
1110          break;
1111       case GL_POLYGON:
1112          if (HAVE_POLYGONS) {
1113             ok = GL_TRUE;
1114          }
1115          else {
1116             ok = (HAVE_TRI_FANS &&
1117                   (ctx->Light.ShadeModel == GL_SMOOTH ||
1118                    ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION_EXT));
1119          }
1120          break;
1121       case GL_QUAD_STRIP:
1122          if (VB->Elts) {
1123             ok = HAVE_TRI_STRIPS;
1124          } else if (HAVE_QUAD_STRIPS) {
1125             ok = GL_TRUE;
1126          } else {
1127             ok = HAVE_TRI_STRIPS;
1128          }
1129          break;
1130       case GL_QUADS:
1131          if (HAVE_QUADS) {
1132             ok = GL_TRUE;
1133          } else {
1134             ok = HAVE_TRIANGLES; /* flatshading is ok. */
1135          }
1136          break;
1137       default:
1138          break;
1139       }
1140       
1141       if (!ok) {
1142 /*       fprintf(stderr, "not ok %s\n", _mesa_lookup_enum_by_nr(prim & PRIM_MODE_MASK)); */
1143          return GL_FALSE;
1144       }
1145    }
1146
1147    return GL_TRUE;
1148 }
1149