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