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
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
26 * Keith Whitwell <keith@tungstengraphics.com>
31 * \file t_dd_dmatmp2.h
32 * Template for render stages which build and emit vertices directly
33 * to fixed-size dma buffers. Useful for rendering strips and other
34 * native primitives where clipping and per-vertex tweaks such as
35 * those in t_dd_tritmp.h are not required.
39 #if !HAVE_TRIANGLES || !HAVE_POINTS || !HAVE_LINES
40 #error "must have points, lines & triangles to use render template"
43 #if !HAVE_TRI_STRIPS || !HAVE_TRI_FANS
44 #error "must have tri strip and fans to use render template"
48 #error "must have line strips to use render template"
52 #error "must have polygons to use render template"
56 #error "must have elts to use render template"
61 #define EMIT_TWO_ELTS( dest, offset, elt0, elt1 ) \
63 (dest)[offset] = (elt0); \
64 (dest)[offset+1] = (elt1); \
69 /**********************************************************************/
70 /* Render whole begin/end objects */
71 /**********************************************************************/
74 static ELT_TYPE
*TAG(emit_elts
)( struct gl_context
*ctx
,
76 GLuint
*elts
, GLuint nr
)
81 for ( i
= 0 ; i
+1 < nr
; i
+=2, elts
+= 2 ) {
82 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
86 EMIT_ELT( dest
, 0, elts
[0] );
93 static ELT_TYPE
*TAG(emit_consecutive_elts
)( struct gl_context
*ctx
,
95 GLuint start
, GLuint nr
)
100 for ( i
= 0 ; i
+1 < nr
; i
+=2, start
+= 2 ) {
101 EMIT_TWO_ELTS( dest
, 0, start
, start
+1 );
105 EMIT_ELT( dest
, 0, start
);
112 /***********************************************************************
113 * Render non-indexed primitives.
114 ***********************************************************************/
118 static void TAG(render_points_verts
)( struct gl_context
*ctx
,
125 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
126 EMIT_PRIM( ctx
, GL_POINTS
, HW_POINTS
, start
, count
);
130 static void TAG(render_lines_verts
)( struct gl_context
*ctx
,
136 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
137 count
-= (count
-start
) & 1;
139 if (start
+1 >= count
)
142 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
) {
144 AUTO_STIPPLE( GL_TRUE
);
147 EMIT_PRIM( ctx
, GL_LINES
, HW_LINES
, start
, count
);
149 if ((flags
& PRIM_END
) && ctx
->Line
.StippleFlag
)
150 AUTO_STIPPLE( GL_FALSE
);
154 static void TAG(render_line_strip_verts
)( struct gl_context
*ctx
,
160 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
162 if (start
+1 >= count
)
165 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
169 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_LINES
))
171 int dmasz
= GET_MAX_HW_ELTS();
174 ELT_INIT( GL_LINES
, HW_LINES
);
176 /* Emit whole number of lines in each full buffer.
181 for (j
= start
; j
+ 1 < count
; j
+= nr
- 1 ) {
185 nr
= MIN2( dmasz
, count
- j
);
186 dest
= ALLOC_ELTS( (nr
-1)*2 );
188 for ( i
= j
; i
+1 < j
+nr
; i
+=1 ) {
189 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
197 EMIT_PRIM( ctx
, GL_LINE_STRIP
, HW_LINE_STRIP
, start
, count
);
201 static void TAG(render_line_loop_verts
)( struct gl_context
*ctx
,
208 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
210 if (flags
& PRIM_BEGIN
) {
212 if (ctx
->Line
.StippleFlag
)
218 if (flags
& PRIM_END
) {
220 if (start
+1 >= count
)
223 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_LINES
)) {
224 int dmasz
= GET_MAX_HW_ELTS();
226 ELT_INIT( GL_LINES
, HW_LINES
);
228 /* Emit whole number of lines in each full buffer.
232 /* Ensure last vertex doesn't wrap:
236 for (; j
+ 1 < count
; ) {
240 nr
= MIN2( dmasz
, count
- j
);
241 dest
= ALLOC_ELTS( nr
*2 ); /* allocs room for 1 more line */
243 for ( i
= 0 ; i
< nr
- 1 ; i
+=1 ) {
244 EMIT_TWO_ELTS( dest
, 0, (j
+i
), (j
+i
+1) );
250 /* Emit 1 more line into space alloced above */
251 if (j
+ 1 >= count
) {
252 EMIT_TWO_ELTS( dest
, 0, (j
), (start
) );
261 int dmasz
= GET_MAX_HW_ELTS() - 1;
263 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
265 for ( ; j
+ 1 < count
; ) {
266 nr
= MIN2( dmasz
, count
- j
);
267 if (j
+ nr
< count
) {
268 ELT_TYPE
*dest
= ALLOC_ELTS( nr
);
269 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, j
, nr
);
275 ELT_TYPE
*dest
= ALLOC_ELTS( nr
+ 1 );
276 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, j
, nr
);
277 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, start
, 1 );
285 TAG(render_line_strip_verts
)( ctx
, j
, count
, flags
);
290 static void TAG(render_triangles_verts
)( struct gl_context
*ctx
,
296 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
298 count
-= (count
-start
)%3;
300 if (start
+2 >= count
) {
304 /* need a PREFER_DISCRETE_ELT_PRIM here too..
306 EMIT_PRIM( ctx
, GL_TRIANGLES
, HW_TRIANGLES
, start
, count
);
311 static void TAG(render_tri_strip_verts
)( struct gl_context
*ctx
,
317 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
319 if (start
+ 2 >= count
)
322 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_TRIANGLES
))
324 int dmasz
= GET_MAX_HW_ELTS();
328 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
330 /* Emit even number of tris in each full buffer.
335 for (j
= start
; j
+ 2 < count
; j
+= nr
- 2 ) {
339 nr
= MIN2( dmasz
, count
- j
);
340 dest
= ALLOC_ELTS( (nr
-2)*3 );
342 for ( i
= j
; i
+2 < j
+nr
; i
++, parity
^=1 ) {
343 EMIT_ELT( dest
, 0, (i
+0+parity
) );
344 EMIT_ELT( dest
, 1, (i
+1-parity
) );
345 EMIT_ELT( dest
, 2, (i
+2) );
353 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
, start
, count
);
356 static void TAG(render_tri_fan_verts
)( struct gl_context
*ctx
,
362 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
364 if (start
+2 >= count
)
367 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_TRIANGLES
))
369 int dmasz
= GET_MAX_HW_ELTS();
372 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
376 for (j
= start
+ 1; j
+ 1 < count
; j
+= nr
- 1 ) {
380 nr
= MIN2( dmasz
, count
- j
);
381 dest
= ALLOC_ELTS( (nr
-1)*3 );
383 for ( i
= j
; i
+1 < j
+nr
; i
++ ) {
384 EMIT_ELT( dest
, 0, (start
) );
385 EMIT_ELT( dest
, 1, (i
) );
386 EMIT_ELT( dest
, 2, (i
+1) );
394 EMIT_PRIM( ctx
, GL_TRIANGLE_FAN
, HW_TRIANGLE_FAN
, start
, count
);
399 static void TAG(render_poly_verts
)( struct gl_context
*ctx
,
405 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
407 if (start
+2 >= count
)
410 EMIT_PRIM( ctx
, GL_POLYGON
, HW_POLYGON
, start
, count
);
413 static void TAG(render_quad_strip_verts
)( struct gl_context
*ctx
,
419 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
421 count
-= (count
-start
) & 1;
423 if (start
+3 >= count
)
426 if (HAVE_QUAD_STRIPS
) {
427 EMIT_PRIM( ctx
, GL_QUAD_STRIP
, HW_QUAD_STRIP
, start
, count
);
429 else if (ctx
->Light
.ShadeModel
== GL_FLAT
) {
431 int dmasz
= GET_MAX_HW_ELTS();
434 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
436 /* Emit whole number of quads in total, and in each buffer.
440 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
444 nr
= MIN2( dmasz
, count
- j
);
446 dest
= ALLOC_ELTS( quads
*6 );
448 for ( i
= j
; i
< j
+quads
*2 ; i
+=2 ) {
449 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
450 EMIT_TWO_ELTS( dest
, 2, (i
+2), (i
+1) );
451 EMIT_TWO_ELTS( dest
, 4, (i
+3), (i
+2) );
459 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
, start
, count
);
464 static void TAG(render_quads_verts
)( struct gl_context
*ctx
,
470 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
471 count
-= (count
-start
)%4;
473 if (start
+3 >= count
)
477 EMIT_PRIM( ctx
, GL_QUADS
, HW_QUADS
, start
, count
);
480 /* Hardware doesn't have a quad primitive type -- simulate it
481 * using indexed vertices and the triangle primitive:
484 int dmasz
= GET_MAX_HW_ELTS();
487 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
489 /* Adjust for rendering as triangles:
493 for (j
= start
; j
< count
; j
+= nr
) {
497 nr
= MIN2( dmasz
, count
- j
);
499 dest
= ALLOC_ELTS( quads
*6 );
501 for ( i
= j
; i
< j
+quads
*4 ; i
+=4 ) {
502 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
503 EMIT_TWO_ELTS( dest
, 2, (i
+3), (i
+1) );
504 EMIT_TWO_ELTS( dest
, 4, (i
+2), (i
+3) );
513 static void TAG(render_noop
)( struct gl_context
*ctx
,
523 static tnl_render_func
TAG(render_tab_verts
)[GL_POLYGON
+2] =
525 TAG(render_points_verts
),
526 TAG(render_lines_verts
),
527 TAG(render_line_loop_verts
),
528 TAG(render_line_strip_verts
),
529 TAG(render_triangles_verts
),
530 TAG(render_tri_strip_verts
),
531 TAG(render_tri_fan_verts
),
532 TAG(render_quads_verts
),
533 TAG(render_quad_strip_verts
),
534 TAG(render_poly_verts
),
539 /****************************************************************************
540 * Render elts using hardware indexed verts *
541 ****************************************************************************/
543 static void TAG(render_points_elts
)( struct gl_context
*ctx
,
549 int dmasz
= GET_MAX_HW_ELTS();
550 GLuint
*elts
= GET_MESA_ELTS();
554 ELT_INIT( GL_POINTS
, HW_POINTS
);
556 for (j
= start
; j
< count
; j
+= nr
) {
557 nr
= MIN2( dmasz
, count
- j
);
558 dest
= ALLOC_ELTS( nr
);
559 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
567 static void TAG(render_lines_elts
)( struct gl_context
*ctx
,
573 int dmasz
= GET_MAX_HW_ELTS();
574 GLuint
*elts
= GET_MESA_ELTS();
578 if (start
+1 >= count
)
581 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
) {
583 AUTO_STIPPLE( GL_TRUE
);
586 ELT_INIT( GL_LINES
, HW_LINES
);
588 /* Emit whole number of lines in total and in each buffer:
590 count
-= (count
-start
) & 1;
593 for (j
= start
; j
< count
; j
+= nr
) {
594 nr
= MIN2( dmasz
, count
- j
);
595 dest
= ALLOC_ELTS( nr
);
596 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
601 if ((flags
& PRIM_END
) && ctx
->Line
.StippleFlag
)
602 AUTO_STIPPLE( GL_FALSE
);
606 static void TAG(render_line_strip_elts
)( struct gl_context
*ctx
,
612 int dmasz
= GET_MAX_HW_ELTS();
613 GLuint
*elts
= GET_MESA_ELTS();
617 if (start
+1 >= count
)
620 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
622 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
625 for (j
= start
; j
+ 1 < count
; j
+= nr
- 1 ) {
626 nr
= MIN2( dmasz
, count
- j
);
627 dest
= ALLOC_ELTS( nr
);
628 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
635 static void TAG(render_line_loop_elts
)( struct gl_context
*ctx
,
641 int dmasz
= GET_MAX_HW_ELTS();
642 GLuint
*elts
= GET_MESA_ELTS();
646 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
648 if (flags
& PRIM_BEGIN
)
654 if (flags
& PRIM_END
) {
655 if (start
+1 >= count
)
663 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
665 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
669 /* Ensure last vertex doesn't wrap:
673 for ( ; j
+ 1 < count
; ) {
674 nr
= MIN2( dmasz
, count
- j
);
675 dest
= ALLOC_ELTS( nr
+1 ); /* Reserve possible space for last elt */
676 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
678 if (j
+ 1 >= count
&& (flags
& PRIM_END
)) {
679 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
687 static void TAG(render_triangles_elts
)( struct gl_context
*ctx
,
693 GLuint
*elts
= GET_MESA_ELTS();
694 int dmasz
= GET_MAX_HW_ELTS()/3*3;
698 if (start
+2 >= count
)
701 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
704 /* Emit whole number of tris in total. dmasz is already a multiple
707 count
-= (count
-start
)%3;
709 for (j
= start
; j
< count
; j
+= nr
) {
710 nr
= MIN2( dmasz
, count
- j
);
711 dest
= ALLOC_ELTS( nr
);
712 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
720 static void TAG(render_tri_strip_elts
)( struct gl_context
*ctx
,
727 GLuint
*elts
= GET_MESA_ELTS();
728 int dmasz
= GET_MAX_HW_ELTS();
731 if (start
+2 >= count
)
734 ELT_INIT( GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
);
736 /* Keep the same winding over multiple buffers:
738 dmasz
-= (dmasz
& 1);
740 for (j
= start
; j
+ 2 < count
; j
+= nr
- 2 ) {
741 nr
= MIN2( dmasz
, count
- j
);
743 dest
= ALLOC_ELTS( nr
);
744 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
750 static void TAG(render_tri_fan_elts
)( struct gl_context
*ctx
,
756 GLuint
*elts
= GET_MESA_ELTS();
758 int dmasz
= GET_MAX_HW_ELTS();
761 if (start
+2 >= count
)
764 ELT_INIT( GL_TRIANGLE_FAN
, HW_TRIANGLE_FAN
);
766 for (j
= start
+ 1 ; j
+ 1 < count
; j
+= nr
- 1 ) {
767 nr
= MIN2( dmasz
, count
- j
+ 1 );
768 dest
= ALLOC_ELTS( nr
);
769 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
770 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
- 1 );
777 static void TAG(render_poly_elts
)( struct gl_context
*ctx
,
783 GLuint
*elts
= GET_MESA_ELTS();
785 int dmasz
= GET_MAX_HW_ELTS();
788 if (start
+2 >= count
)
791 ELT_INIT( GL_POLYGON
, HW_POLYGON
);
793 for (j
= start
+ 1 ; j
+ 1 < count
; j
+= nr
- 1 ) {
794 nr
= MIN2( dmasz
, count
- j
+ 1 );
795 dest
= ALLOC_ELTS( nr
);
796 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
797 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
- 1 );
803 static void TAG(render_quad_strip_elts
)( struct gl_context
*ctx
,
808 if (start
+3 >= count
)
811 if (HAVE_QUAD_STRIPS
&& 0) {
815 GLuint
*elts
= GET_MESA_ELTS();
816 int dmasz
= GET_MAX_HW_ELTS();
820 /* Emit whole number of quads in total, and in each buffer.
823 count
-= (count
-start
) & 1;
825 if (ctx
->Light
.ShadeModel
== GL_FLAT
) {
826 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
830 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
831 nr
= MIN2( dmasz
, count
- j
);
835 GLint quads
= (nr
/2)-1;
836 ELT_TYPE
*dest
= ALLOC_ELTS( quads
*6 );
839 for ( i
= j
-start
; i
< j
-start
+quads
; i
++, elts
+= 2 ) {
840 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
841 EMIT_TWO_ELTS( dest
, 2, elts
[2], elts
[1] );
842 EMIT_TWO_ELTS( dest
, 4, elts
[3], elts
[2] );
851 ELT_INIT( GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
);
853 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
854 nr
= MIN2( dmasz
, count
- j
);
855 dest
= ALLOC_ELTS( nr
);
856 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
865 static void TAG(render_quads_elts
)( struct gl_context
*ctx
,
870 if (start
+3 >= count
)
873 if (HAVE_QUADS
&& 0) {
876 GLuint
*elts
= GET_MESA_ELTS();
877 int dmasz
= GET_MAX_HW_ELTS();
880 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
882 /* Emit whole number of quads in total, and in each buffer.
885 count
-= (count
-start
) & 3;
887 /* Adjust for rendering as triangles:
891 for (j
= start
; j
+ 3 < count
; j
+= nr
) {
892 nr
= MIN2( dmasz
, count
- j
);
896 ELT_TYPE
*dest
= ALLOC_ELTS( quads
* 6 );
899 for ( i
= j
-start
; i
< j
-start
+quads
; i
++, elts
+= 4 ) {
900 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
901 EMIT_TWO_ELTS( dest
, 2, elts
[3], elts
[1] );
902 EMIT_TWO_ELTS( dest
, 4, elts
[2], elts
[3] );
914 static tnl_render_func
TAG(render_tab_elts
)[GL_POLYGON
+2] =
916 TAG(render_points_elts
),
917 TAG(render_lines_elts
),
918 TAG(render_line_loop_elts
),
919 TAG(render_line_strip_elts
),
920 TAG(render_triangles_elts
),
921 TAG(render_tri_strip_elts
),
922 TAG(render_tri_fan_elts
),
923 TAG(render_quads_elts
),
924 TAG(render_quad_strip_elts
),
925 TAG(render_poly_elts
),