t_dd_dmatmp: Require HAVE_TRI_STRIPS
[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 !HAVE_TRIANGLES || !HAVE_LINES || !HAVE_LINE_STRIPS || !HAVE_TRI_STRIPS
43 #error "must have lines, line strips, triangles, and triangle strips to use render template"
44 #endif
45
46 #if HAVE_QUAD_STRIPS || HAVE_QUADS
47 #error "quads and quad strips not supported by render template"
48 #endif
49
50 #if !HAVE_ELTS
51 #define ELTS_VARS(buf)
52 #define ALLOC_ELTS(nr) 0
53 #define EMIT_ELT( offset, elt )
54 #define EMIT_TWO_ELTS( offset, elt0, elt1 )
55 #define INCR_ELTS( nr )
56 #define ELT_INIT(prim)
57 #define GET_CURRENT_VB_MAX_ELTS() 0
58 #define GET_SUBSEQUENT_VB_MAX_ELTS() 0
59 #define RELEASE_ELT_VERTS()
60 #define EMIT_INDEXED_VERTS( ctx, start, count )
61 #endif
62
63 #ifndef EMIT_TWO_ELTS
64 #define EMIT_TWO_ELTS( offset, elt0, elt1 ) \
65 do { \
66 EMIT_ELT( offset, elt0 ); \
67 EMIT_ELT( offset+1, elt1 ); \
68 } while (0)
69 #endif
70
71
72 /**********************************************************************/
73 /* Render whole begin/end objects */
74 /**********************************************************************/
75
76
77
78
79 #if (HAVE_ELTS)
80 static void *TAG(emit_elts)( struct gl_context *ctx, GLuint *elts, GLuint nr,
81 void *buf)
82 {
83 GLint i;
84 LOCAL_VARS;
85 ELTS_VARS(buf);
86
87 for ( i = 0 ; i+1 < nr ; i+=2, elts += 2 ) {
88 EMIT_TWO_ELTS( 0, elts[0], elts[1] );
89 INCR_ELTS( 2 );
90 }
91
92 if (i < nr) {
93 EMIT_ELT( 0, elts[0] );
94 INCR_ELTS( 1 );
95 }
96
97 return (void *)ELTPTR;
98 }
99 #endif
100
101 static __inline void *TAG(emit_verts)( struct gl_context *ctx, GLuint start,
102 GLuint count, void *buf )
103 {
104 return EMIT_VERTS(ctx, start, count, buf);
105 }
106
107 /***********************************************************************
108 * Render non-indexed primitives.
109 ***********************************************************************/
110
111 static void TAG(render_points_verts)( struct gl_context *ctx,
112 GLuint start,
113 GLuint count,
114 GLuint flags )
115 {
116 if (HAVE_POINTS) {
117 LOCAL_VARS;
118 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
119 int currentsz;
120 GLuint j, nr;
121
122 INIT( GL_POINTS );
123
124 currentsz = GET_CURRENT_VB_MAX_VERTS();
125 if (currentsz < 8)
126 currentsz = dmasz;
127
128 for (j = 0; j < count; j += nr) {
129 nr = MIN2( currentsz, count - j );
130 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
131 currentsz = dmasz;
132 }
133
134 } else {
135 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
136 return;
137 }
138 }
139
140 static void TAG(render_lines_verts)(struct gl_context *ctx,
141 GLuint start,
142 GLuint count,
143 GLuint flags)
144 {
145 LOCAL_VARS;
146 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
147 int currentsz;
148 GLuint j, nr;
149
150 INIT(GL_LINES);
151
152 /* Emit whole number of lines in total and in each buffer:
153 */
154 count -= count & 1;
155 currentsz = GET_CURRENT_VB_MAX_VERTS();
156 currentsz -= currentsz & 1;
157 dmasz -= dmasz & 1;
158
159 if (currentsz < 8)
160 currentsz = dmasz;
161
162 for (j = 0; j < count; j += nr) {
163 nr = MIN2(currentsz, count - j);
164 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
165 currentsz = dmasz;
166 }
167 }
168
169
170 static void TAG(render_line_strip_verts)(struct gl_context *ctx,
171 GLuint start,
172 GLuint count,
173 GLuint flags)
174 {
175 LOCAL_VARS;
176 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
177 int currentsz;
178 GLuint j, nr;
179
180 INIT(GL_LINE_STRIP);
181
182 currentsz = GET_CURRENT_VB_MAX_VERTS();
183 if (currentsz < 8)
184 currentsz = dmasz;
185
186 for (j = 0; j + 1 < count; j += nr - 1) {
187 nr = MIN2(currentsz, count - j);
188 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
189 currentsz = dmasz;
190 }
191
192 FLUSH();
193 }
194
195
196 static void TAG(render_line_loop_verts)(struct gl_context *ctx,
197 GLuint start,
198 GLuint count,
199 GLuint flags)
200 {
201 LOCAL_VARS;
202 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
203 int currentsz;
204 GLuint j, nr;
205
206 INIT(GL_LINE_STRIP);
207
208 j = (flags & PRIM_BEGIN) ? 0 : 1;
209
210 /* Ensure last vertex won't wrap buffers:
211 */
212 currentsz = GET_CURRENT_VB_MAX_VERTS();
213 currentsz--;
214 dmasz--;
215
216 if (currentsz < 8)
217 currentsz = dmasz;
218
219 if (j + 1 < count) {
220 for (/* empty */; j + 1 < count; j += nr - 1) {
221 nr = MIN2(currentsz, count - j);
222
223 if (j + nr >= count &&
224 count > 1 &&
225 (flags & PRIM_END)) {
226 void *tmp;
227 tmp = ALLOC_VERTS(nr+1);
228 tmp = TAG(emit_verts)(ctx, start + j, nr, tmp);
229 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
230 (void) tmp;
231 } else {
232 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
233 currentsz = dmasz;
234 }
235 }
236 } else if (count > 1 && (flags & PRIM_END)) {
237 void *tmp;
238 tmp = ALLOC_VERTS(2);
239 tmp = TAG(emit_verts)( ctx, start+1, 1, tmp );
240 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
241 (void) tmp;
242 }
243
244 FLUSH();
245 }
246
247
248 static void TAG(render_triangles_verts)( struct gl_context *ctx,
249 GLuint start,
250 GLuint count,
251 GLuint flags )
252 {
253 LOCAL_VARS;
254 int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/3) * 3;
255 int currentsz;
256 GLuint j, nr;
257
258 INIT(GL_TRIANGLES);
259
260 currentsz = (GET_CURRENT_VB_MAX_VERTS()/3) * 3;
261
262 /* Emit whole number of tris in total. dmasz is already a multiple
263 * of 3.
264 */
265 count -= count % 3;
266
267 if (currentsz < 8)
268 currentsz = dmasz;
269
270 for (j = 0; j < count; j += nr) {
271 nr = MIN2( currentsz, count - j );
272 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
273 currentsz = dmasz;
274 }
275 }
276
277
278
279 static void TAG(render_tri_strip_verts)( struct gl_context *ctx,
280 GLuint start,
281 GLuint count,
282 GLuint flags )
283 {
284 LOCAL_VARS;
285 GLuint j, nr;
286 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
287 int currentsz;
288
289 INIT(GL_TRIANGLE_STRIP);
290
291 currentsz = GET_CURRENT_VB_MAX_VERTS();
292
293 if (currentsz < 8) {
294 currentsz = dmasz;
295 }
296
297 /* From here on emit even numbers of tris when wrapping over buffers:
298 */
299 dmasz -= (dmasz & 1);
300 currentsz -= (currentsz & 1);
301
302 for (j = 0; j + 2 < count; j += nr - 2) {
303 nr = MIN2( currentsz, count - j );
304 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
305 currentsz = dmasz;
306 }
307
308 FLUSH();
309 }
310
311 static void TAG(render_tri_fan_verts)( struct gl_context *ctx,
312 GLuint start,
313 GLuint count,
314 GLuint flags )
315 {
316 if (HAVE_TRI_FANS) {
317 LOCAL_VARS;
318 GLuint j, nr;
319 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
320 int currentsz;
321
322 INIT(GL_TRIANGLE_FAN);
323
324 currentsz = GET_CURRENT_VB_MAX_VERTS();
325 if (currentsz < 8) {
326 currentsz = dmasz;
327 }
328
329 for (j = 1; j + 1 < count; j += nr - 2) {
330 void *tmp;
331 nr = MIN2( currentsz, count - j + 1 );
332 tmp = ALLOC_VERTS( nr );
333 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
334 tmp = TAG(emit_verts)( ctx, start + j, nr - 1, tmp );
335 (void) tmp;
336 currentsz = dmasz;
337 }
338
339 FLUSH();
340 }
341 else {
342 /* Could write code to emit these as indexed vertices (for the
343 * g400, for instance).
344 */
345 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
346 return;
347 }
348 }
349
350
351 static void TAG(render_poly_verts)( struct gl_context *ctx,
352 GLuint start,
353 GLuint count,
354 GLuint flags )
355 {
356 if (HAVE_POLYGONS) {
357 LOCAL_VARS;
358 GLuint j, nr;
359 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
360 int currentsz;
361
362 INIT(GL_POLYGON);
363
364 currentsz = GET_CURRENT_VB_MAX_VERTS();
365 if (currentsz < 8) {
366 currentsz = dmasz;
367 }
368
369 for (j = 1 ; j + 1 < count ; j += nr - 2 ) {
370 void *tmp;
371 nr = MIN2( currentsz, count - j + 1 );
372 tmp = ALLOC_VERTS( nr );
373 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
374 tmp = TAG(emit_verts)(ctx, start + j, nr - 1, tmp);
375 (void) tmp;
376 currentsz = dmasz;
377 }
378
379 FLUSH();
380 }
381 else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
382 TAG(render_tri_fan_verts)( ctx, start, count, flags );
383 } else {
384 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
385 return;
386 }
387 }
388
389 static void TAG(render_quad_strip_verts)( struct gl_context *ctx,
390 GLuint start,
391 GLuint count,
392 GLuint flags )
393 {
394 GLuint j, nr;
395
396 if (ctx->Light.ShadeModel == GL_FLAT &&
397 TNL_CONTEXT(ctx)->vb.AttribPtr[_TNL_ATTRIB_COLOR0]->stride) {
398 if (HAVE_ELTS) {
399 LOCAL_VARS;
400 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
401 int currentsz;
402 GLuint j, nr;
403
404 EMIT_INDEXED_VERTS( ctx, start, count );
405
406 /* Simulate flat-shaded quadstrips using indexed vertices:
407 */
408 ELT_INIT( GL_TRIANGLES );
409
410 currentsz = GET_CURRENT_VB_MAX_ELTS();
411
412 /* Emit whole number of quads in total, and in each buffer.
413 */
414 dmasz -= dmasz & 1;
415 count -= count & 1;
416 currentsz -= currentsz & 1;
417
418 if (currentsz < 12)
419 currentsz = dmasz;
420
421 currentsz = currentsz/6*2;
422 dmasz = dmasz/6*2;
423
424 for (j = 0; j + 3 < count; j += nr - 2) {
425 nr = MIN2( currentsz, count - j );
426 if (nr >= 4) {
427 GLint quads = (nr/2)-1;
428 GLint i;
429 ELTS_VARS( ALLOC_ELTS( quads*6 ) );
430
431 for (i = j; i < j + quads * 2; i += 2) {
432 EMIT_TWO_ELTS( 0, (i+0), (i+1) );
433 EMIT_TWO_ELTS( 2, (i+2), (i+1) );
434 EMIT_TWO_ELTS( 4, (i+3), (i+2) );
435 INCR_ELTS( 6 );
436 }
437
438 FLUSH();
439 }
440 currentsz = dmasz;
441 }
442
443 RELEASE_ELT_VERTS();
444 FLUSH();
445 }
446 else {
447 /* Vertices won't fit in a single buffer or elts not
448 * available - should never happen.
449 */
450 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
451 return;
452 }
453 }
454 else {
455 LOCAL_VARS;
456 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
457 int currentsz;
458
459 /* Emit smooth-shaded quadstrips as tristrips:
460 */
461 FLUSH();
462 INIT( GL_TRIANGLE_STRIP );
463
464 /* Emit whole number of quads in total, and in each buffer.
465 */
466 dmasz -= dmasz & 1;
467 currentsz = GET_CURRENT_VB_MAX_VERTS();
468 currentsz -= currentsz & 1;
469 count -= count & 1;
470
471 if (currentsz < 8) {
472 currentsz = dmasz;
473 }
474
475 for (j = 0; j + 3 < count; j += nr - 2) {
476 nr = MIN2( currentsz, count - j );
477 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
478 currentsz = dmasz;
479 }
480
481 FLUSH();
482 }
483 }
484
485
486 static void TAG(render_quads_verts)(struct gl_context *ctx,
487 GLuint start,
488 GLuint count,
489 GLuint flags)
490 {
491 /* Emit whole number of quads in total. */
492 count -= count & 3;
493
494 if (HAVE_ELTS) {
495 /* Hardware doesn't have a quad primitive type -- try to
496 * simulate it using indexed vertices and the triangle
497 * primitive:
498 */
499 LOCAL_VARS;
500 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
501 int currentsz;
502 GLuint j, nr;
503
504 EMIT_INDEXED_VERTS( ctx, start, count );
505
506 FLUSH();
507 ELT_INIT( GL_TRIANGLES );
508 currentsz = GET_CURRENT_VB_MAX_ELTS();
509
510 /* Emit whole number of quads in total, and in each buffer.
511 */
512 dmasz -= dmasz & 3;
513 currentsz -= currentsz & 3;
514
515 /* Adjust for rendering as triangles:
516 */
517 currentsz = currentsz/6*4;
518 dmasz = dmasz/6*4;
519
520 if (currentsz < 8)
521 currentsz = dmasz;
522
523 for (j = 0; j < count; j += nr ) {
524 nr = MIN2( currentsz, count - j );
525 if (nr >= 4) {
526 GLint quads = nr/4;
527 GLint i;
528 ELTS_VARS( ALLOC_ELTS( quads*6 ) );
529
530 for (i = j; i < j + quads * 4; i += 4) {
531 EMIT_TWO_ELTS( 0, (i+0), (i+1) );
532 EMIT_TWO_ELTS( 2, (i+3), (i+1) );
533 EMIT_TWO_ELTS( 4, (i+2), (i+3) );
534 INCR_ELTS( 6 );
535 }
536
537 FLUSH();
538 }
539 currentsz = dmasz;
540 }
541
542 RELEASE_ELT_VERTS();
543 }
544 else {
545 /* Hardware doesn't have a quad primitive type -- try to
546 * simulate it using triangle primitive. This is a win for
547 * gears, but is it useful in the broader world?
548 */
549 LOCAL_VARS;
550 GLuint j;
551
552 INIT(GL_TRIANGLES);
553
554 for (j = 0; j + 3 < count; j += 4) {
555 void *tmp = ALLOC_VERTS( 6 );
556 /* Send v0, v1, v3
557 */
558 tmp = EMIT_VERTS(ctx, start + j, 2, tmp);
559 tmp = EMIT_VERTS(ctx, start + j + 3, 1, tmp);
560 /* Send v1, v2, v3
561 */
562 tmp = EMIT_VERTS(ctx, start + j + 1, 3, tmp);
563 (void) tmp;
564 }
565 }
566 }
567
568 static void TAG(render_noop)( struct gl_context *ctx,
569 GLuint start,
570 GLuint count,
571 GLuint flags )
572 {
573 }
574
575
576
577
578 static tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] =
579 {
580 TAG(render_points_verts),
581 TAG(render_lines_verts),
582 TAG(render_line_loop_verts),
583 TAG(render_line_strip_verts),
584 TAG(render_triangles_verts),
585 TAG(render_tri_strip_verts),
586 TAG(render_tri_fan_verts),
587 TAG(render_quads_verts),
588 TAG(render_quad_strip_verts),
589 TAG(render_poly_verts),
590 TAG(render_noop),
591 };
592
593
594 /****************************************************************************
595 * Render elts using hardware indexed verts *
596 ****************************************************************************/
597
598 #if (HAVE_ELTS)
599 static void TAG(render_points_elts)( struct gl_context *ctx,
600 GLuint start,
601 GLuint count,
602 GLuint flags )
603 {
604 if (HAVE_POINTS) {
605 LOCAL_VARS;
606 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
607 int currentsz;
608 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
609 GLuint j, nr;
610
611 ELT_INIT( GL_POINTS );
612
613 currentsz = GET_CURRENT_VB_MAX_ELTS();
614 if (currentsz < 8)
615 currentsz = dmasz;
616
617 for (j = 0; j < count; j += nr ) {
618 nr = MIN2( currentsz, count - j );
619 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
620 FLUSH();
621 currentsz = dmasz;
622 }
623 } else {
624 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
625 return;
626 }
627 }
628
629
630
631 static void TAG(render_lines_elts)(struct gl_context *ctx,
632 GLuint start,
633 GLuint count,
634 GLuint flags)
635 {
636 LOCAL_VARS;
637 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
638 int currentsz;
639 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
640 GLuint j, nr;
641
642 ELT_INIT(GL_LINES);
643
644 /* Emit whole number of lines in total and in each buffer:
645 */
646 count -= count & 1;
647 currentsz -= currentsz & 1;
648 dmasz -= dmasz & 1;
649
650 currentsz = GET_CURRENT_VB_MAX_ELTS();
651 if (currentsz < 8)
652 currentsz = dmasz;
653
654 for (j = 0; j < count; j += nr ) {
655 nr = MIN2(currentsz, count - j);
656 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
657 FLUSH();
658 currentsz = dmasz;
659 }
660 }
661
662
663 static void TAG(render_line_strip_elts)(struct gl_context *ctx,
664 GLuint start,
665 GLuint count,
666 GLuint flags)
667 {
668 LOCAL_VARS;
669 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
670 int currentsz;
671 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
672 GLuint j, nr;
673
674 FLUSH(); /* always a new primitive */
675 ELT_INIT(GL_LINE_STRIP);
676
677 currentsz = GET_CURRENT_VB_MAX_ELTS();
678 if (currentsz < 8)
679 currentsz = dmasz;
680
681 for (j = 0; j + 1 < count; j += nr - 1) {
682 nr = MIN2(currentsz, count - j);
683 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
684 FLUSH();
685 currentsz = dmasz;
686 }
687 }
688
689
690 static void TAG(render_line_loop_elts)(struct gl_context *ctx,
691 GLuint start,
692 GLuint count,
693 GLuint flags)
694 {
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 FLUSH();
702 ELT_INIT(GL_LINE_STRIP);
703
704 j = (flags & PRIM_BEGIN) ? 0 : 1;
705
706 currentsz = GET_CURRENT_VB_MAX_ELTS();
707 if (currentsz < 8)
708 currentsz = dmasz;
709
710 /* Ensure last vertex doesn't wrap:
711 */
712 currentsz--;
713 dmasz--;
714
715 if (j + 1 < count) {
716 for (/* empty */; j + 1 < count; j += nr - 1) {
717 nr = MIN2(currentsz, count - j);
718
719 if (j + nr >= count &&
720 count > 1 &&
721 (flags & PRIM_END)) {
722 void *tmp;
723 tmp = ALLOC_ELTS(nr+1);
724 tmp = TAG(emit_elts)(ctx, elts + start + j, nr, tmp);
725 tmp = TAG(emit_elts)(ctx, elts + start, 1, tmp);
726 (void) tmp;
727 } else {
728 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
729 currentsz = dmasz;
730 }
731 }
732 } else if (count > 1 && (flags & PRIM_END)) {
733 void *tmp;
734 tmp = ALLOC_ELTS(2);
735 tmp = TAG(emit_elts)( ctx, elts+start+1, 1, tmp );
736 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
737 (void) tmp;
738 }
739
740 FLUSH();
741 }
742
743
744 /* For verts, we still eliminate the copy from main memory to dma
745 * buffers. For elts, this is probably no better (worse?) than the
746 * standard path.
747 */
748 static void TAG(render_triangles_elts)( struct gl_context *ctx,
749 GLuint start,
750 GLuint count,
751 GLuint flags )
752 {
753 LOCAL_VARS;
754 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
755 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/3*3;
756 int currentsz;
757 GLuint j, nr;
758
759 FLUSH();
760 ELT_INIT( GL_TRIANGLES );
761
762 currentsz = GET_CURRENT_VB_MAX_ELTS();
763
764 /* Emit whole number of tris in total. dmasz is already a multiple
765 * of 3.
766 */
767 count -= count % 3;
768 currentsz -= currentsz%3;
769 if (currentsz < 8)
770 currentsz = dmasz;
771
772 for (j = 0; j < count; j += nr) {
773 nr = MIN2( currentsz, count - j );
774 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
775 FLUSH();
776 currentsz = dmasz;
777 }
778 }
779
780
781
782 static void TAG(render_tri_strip_elts)( struct gl_context *ctx,
783 GLuint start,
784 GLuint count,
785 GLuint flags )
786 {
787 LOCAL_VARS;
788 GLuint j, nr;
789 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
790 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
791 int currentsz;
792
793 FLUSH();
794 ELT_INIT( GL_TRIANGLE_STRIP );
795
796 currentsz = GET_CURRENT_VB_MAX_ELTS();
797 if (currentsz < 8) {
798 currentsz = dmasz;
799 }
800
801 /* Keep the same winding over multiple buffers:
802 */
803 dmasz -= (dmasz & 1);
804 currentsz -= (currentsz & 1);
805
806 for (j = 0; j + 2 < count; j += nr - 2) {
807 nr = MIN2( currentsz, count - j );
808 TAG(emit_elts)( ctx, elts + start + j, nr, ALLOC_ELTS(nr) );
809 FLUSH();
810 currentsz = dmasz;
811 }
812 }
813
814 static void TAG(render_tri_fan_elts)( struct gl_context *ctx,
815 GLuint start,
816 GLuint count,
817 GLuint flags )
818 {
819 if (HAVE_TRI_FANS) {
820 LOCAL_VARS;
821 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
822 GLuint j, nr;
823 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
824 int currentsz;
825
826 FLUSH();
827 ELT_INIT( GL_TRIANGLE_FAN );
828
829 currentsz = GET_CURRENT_VB_MAX_ELTS();
830 if (currentsz < 8) {
831 currentsz = dmasz;
832 }
833
834 for (j = 1; j + 1 < count; j += nr - 2) {
835 void *tmp;
836 nr = MIN2( currentsz, count - j + 1 );
837 tmp = ALLOC_ELTS( nr );
838 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
839 tmp = TAG(emit_elts)(ctx, elts + start + j, nr - 1, tmp);
840 (void) tmp;
841 FLUSH();
842 currentsz = dmasz;
843 }
844 } else {
845 /* TODO: try to emit as indexed triangles */
846 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
847 return;
848 }
849 }
850
851
852 static void TAG(render_poly_elts)( struct gl_context *ctx,
853 GLuint start,
854 GLuint count,
855 GLuint flags )
856 {
857 if (HAVE_POLYGONS) {
858 LOCAL_VARS;
859 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
860 GLuint j, nr;
861 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
862 int currentsz;
863
864 FLUSH();
865 ELT_INIT( GL_POLYGON );
866
867 currentsz = GET_CURRENT_VB_MAX_ELTS();
868 if (currentsz < 8) {
869 currentsz = dmasz;
870 }
871
872 for (j = 1 ; j + 1 < count; j += nr - 2) {
873 void *tmp;
874 nr = MIN2( currentsz, count - j + 1 );
875 tmp = ALLOC_ELTS( nr );
876 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
877 tmp = TAG(emit_elts)(ctx, elts + start + j, nr - 1, tmp);
878 (void) tmp;
879 FLUSH();
880 currentsz = dmasz;
881 }
882 } else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
883 TAG(render_tri_fan_verts)( ctx, start, count, flags );
884 } else {
885 fprintf(stderr, "%s - cannot draw primitive\n", __func__);
886 return;
887 }
888 }
889
890 static void TAG(render_quad_strip_elts)( struct gl_context *ctx,
891 GLuint start,
892 GLuint count,
893 GLuint flags )
894 {
895 LOCAL_VARS;
896 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
897 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
898 int currentsz;
899 GLuint j, nr;
900
901 FLUSH();
902 currentsz = GET_CURRENT_VB_MAX_ELTS();
903
904 /* Emit whole number of quads in total, and in each buffer.
905 */
906 dmasz -= dmasz & 1;
907 count -= count & 1;
908 currentsz -= currentsz & 1;
909
910 if (currentsz < 12)
911 currentsz = dmasz;
912
913 if (ctx->Light.ShadeModel == GL_FLAT) {
914 ELT_INIT( GL_TRIANGLES );
915
916 currentsz = currentsz/6*2;
917 dmasz = dmasz/6*2;
918
919 for (j = 0; j + 3 < count; j += nr - 2) {
920 nr = MIN2( currentsz, count - j );
921
922 if (nr >= 4)
923 {
924 GLint i;
925 GLint quads = (nr/2)-1;
926 ELTS_VARS( ALLOC_ELTS( quads*6 ) );
927
928 for (i = j; i < j + quads; i++, elts += 2) {
929 EMIT_TWO_ELTS( 0, elts[0], elts[1] );
930 EMIT_TWO_ELTS( 2, elts[2], elts[1] );
931 EMIT_TWO_ELTS( 4, elts[3], elts[2] );
932 INCR_ELTS( 6 );
933 }
934
935 FLUSH();
936 }
937
938 currentsz = dmasz;
939 }
940 }
941 else {
942 ELT_INIT( GL_TRIANGLE_STRIP );
943
944 for (j = 0; j + 3 < count; j += nr - 2) {
945 nr = MIN2( currentsz, count - j );
946 TAG(emit_elts)(ctx, elts + start + j, nr, ALLOC_ELTS(nr));
947 FLUSH();
948 currentsz = dmasz;
949 }
950 }
951 }
952
953
954 static void TAG(render_quads_elts)(struct gl_context *ctx,
955 GLuint start,
956 GLuint count,
957 GLuint flags)
958 {
959 LOCAL_VARS;
960 GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
961 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
962 int currentsz;
963 GLuint j, nr;
964
965 ELT_INIT(GL_TRIANGLES);
966 currentsz = GET_CURRENT_VB_MAX_ELTS();
967
968 /* Emit whole number of quads in total, and in each buffer.
969 */
970 count -= count & 3;
971 dmasz -= dmasz & 3;
972 currentsz -= currentsz & 3;
973
974 /* Adjust for rendering as triangles:
975 */
976 currentsz = currentsz / 6 * 4;
977 dmasz = dmasz / 6 * 4;
978
979 if (currentsz < 8)
980 currentsz = dmasz;
981
982 for (j = 0; j + 3 < count; j += nr - 2) {
983 nr = MIN2(currentsz, count - j);
984
985 if (nr >= 4) {
986 GLint quads = nr / 4;
987 GLint i;
988 ELTS_VARS(ALLOC_ELTS(quads * 6));
989
990 for (i = j; i < j + quads; i++, elts += 4) {
991 EMIT_TWO_ELTS(0, elts[0], elts[1]);
992 EMIT_TWO_ELTS(2, elts[3], elts[1]);
993 EMIT_TWO_ELTS(4, elts[2], elts[3]);
994 INCR_ELTS(6);
995 }
996
997 FLUSH();
998 }
999
1000 currentsz = dmasz;
1001 }
1002 }
1003
1004
1005
1006 static tnl_render_func TAG(render_tab_elts)[GL_POLYGON+2] =
1007 {
1008 TAG(render_points_elts),
1009 TAG(render_lines_elts),
1010 TAG(render_line_loop_elts),
1011 TAG(render_line_strip_elts),
1012 TAG(render_triangles_elts),
1013 TAG(render_tri_strip_elts),
1014 TAG(render_tri_fan_elts),
1015 TAG(render_quads_elts),
1016 TAG(render_quad_strip_elts),
1017 TAG(render_poly_elts),
1018 TAG(render_noop),
1019 };
1020
1021
1022
1023 #endif
1024
1025
1026
1027 /* Pre-check the primitives in the VB to prevent the need for
1028 * fallbacks later on.
1029 */
1030 static GLboolean TAG(validate_render)( struct gl_context *ctx,
1031 struct vertex_buffer *VB )
1032 {
1033 GLint i;
1034
1035 if (VB->ClipOrMask & ~CLIP_CULL_BIT)
1036 return GL_FALSE;
1037
1038 if (VB->Elts && !HAVE_ELTS)
1039 return GL_FALSE;
1040
1041 for (i = 0 ; i < VB->PrimitiveCount ; i++) {
1042 GLuint prim = VB->Primitive[i].mode;
1043 GLuint count = VB->Primitive[i].count;
1044 GLboolean ok = GL_FALSE;
1045
1046 if (!count)
1047 continue;
1048
1049 switch (prim & PRIM_MODE_MASK) {
1050 case GL_POINTS:
1051 ok = HAVE_POINTS;
1052 break;
1053 case GL_LINES:
1054 case GL_LINE_STRIP:
1055 case GL_LINE_LOOP:
1056 ok = !ctx->Line.StippleFlag;
1057 break;
1058 case GL_TRIANGLES:
1059 ok = GL_TRUE;
1060 break;
1061 case GL_TRIANGLE_STRIP:
1062 ok = GL_TRUE;
1063 break;
1064 case GL_TRIANGLE_FAN:
1065 ok = HAVE_TRI_FANS;
1066 break;
1067 case GL_POLYGON:
1068 if (HAVE_POLYGONS) {
1069 ok = GL_TRUE;
1070 }
1071 else {
1072 ok = (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH);
1073 }
1074 break;
1075 case GL_QUAD_STRIP:
1076 if (VB->Elts) {
1077 ok = GL_TRUE;
1078 } else if (ctx->Light.ShadeModel == GL_FLAT &&
1079 VB->AttribPtr[_TNL_ATTRIB_COLOR0]->stride != 0) {
1080 if (HAVE_ELTS) {
1081 ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
1082 }
1083 else {
1084 ok = GL_FALSE;
1085 }
1086 }
1087 else
1088 ok = GL_TRUE;
1089 break;
1090 case GL_QUADS:
1091 if (HAVE_ELTS) {
1092 ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
1093 }
1094 else {
1095 ok = GL_TRUE; /* flatshading is ok. */
1096 }
1097 break;
1098 default:
1099 break;
1100 }
1101
1102 if (!ok) {
1103 /* fprintf(stderr, "not ok %s\n", _mesa_enum_to_string(prim & PRIM_MODE_MASK)); */
1104 return GL_FALSE;
1105 }
1106 }
1107
1108 return GL_TRUE;
1109 }
1110