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