2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
25 * Keith Whitwell <keith@tungstengraphics.com>
30 * \file t_dd_dmatmp2.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.
38 #if !HAVE_TRIANGLES || !HAVE_POINTS || !HAVE_LINES
39 #error "must have points, lines & triangles to use render template"
42 #if !HAVE_TRI_STRIPS || !HAVE_TRI_FANS
43 #error "must have tri strip and fans to use render template"
47 #error "must have line strips to use render template"
51 #error "must have polygons to use render template"
55 #error "must have elts to use render template"
60 #define EMIT_TWO_ELTS( dest, offset, elt0, elt1 ) \
62 (dest)[offset] = (elt0); \
63 (dest)[offset+1] = (elt1); \
68 /**********************************************************************/
69 /* Render whole begin/end objects */
70 /**********************************************************************/
73 static ELT_TYPE
*TAG(emit_elts
)( GLcontext
*ctx
,
75 GLuint
*elts
, GLuint nr
)
80 for ( i
= 0 ; i
+1 < nr
; i
+=2, elts
+= 2 ) {
81 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
85 EMIT_ELT( dest
, 0, elts
[0] );
92 static ELT_TYPE
*TAG(emit_consecutive_elts
)( GLcontext
*ctx
,
94 GLuint start
, GLuint nr
)
99 for ( i
= 0 ; i
+1 < nr
; i
+=2, start
+= 2 ) {
100 EMIT_TWO_ELTS( dest
, 0, start
, start
+1 );
104 EMIT_ELT( dest
, 0, start
);
111 /***********************************************************************
112 * Render non-indexed primitives.
113 ***********************************************************************/
117 static void TAG(render_points_verts
)( GLcontext
*ctx
,
124 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
125 EMIT_PRIM( ctx
, GL_POINTS
, HW_POINTS
, start
, count
);
129 static void TAG(render_lines_verts
)( GLcontext
*ctx
,
135 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
136 count
-= (count
-start
) & 1;
138 if (start
+1 >= count
)
141 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
) {
143 AUTO_STIPPLE( GL_TRUE
);
146 EMIT_PRIM( ctx
, GL_LINES
, HW_LINES
, start
, count
);
148 if ((flags
& PRIM_END
) && ctx
->Line
.StippleFlag
)
149 AUTO_STIPPLE( GL_FALSE
);
153 static void TAG(render_line_strip_verts
)( GLcontext
*ctx
,
159 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
161 if (start
+1 >= count
)
164 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
168 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_LINES
))
170 int dmasz
= GET_MAX_HW_ELTS();
173 ELT_INIT( GL_LINES
, HW_LINES
);
175 /* Emit whole number of lines in each full buffer.
180 for (j
= start
; j
+ 1 < count
; j
+= nr
- 1 ) {
184 nr
= MIN2( dmasz
, count
- j
);
185 dest
= ALLOC_ELTS( (nr
-1)*2 );
187 for ( i
= j
; i
+1 < j
+nr
; i
+=1 ) {
188 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
196 EMIT_PRIM( ctx
, GL_LINE_STRIP
, HW_LINE_STRIP
, start
, count
);
200 static void TAG(render_line_loop_verts
)( GLcontext
*ctx
,
207 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
209 if (flags
& PRIM_BEGIN
) {
211 if (ctx
->Line
.StippleFlag
)
217 if (flags
& PRIM_END
) {
219 if (start
+1 >= count
)
222 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_LINES
)) {
223 int dmasz
= GET_MAX_HW_ELTS();
225 ELT_INIT( GL_LINES
, HW_LINES
);
227 /* Emit whole number of lines in each full buffer.
231 /* Ensure last vertex doesn't wrap:
235 for (; j
+ 1 < count
; ) {
239 nr
= MIN2( dmasz
, count
- j
);
240 dest
= ALLOC_ELTS( nr
*2 ); /* allocs room for 1 more line */
242 for ( i
= 0 ; i
< nr
- 1 ; i
+=1 ) {
243 EMIT_TWO_ELTS( dest
, 0, (j
+i
), (j
+i
+1) );
249 /* Emit 1 more line into space alloced above */
250 if (j
+ 1 >= count
) {
251 EMIT_TWO_ELTS( dest
, 0, (j
), (start
) );
260 int dmasz
= GET_MAX_HW_ELTS() - 1;
262 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
264 for ( ; j
+ 1 < count
; ) {
265 nr
= MIN2( dmasz
, count
- j
);
266 if (j
+ nr
< count
) {
267 ELT_TYPE
*dest
= ALLOC_ELTS( nr
);
268 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, j
, nr
);
273 ELT_TYPE
*dest
= ALLOC_ELTS( nr
+ 1 );
274 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, j
, nr
);
275 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, start
, 1 );
282 TAG(render_line_strip_verts
)( ctx
, j
, count
, flags
);
287 static void TAG(render_triangles_verts
)( GLcontext
*ctx
,
293 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
295 count
-= (count
-start
)%3;
297 if (start
+2 >= count
) {
301 /* need a PREFER_DISCRETE_ELT_PRIM here too..
303 EMIT_PRIM( ctx
, GL_TRIANGLES
, HW_TRIANGLES
, start
, count
);
308 static void TAG(render_tri_strip_verts
)( GLcontext
*ctx
,
314 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
316 if (start
+ 2 >= count
)
319 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_TRIANGLES
))
321 int dmasz
= GET_MAX_HW_ELTS();
325 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
327 /* Emit even number of tris in each full buffer.
332 for (j
= start
; j
+ 2 < count
; j
+= nr
- 2 ) {
336 nr
= MIN2( dmasz
, count
- j
);
337 dest
= ALLOC_ELTS( (nr
-2)*3 );
339 for ( i
= j
; i
+2 < j
+nr
; i
++, parity
^=1 ) {
340 EMIT_ELT( dest
, 0, (i
+0+parity
) );
341 EMIT_ELT( dest
, 1, (i
+1-parity
) );
342 EMIT_ELT( dest
, 2, (i
+2) );
350 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
, start
, count
);
353 static void TAG(render_tri_fan_verts
)( GLcontext
*ctx
,
359 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
361 if (start
+2 >= count
)
364 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_TRIANGLES
))
366 int dmasz
= GET_MAX_HW_ELTS();
369 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
373 for (j
= start
+ 1; j
+ 1 < count
; j
+= nr
- 1 ) {
377 nr
= MIN2( dmasz
, count
- j
);
378 dest
= ALLOC_ELTS( (nr
-1)*3 );
380 for ( i
= j
; i
+1 < j
+nr
; i
++ ) {
381 EMIT_ELT( dest
, 0, (start
) );
382 EMIT_ELT( dest
, 1, (i
) );
383 EMIT_ELT( dest
, 2, (i
+1) );
391 EMIT_PRIM( ctx
, GL_TRIANGLE_FAN
, HW_TRIANGLE_FAN
, start
, count
);
396 static void TAG(render_poly_verts
)( GLcontext
*ctx
,
402 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
404 if (start
+2 >= count
)
407 EMIT_PRIM( ctx
, GL_POLYGON
, HW_POLYGON
, start
, count
);
410 static void TAG(render_quad_strip_verts
)( GLcontext
*ctx
,
416 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
418 count
-= (count
-start
) & 1;
420 if (start
+3 >= count
)
423 if (HAVE_QUAD_STRIPS
) {
424 EMIT_PRIM( ctx
, GL_QUAD_STRIP
, HW_QUAD_STRIP
, start
, count
);
426 else if (ctx
->Light
.ShadeModel
== GL_FLAT
) {
428 int dmasz
= GET_MAX_HW_ELTS();
431 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
433 /* Emit whole number of quads in total, and in each buffer.
437 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
441 nr
= MIN2( dmasz
, count
- j
);
443 dest
= ALLOC_ELTS( quads
*6 );
445 for ( i
= j
; i
< j
+quads
*2 ; i
+=2 ) {
446 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
447 EMIT_TWO_ELTS( dest
, 2, (i
+2), (i
+1) );
448 EMIT_TWO_ELTS( dest
, 4, (i
+3), (i
+2) );
456 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
, start
, count
);
461 static void TAG(render_quads_verts
)( GLcontext
*ctx
,
467 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
468 count
-= (count
-start
)%4;
470 if (start
+3 >= count
)
474 EMIT_PRIM( ctx
, GL_QUADS
, HW_QUADS
, start
, count
);
477 /* Hardware doesn't have a quad primitive type -- simulate it
478 * using indexed vertices and the triangle primitive:
481 int dmasz
= GET_MAX_HW_ELTS();
484 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
486 /* Adjust for rendering as triangles:
490 for (j
= start
; j
< count
; j
+= nr
) {
494 nr
= MIN2( dmasz
, count
- j
);
496 dest
= ALLOC_ELTS( quads
*6 );
498 for ( i
= j
; i
< j
+quads
*4 ; i
+=4 ) {
499 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
500 EMIT_TWO_ELTS( dest
, 2, (i
+3), (i
+1) );
501 EMIT_TWO_ELTS( dest
, 4, (i
+2), (i
+3) );
510 static void TAG(render_noop
)( GLcontext
*ctx
,
520 static tnl_render_func
TAG(render_tab_verts
)[GL_POLYGON
+2] =
522 TAG(render_points_verts
),
523 TAG(render_lines_verts
),
524 TAG(render_line_loop_verts
),
525 TAG(render_line_strip_verts
),
526 TAG(render_triangles_verts
),
527 TAG(render_tri_strip_verts
),
528 TAG(render_tri_fan_verts
),
529 TAG(render_quads_verts
),
530 TAG(render_quad_strip_verts
),
531 TAG(render_poly_verts
),
536 /****************************************************************************
537 * Render elts using hardware indexed verts *
538 ****************************************************************************/
540 static void TAG(render_points_elts
)( GLcontext
*ctx
,
546 int dmasz
= GET_MAX_HW_ELTS();
547 GLuint
*elts
= GET_MESA_ELTS();
551 ELT_INIT( GL_POINTS
, HW_POINTS
);
553 for (j
= start
; j
< count
; j
+= nr
) {
554 nr
= MIN2( dmasz
, count
- j
);
555 dest
= ALLOC_ELTS( nr
);
556 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
563 static void TAG(render_lines_elts
)( GLcontext
*ctx
,
569 int dmasz
= GET_MAX_HW_ELTS();
570 GLuint
*elts
= GET_MESA_ELTS();
574 if (start
+1 >= count
)
577 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
) {
579 AUTO_STIPPLE( GL_TRUE
);
582 ELT_INIT( GL_LINES
, HW_LINES
);
584 /* Emit whole number of lines in total and in each buffer:
586 count
-= (count
-start
) & 1;
589 for (j
= start
; j
< count
; j
+= nr
) {
590 nr
= MIN2( dmasz
, count
- j
);
591 dest
= ALLOC_ELTS( nr
);
592 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
596 if ((flags
& PRIM_END
) && ctx
->Line
.StippleFlag
)
597 AUTO_STIPPLE( GL_FALSE
);
601 static void TAG(render_line_strip_elts
)( GLcontext
*ctx
,
607 int dmasz
= GET_MAX_HW_ELTS();
608 GLuint
*elts
= GET_MESA_ELTS();
612 if (start
+1 >= count
)
615 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
617 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
620 for (j
= start
; j
+ 1 < count
; j
+= nr
- 1 ) {
621 nr
= MIN2( dmasz
, count
- j
);
622 dest
= ALLOC_ELTS( nr
);
623 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
629 static void TAG(render_line_loop_elts
)( GLcontext
*ctx
,
635 int dmasz
= GET_MAX_HW_ELTS();
636 GLuint
*elts
= GET_MESA_ELTS();
640 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
642 if (flags
& PRIM_BEGIN
)
648 if (flags
& PRIM_END
) {
649 if (start
+1 >= count
)
657 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
659 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
663 /* Ensure last vertex doesn't wrap:
667 for ( ; j
+ 1 < count
; ) {
668 nr
= MIN2( dmasz
, count
- j
);
669 dest
= ALLOC_ELTS( nr
+1 ); /* Reserve possible space for last elt */
670 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
672 if (j
+ 1 >= count
&& (flags
& PRIM_END
)) {
673 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
680 static void TAG(render_triangles_elts
)( GLcontext
*ctx
,
686 GLuint
*elts
= GET_MESA_ELTS();
687 int dmasz
= GET_MAX_HW_ELTS()/3*3;
691 if (start
+2 >= count
)
694 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
697 /* Emit whole number of tris in total. dmasz is already a multiple
700 count
-= (count
-start
)%3;
702 for (j
= start
; j
< count
; j
+= nr
) {
703 nr
= MIN2( dmasz
, count
- j
);
704 dest
= ALLOC_ELTS( nr
);
705 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
712 static void TAG(render_tri_strip_elts
)( GLcontext
*ctx
,
719 GLuint
*elts
= GET_MESA_ELTS();
720 int dmasz
= GET_MAX_HW_ELTS();
723 if (start
+2 >= count
)
726 ELT_INIT( GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
);
728 /* Keep the same winding over multiple buffers:
730 dmasz
-= (dmasz
& 1);
732 for (j
= start
; j
+ 2 < count
; j
+= nr
- 2 ) {
733 nr
= MIN2( dmasz
, count
- j
);
735 dest
= ALLOC_ELTS( nr
);
736 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
741 static void TAG(render_tri_fan_elts
)( GLcontext
*ctx
,
747 GLuint
*elts
= GET_MESA_ELTS();
749 int dmasz
= GET_MAX_HW_ELTS();
752 if (start
+2 >= count
)
755 ELT_INIT( GL_TRIANGLE_FAN
, HW_TRIANGLE_FAN
);
757 for (j
= start
+ 1 ; j
+ 1 < count
; j
+= nr
- 1 ) {
758 nr
= MIN2( dmasz
, count
- j
+ 1 );
759 dest
= ALLOC_ELTS( nr
);
760 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
761 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
- 1 );
767 static void TAG(render_poly_elts
)( GLcontext
*ctx
,
773 GLuint
*elts
= GET_MESA_ELTS();
775 int dmasz
= GET_MAX_HW_ELTS();
778 if (start
+2 >= count
)
781 ELT_INIT( GL_POLYGON
, HW_POLYGON
);
783 for (j
= start
+ 1 ; j
+ 1 < count
; j
+= nr
- 1 ) {
784 nr
= MIN2( dmasz
, count
- j
+ 1 );
785 dest
= ALLOC_ELTS( nr
);
786 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
787 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
- 1 );
792 static void TAG(render_quad_strip_elts
)( GLcontext
*ctx
,
797 if (start
+3 >= count
)
800 if (HAVE_QUAD_STRIPS
&& 0) {
804 GLuint
*elts
= GET_MESA_ELTS();
805 int dmasz
= GET_MAX_HW_ELTS();
809 /* Emit whole number of quads in total, and in each buffer.
812 count
-= (count
-start
) & 1;
814 if (ctx
->Light
.ShadeModel
== GL_FLAT
) {
815 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
819 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
820 nr
= MIN2( dmasz
, count
- j
);
824 GLint quads
= (nr
/2)-1;
825 ELT_TYPE
*dest
= ALLOC_ELTS( quads
*6 );
828 for ( i
= j
-start
; i
< j
-start
+quads
; i
++, elts
+= 2 ) {
829 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
830 EMIT_TWO_ELTS( dest
, 2, elts
[2], elts
[1] );
831 EMIT_TWO_ELTS( dest
, 4, elts
[3], elts
[2] );
840 ELT_INIT( GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
);
842 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
843 nr
= MIN2( dmasz
, count
- j
);
844 dest
= ALLOC_ELTS( nr
);
845 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
853 static void TAG(render_quads_elts
)( GLcontext
*ctx
,
858 if (start
+3 >= count
)
861 if (HAVE_QUADS
&& 0) {
864 GLuint
*elts
= GET_MESA_ELTS();
865 int dmasz
= GET_MAX_HW_ELTS();
868 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
870 /* Emit whole number of quads in total, and in each buffer.
873 count
-= (count
-start
) & 3;
875 /* Adjust for rendering as triangles:
879 for (j
= start
; j
+ 3 < count
; j
+= nr
) {
880 nr
= MIN2( dmasz
, count
- j
);
884 ELT_TYPE
*dest
= ALLOC_ELTS( quads
* 6 );
887 for ( i
= j
-start
; i
< j
-start
+quads
; i
++, elts
+= 4 ) {
888 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
889 EMIT_TWO_ELTS( dest
, 2, elts
[3], elts
[1] );
890 EMIT_TWO_ELTS( dest
, 4, elts
[2], elts
[3] );
902 static tnl_render_func
TAG(render_tab_elts
)[GL_POLYGON
+2] =
904 TAG(render_points_elts
),
905 TAG(render_lines_elts
),
906 TAG(render_line_loop_elts
),
907 TAG(render_line_strip_elts
),
908 TAG(render_triangles_elts
),
909 TAG(render_tri_strip_elts
),
910 TAG(render_tri_fan_elts
),
911 TAG(render_quads_elts
),
912 TAG(render_quad_strip_elts
),
913 TAG(render_poly_elts
),