tnl: Replace deprecated ColorPtr[] with AttribPtr or new BackfaceColorPtr.
[mesa.git] / src / mesa / tnl_dd / t_dd_dmatmp.h
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)
76 static void *TAG(emit_elts)( GLcontext *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)( GLcontext *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)( GLcontext *ctx,
108 GLuint start,
109 GLuint count,
110 GLuint flags )
111 {
112 if (HAVE_POINTS) {
113 LOCAL_VARS;
114 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
115 int currentsz;
116 GLuint j, nr;
117
118 INIT( GL_POINTS );
119
120 currentsz = GET_CURRENT_VB_MAX_VERTS();
121 if (currentsz < 8)
122 currentsz = dmasz;
123
124 for (j = start; j < count; j += nr ) {
125 nr = MIN2( currentsz, count - j );
126 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
127 currentsz = dmasz;
128 }
129
130 } else {
131 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
132 return;
133 }
134 }
135
136 static void TAG(render_lines_verts)( GLcontext *ctx,
137 GLuint start,
138 GLuint count,
139 GLuint flags )
140 {
141 if (HAVE_LINES) {
142 LOCAL_VARS;
143 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
144 int currentsz;
145 GLuint j, nr;
146
147 INIT( GL_LINES );
148
149 /* Emit whole number of lines in total and in each buffer:
150 */
151 count -= (count-start) & 1;
152 currentsz = GET_CURRENT_VB_MAX_VERTS();
153 currentsz -= currentsz & 1;
154 dmasz -= dmasz & 1;
155
156 if (currentsz < 8)
157 currentsz = dmasz;
158
159 for (j = start; j < count; j += nr ) {
160 nr = MIN2( currentsz, count - j );
161 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
162 currentsz = dmasz;
163 }
164
165 } else {
166 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
167 return;
168 }
169 }
170
171
172 static void TAG(render_line_strip_verts)( GLcontext *ctx,
173 GLuint start,
174 GLuint count,
175 GLuint flags )
176 {
177 if (HAVE_LINE_STRIPS) {
178 LOCAL_VARS;
179 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
180 int currentsz;
181 GLuint j, nr;
182
183 INIT( GL_LINE_STRIP );
184
185 currentsz = GET_CURRENT_VB_MAX_VERTS();
186 if (currentsz < 8)
187 currentsz = dmasz;
188
189 for (j = start; j + 1 < count; j += nr - 1 ) {
190 nr = MIN2( currentsz, count - j );
191 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
192 currentsz = dmasz;
193 }
194
195 FLUSH();
196
197 } else {
198 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
199 return;
200 }
201 }
202
203
204 static void TAG(render_line_loop_verts)( GLcontext *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 }
245 else {
246 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
247 currentsz = dmasz;
248 }
249 }
250
251 }
252 else if (start + 1 < count && (flags & PRIM_END)) {
253 void *tmp;
254 tmp = ALLOC_VERTS(2);
255 tmp = TAG(emit_verts)( ctx, start+1, 1, tmp );
256 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
257 }
258
259 FLUSH();
260
261 } else {
262 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
263 return;
264 }
265 }
266
267
268 static void TAG(render_triangles_verts)( GLcontext *ctx,
269 GLuint start,
270 GLuint count,
271 GLuint flags )
272 {
273 LOCAL_VARS;
274 int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/3) * 3;
275 int currentsz;
276 GLuint j, nr;
277
278 INIT(GL_TRIANGLES);
279
280 currentsz = (GET_CURRENT_VB_MAX_VERTS()/3) * 3;
281
282 /* Emit whole number of tris in total. dmasz is already a multiple
283 * of 3.
284 */
285 count -= (count-start)%3;
286
287 if (currentsz < 8)
288 currentsz = dmasz;
289
290 for (j = start; j < count; j += nr) {
291 nr = MIN2( currentsz, count - j );
292 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
293 currentsz = dmasz;
294 }
295 }
296
297
298
299 static void TAG(render_tri_strip_verts)( GLcontext *ctx,
300 GLuint start,
301 GLuint count,
302 GLuint flags )
303 {
304 if (HAVE_TRI_STRIPS) {
305 LOCAL_VARS;
306 GLuint j, nr;
307 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
308 int currentsz;
309
310 INIT(GL_TRIANGLE_STRIP);
311
312 currentsz = GET_CURRENT_VB_MAX_VERTS();
313
314 if (currentsz < 8) {
315 currentsz = dmasz;
316 }
317
318 /* From here on emit even numbers of tris when wrapping over buffers:
319 */
320 dmasz -= (dmasz & 1);
321 currentsz -= (currentsz & 1);
322
323 for (j = start ; j + 2 < count; j += nr - 2 ) {
324 nr = MIN2( currentsz, count - j );
325 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
326 currentsz = dmasz;
327 }
328
329 FLUSH();
330
331 } else {
332 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
333 return;
334 }
335 }
336
337 static void TAG(render_tri_fan_verts)( GLcontext *ctx,
338 GLuint start,
339 GLuint count,
340 GLuint flags )
341 {
342 if (HAVE_TRI_FANS) {
343 LOCAL_VARS;
344 GLuint j, nr;
345 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
346 int currentsz;
347
348 INIT(GL_TRIANGLE_FAN);
349
350 currentsz = GET_CURRENT_VB_MAX_VERTS();
351 if (currentsz < 8) {
352 currentsz = dmasz;
353 }
354
355 for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
356 void *tmp;
357 nr = MIN2( currentsz, count - j + 1 );
358 tmp = ALLOC_VERTS( nr );
359 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
360 tmp = TAG(emit_verts)( ctx, j, nr - 1, 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", __FUNCTION__);
371 return;
372 }
373 }
374
375
376 static void TAG(render_poly_verts)( GLcontext *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 = start + 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, j, nr - 1, tmp );
400 currentsz = dmasz;
401 }
402
403 FLUSH();
404 }
405 else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
406 TAG(render_tri_fan_verts)( ctx, start, count, flags );
407 } else {
408 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
409 return;
410 }
411 }
412
413 static void TAG(render_quad_strip_verts)( GLcontext *ctx,
414 GLuint start,
415 GLuint count,
416 GLuint flags )
417 {
418 GLuint j, nr;
419
420 if (HAVE_QUAD_STRIPS) {
421 LOCAL_VARS;
422 GLuint j, nr;
423 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
424 int currentsz;
425
426 INIT(GL_QUAD_STRIP);
427
428 currentsz = GET_CURRENT_VB_MAX_VERTS();
429 if (currentsz < 8) {
430 currentsz = dmasz;
431 }
432
433 dmasz -= (dmasz & 2);
434 currentsz -= (currentsz & 2);
435
436 for (j = start ; j + 3 < count; j += nr - 2 ) {
437 nr = MIN2( currentsz, count - j );
438 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
439 currentsz = dmasz;
440 }
441
442 FLUSH();
443
444 } else if (HAVE_TRI_STRIPS &&
445 ctx->Light.ShadeModel == GL_FLAT &&
446 TNL_CONTEXT(ctx)->vb.AttribPtr[_TNL_ATTRIB_COLOR0]->stride) {
447 if (HAVE_ELTS) {
448 LOCAL_VARS;
449 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
450 int currentsz;
451 GLuint j, nr;
452
453 EMIT_INDEXED_VERTS( ctx, start, count );
454
455 /* Simulate flat-shaded quadstrips using indexed vertices:
456 */
457 ELT_INIT( GL_TRIANGLES );
458
459 currentsz = GET_CURRENT_VB_MAX_ELTS();
460
461 /* Emit whole number of quads in total, and in each buffer.
462 */
463 dmasz -= dmasz & 1;
464 count -= (count-start) & 1;
465 currentsz -= currentsz & 1;
466
467 if (currentsz < 12)
468 currentsz = dmasz;
469
470 currentsz = currentsz/6*2;
471 dmasz = dmasz/6*2;
472
473 for (j = start; j + 3 < count; j += nr - 2 ) {
474 nr = MIN2( currentsz, count - j );
475 if (nr >= 4) {
476 GLint quads = (nr/2)-1;
477 GLint i;
478 ELTS_VARS( ALLOC_ELTS( quads*6 ) );
479
480 for ( i = j-start ; i < j-start+quads*2 ; i+=2 ) {
481 EMIT_TWO_ELTS( 0, (i+0), (i+1) );
482 EMIT_TWO_ELTS( 2, (i+2), (i+1) );
483 EMIT_TWO_ELTS( 4, (i+3), (i+2) );
484 INCR_ELTS( 6 );
485 }
486
487 FLUSH();
488 }
489 currentsz = dmasz;
490 }
491
492 RELEASE_ELT_VERTS();
493 FLUSH();
494 }
495 else {
496 /* Vertices won't fit in a single buffer or elts not
497 * available - should never happen.
498 */
499 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
500 return;
501 }
502 }
503 else if (HAVE_TRI_STRIPS) {
504 LOCAL_VARS;
505 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
506 int currentsz;
507
508 /* Emit smooth-shaded quadstrips as tristrips:
509 */
510 FLUSH();
511 INIT( GL_TRIANGLE_STRIP );
512
513 /* Emit whole number of quads in total, and in each buffer.
514 */
515 dmasz -= dmasz & 1;
516 currentsz = GET_CURRENT_VB_MAX_VERTS();
517 currentsz -= currentsz & 1;
518 count -= (count-start) & 1;
519
520 if (currentsz < 8) {
521 currentsz = dmasz;
522 }
523
524 for (j = start; j + 3 < count; j += nr - 2 ) {
525 nr = MIN2( currentsz, count - j );
526 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
527 currentsz = dmasz;
528 }
529
530 FLUSH();
531
532 } else {
533 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
534 return;
535 }
536 }
537
538
539 static void TAG(render_quads_verts)( GLcontext *ctx,
540 GLuint start,
541 GLuint count,
542 GLuint flags )
543 {
544 if (HAVE_QUADS) {
545 LOCAL_VARS;
546 int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/4) * 4;
547 int currentsz;
548 GLuint j, nr;
549
550 INIT(GL_QUADS);
551
552 /* Emit whole number of quads in total. dmasz is already a multiple
553 * of 4.
554 */
555 count -= (count-start)%4;
556
557 currentsz = (GET_CURRENT_VB_MAX_VERTS()/4) * 4;
558 if (currentsz < 8)
559 currentsz = dmasz;
560
561 for (j = start; j < count; j += nr) {
562 nr = MIN2( currentsz, count - j );
563 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
564 currentsz = dmasz;
565 }
566 }
567 else if (HAVE_ELTS) {
568 /* Hardware doesn't have a quad primitive type -- try to
569 * simulate it using indexed vertices and the triangle
570 * primitive:
571 */
572 LOCAL_VARS;
573 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
574 int currentsz;
575 GLuint j, nr;
576
577 EMIT_INDEXED_VERTS( ctx, start, count );
578
579 FLUSH();
580 ELT_INIT( GL_TRIANGLES );
581 currentsz = GET_CURRENT_VB_MAX_ELTS();
582
583 /* Emit whole number of quads in total, and in each buffer.
584 */
585 dmasz -= dmasz & 3;
586 count -= (count-start) & 3;
587 currentsz -= currentsz & 3;
588
589 /* Adjust for rendering as triangles:
590 */
591 currentsz = currentsz/6*4;
592 dmasz = dmasz/6*4;
593
594 if (currentsz < 8)
595 currentsz = dmasz;
596
597 for (j = start; j < count; j += nr ) {
598 nr = MIN2( currentsz, count - j );
599 if (nr >= 4) {
600 GLint quads = nr/4;
601 GLint i;
602 ELTS_VARS( ALLOC_ELTS( quads*6 ) );
603
604 for ( i = j-start ; i < j-start+quads*4 ; i+=4 ) {
605 EMIT_TWO_ELTS( 0, (i+0), (i+1) );
606 EMIT_TWO_ELTS( 2, (i+3), (i+1) );
607 EMIT_TWO_ELTS( 4, (i+2), (i+3) );
608 INCR_ELTS( 6 );
609 }
610
611 FLUSH();
612 }
613 currentsz = dmasz;
614 }
615
616 RELEASE_ELT_VERTS();
617 }
618 else if (HAVE_TRIANGLES) {
619 /* Hardware doesn't have a quad primitive type -- try to
620 * simulate it using triangle primitive. This is a win for
621 * gears, but is it useful in the broader world?
622 */
623 LOCAL_VARS;
624 GLuint j;
625
626 INIT(GL_TRIANGLES);
627
628 for (j = start; j < count-3; j += 4) {
629 void *tmp = ALLOC_VERTS( 6 );
630 /* Send v0, v1, v3
631 */
632 tmp = EMIT_VERTS(ctx, j, 2, tmp);
633 tmp = EMIT_VERTS(ctx, j + 3, 1, tmp);
634 /* Send v1, v2, v3
635 */
636 tmp = EMIT_VERTS(ctx, j + 1, 3, tmp);
637 }
638 }
639 else {
640 /* Vertices won't fit in a single buffer, should never happen.
641 */
642 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
643 return;
644 }
645 }
646
647 static void TAG(render_noop)( GLcontext *ctx,
648 GLuint start,
649 GLuint count,
650 GLuint flags )
651 {
652 }
653
654
655
656
657 static tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] =
658 {
659 TAG(render_points_verts),
660 TAG(render_lines_verts),
661 TAG(render_line_loop_verts),
662 TAG(render_line_strip_verts),
663 TAG(render_triangles_verts),
664 TAG(render_tri_strip_verts),
665 TAG(render_tri_fan_verts),
666 TAG(render_quads_verts),
667 TAG(render_quad_strip_verts),
668 TAG(render_poly_verts),
669 TAG(render_noop),
670 };
671
672
673 /****************************************************************************
674 * Render elts using hardware indexed verts *
675 ****************************************************************************/
676
677 #if (HAVE_ELTS)
678 static void TAG(render_points_elts)( GLcontext *ctx,
679 GLuint start,
680 GLuint count,
681 GLuint flags )
682 {
683 if (HAVE_POINTS) {
684 LOCAL_VARS;
685 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
686 int currentsz;
687 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
688 GLuint j, nr;
689
690 ELT_INIT( GL_POINTS );
691
692 currentsz = GET_CURRENT_VB_MAX_ELTS();
693 if (currentsz < 8)
694 currentsz = dmasz;
695
696 for (j = start; j < count; j += nr ) {
697 nr = MIN2( currentsz, count - j );
698 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
699 FLUSH();
700 currentsz = dmasz;
701 }
702 } else {
703 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
704 return;
705 }
706 }
707
708
709
710 static void TAG(render_lines_elts)( GLcontext *ctx,
711 GLuint start,
712 GLuint count,
713 GLuint flags )
714 {
715 if (HAVE_LINES) {
716 LOCAL_VARS;
717 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
718 int currentsz;
719 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
720 GLuint j, nr;
721
722 ELT_INIT( GL_LINES );
723
724 /* Emit whole number of lines in total and in each buffer:
725 */
726 count -= (count-start) & 1;
727 currentsz -= currentsz & 1;
728 dmasz -= dmasz & 1;
729
730 currentsz = GET_CURRENT_VB_MAX_ELTS();
731 if (currentsz < 8)
732 currentsz = dmasz;
733
734 for (j = start; j < count; j += nr ) {
735 nr = MIN2( currentsz, count - j );
736 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
737 FLUSH();
738 currentsz = dmasz;
739 }
740 } else {
741 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
742 return;
743 }
744 }
745
746
747 static void TAG(render_line_strip_elts)( GLcontext *ctx,
748 GLuint start,
749 GLuint count,
750 GLuint flags )
751 {
752 if (HAVE_LINE_STRIPS) {
753 LOCAL_VARS;
754 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
755 int currentsz;
756 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
757 GLuint j, nr;
758
759 FLUSH(); /* always a new primitive */
760 ELT_INIT( GL_LINE_STRIP );
761
762 currentsz = GET_CURRENT_VB_MAX_ELTS();
763 if (currentsz < 8)
764 currentsz = dmasz;
765
766 for (j = start; j + 1 < count; j += nr - 1 ) {
767 nr = MIN2( currentsz, count - j );
768 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
769 FLUSH();
770 currentsz = dmasz;
771 }
772 } else {
773 /* TODO: Try to emit as indexed lines.
774 */
775 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
776 return;
777 }
778 }
779
780
781 static void TAG(render_line_loop_elts)( GLcontext *ctx,
782 GLuint start,
783 GLuint count,
784 GLuint flags )
785 {
786 if (HAVE_LINE_STRIPS) {
787 LOCAL_VARS;
788 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
789 int currentsz;
790 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
791 GLuint j, nr;
792
793 FLUSH();
794 ELT_INIT( GL_LINE_STRIP );
795
796 if (flags & PRIM_BEGIN)
797 j = start;
798 else
799 j = start + 1;
800
801 currentsz = GET_CURRENT_VB_MAX_ELTS();
802 if (currentsz < 8) {
803 currentsz = dmasz;
804 }
805
806 /* Ensure last vertex doesn't wrap:
807 */
808 currentsz--;
809 dmasz--;
810
811 if (j + 1 < count) {
812 for ( ; j + 1 < count; j += nr - 1 ) {
813 nr = MIN2( currentsz, count - j );
814
815 if (j + nr >= count &&
816 start < count - 1 &&
817 (flags & PRIM_END))
818 {
819 void *tmp;
820 tmp = ALLOC_ELTS(nr+1);
821 tmp = TAG(emit_elts)( ctx, elts+j, nr, tmp );
822 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
823 }
824 else {
825 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
826 currentsz = dmasz;
827 }
828 }
829
830 }
831 else if (start + 1 < count && (flags & PRIM_END)) {
832 void *tmp;
833 tmp = ALLOC_ELTS(2);
834 tmp = TAG(emit_elts)( ctx, elts+start+1, 1, tmp );
835 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
836 }
837
838 FLUSH();
839 } else {
840 /* TODO: Try to emit as indexed lines */
841 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
842 return;
843 }
844 }
845
846
847 /* For verts, we still eliminate the copy from main memory to dma
848 * buffers. For elts, this is probably no better (worse?) than the
849 * standard path.
850 */
851 static void TAG(render_triangles_elts)( GLcontext *ctx,
852 GLuint start,
853 GLuint count,
854 GLuint flags )
855 {
856 LOCAL_VARS;
857 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
858 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/3*3;
859 int currentsz;
860 GLuint j, nr;
861
862 FLUSH();
863 ELT_INIT( GL_TRIANGLES );
864
865 currentsz = GET_CURRENT_VB_MAX_ELTS();
866
867 /* Emit whole number of tris in total. dmasz is already a multiple
868 * of 3.
869 */
870 count -= (count-start)%3;
871 currentsz -= currentsz%3;
872 if (currentsz < 8)
873 currentsz = dmasz;
874
875 for (j = start; j < count; j += nr) {
876 nr = MIN2( currentsz, count - j );
877 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
878 FLUSH();
879 currentsz = dmasz;
880 }
881 }
882
883
884
885 static void TAG(render_tri_strip_elts)( GLcontext *ctx,
886 GLuint start,
887 GLuint count,
888 GLuint flags )
889 {
890 if (HAVE_TRI_STRIPS) {
891 LOCAL_VARS;
892 GLuint j, nr;
893 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
894 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
895 int currentsz;
896
897 FLUSH();
898 ELT_INIT( GL_TRIANGLE_STRIP );
899
900 currentsz = GET_CURRENT_VB_MAX_ELTS();
901 if (currentsz < 8) {
902 currentsz = dmasz;
903 }
904
905 /* Keep the same winding over multiple buffers:
906 */
907 dmasz -= (dmasz & 1);
908 currentsz -= (currentsz & 1);
909
910 for (j = start ; j + 2 < count; j += nr - 2 ) {
911 nr = MIN2( currentsz, count - j );
912 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
913 FLUSH();
914 currentsz = dmasz;
915 }
916 } else {
917 /* TODO: try to emit as indexed triangles */
918 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
919 return;
920 }
921 }
922
923 static void TAG(render_tri_fan_elts)( GLcontext *ctx,
924 GLuint start,
925 GLuint count,
926 GLuint flags )
927 {
928 if (HAVE_TRI_FANS) {
929 LOCAL_VARS;
930 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
931 GLuint j, nr;
932 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
933 int currentsz;
934
935 FLUSH();
936 ELT_INIT( GL_TRIANGLE_FAN );
937
938 currentsz = GET_CURRENT_VB_MAX_ELTS();
939 if (currentsz < 8) {
940 currentsz = dmasz;
941 }
942
943 for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
944 void *tmp;
945 nr = MIN2( currentsz, count - j + 1 );
946 tmp = ALLOC_ELTS( nr );
947 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
948 tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp );
949 FLUSH();
950 currentsz = dmasz;
951 }
952 } else {
953 /* TODO: try to emit as indexed triangles */
954 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
955 return;
956 }
957 }
958
959
960 static void TAG(render_poly_elts)( GLcontext *ctx,
961 GLuint start,
962 GLuint count,
963 GLuint flags )
964 {
965 if (HAVE_POLYGONS) {
966 LOCAL_VARS;
967 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
968 GLuint j, nr;
969 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
970 int currentsz;
971
972 FLUSH();
973 ELT_INIT( GL_POLYGON );
974
975 currentsz = GET_CURRENT_VB_MAX_ELTS();
976 if (currentsz < 8) {
977 currentsz = dmasz;
978 }
979
980 for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
981 void *tmp;
982 nr = MIN2( currentsz, count - j + 1 );
983 tmp = ALLOC_ELTS( nr );
984 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
985 tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, 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", __FUNCTION__);
993 return;
994 }
995 }
996
997 static void TAG(render_quad_strip_elts)( GLcontext *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-start) & 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 = start; 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-start ; i < j-start+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 = start; j + 3 < count; j += nr - 2 ) {
1055 nr = MIN2( currentsz, count - j );
1056 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
1057 FLUSH();
1058 currentsz = dmasz;
1059 }
1060 }
1061 }
1062 }
1063
1064
1065 static void TAG(render_quads_elts)( GLcontext *ctx,
1066 GLuint start,
1067 GLuint count,
1068 GLuint flags )
1069 {
1070 if (HAVE_QUADS) {
1071 LOCAL_VARS;
1072 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1073 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/4*4;
1074 int currentsz;
1075 GLuint j, nr;
1076
1077 FLUSH();
1078 ELT_INIT( GL_TRIANGLES );
1079
1080 currentsz = GET_CURRENT_VB_MAX_ELTS()/4*4;
1081
1082 count -= (count-start)%4;
1083
1084 if (currentsz < 8)
1085 currentsz = dmasz;
1086
1087 for (j = start; j < count; j += nr) {
1088 nr = MIN2( currentsz, count - j );
1089 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
1090 FLUSH();
1091 currentsz = dmasz;
1092 }
1093 } else {
1094 LOCAL_VARS;
1095 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1096 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
1097 int currentsz;
1098 GLuint j, nr;
1099
1100 ELT_INIT( GL_TRIANGLES );
1101 currentsz = GET_CURRENT_VB_MAX_ELTS();
1102
1103 /* Emit whole number of quads in total, and in each buffer.
1104 */
1105 dmasz -= dmasz & 3;
1106 count -= (count-start) & 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 = start; 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-start ; i < j-start+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)( GLcontext *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_lookup_enum_by_nr(prim & PRIM_MODE_MASK)); */
1251 return GL_FALSE;
1252 }
1253 }
1254
1255 return GL_TRUE;
1256 }
1257