7182978a1710ac72da0e0651abe9d3c57235897c
[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 (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
270 static void TAG(render_triangles_verts)( GLcontext *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
301 static void TAG(render_tri_strip_verts)( GLcontext *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
339 static void TAG(render_tri_fan_verts)( GLcontext *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
379 static void TAG(render_poly_verts)( GLcontext *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
417 static void TAG(render_quad_strip_verts)( GLcontext *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.ColorPtr[0]->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
543 static void TAG(render_quads_verts)( GLcontext *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
652 static void TAG(render_noop)( GLcontext *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)
683 static void TAG(render_points_elts)( GLcontext *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
715 static void TAG(render_lines_elts)( GLcontext *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
752 static void TAG(render_line_strip_elts)( GLcontext *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
786 static void TAG(render_line_loop_elts)( GLcontext *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 */
858 static void TAG(render_triangles_elts)( GLcontext *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
892 static void TAG(render_tri_strip_elts)( GLcontext *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
930 static void TAG(render_tri_fan_elts)( GLcontext *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
968 static void TAG(render_poly_elts)( GLcontext *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 FLUSH();
995 currentsz = dmasz;
996 }
997 } else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
998 TAG(render_tri_fan_verts)( ctx, start, count, flags );
999 } else {
1000 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
1001 return;
1002 }
1003 }
1004
1005 static void TAG(render_quad_strip_elts)( GLcontext *ctx,
1006 GLuint start,
1007 GLuint count,
1008 GLuint flags )
1009 {
1010 if (HAVE_QUAD_STRIPS && 0) {
1011 }
1012 else if (HAVE_TRI_STRIPS) {
1013 LOCAL_VARS;
1014 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1015 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
1016 int currentsz;
1017 GLuint j, nr;
1018
1019 FLUSH();
1020 currentsz = GET_CURRENT_VB_MAX_ELTS();
1021
1022 /* Emit whole number of quads in total, and in each buffer.
1023 */
1024 dmasz -= dmasz & 1;
1025 count -= (count-start) & 1;
1026 currentsz -= currentsz & 1;
1027
1028 if (currentsz < 12)
1029 currentsz = dmasz;
1030
1031 if (ctx->Light.ShadeModel == GL_FLAT) {
1032 ELT_INIT( GL_TRIANGLES );
1033
1034 currentsz = currentsz/6*2;
1035 dmasz = dmasz/6*2;
1036
1037 for (j = start; j + 3 < count; j += nr - 2 ) {
1038 nr = MIN2( currentsz, count - j );
1039
1040 if (nr >= 4)
1041 {
1042 GLint i;
1043 GLint quads = (nr/2)-1;
1044 ELTS_VARS( ALLOC_ELTS( quads*6 ) );
1045
1046 for ( i = j-start ; i < j-start+quads ; i++, elts += 2 ) {
1047 EMIT_TWO_ELTS( 0, elts[0], elts[1] );
1048 EMIT_TWO_ELTS( 2, elts[2], elts[1] );
1049 EMIT_TWO_ELTS( 4, elts[3], elts[2] );
1050 INCR_ELTS( 6 );
1051 }
1052
1053 FLUSH();
1054 }
1055
1056 currentsz = dmasz;
1057 }
1058 }
1059 else {
1060 ELT_INIT( GL_TRIANGLE_STRIP );
1061
1062 for (j = start; j + 3 < count; j += nr - 2 ) {
1063 nr = MIN2( currentsz, count - j );
1064 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
1065 FLUSH();
1066 currentsz = dmasz;
1067 }
1068 }
1069 }
1070 }
1071
1072
1073 static void TAG(render_quads_elts)( GLcontext *ctx,
1074 GLuint start,
1075 GLuint count,
1076 GLuint flags )
1077 {
1078 if (HAVE_QUADS) {
1079 LOCAL_VARS;
1080 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1081 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/4*4;
1082 int currentsz;
1083 GLuint j, nr;
1084
1085 FLUSH();
1086 ELT_INIT( GL_TRIANGLES );
1087
1088 currentsz = GET_CURRENT_VB_MAX_ELTS()/4*4;
1089
1090 count -= (count-start)%4;
1091
1092 if (currentsz < 8)
1093 currentsz = dmasz;
1094
1095 for (j = start; j < count; j += nr) {
1096 nr = MIN2( currentsz, count - j );
1097 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
1098 FLUSH();
1099 currentsz = dmasz;
1100 }
1101 } else {
1102 LOCAL_VARS;
1103 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1104 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
1105 int currentsz;
1106 GLuint j, nr;
1107
1108 ELT_INIT( GL_TRIANGLES );
1109 currentsz = GET_CURRENT_VB_MAX_ELTS();
1110
1111 /* Emit whole number of quads in total, and in each buffer.
1112 */
1113 dmasz -= dmasz & 3;
1114 count -= (count-start) & 3;
1115 currentsz -= currentsz & 3;
1116
1117 /* Adjust for rendering as triangles:
1118 */
1119 currentsz = currentsz/6*4;
1120 dmasz = dmasz/6*4;
1121
1122 if (currentsz < 8)
1123 currentsz = dmasz;
1124
1125 for (j = start; j + 3 < count; j += nr - 2 ) {
1126 nr = MIN2( currentsz, count - j );
1127
1128 if (nr >= 4)
1129 {
1130 GLint quads = nr/4;
1131 GLint i;
1132 ELTS_VARS( ALLOC_ELTS( quads * 6 ) );
1133
1134 for ( i = j-start ; i < j-start+quads ; i++, elts += 4 ) {
1135 EMIT_TWO_ELTS( 0, elts[0], elts[1] );
1136 EMIT_TWO_ELTS( 2, elts[3], elts[1] );
1137 EMIT_TWO_ELTS( 4, elts[2], elts[3] );
1138 INCR_ELTS( 6 );
1139 }
1140
1141 FLUSH();
1142 }
1143
1144 currentsz = dmasz;
1145 }
1146 }
1147 }
1148
1149
1150
1151 static tnl_render_func TAG(render_tab_elts)[GL_POLYGON+2] =
1152 {
1153 TAG(render_points_elts),
1154 TAG(render_lines_elts),
1155 TAG(render_line_loop_elts),
1156 TAG(render_line_strip_elts),
1157 TAG(render_triangles_elts),
1158 TAG(render_tri_strip_elts),
1159 TAG(render_tri_fan_elts),
1160 TAG(render_quads_elts),
1161 TAG(render_quad_strip_elts),
1162 TAG(render_poly_elts),
1163 TAG(render_noop),
1164 };
1165
1166
1167
1168 #endif
1169
1170
1171
1172 /* Pre-check the primitives in the VB to prevent the need for
1173 * fallbacks later on.
1174 */
1175 static GLboolean TAG(validate_render)( GLcontext *ctx,
1176 struct vertex_buffer *VB )
1177 {
1178 GLint i;
1179
1180 if (VB->ClipOrMask & ~CLIP_CULL_BIT)
1181 return GL_FALSE;
1182
1183 if (VB->Elts && !HAVE_ELTS)
1184 return GL_FALSE;
1185
1186 for (i = 0 ; i < VB->PrimitiveCount ; i++) {
1187 GLuint prim = VB->Primitive[i].mode;
1188 GLuint count = VB->Primitive[i].count;
1189 GLboolean ok = GL_FALSE;
1190
1191 if (!count)
1192 continue;
1193
1194 switch (prim & PRIM_MODE_MASK) {
1195 case GL_POINTS:
1196 ok = HAVE_POINTS;
1197 break;
1198 case GL_LINES:
1199 ok = HAVE_LINES && !ctx->Line.StippleFlag;
1200 break;
1201 case GL_LINE_STRIP:
1202 ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
1203 break;
1204 case GL_LINE_LOOP:
1205 ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
1206 break;
1207 case GL_TRIANGLES:
1208 ok = HAVE_TRIANGLES;
1209 break;
1210 case GL_TRIANGLE_STRIP:
1211 ok = HAVE_TRI_STRIPS;
1212 break;
1213 case GL_TRIANGLE_FAN:
1214 ok = HAVE_TRI_FANS;
1215 break;
1216 case GL_POLYGON:
1217 if (HAVE_POLYGONS) {
1218 ok = GL_TRUE;
1219 }
1220 else {
1221 ok = (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH);
1222 }
1223 break;
1224 case GL_QUAD_STRIP:
1225 if (VB->Elts) {
1226 ok = HAVE_TRI_STRIPS;
1227 }
1228 else if (HAVE_QUAD_STRIPS) {
1229 ok = GL_TRUE;
1230 } else if (HAVE_TRI_STRIPS &&
1231 ctx->Light.ShadeModel == GL_FLAT &&
1232 VB->ColorPtr[0]->stride != 0) {
1233 if (HAVE_ELTS) {
1234 ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
1235 }
1236 else {
1237 ok = GL_FALSE;
1238 }
1239 }
1240 else
1241 ok = HAVE_TRI_STRIPS;
1242 break;
1243 case GL_QUADS:
1244 if (HAVE_QUADS) {
1245 ok = GL_TRUE;
1246 } else if (HAVE_ELTS) {
1247 ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
1248 }
1249 else {
1250 ok = HAVE_TRIANGLES; /* flatshading is ok. */
1251 }
1252 break;
1253 default:
1254 break;
1255 }
1256
1257 if (!ok) {
1258 /* fprintf(stderr, "not ok %s\n", _mesa_lookup_enum_by_nr(prim & PRIM_MODE_MASK)); */
1259 return GL_FALSE;
1260 }
1261 }
1262
1263 return GL_TRUE;
1264 }
1265