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_dmatmp2.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 */
37
38#if !HAVE_TRIANGLES || !HAVE_POINTS || !HAVE_LINES
39#error "must have points, lines & triangles to use render template"
40#endif
41
42#if !HAVE_TRI_STRIPS || !HAVE_TRI_FANS
43#error "must have tri strip and fans to use render template"
44#endif
45
46#if !HAVE_LINE_STRIPS
47#error "must have line strips to use render template"
48#endif
49
50#if !HAVE_POLYGONS
51#error "must have polygons to use render template"
52#endif
53
54#if !HAVE_ELTS
55#error "must have elts to use render template"
56#endif
57
58
59#ifndef EMIT_TWO_ELTS
60#define EMIT_TWO_ELTS( dest, offset, elt0, elt1 )	\
61do { 						\
62   (dest)[offset] = (elt0); 			\
63   (dest)[offset+1] = (elt1); 			\
64} while (0)
65#endif
66
67
68/**********************************************************************/
69/*                  Render whole begin/end objects                    */
70/**********************************************************************/
71
72
73static ELT_TYPE *TAG(emit_elts)( struct gl_context *ctx,
74			    ELT_TYPE *dest,
75			    GLuint *elts, GLuint nr )
76{
77   GLint i;
78   LOCAL_VARS;
79
80   for ( i = 0 ; i+1 < nr ; i+=2, elts += 2 ) {
81      EMIT_TWO_ELTS( dest, 0, elts[0], elts[1] );
82      dest += 2;
83   }
84   if (i < nr) {
85      EMIT_ELT( dest, 0, elts[0] );
86      dest += 1;
87   }
88
89   return dest;
90}
91
92static ELT_TYPE *TAG(emit_consecutive_elts)( struct gl_context *ctx,
93					ELT_TYPE *dest,
94					GLuint start, GLuint nr )
95{
96   GLint i;
97   LOCAL_VARS;
98
99   for ( i = 0 ; i+1 < nr ; i+=2, start += 2 ) {
100      EMIT_TWO_ELTS( dest, 0, start, start+1 );
101      dest += 2;
102   }
103   if (i < nr) {
104      EMIT_ELT( dest, 0, start );
105      dest += 1;
106   }
107
108   return dest;
109}
110
111/***********************************************************************
112 *                    Render non-indexed primitives.
113 ***********************************************************************/
114
115
116
117static void TAG(render_points_verts)( struct gl_context *ctx,
118				      GLuint start,
119				      GLuint count,
120				      GLuint flags )
121{
122   if (start < count) {
123      LOCAL_VARS;
124      if (0) fprintf(stderr, "%s\n", __func__);
125      EMIT_PRIM( ctx, GL_POINTS, HW_POINTS, start, count );
126   }
127}
128
129static void TAG(render_lines_verts)( struct gl_context *ctx,
130				     GLuint start,
131				     GLuint count,
132				     GLuint flags )
133{
134   LOCAL_VARS;
135   if (0) fprintf(stderr, "%s\n", __func__);
136   count -= (count-start) & 1;
137
138   if (start+1 >= count)
139      return;
140
141   if ((flags & PRIM_BEGIN) && ctx->Line.StippleFlag) {
142      RESET_STIPPLE();
143      AUTO_STIPPLE( GL_TRUE );
144   }
145
146   EMIT_PRIM( ctx, GL_LINES, HW_LINES, start, count );
147
148   if ((flags & PRIM_END) && ctx->Line.StippleFlag)
149      AUTO_STIPPLE( GL_FALSE );
150}
151
152
153static void TAG(render_line_strip_verts)( struct gl_context *ctx,
154					  GLuint start,
155					  GLuint count,
156					  GLuint flags )
157{
158   LOCAL_VARS;
159   if (0) fprintf(stderr, "%s\n", __func__);
160
161   if (start+1 >= count)
162      return;
163
164   if ((flags & PRIM_BEGIN) && ctx->Line.StippleFlag)
165      RESET_STIPPLE();
166
167
168   if (PREFER_DISCRETE_ELT_PRIM( count-start, HW_LINES ))
169   {
170      int dmasz = GET_MAX_HW_ELTS();
171      GLuint j, nr;
172
173      ELT_INIT( GL_LINES, HW_LINES );
174
175      /* Emit whole number of lines in each full buffer.
176       */
177      dmasz = dmasz/2;
178
179
180      for (j = start; j + 1 < count; j += nr - 1 ) {
181	 ELT_TYPE *dest;
182	 GLint i;
183
184	 nr = MIN2( dmasz, count - j );
185	 dest = ALLOC_ELTS( (nr-1)*2 );
186
187	 for ( i = j ; i+1 < j+nr ; i+=1 ) {
188	    EMIT_TWO_ELTS( dest, 0, (i+0), (i+1) );
189	    dest += 2;
190	 }
191
192	 CLOSE_ELTS();
193      }
194   }
195   else
196      EMIT_PRIM( ctx, GL_LINE_STRIP, HW_LINE_STRIP, start, count );
197}
198
199
200static void TAG(render_line_loop_verts)( struct gl_context *ctx,
201					 GLuint start,
202					 GLuint count,
203					 GLuint flags )
204{
205   LOCAL_VARS;
206   GLuint j, nr;
207   if (0) fprintf(stderr, "%s\n", __func__);
208
209   if (flags & PRIM_BEGIN) {
210      j = start;
211      if (ctx->Line.StippleFlag)
212	 RESET_STIPPLE( );
213   }
214   else
215      j = start + 1;
216
217   if (flags & PRIM_END) {
218
219      if (start+1 >= count)
220	 return;
221
222      if (PREFER_DISCRETE_ELT_PRIM( count-start, HW_LINES )) {
223	 int dmasz = GET_MAX_HW_ELTS();
224
225	 ELT_INIT( GL_LINES, HW_LINES );
226
227	 /* Emit whole number of lines in each full buffer.
228	  */
229	 dmasz = dmasz/2;
230
231	 /* Ensure last vertex doesn't wrap:
232	  */
233	 dmasz--;
234
235	 for (; j + 1 < count;  ) {
236	    GLint i;
237	    ELT_TYPE *dest;
238
239	    nr = MIN2( dmasz, count - j );
240	    dest = ALLOC_ELTS( nr*2 );	/* allocs room for 1 more line */
241
242	    for ( i = 0 ; i < nr - 1 ; i+=1 ) {
243	       EMIT_TWO_ELTS( dest, 0, (j+i), (j+i+1) );
244	       dest += 2;
245	    }
246
247	    j += nr - 1;
248
249	    /* Emit 1 more line into space alloced above */
250	    if (j + 1 >= count) {
251 	       EMIT_TWO_ELTS( dest, 0, (j), (start) );
252 	       dest += 2;
253 	    }
254
255	    CLOSE_ELTS();
256	 }
257      }
258      else
259      {
260	 int dmasz = GET_MAX_HW_ELTS() - 1;
261
262	 ELT_INIT( GL_LINE_STRIP, HW_LINE_STRIP );
263
264	 for ( ; j + 1 < count;  ) {
265	    nr = MIN2( dmasz, count - j );
266	    if (j + nr < count) {
267	       ELT_TYPE *dest = ALLOC_ELTS( nr );
268	       dest = TAG(emit_consecutive_elts)( ctx, dest, j, nr );
269	       (void) dest;
270	       j += nr - 1;
271	       CLOSE_ELTS();
272	    }
273	    else if (nr) {
274	       ELT_TYPE *dest = ALLOC_ELTS( nr + 1 );
275	       dest = TAG(emit_consecutive_elts)( ctx, dest, j, nr );
276	       dest = TAG(emit_consecutive_elts)( ctx, dest, start, 1 );
277	       (void) dest;
278	       j += nr;
279	       CLOSE_ELTS();
280	    }
281	 }
282      }
283   } else {
284      TAG(render_line_strip_verts)( ctx, j, count, flags );
285   }
286}
287
288
289static void TAG(render_triangles_verts)( struct gl_context *ctx,
290					 GLuint start,
291					 GLuint count,
292					 GLuint flags )
293{
294   LOCAL_VARS;
295   if (0) fprintf(stderr, "%s\n", __func__);
296
297   count -= (count-start)%3;
298
299   if (start+2 >= count) {
300      return;
301   }
302
303   /* need a PREFER_DISCRETE_ELT_PRIM here too..
304    */
305   EMIT_PRIM( ctx, GL_TRIANGLES, HW_TRIANGLES, start, count );
306}
307
308
309
310static void TAG(render_tri_strip_verts)( struct gl_context *ctx,
311					 GLuint start,
312					 GLuint count,
313					 GLuint flags )
314{
315   LOCAL_VARS;
316   if (0) fprintf(stderr, "%s\n", __func__);
317
318   if (start + 2 >= count)
319      return;
320
321   if (PREFER_DISCRETE_ELT_PRIM( count-start, HW_TRIANGLES ))
322   {
323      int dmasz = GET_MAX_HW_ELTS();
324      int parity = 0;
325      GLuint j, nr;
326
327      ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
328
329      /* Emit even number of tris in each full buffer.
330       */
331      dmasz = dmasz/3;
332      dmasz -= dmasz & 1;
333
334      for (j = start; j + 2 < count; j += nr - 2 ) {
335	 ELT_TYPE *dest;
336	 GLint i;
337
338	 nr = MIN2( dmasz, count - j );
339	 dest = ALLOC_ELTS( (nr-2)*3 );
340
341	 for ( i = j ; i+2 < j+nr ; i++, parity^=1 ) {
342	    EMIT_ELT( dest, 0, (i+0+parity) );
343	    EMIT_ELT( dest, 1, (i+1-parity) );
344	    EMIT_ELT( dest, 2, (i+2) );
345	    dest += 3;
346	 }
347
348	 CLOSE_ELTS();
349      }
350   }
351   else
352      EMIT_PRIM( ctx, GL_TRIANGLE_STRIP, HW_TRIANGLE_STRIP_0, start, count );
353}
354
355static void TAG(render_tri_fan_verts)( struct gl_context *ctx,
356				       GLuint start,
357				       GLuint count,
358				       GLuint flags )
359{
360   LOCAL_VARS;
361   if (0) fprintf(stderr, "%s\n", __func__);
362
363   if (start+2 >= count)
364      return;
365
366   if (PREFER_DISCRETE_ELT_PRIM( count-start, HW_TRIANGLES ))
367   {
368      int dmasz = GET_MAX_HW_ELTS();
369      GLuint j, nr;
370
371      ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
372
373      dmasz = dmasz/3;
374
375      for (j = start + 1; j + 1 < count; j += nr - 1 ) {
376	 ELT_TYPE *dest;
377	 GLint i;
378
379	 nr = MIN2( dmasz, count - j );
380	 dest = ALLOC_ELTS( (nr-1)*3 );
381
382	 for ( i = j ; i+1 < j+nr ; i++ ) {
383	    EMIT_ELT( dest, 0, (start) );
384	    EMIT_ELT( dest, 1, (i) );
385	    EMIT_ELT( dest, 2, (i+1) );
386	    dest += 3;
387	 }
388
389	 CLOSE_ELTS();
390      }
391   }
392   else {
393      EMIT_PRIM( ctx, GL_TRIANGLE_FAN, HW_TRIANGLE_FAN, start, count );
394   }
395}
396
397
398static void TAG(render_poly_verts)( struct gl_context *ctx,
399				    GLuint start,
400				    GLuint count,
401				    GLuint flags )
402{
403   LOCAL_VARS;
404   if (0) fprintf(stderr, "%s\n", __func__);
405
406   if (start+2 >= count)
407      return;
408
409   EMIT_PRIM( ctx, GL_POLYGON, HW_POLYGON, start, count );
410}
411
412static void TAG(render_quad_strip_verts)( struct gl_context *ctx,
413					  GLuint start,
414					  GLuint count,
415					  GLuint flags )
416{
417   LOCAL_VARS;
418   if (0) fprintf(stderr, "%s\n", __func__);
419
420   count -= (count-start) & 1;
421
422   if (start+3 >= count)
423      return;
424
425   if (HAVE_QUAD_STRIPS) {
426      EMIT_PRIM( ctx, GL_QUAD_STRIP, HW_QUAD_STRIP, start, count );
427   }
428   else if (ctx->Light.ShadeModel == GL_FLAT) {
429      LOCAL_VARS;
430      int dmasz = GET_MAX_HW_ELTS();
431      GLuint j, nr;
432
433      ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
434
435      /* Emit whole number of quads in total, and in each buffer.
436       */
437      dmasz = (dmasz/6)*2;
438
439      for (j = start; j + 3 < count; j += nr - 2 ) {
440	 ELT_TYPE *dest;
441	 GLint quads, i;
442
443	 nr = MIN2( dmasz, count - j );
444	 quads = (nr/2)-1;
445	 dest = ALLOC_ELTS( quads*6 );
446
447	 for ( i = j ; i < j+quads*2 ; i+=2 ) {
448	    EMIT_TWO_ELTS( dest, 0, (i+0), (i+1) );
449	    EMIT_TWO_ELTS( dest, 2, (i+2), (i+1) );
450	    EMIT_TWO_ELTS( dest, 4, (i+3), (i+2) );
451	    dest += 6;
452	 }
453
454	 CLOSE_ELTS();
455      }
456   }
457   else {
458      EMIT_PRIM( ctx, GL_TRIANGLE_STRIP, HW_TRIANGLE_STRIP_0, start, count );
459   }
460}
461
462
463static void TAG(render_quads_verts)( struct gl_context *ctx,
464				     GLuint start,
465				     GLuint count,
466				     GLuint flags )
467{
468   LOCAL_VARS;
469   if (0) fprintf(stderr, "%s\n", __func__);
470   count -= (count-start)%4;
471
472   if (start+3 >= count)
473      return;
474
475   if (HAVE_QUADS) {
476      EMIT_PRIM( ctx, GL_QUADS, HW_QUADS, start, count );
477   }
478   else {
479      /* Hardware doesn't have a quad primitive type -- simulate it
480       * using indexed vertices and the triangle primitive:
481       */
482      LOCAL_VARS;
483      int dmasz = GET_MAX_HW_ELTS();
484      GLuint j, nr;
485
486      ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
487
488      /* Adjust for rendering as triangles:
489       */
490      dmasz = (dmasz/6)*4;
491
492      for (j = start; j < count; j += nr ) {
493	 ELT_TYPE *dest;
494	 GLint quads, i;
495
496	 nr = MIN2( dmasz, count - j );
497	 quads = nr/4;
498	 dest = ALLOC_ELTS( quads*6 );
499
500	 for ( i = j ; i < j+quads*4 ; i+=4 ) {
501	    EMIT_TWO_ELTS( dest, 0, (i+0), (i+1) );
502	    EMIT_TWO_ELTS( dest, 2, (i+3), (i+1) );
503	    EMIT_TWO_ELTS( dest, 4, (i+2), (i+3) );
504	    dest += 6;
505	 }
506
507	 CLOSE_ELTS();
508      }
509   }
510}
511
512static void TAG(render_noop)( struct gl_context *ctx,
513			      GLuint start,
514			      GLuint count,
515			      GLuint flags )
516{
517}
518
519
520
521
522static tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] =
523{
524   TAG(render_points_verts),
525   TAG(render_lines_verts),
526   TAG(render_line_loop_verts),
527   TAG(render_line_strip_verts),
528   TAG(render_triangles_verts),
529   TAG(render_tri_strip_verts),
530   TAG(render_tri_fan_verts),
531   TAG(render_quads_verts),
532   TAG(render_quad_strip_verts),
533   TAG(render_poly_verts),
534   TAG(render_noop),
535};
536
537
538/****************************************************************************
539 *                 Render elts using hardware indexed verts                 *
540 ****************************************************************************/
541
542static void TAG(render_points_elts)( struct gl_context *ctx,
543				     GLuint start,
544				     GLuint count,
545				     GLuint flags )
546{
547   LOCAL_VARS;
548   int dmasz = GET_MAX_HW_ELTS();
549   GLuint *elts = GET_MESA_ELTS();
550   GLuint j, nr;
551   ELT_TYPE *dest;
552
553   ELT_INIT( GL_POINTS, HW_POINTS );
554
555   for (j = start; j < count; j += nr ) {
556      nr = MIN2( dmasz, count - j );
557      dest = ALLOC_ELTS( nr );
558      dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
559      (void) dest;
560      CLOSE_ELTS();
561   }
562}
563
564
565
566static void TAG(render_lines_elts)( struct gl_context *ctx,
567				    GLuint start,
568				    GLuint count,
569				    GLuint flags )
570{
571   LOCAL_VARS;
572   int dmasz = GET_MAX_HW_ELTS();
573   GLuint *elts = GET_MESA_ELTS();
574   GLuint j, nr;
575   ELT_TYPE *dest;
576
577   if (start+1 >= count)
578      return;
579
580   if ((flags & PRIM_BEGIN) && ctx->Line.StippleFlag) {
581      RESET_STIPPLE();
582      AUTO_STIPPLE( GL_TRUE );
583   }
584
585   ELT_INIT( GL_LINES, HW_LINES );
586
587   /* Emit whole number of lines in total and in each buffer:
588    */
589   count -= (count-start) & 1;
590   dmasz -= dmasz & 1;
591
592   for (j = start; j < count; j += nr ) {
593      nr = MIN2( dmasz, count - j );
594      dest = ALLOC_ELTS( nr );
595      dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
596      (void) dest;
597      CLOSE_ELTS();
598   }
599
600   if ((flags & PRIM_END) && ctx->Line.StippleFlag)
601      AUTO_STIPPLE( GL_FALSE );
602}
603
604
605static void TAG(render_line_strip_elts)( struct gl_context *ctx,
606					 GLuint start,
607					 GLuint count,
608					 GLuint flags )
609{
610   LOCAL_VARS;
611   int dmasz = GET_MAX_HW_ELTS();
612   GLuint *elts = GET_MESA_ELTS();
613   GLuint j, nr;
614   ELT_TYPE *dest;
615
616   if (start+1 >= count)
617      return;
618
619   ELT_INIT( GL_LINE_STRIP, HW_LINE_STRIP );
620
621   if ((flags & PRIM_BEGIN) && ctx->Line.StippleFlag)
622      RESET_STIPPLE();
623
624   for (j = start; j + 1 < count; j += nr - 1 ) {
625      nr = MIN2( dmasz, count - j );
626      dest = ALLOC_ELTS( nr );
627      dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
628      (void) dest;
629      CLOSE_ELTS();
630   }
631}
632
633
634static void TAG(render_line_loop_elts)( struct gl_context *ctx,
635					GLuint start,
636					GLuint count,
637					GLuint flags )
638{
639   LOCAL_VARS;
640   int dmasz = GET_MAX_HW_ELTS();
641   GLuint *elts = GET_MESA_ELTS();
642   GLuint j, nr;
643   ELT_TYPE *dest;
644
645   if (0) fprintf(stderr, "%s\n", __func__);
646
647   if (flags & PRIM_BEGIN)
648      j = start;
649   else
650      j = start + 1;
651
652
653   if (flags & PRIM_END) {
654      if (start+1 >= count)
655	 return;
656   }
657   else {
658      if (j+1 >= count)
659	 return;
660   }
661
662   ELT_INIT( GL_LINE_STRIP, HW_LINE_STRIP );
663
664   if ((flags & PRIM_BEGIN) && ctx->Line.StippleFlag)
665      RESET_STIPPLE();
666
667
668   /* Ensure last vertex doesn't wrap:
669    */
670   dmasz--;
671
672   for ( ; j + 1 < count; ) {
673      nr = MIN2( dmasz, count - j );
674      dest = ALLOC_ELTS( nr+1 );	/* Reserve possible space for last elt */
675      dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
676      j += nr - 1;
677      if (j + 1 >= count && (flags & PRIM_END)) {
678	 dest = TAG(emit_elts)( ctx, dest, elts+start, 1 );
679	 (void) dest;
680      }
681      CLOSE_ELTS();
682   }
683}
684
685
686static void TAG(render_triangles_elts)( struct gl_context *ctx,
687					GLuint start,
688					GLuint count,
689					GLuint flags )
690{
691   LOCAL_VARS;
692   GLuint *elts = GET_MESA_ELTS();
693   int dmasz = GET_MAX_HW_ELTS()/3*3;
694   GLuint j, nr;
695   ELT_TYPE *dest;
696
697   if (start+2 >= count)
698      return;
699
700   ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
701
702
703   /* Emit whole number of tris in total.  dmasz is already a multiple
704    * of 3.
705    */
706   count -= (count-start)%3;
707
708   for (j = start; j < count; j += nr) {
709      nr = MIN2( dmasz, count - j );
710      dest = ALLOC_ELTS( nr );
711      dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
712      (void) dest;
713      CLOSE_ELTS();
714   }
715}
716
717
718
719static void TAG(render_tri_strip_elts)( struct gl_context *ctx,
720					GLuint start,
721					GLuint count,
722					GLuint flags )
723{
724   LOCAL_VARS;
725   GLuint j, nr;
726   GLuint *elts = GET_MESA_ELTS();
727   int dmasz = GET_MAX_HW_ELTS();
728   ELT_TYPE *dest;
729
730   if (start+2 >= count)
731      return;
732
733   ELT_INIT( GL_TRIANGLE_STRIP, HW_TRIANGLE_STRIP_0 );
734
735   /* Keep the same winding over multiple buffers:
736    */
737   dmasz -= (dmasz & 1);
738
739   for (j = start ; j + 2 < count; j += nr - 2 ) {
740      nr = MIN2( dmasz, count - j );
741
742      dest = ALLOC_ELTS( nr );
743      dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
744      (void) dest;
745      CLOSE_ELTS();
746   }
747}
748
749static void TAG(render_tri_fan_elts)( struct gl_context *ctx,
750				      GLuint start,
751				      GLuint count,
752				      GLuint flags )
753{
754   LOCAL_VARS;
755   GLuint *elts = GET_MESA_ELTS();
756   GLuint j, nr;
757   int dmasz = GET_MAX_HW_ELTS();
758   ELT_TYPE *dest;
759
760   if (start+2 >= count)
761      return;
762
763   ELT_INIT( GL_TRIANGLE_FAN, HW_TRIANGLE_FAN );
764
765   for (j = start + 1 ; j + 1 < count; j += nr - 1 ) {
766      nr = MIN2( dmasz, count - j + 1 );
767      dest = ALLOC_ELTS( nr );
768      dest = TAG(emit_elts)( ctx, dest, elts+start, 1 );
769      dest = TAG(emit_elts)( ctx, dest, elts+j, nr - 1 );
770      (void) dest;
771      CLOSE_ELTS();
772   }
773}
774
775
776static void TAG(render_poly_elts)( struct gl_context *ctx,
777				   GLuint start,
778				   GLuint count,
779				   GLuint flags )
780{
781   LOCAL_VARS;
782   GLuint *elts = GET_MESA_ELTS();
783   GLuint j, nr;
784   int dmasz = GET_MAX_HW_ELTS();
785   ELT_TYPE *dest;
786
787   if (start+2 >= count)
788      return;
789
790   ELT_INIT( GL_POLYGON, HW_POLYGON );
791
792   for (j = start + 1 ; j + 1 < count ; j += nr - 1 ) {
793      nr = MIN2( dmasz, count - j + 1 );
794      dest = ALLOC_ELTS( nr );
795      dest = TAG(emit_elts)( ctx, dest, elts+start, 1 );
796      dest = TAG(emit_elts)( ctx, dest, elts+j, nr - 1 );
797      (void) dest;
798      CLOSE_ELTS();
799   }
800}
801
802static void TAG(render_quad_strip_elts)( struct gl_context *ctx,
803					 GLuint start,
804					 GLuint count,
805					 GLuint flags )
806{
807   if (start+3 >= count)
808      return;
809
810   if (HAVE_QUAD_STRIPS && 0) {
811   }
812   else {
813      LOCAL_VARS;
814      GLuint *elts = GET_MESA_ELTS();
815      int dmasz = GET_MAX_HW_ELTS();
816      GLuint j, nr;
817      ELT_TYPE *dest;
818
819      /* Emit whole number of quads in total, and in each buffer.
820       */
821      dmasz -= dmasz & 1;
822      count -= (count-start) & 1;
823
824      if (ctx->Light.ShadeModel == GL_FLAT) {
825	 ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
826
827	 dmasz = dmasz/6*2;
828
829	 for (j = start; j + 3 < count; j += nr - 2 ) {
830	    nr = MIN2( dmasz, count - j );
831
832	    if (nr >= 4)
833	    {
834	       GLint quads = (nr/2)-1;
835	       ELT_TYPE *dest = ALLOC_ELTS( quads*6 );
836	       GLint i;
837
838	       for ( i = j-start ; i < j-start+quads ; i++, elts += 2 ) {
839		  EMIT_TWO_ELTS( dest, 0, elts[0], elts[1] );
840		  EMIT_TWO_ELTS( dest, 2, elts[2], elts[1] );
841		  EMIT_TWO_ELTS( dest, 4, elts[3], elts[2] );
842		  dest += 6;
843	       }
844
845	       CLOSE_ELTS();
846	    }
847	 }
848      }
849      else {
850	 ELT_INIT( GL_TRIANGLE_STRIP, HW_TRIANGLE_STRIP_0 );
851
852	 for (j = start; j + 3 < count; j += nr - 2 ) {
853	    nr = MIN2( dmasz, count - j );
854	    dest = ALLOC_ELTS( nr );
855	    dest = TAG(emit_elts)( ctx, dest, elts+j, nr );
856	    (void) dest;
857	    CLOSE_ELTS();
858	 }
859      }
860   }
861}
862
863
864static void TAG(render_quads_elts)( struct gl_context *ctx,
865				    GLuint start,
866				    GLuint count,
867				    GLuint flags )
868{
869   if (start+3 >= count)
870      return;
871
872   if (HAVE_QUADS && 0) {
873   } else {
874      LOCAL_VARS;
875      GLuint *elts = GET_MESA_ELTS();
876      int dmasz = GET_MAX_HW_ELTS();
877      GLuint j, nr;
878
879      ELT_INIT( GL_TRIANGLES, HW_TRIANGLES );
880
881      /* Emit whole number of quads in total, and in each buffer.
882       */
883      dmasz -= dmasz & 3;
884      count -= (count-start) & 3;
885
886      /* Adjust for rendering as triangles:
887       */
888      dmasz = dmasz/6*4;
889
890      for (j = start; j + 3 < count; j += nr ) {
891	 nr = MIN2( dmasz, count - j );
892
893	 {
894	    GLint quads = nr/4;
895	    ELT_TYPE *dest = ALLOC_ELTS( quads * 6 );
896	    GLint i;
897
898	    for ( i = j-start ; i < j-start+quads ; i++, elts += 4 ) {
899	       EMIT_TWO_ELTS( dest, 0, elts[0], elts[1] );
900	       EMIT_TWO_ELTS( dest, 2, elts[3], elts[1] );
901	       EMIT_TWO_ELTS( dest, 4, elts[2], elts[3] );
902	       dest += 6;
903	    }
904
905	    CLOSE_ELTS();
906	 }
907      }
908   }
909}
910
911
912
913static tnl_render_func TAG(render_tab_elts)[GL_POLYGON+2] =
914{
915   TAG(render_points_elts),
916   TAG(render_lines_elts),
917   TAG(render_line_loop_elts),
918   TAG(render_line_strip_elts),
919   TAG(render_triangles_elts),
920   TAG(render_tri_strip_elts),
921   TAG(render_tri_fan_elts),
922   TAG(render_quads_elts),
923   TAG(render_quad_strip_elts),
924   TAG(render_poly_elts),
925   TAG(render_noop),
926};
927