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