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 )	\
61do { 						\
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)
76static 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
97static __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
107static 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
136static 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
172static 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
204static 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
270static 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
301static 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
339static 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
379static 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
417static 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
543static 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
652static void TAG(render_noop)( struct gl_context *ctx,
653			      GLuint start,
654			      GLuint count,
655			      GLuint flags )
656{
657}
658
659
660
661
662static 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)
683static 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
715static 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
752static 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
786static 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 */
858static 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
892static 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
930static 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
968static 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
1006static 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
1074static 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
1152static 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 */
1176static 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