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