t_dd_dmatmp: Pull out common 'count -= count & 3' code
[mesa.git] / src / mesa / tnl_dd / t_dd_dmatmp.h
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Keith Whitwell <keithw@vmware.com>
26 */
27
28
29 /**
30 * \file t_dd_dmatmp.h
31 * Template for render stages which build and emit vertices directly
32 * to fixed-size dma buffers. Useful for rendering strips and other
33 * native primitives where clipping and per-vertex tweaks such as
34 * those in t_dd_tritmp.h are not required.
35 *
36 * Produces code for both inline triangles and indexed triangles.
37 * Where various primitive types are unaccelerated by hardware, the
38 * code attempts to fallback to other primitive types (quadstrips to
39 * tristrips, lineloops to linestrips), or to indexed vertices.
40 */
41
42 #if !defined(HAVE_TRIANGLES)
43 #error "must have at least triangles to use render template"
44 #endif
45
46 #if !HAVE_ELTS
47 #define ELTS_VARS(buf)
48 #define ALLOC_ELTS(nr) 0
49 #define EMIT_ELT( offset, elt )
50 #define EMIT_TWO_ELTS( offset, elt0, elt1 )
51 #define INCR_ELTS( nr )
52 #define ELT_INIT(prim)
53 #define GET_CURRENT_VB_MAX_ELTS() 0
54 #define GET_SUBSEQUENT_VB_MAX_ELTS() 0
55 #define RELEASE_ELT_VERTS()
56 #define EMIT_INDEXED_VERTS( ctx, start, count )
57 #endif
58
59 #ifndef EMIT_TWO_ELTS
60 #define EMIT_TWO_ELTS( offset, elt0, elt1 ) \
61 do { \
62 EMIT_ELT( offset, elt0 ); \
63 EMIT_ELT( offset+1, elt1 ); \
64 } while (0)
65 #endif
66
67
68 /**********************************************************************/
69 /* Render whole begin/end objects */
70 /**********************************************************************/
71
72
73
74
75 #if (HAVE_ELTS)
76 static void *TAG(emit_elts)( struct gl_context *ctx, GLuint *elts, GLuint nr,
77 void *buf)
78 {
79 GLint i;
80 LOCAL_VARS;
81 ELTS_VARS(buf);
82
83 for ( i = 0 ; i+1 < nr ; i+=2, elts += 2 ) {
84 EMIT_TWO_ELTS( 0, elts[0], elts[1] );
85 INCR_ELTS( 2 );
86 }
87
88 if (i < nr) {
89 EMIT_ELT( 0, elts[0] );
90 INCR_ELTS( 1 );
91 }
92
93 return (void *)ELTPTR;
94 }
95 #endif
96
97 static __inline void *TAG(emit_verts)( struct gl_context *ctx, GLuint start,
98 GLuint count, void *buf )
99 {
100 return EMIT_VERTS(ctx, start, count, buf);
101 }
102
103 /***********************************************************************
104 * Render non-indexed primitives.
105 ***********************************************************************/
106
107 static void TAG(render_points_verts)( struct gl_context *ctx,
108 GLuint start,
109 GLuint count,
110 GLuint flags )
111 {
112 if (HAVE_POINTS) {
113 LOCAL_VARS;
114 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
115 int currentsz;
116 GLuint j, nr;
117
118 INIT( GL_POINTS );
119
120 currentsz = GET_CURRENT_VB_MAX_VERTS();
121 if (currentsz < 8)
122 currentsz = dmasz;
123
124 for (j = 0; j < count; j += nr) {
125 nr = MIN2( currentsz, count - j );
126 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
127 currentsz = dmasz;
128 }
129
130 } else {
131 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
132 return;
133 }
134 }
135
136 static void TAG(render_lines_verts)( struct gl_context *ctx,
137 GLuint start,
138 GLuint count,
139 GLuint flags )
140 {
141 if (HAVE_LINES) {
142 LOCAL_VARS;
143 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
144 int currentsz;
145 GLuint j, nr;
146
147 INIT( GL_LINES );
148
149 /* Emit whole number of lines in total and in each buffer:
150 */
151 count -= count & 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 = 0; j < count; j += nr) {
160 nr = MIN2( currentsz, count - j );
161 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
162 currentsz = dmasz;
163 }
164
165 } else {
166 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
167 return;
168 }
169 }
170
171
172 static void TAG(render_line_strip_verts)( struct gl_context *ctx,
173 GLuint start,
174 GLuint count,
175 GLuint flags )
176 {
177 if (HAVE_LINE_STRIPS) {
178 LOCAL_VARS;
179 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
180 int currentsz;
181 GLuint j, nr;
182
183 INIT( GL_LINE_STRIP );
184
185 currentsz = GET_CURRENT_VB_MAX_VERTS();
186 if (currentsz < 8)
187 currentsz = dmasz;
188
189 for (j = 0; j + 1 < count; j += nr - 1 ) {
190 nr = MIN2( currentsz, count - j );
191 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
192 currentsz = dmasz;
193 }
194
195 FLUSH();
196
197 } else {
198 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
199 return;
200 }
201 }
202
203
204 static void TAG(render_line_loop_verts)( struct gl_context *ctx,
205 GLuint start,
206 GLuint count,
207 GLuint flags )
208 {
209 if (HAVE_LINE_STRIPS) {
210 LOCAL_VARS;
211 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
212 int currentsz;
213 GLuint j, nr;
214
215 INIT( GL_LINE_STRIP );
216
217 j = (flags & PRIM_BEGIN) ? 0 : 1;
218
219 /* Ensure last vertex won't wrap buffers:
220 */
221 currentsz = GET_CURRENT_VB_MAX_VERTS();
222 currentsz--;
223 dmasz--;
224
225 if (currentsz < 8) {
226 currentsz = dmasz;
227 }
228
229 if (j + 1 < count) {
230 for ( ; j + 1 < count; j += nr - 1 ) {
231 nr = MIN2( currentsz, count - j );
232
233 if (j + nr >= count &&
234 count > 1 &&
235 (flags & PRIM_END))
236 {
237 void *tmp;
238 tmp = ALLOC_VERTS(nr+1);
239 tmp = TAG(emit_verts)(ctx, start + j, nr, tmp);
240 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
241 (void) tmp;
242 }
243 else {
244 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
245 currentsz = dmasz;
246 }
247 }
248
249 }
250 else if (count > 1 && (flags & PRIM_END)) {
251 void *tmp;
252 tmp = ALLOC_VERTS(2);
253 tmp = TAG(emit_verts)( ctx, start+1, 1, tmp );
254 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
255 (void) tmp;
256 }
257
258 FLUSH();
259
260 } else {
261 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
262 return;
263 }
264 }
265
266
267 static void TAG(render_triangles_verts)( struct gl_context *ctx,
268 GLuint start,
269 GLuint count,
270 GLuint flags )
271 {
272 LOCAL_VARS;
273 int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/3) * 3;
274 int currentsz;
275 GLuint j, nr;
276
277 INIT(GL_TRIANGLES);
278
279 currentsz = (GET_CURRENT_VB_MAX_VERTS()/3) * 3;
280
281 /* Emit whole number of tris in total. dmasz is already a multiple
282 * of 3.
283 */
284 count -= count % 3;
285
286 if (currentsz < 8)
287 currentsz = dmasz;
288
289 for (j = 0; j < count; j += nr) {
290 nr = MIN2( currentsz, count - j );
291 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
292 currentsz = dmasz;
293 }
294 }
295
296
297
298 static void TAG(render_tri_strip_verts)( struct gl_context *ctx,
299 GLuint start,
300 GLuint count,
301 GLuint flags )
302 {
303 if (HAVE_TRI_STRIPS) {
304 LOCAL_VARS;
305 GLuint j, nr;
306 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
307 int currentsz;
308
309 INIT(GL_TRIANGLE_STRIP);
310
311 currentsz = GET_CURRENT_VB_MAX_VERTS();
312
313 if (currentsz < 8) {
314 currentsz = dmasz;
315 }
316
317 /* From here on emit even numbers of tris when wrapping over buffers:
318 */
319 dmasz -= (dmasz & 1);
320 currentsz -= (currentsz & 1);
321
322 for (j = 0; j + 2 < count; j += nr - 2) {
323 nr = MIN2( currentsz, count - j );
324 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
325 currentsz = dmasz;
326 }
327
328 FLUSH();
329
330 } else {
331 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
332 return;
333 }
334 }
335
336 static void TAG(render_tri_fan_verts)( struct gl_context *ctx,
337 GLuint start,
338 GLuint count,
339 GLuint flags )
340 {
341 if (HAVE_TRI_FANS) {
342 LOCAL_VARS;
343 GLuint j, nr;
344 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
345 int currentsz;
346
347 INIT(GL_TRIANGLE_FAN);
348
349 currentsz = GET_CURRENT_VB_MAX_VERTS();
350 if (currentsz < 8) {
351 currentsz = dmasz;
352 }
353
354 for (j = 1; j + 1 < count; j += nr - 2) {
355 void *tmp;
356 nr = MIN2( currentsz, count - j + 1 );
357 tmp = ALLOC_VERTS( nr );
358 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
359 tmp = TAG(emit_verts)( ctx, start + j, nr - 1, tmp );
360 (void) tmp;
361 currentsz = dmasz;
362 }
363
364 FLUSH();
365 }
366 else {
367 /* Could write code to emit these as indexed vertices (for the
368 * g400, for instance).
369 */
370 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
371 return;
372 }
373 }
374
375
376 static void TAG(render_poly_verts)( struct gl_context *ctx,
377 GLuint start,
378 GLuint count,
379 GLuint flags )
380 {
381 if (HAVE_POLYGONS) {
382 LOCAL_VARS;
383 GLuint j, nr;
384 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
385 int currentsz;
386
387 INIT(GL_POLYGON);
388
389 currentsz = GET_CURRENT_VB_MAX_VERTS();
390 if (currentsz < 8) {
391 currentsz = dmasz;
392 }
393
394 for (j = 1 ; j + 1 < count ; j += nr - 2 ) {
395 void *tmp;
396 nr = MIN2( currentsz, count - j + 1 );
397 tmp = ALLOC_VERTS( nr );
398 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
399 tmp = TAG(emit_verts)(ctx, start + j, nr - 1, tmp);
400 (void) tmp;
401 currentsz = dmasz;
402 }
403
404 FLUSH();
405 }
406 else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
407 TAG(render_tri_fan_verts)( ctx, start, count, flags );
408 } else {
409 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
410 return;
411 }
412 }
413
414 static void TAG(render_quad_strip_verts)( struct gl_context *ctx,
415 GLuint start,
416 GLuint count,
417 GLuint flags )
418 {
419 GLuint j, nr;
420
421 if (HAVE_QUAD_STRIPS) {
422 LOCAL_VARS;
423 GLuint j, nr;
424 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
425 int currentsz;
426
427 INIT(GL_QUAD_STRIP);
428
429 currentsz = GET_CURRENT_VB_MAX_VERTS();
430 if (currentsz < 8) {
431 currentsz = dmasz;
432 }
433
434 dmasz -= (dmasz & 2);
435 currentsz -= (currentsz & 2);
436
437 for (j = 0; j + 3 < count; j += nr - 2 ) {
438 nr = MIN2( currentsz, count - j );
439 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
440 currentsz = dmasz;
441 }
442
443 FLUSH();
444
445 } else if (HAVE_TRI_STRIPS &&
446 ctx->Light.ShadeModel == GL_FLAT &&
447 TNL_CONTEXT(ctx)->vb.AttribPtr[_TNL_ATTRIB_COLOR0]->stride) {
448 if (HAVE_ELTS) {
449 LOCAL_VARS;
450 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
451 int currentsz;
452 GLuint j, nr;
453
454 EMIT_INDEXED_VERTS( ctx, start, count );
455
456 /* Simulate flat-shaded quadstrips using indexed vertices:
457 */
458 ELT_INIT( GL_TRIANGLES );
459
460 currentsz = GET_CURRENT_VB_MAX_ELTS();
461
462 /* Emit whole number of quads in total, and in each buffer.
463 */
464 dmasz -= dmasz & 1;
465 count -= count & 1;
466 currentsz -= currentsz & 1;
467
468 if (currentsz < 12)
469 currentsz = dmasz;
470
471 currentsz = currentsz/6*2;
472 dmasz = dmasz/6*2;
473
474 for (j = 0; j + 3 < count; j += nr - 2) {
475 nr = MIN2( currentsz, count - j );
476 if (nr >= 4) {
477 GLint quads = (nr/2)-1;
478 GLint i;
479 ELTS_VARS( ALLOC_ELTS( quads*6 ) );
480
481 for (i = j; i < j + quads * 2; i += 2) {
482 EMIT_TWO_ELTS( 0, (i+0), (i+1) );
483 EMIT_TWO_ELTS( 2, (i+2), (i+1) );
484 EMIT_TWO_ELTS( 4, (i+3), (i+2) );
485 INCR_ELTS( 6 );
486 }
487
488 FLUSH();
489 }
490 currentsz = dmasz;
491 }
492
493 RELEASE_ELT_VERTS();
494 FLUSH();
495 }
496 else {
497 /* Vertices won't fit in a single buffer or elts not
498 * available - should never happen.
499 */
500 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
501 return;
502 }
503 }
504 else if (HAVE_TRI_STRIPS) {
505 LOCAL_VARS;
506 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
507 int currentsz;
508
509 /* Emit smooth-shaded quadstrips as tristrips:
510 */
511 FLUSH();
512 INIT( GL_TRIANGLE_STRIP );
513
514 /* Emit whole number of quads in total, and in each buffer.
515 */
516 dmasz -= dmasz & 1;
517 currentsz = GET_CURRENT_VB_MAX_VERTS();
518 currentsz -= currentsz & 1;
519 count -= count & 1;
520
521 if (currentsz < 8) {
522 currentsz = dmasz;
523 }
524
525 for (j = 0; j + 3 < count; j += nr - 2) {
526 nr = MIN2( currentsz, count - j );
527 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
528 currentsz = dmasz;
529 }
530
531 FLUSH();
532
533 } else {
534 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
535 return;
536 }
537 }
538
539
540 static void TAG(render_quads_verts)( struct gl_context *ctx,
541 GLuint start,
542 GLuint count,
543 GLuint flags )
544 {
545 /* Emit whole number of quads in total. */
546 count -= count & 3;
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 currentsz = (GET_CURRENT_VB_MAX_VERTS()/4) * 4;
557 if (currentsz < 8)
558 currentsz = dmasz;
559
560 for (j = 0; j < count; j += nr) {
561 nr = MIN2( currentsz, count - j );
562 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
563 currentsz = dmasz;
564 }
565 }
566 else if (HAVE_ELTS) {
567 /* Hardware doesn't have a quad primitive type -- try to
568 * simulate it using indexed vertices and the triangle
569 * primitive:
570 */
571 LOCAL_VARS;
572 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
573 int currentsz;
574 GLuint j, nr;
575
576 EMIT_INDEXED_VERTS( ctx, start, count );
577
578 FLUSH();
579 ELT_INIT( GL_TRIANGLES );
580 currentsz = GET_CURRENT_VB_MAX_ELTS();
581
582 /* Emit whole number of quads in total, and in each buffer.
583 */
584 dmasz -= dmasz & 3;
585 currentsz -= currentsz & 3;
586
587 /* Adjust for rendering as triangles:
588 */
589 currentsz = currentsz/6*4;
590 dmasz = dmasz/6*4;
591
592 if (currentsz < 8)
593 currentsz = dmasz;
594
595 for (j = 0; j < count; j += nr ) {
596 nr = MIN2( currentsz, count - j );
597 if (nr >= 4) {
598 GLint quads = nr/4;
599 GLint i;
600 ELTS_VARS( ALLOC_ELTS( quads*6 ) );
601
602 for (i = j; i < j + quads * 4; i += 4) {
603 EMIT_TWO_ELTS( 0, (i+0), (i+1) );
604 EMIT_TWO_ELTS( 2, (i+3), (i+1) );
605 EMIT_TWO_ELTS( 4, (i+2), (i+3) );
606 INCR_ELTS( 6 );
607 }
608
609 FLUSH();
610 }
611 currentsz = dmasz;
612 }
613
614 RELEASE_ELT_VERTS();
615 }
616 else if (HAVE_TRIANGLES) {
617 /* Hardware doesn't have a quad primitive type -- try to
618 * simulate it using triangle primitive. This is a win for
619 * gears, but is it useful in the broader world?
620 */
621 LOCAL_VARS;
622 GLuint j;
623
624 INIT(GL_TRIANGLES);
625
626 for (j = 0; j < count-3; j += 4) {
627 void *tmp = ALLOC_VERTS( 6 );
628 /* Send v0, v1, v3
629 */
630 tmp = EMIT_VERTS(ctx, start + j, 2, tmp);
631 tmp = EMIT_VERTS(ctx, start + j + 3, 1, tmp);
632 /* Send v1, v2, v3
633 */
634 tmp = EMIT_VERTS(ctx, start + j + 1, 3, tmp);
635 (void) tmp;
636 }
637 }
638 else {
639 /* Vertices won't fit in a single buffer, should never happen.
640 */
641 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
642 return;
643 }
644 }
645
646 static void TAG(render_noop)( struct gl_context *ctx,
647 GLuint start,
648 GLuint count,
649 GLuint flags )
650 {
651 }
652
653
654
655
656 static tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] =
657 {
658 TAG(render_points_verts),
659 TAG(render_lines_verts),
660 TAG(render_line_loop_verts),
661 TAG(render_line_strip_verts),
662 TAG(render_triangles_verts),
663 TAG(render_tri_strip_verts),
664 TAG(render_tri_fan_verts),
665 TAG(render_quads_verts),
666 TAG(render_quad_strip_verts),
667 TAG(render_poly_verts),
668 TAG(render_noop),
669 };
670
671
672 /****************************************************************************
673 * Render elts using hardware indexed verts *
674 ****************************************************************************/
675
676 #if (HAVE_ELTS)
677 static void TAG(render_points_elts)( struct gl_context *ctx,
678 GLuint start,
679 GLuint count,
680 GLuint flags )
681 {
682 if (HAVE_POINTS) {
683 LOCAL_VARS;
684 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
685 int currentsz;
686 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
687 GLuint j, nr;
688
689 ELT_INIT( GL_POINTS );
690
691 currentsz = GET_CURRENT_VB_MAX_ELTS();
692 if (currentsz < 8)
693 currentsz = dmasz;
694
695 for (j = 0; j < count; j += nr ) {
696 nr = MIN2( currentsz, count - j );
697 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
698 FLUSH();
699 currentsz = dmasz;
700 }
701 } else {
702 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
703 return;
704 }
705 }
706
707
708
709 static void TAG(render_lines_elts)( struct gl_context *ctx,
710 GLuint start,
711 GLuint count,
712 GLuint flags )
713 {
714 if (HAVE_LINES) {
715 LOCAL_VARS;
716 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
717 int currentsz;
718 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
719 GLuint j, nr;
720
721 ELT_INIT( GL_LINES );
722
723 /* Emit whole number of lines in total and in each buffer:
724 */
725 count -= count & 1;
726 currentsz -= currentsz & 1;
727 dmasz -= dmasz & 1;
728
729 currentsz = GET_CURRENT_VB_MAX_ELTS();
730 if (currentsz < 8)
731 currentsz = dmasz;
732
733 for (j = 0; j < count; j += nr ) {
734 nr = MIN2( currentsz, count - j );
735 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
736 FLUSH();
737 currentsz = dmasz;
738 }
739 } else {
740 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
741 return;
742 }
743 }
744
745
746 static void TAG(render_line_strip_elts)( struct gl_context *ctx,
747 GLuint start,
748 GLuint count,
749 GLuint flags )
750 {
751 if (HAVE_LINE_STRIPS) {
752 LOCAL_VARS;
753 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
754 int currentsz;
755 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
756 GLuint j, nr;
757
758 FLUSH(); /* always a new primitive */
759 ELT_INIT( GL_LINE_STRIP );
760
761 currentsz = GET_CURRENT_VB_MAX_ELTS();
762 if (currentsz < 8)
763 currentsz = dmasz;
764
765 for (j = 0; j + 1 < count; j += nr - 1) {
766 nr = MIN2( currentsz, count - j );
767 TAG(emit_elts)( ctx, elts + start + j, nr, ALLOC_ELTS(nr));
768 FLUSH();
769 currentsz = dmasz;
770 }
771 } else {
772 /* TODO: Try to emit as indexed lines.
773 */
774 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
775 return;
776 }
777 }
778
779
780 static void TAG(render_line_loop_elts)( struct gl_context *ctx,
781 GLuint start,
782 GLuint count,
783 GLuint flags )
784 {
785 if (HAVE_LINE_STRIPS) {
786 LOCAL_VARS;
787 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
788 int currentsz;
789 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
790 GLuint j, nr;
791
792 FLUSH();
793 ELT_INIT( GL_LINE_STRIP );
794
795 j = (flags & PRIM_BEGIN) ? 0 : 1;
796
797 currentsz = GET_CURRENT_VB_MAX_ELTS();
798 if (currentsz < 8) {
799 currentsz = dmasz;
800 }
801
802 /* Ensure last vertex doesn't wrap:
803 */
804 currentsz--;
805 dmasz--;
806
807 if (j + 1 < count) {
808 for ( ; j + 1 < count; j += nr - 1 ) {
809 nr = MIN2( currentsz, count - j );
810
811 if (j + nr >= count &&
812 count > 1 &&
813 (flags & PRIM_END))
814 {
815 void *tmp;
816 tmp = ALLOC_ELTS(nr+1);
817 tmp = TAG(emit_elts)(ctx, elts + start + j, nr, tmp);
818 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
819 (void) tmp;
820 }
821 else {
822 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
823 currentsz = dmasz;
824 }
825 }
826
827 }
828 else if (count > 1 && (flags & PRIM_END)) {
829 void *tmp;
830 tmp = ALLOC_ELTS(2);
831 tmp = TAG(emit_elts)( ctx, elts+start+1, 1, tmp );
832 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
833 (void) tmp;
834 }
835
836 FLUSH();
837 } else {
838 /* TODO: Try to emit as indexed lines */
839 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
840 return;
841 }
842 }
843
844
845 /* For verts, we still eliminate the copy from main memory to dma
846 * buffers. For elts, this is probably no better (worse?) than the
847 * standard path.
848 */
849 static void TAG(render_triangles_elts)( struct gl_context *ctx,
850 GLuint start,
851 GLuint count,
852 GLuint flags )
853 {
854 LOCAL_VARS;
855 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
856 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/3*3;
857 int currentsz;
858 GLuint j, nr;
859
860 FLUSH();
861 ELT_INIT( GL_TRIANGLES );
862
863 currentsz = GET_CURRENT_VB_MAX_ELTS();
864
865 /* Emit whole number of tris in total. dmasz is already a multiple
866 * of 3.
867 */
868 count -= count % 3;
869 currentsz -= currentsz%3;
870 if (currentsz < 8)
871 currentsz = dmasz;
872
873 for (j = 0; j < count; j += nr) {
874 nr = MIN2( currentsz, count - j );
875 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
876 FLUSH();
877 currentsz = dmasz;
878 }
879 }
880
881
882
883 static void TAG(render_tri_strip_elts)( struct gl_context *ctx,
884 GLuint start,
885 GLuint count,
886 GLuint flags )
887 {
888 if (HAVE_TRI_STRIPS) {
889 LOCAL_VARS;
890 GLuint j, nr;
891 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
892 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
893 int currentsz;
894
895 FLUSH();
896 ELT_INIT( GL_TRIANGLE_STRIP );
897
898 currentsz = GET_CURRENT_VB_MAX_ELTS();
899 if (currentsz < 8) {
900 currentsz = dmasz;
901 }
902
903 /* Keep the same winding over multiple buffers:
904 */
905 dmasz -= (dmasz & 1);
906 currentsz -= (currentsz & 1);
907
908 for (j = 0; j + 2 < count; j += nr - 2) {
909 nr = MIN2( currentsz, count - j );
910 TAG(emit_elts)( ctx, elts + start + j, nr, ALLOC_ELTS(nr) );
911 FLUSH();
912 currentsz = dmasz;
913 }
914 } else {
915 /* TODO: try to emit as indexed triangles */
916 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
917 return;
918 }
919 }
920
921 static void TAG(render_tri_fan_elts)( struct gl_context *ctx,
922 GLuint start,
923 GLuint count,
924 GLuint flags )
925 {
926 if (HAVE_TRI_FANS) {
927 LOCAL_VARS;
928 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
929 GLuint j, nr;
930 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
931 int currentsz;
932
933 FLUSH();
934 ELT_INIT( GL_TRIANGLE_FAN );
935
936 currentsz = GET_CURRENT_VB_MAX_ELTS();
937 if (currentsz < 8) {
938 currentsz = dmasz;
939 }
940
941 for (j = 1; j + 1 < count; j += nr - 2) {
942 void *tmp;
943 nr = MIN2( currentsz, count - j + 1 );
944 tmp = ALLOC_ELTS( nr );
945 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
946 tmp = TAG(emit_elts)(ctx, elts + start + j, nr - 1, tmp);
947 (void) tmp;
948 FLUSH();
949 currentsz = dmasz;
950 }
951 } else {
952 /* TODO: try to emit as indexed triangles */
953 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
954 return;
955 }
956 }
957
958
959 static void TAG(render_poly_elts)( struct gl_context *ctx,
960 GLuint start,
961 GLuint count,
962 GLuint flags )
963 {
964 if (HAVE_POLYGONS) {
965 LOCAL_VARS;
966 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
967 GLuint j, nr;
968 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
969 int currentsz;
970
971 FLUSH();
972 ELT_INIT( GL_POLYGON );
973
974 currentsz = GET_CURRENT_VB_MAX_ELTS();
975 if (currentsz < 8) {
976 currentsz = dmasz;
977 }
978
979 for (j = 1 ; j + 1 < count; j += nr - 2) {
980 void *tmp;
981 nr = MIN2( currentsz, count - j + 1 );
982 tmp = ALLOC_ELTS( nr );
983 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
984 tmp = TAG(emit_elts)(ctx, elts + start + j, nr - 1, tmp);
985 (void) tmp;
986 FLUSH();
987 currentsz = dmasz;
988 }
989 } else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
990 TAG(render_tri_fan_verts)( ctx, start, count, flags );
991 } else {
992 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
993 return;
994 }
995 }
996
997 static void TAG(render_quad_strip_elts)( struct gl_context *ctx,
998 GLuint start,
999 GLuint count,
1000 GLuint flags )
1001 {
1002 if (HAVE_QUAD_STRIPS && 0) {
1003 }
1004 else if (HAVE_TRI_STRIPS) {
1005 LOCAL_VARS;
1006 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1007 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
1008 int currentsz;
1009 GLuint j, nr;
1010
1011 FLUSH();
1012 currentsz = GET_CURRENT_VB_MAX_ELTS();
1013
1014 /* Emit whole number of quads in total, and in each buffer.
1015 */
1016 dmasz -= dmasz & 1;
1017 count -= count & 1;
1018 currentsz -= currentsz & 1;
1019
1020 if (currentsz < 12)
1021 currentsz = dmasz;
1022
1023 if (ctx->Light.ShadeModel == GL_FLAT) {
1024 ELT_INIT( GL_TRIANGLES );
1025
1026 currentsz = currentsz/6*2;
1027 dmasz = dmasz/6*2;
1028
1029 for (j = 0; j + 3 < count; j += nr - 2) {
1030 nr = MIN2( currentsz, count - j );
1031
1032 if (nr >= 4)
1033 {
1034 GLint i;
1035 GLint quads = (nr/2)-1;
1036 ELTS_VARS( ALLOC_ELTS( quads*6 ) );
1037
1038 for (i = j; i < j + quads; i++, elts += 2) {
1039 EMIT_TWO_ELTS( 0, elts[0], elts[1] );
1040 EMIT_TWO_ELTS( 2, elts[2], elts[1] );
1041 EMIT_TWO_ELTS( 4, elts[3], elts[2] );
1042 INCR_ELTS( 6 );
1043 }
1044
1045 FLUSH();
1046 }
1047
1048 currentsz = dmasz;
1049 }
1050 }
1051 else {
1052 ELT_INIT( GL_TRIANGLE_STRIP );
1053
1054 for (j = 0; j + 3 < count; j += nr - 2) {
1055 nr = MIN2( currentsz, count - j );
1056 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
1057 FLUSH();
1058 currentsz = dmasz;
1059 }
1060 }
1061 }
1062 }
1063
1064
1065 static void TAG(render_quads_elts)( struct gl_context *ctx,
1066 GLuint start,
1067 GLuint count,
1068 GLuint flags )
1069 {
1070 /* Emit whole number of quads in total. */
1071 count -= count & 3;
1072
1073 if (HAVE_QUADS) {
1074 LOCAL_VARS;
1075 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1076 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/4*4;
1077 int currentsz;
1078 GLuint j, nr;
1079
1080 FLUSH();
1081 ELT_INIT( GL_TRIANGLES );
1082
1083 currentsz = GET_CURRENT_VB_MAX_ELTS()/4*4;
1084
1085 if (currentsz < 8)
1086 currentsz = dmasz;
1087
1088 for (j = 0; j < count; j += nr) {
1089 nr = MIN2( currentsz, count - j );
1090 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
1091 FLUSH();
1092 currentsz = dmasz;
1093 }
1094 } else {
1095 LOCAL_VARS;
1096 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1097 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
1098 int currentsz;
1099 GLuint j, nr;
1100
1101 ELT_INIT( GL_TRIANGLES );
1102 currentsz = GET_CURRENT_VB_MAX_ELTS();
1103
1104 /* Emit whole number of quads in total, and in each buffer.
1105 */
1106 dmasz -= dmasz & 3;
1107 currentsz -= currentsz & 3;
1108
1109 /* Adjust for rendering as triangles:
1110 */
1111 currentsz = currentsz/6*4;
1112 dmasz = dmasz/6*4;
1113
1114 if (currentsz < 8)
1115 currentsz = dmasz;
1116
1117 for (j = 0; j + 3 < count; j += nr - 2) {
1118 nr = MIN2( currentsz, count - j );
1119
1120 if (nr >= 4)
1121 {
1122 GLint quads = nr/4;
1123 GLint i;
1124 ELTS_VARS( ALLOC_ELTS( quads * 6 ) );
1125
1126 for (i = j; i < j + quads; i++, elts += 4) {
1127 EMIT_TWO_ELTS( 0, elts[0], elts[1] );
1128 EMIT_TWO_ELTS( 2, elts[3], elts[1] );
1129 EMIT_TWO_ELTS( 4, elts[2], elts[3] );
1130 INCR_ELTS( 6 );
1131 }
1132
1133 FLUSH();
1134 }
1135
1136 currentsz = dmasz;
1137 }
1138 }
1139 }
1140
1141
1142
1143 static tnl_render_func TAG(render_tab_elts)[GL_POLYGON+2] =
1144 {
1145 TAG(render_points_elts),
1146 TAG(render_lines_elts),
1147 TAG(render_line_loop_elts),
1148 TAG(render_line_strip_elts),
1149 TAG(render_triangles_elts),
1150 TAG(render_tri_strip_elts),
1151 TAG(render_tri_fan_elts),
1152 TAG(render_quads_elts),
1153 TAG(render_quad_strip_elts),
1154 TAG(render_poly_elts),
1155 TAG(render_noop),
1156 };
1157
1158
1159
1160 #endif
1161
1162
1163
1164 /* Pre-check the primitives in the VB to prevent the need for
1165 * fallbacks later on.
1166 */
1167 static GLboolean TAG(validate_render)( struct gl_context *ctx,
1168 struct vertex_buffer *VB )
1169 {
1170 GLint i;
1171
1172 if (VB->ClipOrMask & ~CLIP_CULL_BIT)
1173 return GL_FALSE;
1174
1175 if (VB->Elts && !HAVE_ELTS)
1176 return GL_FALSE;
1177
1178 for (i = 0 ; i < VB->PrimitiveCount ; i++) {
1179 GLuint prim = VB->Primitive[i].mode;
1180 GLuint count = VB->Primitive[i].count;
1181 GLboolean ok = GL_FALSE;
1182
1183 if (!count)
1184 continue;
1185
1186 switch (prim & PRIM_MODE_MASK) {
1187 case GL_POINTS:
1188 ok = HAVE_POINTS;
1189 break;
1190 case GL_LINES:
1191 ok = HAVE_LINES && !ctx->Line.StippleFlag;
1192 break;
1193 case GL_LINE_STRIP:
1194 ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
1195 break;
1196 case GL_LINE_LOOP:
1197 ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
1198 break;
1199 case GL_TRIANGLES:
1200 ok = HAVE_TRIANGLES;
1201 break;
1202 case GL_TRIANGLE_STRIP:
1203 ok = HAVE_TRI_STRIPS;
1204 break;
1205 case GL_TRIANGLE_FAN:
1206 ok = HAVE_TRI_FANS;
1207 break;
1208 case GL_POLYGON:
1209 if (HAVE_POLYGONS) {
1210 ok = GL_TRUE;
1211 }
1212 else {
1213 ok = (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH);
1214 }
1215 break;
1216 case GL_QUAD_STRIP:
1217 if (VB->Elts) {
1218 ok = HAVE_TRI_STRIPS;
1219 }
1220 else if (HAVE_QUAD_STRIPS) {
1221 ok = GL_TRUE;
1222 } else if (HAVE_TRI_STRIPS &&
1223 ctx->Light.ShadeModel == GL_FLAT &&
1224 VB->AttribPtr[_TNL_ATTRIB_COLOR0]->stride != 0) {
1225 if (HAVE_ELTS) {
1226 ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
1227 }
1228 else {
1229 ok = GL_FALSE;
1230 }
1231 }
1232 else
1233 ok = HAVE_TRI_STRIPS;
1234 break;
1235 case GL_QUADS:
1236 if (HAVE_QUADS) {
1237 ok = GL_TRUE;
1238 } else if (HAVE_ELTS) {
1239 ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
1240 }
1241 else {
1242 ok = HAVE_TRIANGLES; /* flatshading is ok. */
1243 }
1244 break;
1245 default:
1246 break;
1247 }
1248
1249 if (!ok) {
1250 /* fprintf(stderr, "not ok %s\n", _mesa_enum_to_string(prim & PRIM_MODE_MASK)); */
1251 return GL_FALSE;
1252 }
1253 }
1254
1255 return GL_TRUE;
1256 }
1257