3 * Mesa 3-D graphics library
6 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Keith Whitwell <keith@tungstengraphics.com>
30 /* Template for render stages which build and emit vertices directly
31 * to fixed-size dma buffers. Useful for rendering strips and other
32 * native primitives where clipping and per-vertex tweaks such as
33 * those in t_dd_tritmp.h are not required.
37 #if !HAVE_TRIANGLES || !HAVE_POINTS || !HAVE_LINES
38 #error "must have points, lines & triangles to use render template"
41 #if !HAVE_TRI_STRIPS || !HAVE_TRI_FANS
42 #error "must have tri strip and fans to use render template"
46 #error "must have line strips to use render template"
50 #error "must have polygons to use render template"
54 #error "must have elts to use render template"
59 #define EMIT_TWO_ELTS( dest, offset, elt0, elt1 ) \
61 (dest)[offset] = (elt0); \
62 (dest)[offset+1] = (elt1); \
67 /**********************************************************************/
68 /* Render whole begin/end objects */
69 /**********************************************************************/
72 static ELT_TYPE
*TAG(emit_elts
)( GLcontext
*ctx
,
74 GLuint
*elts
, GLuint nr
)
79 for ( i
= 0 ; i
+1 < nr
; i
+=2, elts
+= 2 ) {
80 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
84 EMIT_ELT( dest
, 0, elts
[0] );
91 static ELT_TYPE
*TAG(emit_consecutive_elts
)( GLcontext
*ctx
,
93 GLuint start
, GLuint nr
)
98 for ( i
= 0 ; i
+1 < nr
; i
+=2, start
+= 2 ) {
99 EMIT_TWO_ELTS( dest
, 0, start
, start
+1 );
103 EMIT_ELT( dest
, 0, start
);
110 /***********************************************************************
111 * Render non-indexed primitives.
112 ***********************************************************************/
116 static void TAG(render_points_verts
)( GLcontext
*ctx
,
123 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
124 EMIT_PRIM( ctx
, GL_POINTS
, HW_POINTS
, start
, count
);
128 static void TAG(render_lines_verts
)( GLcontext
*ctx
,
134 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
135 count
-= (count
-start
) & 1;
137 if (start
+1 >= count
)
140 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
) {
142 AUTO_STIPPLE( GL_TRUE
);
145 EMIT_PRIM( ctx
, GL_LINES
, HW_LINES
, start
, count
);
147 if ((flags
& PRIM_END
) && ctx
->Line
.StippleFlag
)
148 AUTO_STIPPLE( GL_FALSE
);
152 static void TAG(render_line_strip_verts
)( GLcontext
*ctx
,
158 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
160 if (start
+1 >= count
)
163 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
167 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_LINES
))
169 int dmasz
= GET_MAX_HW_ELTS();
172 ELT_INIT( GL_LINES
, HW_LINES
);
174 /* Emit whole number of lines in each full buffer.
179 for (j
= start
; j
+ 1 < count
; j
+= nr
- 1 ) {
183 nr
= MIN2( dmasz
, count
- j
);
184 dest
= ALLOC_ELTS( (nr
-1)*2 );
186 for ( i
= j
; i
+1 < j
+nr
; i
+=1 ) {
187 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
195 EMIT_PRIM( ctx
, GL_LINE_STRIP
, HW_LINE_STRIP
, start
, count
);
199 static void TAG(render_line_loop_verts
)( GLcontext
*ctx
,
206 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
208 if (flags
& PRIM_BEGIN
) {
210 if (ctx
->Line
.StippleFlag
)
216 if (flags
& PRIM_END
) {
218 if (start
+1 >= count
)
221 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_LINES
)) {
222 int dmasz
= GET_MAX_HW_ELTS();
224 ELT_INIT( GL_LINES
, HW_LINES
);
226 /* Emit whole number of lines in each full buffer.
230 /* Ensure last vertex doesn't wrap:
234 for (; j
+ 1 < count
; ) {
238 nr
= MIN2( dmasz
, count
- j
);
239 dest
= ALLOC_ELTS( nr
*2 ); /* allocs room for 1 more line */
241 for ( i
= 0 ; i
< nr
- 1 ; i
+=1 ) {
242 EMIT_TWO_ELTS( dest
, 0, (j
+i
), (j
+i
+1) );
248 /* Emit 1 more line into space alloced above */
249 if (j
+ 1 >= count
) {
250 EMIT_TWO_ELTS( dest
, 0, (j
), (start
) );
259 int dmasz
= GET_MAX_HW_ELTS() - 1;
261 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
263 for ( ; j
+ 1 < count
; ) {
264 nr
= MIN2( dmasz
, count
- j
);
265 if (j
+ nr
< count
) {
266 ELT_TYPE
*dest
= ALLOC_ELTS( nr
);
267 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, j
, nr
);
272 ELT_TYPE
*dest
= ALLOC_ELTS( nr
+ 1 );
273 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, j
, nr
);
274 dest
= TAG(emit_consecutive_elts
)( ctx
, dest
, start
, 1 );
281 TAG(render_line_strip_verts
)( ctx
, j
, count
, flags
);
286 static void TAG(render_triangles_verts
)( GLcontext
*ctx
,
292 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
294 count
-= (count
-start
)%3;
296 if (start
+2 >= count
) {
300 /* need a PREFER_DISCRETE_ELT_PRIM here too..
302 EMIT_PRIM( ctx
, GL_TRIANGLES
, HW_TRIANGLES
, start
, count
);
307 static void TAG(render_tri_strip_verts
)( GLcontext
*ctx
,
313 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
315 if (start
+ 2 >= count
)
318 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_TRIANGLES
))
320 int dmasz
= GET_MAX_HW_ELTS();
324 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
326 /* Emit even number of tris in each full buffer.
331 for (j
= start
; j
+ 2 < count
; j
+= nr
- 2 ) {
335 nr
= MIN2( dmasz
, count
- j
);
336 dest
= ALLOC_ELTS( (nr
-2)*3 );
338 for ( i
= j
; i
+2 < j
+nr
; i
++, parity
^=1 ) {
339 EMIT_ELT( dest
, 0, (i
+0+parity
) );
340 EMIT_ELT( dest
, 1, (i
+1-parity
) );
341 EMIT_ELT( dest
, 2, (i
+2) );
348 else if (HAVE_TRI_STRIP_1
)
349 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_1
, start
, count
);
351 /* Emit the first triangle with elts, then the rest as a regular strip.
352 * TODO: Make this unlikely in t_imm_api.c
356 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
357 dest
= ALLOC_ELTS( 3 );
358 EMIT_ELT( dest
, 0, (start
+1) );
359 EMIT_ELT( dest
, 1, (start
+0) );
360 EMIT_ELT( dest
, 2, (start
+2) );
365 if (start
+ 2 >= count
)
368 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
, start
,
373 static void TAG(render_tri_fan_verts
)( GLcontext
*ctx
,
379 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
381 if (start
+2 >= count
)
384 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_TRIANGLES
))
386 int dmasz
= GET_MAX_HW_ELTS();
389 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
393 for (j
= start
+ 1; j
+ 1 < count
; j
+= nr
- 1 ) {
397 nr
= MIN2( dmasz
, count
- j
);
398 dest
= ALLOC_ELTS( (nr
-1)*3 );
400 for ( i
= j
; i
+1 < j
+nr
; i
++ ) {
401 EMIT_ELT( dest
, 0, (start
) );
402 EMIT_ELT( dest
, 1, (i
) );
403 EMIT_ELT( dest
, 2, (i
+1) );
411 EMIT_PRIM( ctx
, GL_TRIANGLE_FAN
, HW_TRIANGLE_FAN
, start
, count
);
416 static void TAG(render_poly_verts
)( GLcontext
*ctx
,
422 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
424 if (start
+2 >= count
)
427 EMIT_PRIM( ctx
, GL_POLYGON
, HW_POLYGON
, start
, count
);
430 static void TAG(render_quad_strip_verts
)( GLcontext
*ctx
,
436 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
438 count
-= (count
-start
) & 1;
440 if (start
+3 >= count
)
443 if (HAVE_QUAD_STRIPS
) {
444 EMIT_PRIM( ctx
, GL_QUAD_STRIP
, HW_QUAD_STRIP
, start
, count
);
446 else if (ctx
->_TriangleCaps
& DD_FLATSHADE
) {
448 int dmasz
= GET_MAX_HW_ELTS();
451 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
453 /* Emit whole number of quads in total, and in each buffer.
457 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
461 nr
= MIN2( dmasz
, count
- j
);
463 dest
= ALLOC_ELTS( quads
*6 );
465 for ( i
= j
; i
< j
+quads
*2 ; i
+=2 ) {
466 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
467 EMIT_TWO_ELTS( dest
, 2, (i
+2), (i
+1) );
468 EMIT_TWO_ELTS( dest
, 4, (i
+3), (i
+2) );
476 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
, start
, count
);
481 static void TAG(render_quads_verts
)( GLcontext
*ctx
,
487 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
488 count
-= (count
-start
)%4;
490 if (start
+3 >= count
)
494 EMIT_PRIM( ctx
, HW_QUADS
, GL_QUADS
, start
, count
);
497 /* Hardware doesn't have a quad primitive type -- simulate it
498 * using indexed vertices and the triangle primitive:
501 int dmasz
= GET_MAX_HW_ELTS();
504 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
506 /* Adjust for rendering as triangles:
510 for (j
= start
; j
< count
; j
+= nr
) {
514 nr
= MIN2( dmasz
, count
- j
);
516 dest
= ALLOC_ELTS( quads
*6 );
518 for ( i
= j
; i
< j
+quads
*4 ; i
+=4 ) {
519 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
520 EMIT_TWO_ELTS( dest
, 2, (i
+3), (i
+1) );
521 EMIT_TWO_ELTS( dest
, 4, (i
+2), (i
+3) );
530 static void TAG(render_noop
)( GLcontext
*ctx
,
540 static render_func
TAG(render_tab_verts
)[GL_POLYGON
+2] =
542 TAG(render_points_verts
),
543 TAG(render_lines_verts
),
544 TAG(render_line_loop_verts
),
545 TAG(render_line_strip_verts
),
546 TAG(render_triangles_verts
),
547 TAG(render_tri_strip_verts
),
548 TAG(render_tri_fan_verts
),
549 TAG(render_quads_verts
),
550 TAG(render_quad_strip_verts
),
551 TAG(render_poly_verts
),
556 /****************************************************************************
557 * Render elts using hardware indexed verts *
558 ****************************************************************************/
560 static void TAG(render_points_elts
)( GLcontext
*ctx
,
566 int dmasz
= GET_MAX_HW_ELTS();
567 GLuint
*elts
= GET_MESA_ELTS();
571 ELT_INIT( GL_POINTS
, HW_POINTS
);
573 for (j
= start
; j
< count
; j
+= nr
) {
574 nr
= MIN2( dmasz
, count
- j
);
575 dest
= ALLOC_ELTS( nr
);
576 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
583 static void TAG(render_lines_elts
)( GLcontext
*ctx
,
589 int dmasz
= GET_MAX_HW_ELTS();
590 GLuint
*elts
= GET_MESA_ELTS();
594 if (start
+1 >= count
)
597 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
) {
599 AUTO_STIPPLE( GL_TRUE
);
602 ELT_INIT( GL_LINES
, HW_LINES
);
604 /* Emit whole number of lines in total and in each buffer:
606 count
-= (count
-start
) & 1;
609 for (j
= start
; j
< count
; j
+= nr
) {
610 nr
= MIN2( dmasz
, count
- j
);
611 dest
= ALLOC_ELTS( nr
);
612 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
616 if ((flags
& PRIM_END
) && ctx
->Line
.StippleFlag
)
617 AUTO_STIPPLE( GL_FALSE
);
621 static void TAG(render_line_strip_elts
)( GLcontext
*ctx
,
627 int dmasz
= GET_MAX_HW_ELTS();
628 GLuint
*elts
= GET_MESA_ELTS();
632 if (start
+1 >= count
)
635 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
637 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
640 for (j
= start
; j
+ 1 < count
; j
+= nr
- 1 ) {
641 nr
= MIN2( dmasz
, count
- j
);
642 dest
= ALLOC_ELTS( nr
);
643 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
649 static void TAG(render_line_loop_elts
)( GLcontext
*ctx
,
655 int dmasz
= GET_MAX_HW_ELTS();
656 GLuint
*elts
= GET_MESA_ELTS();
660 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
662 if (flags
& PRIM_BEGIN
)
668 if (flags
& PRIM_END
) {
669 if (start
+1 >= count
)
677 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
679 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
683 /* Ensure last vertex doesn't wrap:
687 for ( ; j
+ 1 < count
; ) {
688 nr
= MIN2( dmasz
, count
- j
);
689 dest
= ALLOC_ELTS( nr
+1 ); /* Reserve possible space for last elt */
690 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
692 if (j
+ 1 >= count
&& (flags
& PRIM_END
)) {
693 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
700 static void TAG(render_triangles_elts
)( GLcontext
*ctx
,
706 GLuint
*elts
= GET_MESA_ELTS();
707 int dmasz
= GET_MAX_HW_ELTS()/3*3;
711 if (start
+2 >= count
)
714 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
717 /* Emit whole number of tris in total. dmasz is already a multiple
720 count
-= (count
-start
)%3;
722 for (j
= start
; j
< count
; j
+= nr
) {
723 nr
= MIN2( dmasz
, count
- j
);
724 dest
= ALLOC_ELTS( nr
);
725 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
732 static void TAG(render_tri_strip_elts
)( GLcontext
*ctx
,
739 GLuint
*elts
= GET_MESA_ELTS();
740 int dmasz
= GET_MAX_HW_ELTS();
743 if (start
+2 >= count
)
746 ELT_INIT( GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
);
748 /* Keep the same winding over multiple buffers:
750 dmasz
-= (dmasz
& 1);
752 for (j
= start
; j
+ 2 < count
; j
+= nr
- 2 ) {
753 nr
= MIN2( dmasz
, count
- j
);
755 dest
= ALLOC_ELTS( nr
);
756 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
761 static void TAG(render_tri_fan_elts
)( GLcontext
*ctx
,
767 GLuint
*elts
= GET_MESA_ELTS();
769 int dmasz
= GET_MAX_HW_ELTS();
772 if (start
+2 >= count
)
775 ELT_INIT( GL_TRIANGLE_FAN
, HW_TRIANGLE_FAN
);
777 for (j
= start
+ 1 ; j
+ 1 < count
; j
+= nr
- 1 ) {
778 nr
= MIN2( dmasz
, count
- j
+ 1 );
779 dest
= ALLOC_ELTS( nr
);
780 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
781 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
- 1 );
787 static void TAG(render_poly_elts
)( GLcontext
*ctx
,
793 GLuint
*elts
= GET_MESA_ELTS();
795 int dmasz
= GET_MAX_HW_ELTS();
798 if (start
+2 >= count
)
801 ELT_INIT( GL_POLYGON
, HW_POLYGON
);
803 for (j
= start
+ 1 ; j
+ 1 < count
; j
+= nr
- 1 ) {
804 nr
= MIN2( dmasz
, count
- j
+ 1 );
805 dest
= ALLOC_ELTS( nr
);
806 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
807 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
- 1 );
812 static void TAG(render_quad_strip_elts
)( GLcontext
*ctx
,
817 if (start
+3 >= count
)
820 if (HAVE_QUAD_STRIPS
&& 0) {
824 GLuint
*elts
= GET_MESA_ELTS();
825 int dmasz
= GET_MAX_HW_ELTS();
829 /* Emit whole number of quads in total, and in each buffer.
832 count
-= (count
-start
) & 1;
834 if (ctx
->_TriangleCaps
& DD_FLATSHADE
) {
835 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
839 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
840 nr
= MIN2( dmasz
, count
- j
);
844 GLint quads
= (nr
/2)-1;
845 ELT_TYPE
*dest
= ALLOC_ELTS( quads
*6 );
848 for ( i
= j
-start
; i
< j
-start
+quads
; i
++, elts
+= 2 ) {
849 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
850 EMIT_TWO_ELTS( dest
, 2, elts
[2], elts
[1] );
851 EMIT_TWO_ELTS( dest
, 4, elts
[3], elts
[2] );
860 ELT_INIT( GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
);
862 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
863 nr
= MIN2( dmasz
, count
- j
);
864 dest
= ALLOC_ELTS( nr
);
865 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
873 static void TAG(render_quads_elts
)( GLcontext
*ctx
,
878 if (start
+3 >= count
)
881 if (HAVE_QUADS
&& 0) {
884 GLuint
*elts
= GET_MESA_ELTS();
885 int dmasz
= GET_MAX_HW_ELTS();
888 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
890 /* Emit whole number of quads in total, and in each buffer.
893 count
-= (count
-start
) & 3;
895 /* Adjust for rendering as triangles:
899 for (j
= start
; j
+ 3 < count
; j
+= nr
) {
900 nr
= MIN2( dmasz
, count
- j
);
904 ELT_TYPE
*dest
= ALLOC_ELTS( quads
* 6 );
907 for ( i
= j
-start
; i
< j
-start
+quads
; i
++, elts
+= 4 ) {
908 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
909 EMIT_TWO_ELTS( dest
, 2, elts
[3], elts
[1] );
910 EMIT_TWO_ELTS( dest
, 4, elts
[2], elts
[3] );
922 static render_func
TAG(render_tab_elts
)[GL_POLYGON
+2] =
924 TAG(render_points_elts
),
925 TAG(render_lines_elts
),
926 TAG(render_line_loop_elts
),
927 TAG(render_line_strip_elts
),
928 TAG(render_triangles_elts
),
929 TAG(render_tri_strip_elts
),
930 TAG(render_tri_fan_elts
),
931 TAG(render_quads_elts
),
932 TAG(render_quad_strip_elts
),
933 TAG(render_poly_elts
),