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 * THE AUTHORS OR COPYRIGHT HOLDERS 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
)( struct gl_context
*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
)( struct gl_context
*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
)( struct gl_context
*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
)( struct gl_context
*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
)( struct gl_context
*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
)( struct gl_context
*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
);
274 ELT_TYPE
*dest
= ALLOC_ELTS( nr
+ 1 );
275 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, j
, nr
);
276 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, start
, 1 );
284 TAG(render_line_strip_verts
)( ctx
, j
, count
, flags
);
289 static void TAG(render_triangles_verts
)( struct gl_context
*ctx
,
295 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
297 count
-= (count
-start
)%3;
299 if (start
+2 >= count
) {
303 /* need a PREFER_DISCRETE_ELT_PRIM here too..
305 EMIT_PRIM( ctx
, GL_TRIANGLES
, HW_TRIANGLES
, start
, count
);
310 static void TAG(render_tri_strip_verts
)( struct gl_context
*ctx
,
316 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
318 if (start
+ 2 >= count
)
321 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_TRIANGLES
))
323 int dmasz
= GET_MAX_HW_ELTS();
327 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
329 /* Emit even number of tris in each full buffer.
334 for (j
= start
; j
+ 2 < count
; j
+= nr
- 2 ) {
338 nr
= MIN2( dmasz
, count
- j
);
339 dest
= ALLOC_ELTS( (nr
-2)*3 );
341 for ( i
= j
; i
+2 < j
+nr
; i
++, parity
^=1 ) {
342 EMIT_ELT( dest
, 0, (i
+0+parity
) );
343 EMIT_ELT( dest
, 1, (i
+1-parity
) );
344 EMIT_ELT( dest
, 2, (i
+2) );
352 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
, start
, count
);
355 static void TAG(render_tri_fan_verts
)( struct gl_context
*ctx
,
361 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
363 if (start
+2 >= count
)
366 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_TRIANGLES
))
368 int dmasz
= GET_MAX_HW_ELTS();
371 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
375 for (j
= start
+ 1; j
+ 1 < count
; j
+= nr
- 1 ) {
379 nr
= MIN2( dmasz
, count
- j
);
380 dest
= ALLOC_ELTS( (nr
-1)*3 );
382 for ( i
= j
; i
+1 < j
+nr
; i
++ ) {
383 EMIT_ELT( dest
, 0, (start
) );
384 EMIT_ELT( dest
, 1, (i
) );
385 EMIT_ELT( dest
, 2, (i
+1) );
393 EMIT_PRIM( ctx
, GL_TRIANGLE_FAN
, HW_TRIANGLE_FAN
, start
, count
);
398 static void TAG(render_poly_verts
)( struct gl_context
*ctx
,
404 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
406 if (start
+2 >= count
)
409 EMIT_PRIM( ctx
, GL_POLYGON
, HW_POLYGON
, start
, count
);
412 static void TAG(render_quad_strip_verts
)( struct gl_context
*ctx
,
418 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
420 count
-= (count
-start
) & 1;
422 if (start
+3 >= count
)
425 if (HAVE_QUAD_STRIPS
) {
426 EMIT_PRIM( ctx
, GL_QUAD_STRIP
, HW_QUAD_STRIP
, start
, count
);
428 else if (ctx
->Light
.ShadeModel
== GL_FLAT
) {
430 int dmasz
= GET_MAX_HW_ELTS();
433 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
435 /* Emit whole number of quads in total, and in each buffer.
439 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
443 nr
= MIN2( dmasz
, count
- j
);
445 dest
= ALLOC_ELTS( quads
*6 );
447 for ( i
= j
; i
< j
+quads
*2 ; i
+=2 ) {
448 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
449 EMIT_TWO_ELTS( dest
, 2, (i
+2), (i
+1) );
450 EMIT_TWO_ELTS( dest
, 4, (i
+3), (i
+2) );
458 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
, start
, count
);
463 static void TAG(render_quads_verts
)( struct gl_context
*ctx
,
469 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
470 count
-= (count
-start
)%4;
472 if (start
+3 >= count
)
476 EMIT_PRIM( ctx
, GL_QUADS
, HW_QUADS
, start
, count
);
479 /* Hardware doesn't have a quad primitive type -- simulate it
480 * using indexed vertices and the triangle primitive:
483 int dmasz
= GET_MAX_HW_ELTS();
486 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
488 /* Adjust for rendering as triangles:
492 for (j
= start
; j
< count
; j
+= nr
) {
496 nr
= MIN2( dmasz
, count
- j
);
498 dest
= ALLOC_ELTS( quads
*6 );
500 for ( i
= j
; i
< j
+quads
*4 ; i
+=4 ) {
501 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
502 EMIT_TWO_ELTS( dest
, 2, (i
+3), (i
+1) );
503 EMIT_TWO_ELTS( dest
, 4, (i
+2), (i
+3) );
512 static void TAG(render_noop
)( struct gl_context
*ctx
,
522 static tnl_render_func
TAG(render_tab_verts
)[GL_POLYGON
+2] =
524 TAG(render_points_verts
),
525 TAG(render_lines_verts
),
526 TAG(render_line_loop_verts
),
527 TAG(render_line_strip_verts
),
528 TAG(render_triangles_verts
),
529 TAG(render_tri_strip_verts
),
530 TAG(render_tri_fan_verts
),
531 TAG(render_quads_verts
),
532 TAG(render_quad_strip_verts
),
533 TAG(render_poly_verts
),
538 /****************************************************************************
539 * Render elts using hardware indexed verts *
540 ****************************************************************************/
542 static void TAG(render_points_elts
)( struct gl_context
*ctx
,
548 int dmasz
= GET_MAX_HW_ELTS();
549 GLuint
*elts
= GET_MESA_ELTS();
553 ELT_INIT( GL_POINTS
, HW_POINTS
);
555 for (j
= start
; j
< count
; j
+= nr
) {
556 nr
= MIN2( dmasz
, count
- j
);
557 dest
= ALLOC_ELTS( nr
);
558 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
566 static void TAG(render_lines_elts
)( struct gl_context
*ctx
,
572 int dmasz
= GET_MAX_HW_ELTS();
573 GLuint
*elts
= GET_MESA_ELTS();
577 if (start
+1 >= count
)
580 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
) {
582 AUTO_STIPPLE( GL_TRUE
);
585 ELT_INIT( GL_LINES
, HW_LINES
);
587 /* Emit whole number of lines in total and in each buffer:
589 count
-= (count
-start
) & 1;
592 for (j
= start
; j
< count
; j
+= nr
) {
593 nr
= MIN2( dmasz
, count
- j
);
594 dest
= ALLOC_ELTS( nr
);
595 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
600 if ((flags
& PRIM_END
) && ctx
->Line
.StippleFlag
)
601 AUTO_STIPPLE( GL_FALSE
);
605 static void TAG(render_line_strip_elts
)( struct gl_context
*ctx
,
611 int dmasz
= GET_MAX_HW_ELTS();
612 GLuint
*elts
= GET_MESA_ELTS();
616 if (start
+1 >= count
)
619 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
621 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
624 for (j
= start
; j
+ 1 < count
; j
+= nr
- 1 ) {
625 nr
= MIN2( dmasz
, count
- j
);
626 dest
= ALLOC_ELTS( nr
);
627 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
634 static void TAG(render_line_loop_elts
)( struct gl_context
*ctx
,
640 int dmasz
= GET_MAX_HW_ELTS();
641 GLuint
*elts
= GET_MESA_ELTS();
645 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
647 if (flags
& PRIM_BEGIN
)
653 if (flags
& PRIM_END
) {
654 if (start
+1 >= count
)
662 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
664 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
668 /* Ensure last vertex doesn't wrap:
672 for ( ; j
+ 1 < count
; ) {
673 nr
= MIN2( dmasz
, count
- j
);
674 dest
= ALLOC_ELTS( nr
+1 ); /* Reserve possible space for last elt */
675 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
677 if (j
+ 1 >= count
&& (flags
& PRIM_END
)) {
678 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
686 static void TAG(render_triangles_elts
)( struct gl_context
*ctx
,
692 GLuint
*elts
= GET_MESA_ELTS();
693 int dmasz
= GET_MAX_HW_ELTS()/3*3;
697 if (start
+2 >= count
)
700 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
703 /* Emit whole number of tris in total. dmasz is already a multiple
706 count
-= (count
-start
)%3;
708 for (j
= start
; j
< count
; j
+= nr
) {
709 nr
= MIN2( dmasz
, count
- j
);
710 dest
= ALLOC_ELTS( nr
);
711 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
719 static void TAG(render_tri_strip_elts
)( struct gl_context
*ctx
,
726 GLuint
*elts
= GET_MESA_ELTS();
727 int dmasz
= GET_MAX_HW_ELTS();
730 if (start
+2 >= count
)
733 ELT_INIT( GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
);
735 /* Keep the same winding over multiple buffers:
737 dmasz
-= (dmasz
& 1);
739 for (j
= start
; j
+ 2 < count
; j
+= nr
- 2 ) {
740 nr
= MIN2( dmasz
, count
- j
);
742 dest
= ALLOC_ELTS( nr
);
743 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
749 static void TAG(render_tri_fan_elts
)( struct gl_context
*ctx
,
755 GLuint
*elts
= GET_MESA_ELTS();
757 int dmasz
= GET_MAX_HW_ELTS();
760 if (start
+2 >= count
)
763 ELT_INIT( GL_TRIANGLE_FAN
, HW_TRIANGLE_FAN
);
765 for (j
= start
+ 1 ; j
+ 1 < count
; j
+= nr
- 1 ) {
766 nr
= MIN2( dmasz
, count
- j
+ 1 );
767 dest
= ALLOC_ELTS( nr
);
768 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
769 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
- 1 );
776 static void TAG(render_poly_elts
)( struct gl_context
*ctx
,
782 GLuint
*elts
= GET_MESA_ELTS();
784 int dmasz
= GET_MAX_HW_ELTS();
787 if (start
+2 >= count
)
790 ELT_INIT( GL_POLYGON
, HW_POLYGON
);
792 for (j
= start
+ 1 ; j
+ 1 < count
; j
+= nr
- 1 ) {
793 nr
= MIN2( dmasz
, count
- j
+ 1 );
794 dest
= ALLOC_ELTS( nr
);
795 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
796 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
- 1 );
802 static void TAG(render_quad_strip_elts
)( struct gl_context
*ctx
,
807 if (start
+3 >= count
)
810 if (HAVE_QUAD_STRIPS
&& 0) {
814 GLuint
*elts
= GET_MESA_ELTS();
815 int dmasz
= GET_MAX_HW_ELTS();
819 /* Emit whole number of quads in total, and in each buffer.
822 count
-= (count
-start
) & 1;
824 if (ctx
->Light
.ShadeModel
== GL_FLAT
) {
825 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
829 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
830 nr
= MIN2( dmasz
, count
- j
);
834 GLint quads
= (nr
/2)-1;
835 ELT_TYPE
*dest
= ALLOC_ELTS( quads
*6 );
838 for ( i
= j
-start
; i
< j
-start
+quads
; i
++, elts
+= 2 ) {
839 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
840 EMIT_TWO_ELTS( dest
, 2, elts
[2], elts
[1] );
841 EMIT_TWO_ELTS( dest
, 4, elts
[3], elts
[2] );
850 ELT_INIT( GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
);
852 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
853 nr
= MIN2( dmasz
, count
- j
);
854 dest
= ALLOC_ELTS( nr
);
855 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
864 static void TAG(render_quads_elts
)( struct gl_context
*ctx
,
869 if (start
+3 >= count
)
872 if (HAVE_QUADS
&& 0) {
875 GLuint
*elts
= GET_MESA_ELTS();
876 int dmasz
= GET_MAX_HW_ELTS();
879 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
881 /* Emit whole number of quads in total, and in each buffer.
884 count
-= (count
-start
) & 3;
886 /* Adjust for rendering as triangles:
890 for (j
= start
; j
+ 3 < count
; j
+= nr
) {
891 nr
= MIN2( dmasz
, count
- j
);
895 ELT_TYPE
*dest
= ALLOC_ELTS( quads
* 6 );
898 for ( i
= j
-start
; i
< j
-start
+quads
; i
++, elts
+= 4 ) {
899 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
900 EMIT_TWO_ELTS( dest
, 2, elts
[3], elts
[1] );
901 EMIT_TWO_ELTS( dest
, 4, elts
[2], elts
[3] );
913 static tnl_render_func
TAG(render_tab_elts
)[GL_POLYGON
+2] =
915 TAG(render_points_elts
),
916 TAG(render_lines_elts
),
917 TAG(render_line_loop_elts
),
918 TAG(render_line_strip_elts
),
919 TAG(render_triangles_elts
),
920 TAG(render_tri_strip_elts
),
921 TAG(render_tri_fan_elts
),
922 TAG(render_quads_elts
),
923 TAG(render_quad_strip_elts
),
924 TAG(render_poly_elts
),