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) );
349 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
, start
, count
);
352 static void TAG(render_tri_fan_verts
)( GLcontext
*ctx
,
358 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
360 if (start
+2 >= count
)
363 if (PREFER_DISCRETE_ELT_PRIM( count
-start
, HW_TRIANGLES
))
365 int dmasz
= GET_MAX_HW_ELTS();
368 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
372 for (j
= start
+ 1; j
+ 1 < count
; j
+= nr
- 1 ) {
376 nr
= MIN2( dmasz
, count
- j
);
377 dest
= ALLOC_ELTS( (nr
-1)*3 );
379 for ( i
= j
; i
+1 < j
+nr
; i
++ ) {
380 EMIT_ELT( dest
, 0, (start
) );
381 EMIT_ELT( dest
, 1, (i
) );
382 EMIT_ELT( dest
, 2, (i
+1) );
390 EMIT_PRIM( ctx
, GL_TRIANGLE_FAN
, HW_TRIANGLE_FAN
, start
, count
);
395 static void TAG(render_poly_verts
)( GLcontext
*ctx
,
401 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
403 if (start
+2 >= count
)
406 EMIT_PRIM( ctx
, GL_POLYGON
, HW_POLYGON
, start
, count
);
409 static void TAG(render_quad_strip_verts
)( GLcontext
*ctx
,
415 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
417 count
-= (count
-start
) & 1;
419 if (start
+3 >= count
)
422 if (HAVE_QUAD_STRIPS
) {
423 EMIT_PRIM( ctx
, GL_QUAD_STRIP
, HW_QUAD_STRIP
, start
, count
);
425 else if (ctx
->_TriangleCaps
& DD_FLATSHADE
) {
427 int dmasz
= GET_MAX_HW_ELTS();
430 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
432 /* Emit whole number of quads in total, and in each buffer.
436 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
440 nr
= MIN2( dmasz
, count
- j
);
442 dest
= ALLOC_ELTS( quads
*6 );
444 for ( i
= j
; i
< j
+quads
*2 ; i
+=2 ) {
445 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
446 EMIT_TWO_ELTS( dest
, 2, (i
+2), (i
+1) );
447 EMIT_TWO_ELTS( dest
, 4, (i
+3), (i
+2) );
455 EMIT_PRIM( ctx
, GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
, start
, count
);
460 static void TAG(render_quads_verts
)( GLcontext
*ctx
,
466 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
467 count
-= (count
-start
)%4;
469 if (start
+3 >= count
)
473 EMIT_PRIM( ctx
, HW_QUADS
, GL_QUADS
, start
, count
);
476 /* Hardware doesn't have a quad primitive type -- simulate it
477 * using indexed vertices and the triangle primitive:
480 int dmasz
= GET_MAX_HW_ELTS();
483 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
485 /* Adjust for rendering as triangles:
489 for (j
= start
; j
< count
; j
+= nr
) {
493 nr
= MIN2( dmasz
, count
- j
);
495 dest
= ALLOC_ELTS( quads
*6 );
497 for ( i
= j
; i
< j
+quads
*4 ; i
+=4 ) {
498 EMIT_TWO_ELTS( dest
, 0, (i
+0), (i
+1) );
499 EMIT_TWO_ELTS( dest
, 2, (i
+3), (i
+1) );
500 EMIT_TWO_ELTS( dest
, 4, (i
+2), (i
+3) );
509 static void TAG(render_noop
)( GLcontext
*ctx
,
519 static render_func
TAG(render_tab_verts
)[GL_POLYGON
+2] =
521 TAG(render_points_verts
),
522 TAG(render_lines_verts
),
523 TAG(render_line_loop_verts
),
524 TAG(render_line_strip_verts
),
525 TAG(render_triangles_verts
),
526 TAG(render_tri_strip_verts
),
527 TAG(render_tri_fan_verts
),
528 TAG(render_quads_verts
),
529 TAG(render_quad_strip_verts
),
530 TAG(render_poly_verts
),
535 /****************************************************************************
536 * Render elts using hardware indexed verts *
537 ****************************************************************************/
539 static void TAG(render_points_elts
)( GLcontext
*ctx
,
545 int dmasz
= GET_MAX_HW_ELTS();
546 GLuint
*elts
= GET_MESA_ELTS();
550 ELT_INIT( GL_POINTS
, HW_POINTS
);
552 for (j
= start
; j
< count
; j
+= nr
) {
553 nr
= MIN2( dmasz
, count
- j
);
554 dest
= ALLOC_ELTS( nr
);
555 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
562 static void TAG(render_lines_elts
)( GLcontext
*ctx
,
568 int dmasz
= GET_MAX_HW_ELTS();
569 GLuint
*elts
= GET_MESA_ELTS();
573 if (start
+1 >= count
)
576 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
) {
578 AUTO_STIPPLE( GL_TRUE
);
581 ELT_INIT( GL_LINES
, HW_LINES
);
583 /* Emit whole number of lines in total and in each buffer:
585 count
-= (count
-start
) & 1;
588 for (j
= start
; j
< count
; j
+= nr
) {
589 nr
= MIN2( dmasz
, count
- j
);
590 dest
= ALLOC_ELTS( nr
);
591 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
595 if ((flags
& PRIM_END
) && ctx
->Line
.StippleFlag
)
596 AUTO_STIPPLE( GL_FALSE
);
600 static void TAG(render_line_strip_elts
)( GLcontext
*ctx
,
606 int dmasz
= GET_MAX_HW_ELTS();
607 GLuint
*elts
= GET_MESA_ELTS();
611 if (start
+1 >= count
)
614 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
616 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
619 for (j
= start
; j
+ 1 < count
; j
+= nr
- 1 ) {
620 nr
= MIN2( dmasz
, count
- j
);
621 dest
= ALLOC_ELTS( nr
);
622 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
628 static void TAG(render_line_loop_elts
)( GLcontext
*ctx
,
634 int dmasz
= GET_MAX_HW_ELTS();
635 GLuint
*elts
= GET_MESA_ELTS();
639 if (0) fprintf(stderr
, "%s\n", __FUNCTION__
);
641 if (flags
& PRIM_BEGIN
)
647 if (flags
& PRIM_END
) {
648 if (start
+1 >= count
)
656 ELT_INIT( GL_LINE_STRIP
, HW_LINE_STRIP
);
658 if ((flags
& PRIM_BEGIN
) && ctx
->Line
.StippleFlag
)
662 /* Ensure last vertex doesn't wrap:
666 for ( ; j
+ 1 < count
; ) {
667 nr
= MIN2( dmasz
, count
- j
);
668 dest
= ALLOC_ELTS( nr
+1 ); /* Reserve possible space for last elt */
669 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
671 if (j
+ 1 >= count
&& (flags
& PRIM_END
)) {
672 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
679 static void TAG(render_triangles_elts
)( GLcontext
*ctx
,
685 GLuint
*elts
= GET_MESA_ELTS();
686 int dmasz
= GET_MAX_HW_ELTS()/3*3;
690 if (start
+2 >= count
)
693 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
696 /* Emit whole number of tris in total. dmasz is already a multiple
699 count
-= (count
-start
)%3;
701 for (j
= start
; j
< count
; j
+= nr
) {
702 nr
= MIN2( dmasz
, count
- j
);
703 dest
= ALLOC_ELTS( nr
);
704 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
711 static void TAG(render_tri_strip_elts
)( GLcontext
*ctx
,
718 GLuint
*elts
= GET_MESA_ELTS();
719 int dmasz
= GET_MAX_HW_ELTS();
722 if (start
+2 >= count
)
725 ELT_INIT( GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
);
727 /* Keep the same winding over multiple buffers:
729 dmasz
-= (dmasz
& 1);
731 for (j
= start
; j
+ 2 < count
; j
+= nr
- 2 ) {
732 nr
= MIN2( dmasz
, count
- j
);
734 dest
= ALLOC_ELTS( nr
);
735 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
740 static void TAG(render_tri_fan_elts
)( GLcontext
*ctx
,
746 GLuint
*elts
= GET_MESA_ELTS();
748 int dmasz
= GET_MAX_HW_ELTS();
751 if (start
+2 >= count
)
754 ELT_INIT( GL_TRIANGLE_FAN
, HW_TRIANGLE_FAN
);
756 for (j
= start
+ 1 ; j
+ 1 < count
; j
+= nr
- 1 ) {
757 nr
= MIN2( dmasz
, count
- j
+ 1 );
758 dest
= ALLOC_ELTS( nr
);
759 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
760 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
- 1 );
766 static void TAG(render_poly_elts
)( GLcontext
*ctx
,
772 GLuint
*elts
= GET_MESA_ELTS();
774 int dmasz
= GET_MAX_HW_ELTS();
777 if (start
+2 >= count
)
780 ELT_INIT( GL_POLYGON
, HW_POLYGON
);
782 for (j
= start
+ 1 ; j
+ 1 < count
; j
+= nr
- 1 ) {
783 nr
= MIN2( dmasz
, count
- j
+ 1 );
784 dest
= ALLOC_ELTS( nr
);
785 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+start
, 1 );
786 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
- 1 );
791 static void TAG(render_quad_strip_elts
)( GLcontext
*ctx
,
796 if (start
+3 >= count
)
799 if (HAVE_QUAD_STRIPS
&& 0) {
803 GLuint
*elts
= GET_MESA_ELTS();
804 int dmasz
= GET_MAX_HW_ELTS();
808 /* Emit whole number of quads in total, and in each buffer.
811 count
-= (count
-start
) & 1;
813 if (ctx
->_TriangleCaps
& DD_FLATSHADE
) {
814 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
818 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
819 nr
= MIN2( dmasz
, count
- j
);
823 GLint quads
= (nr
/2)-1;
824 ELT_TYPE
*dest
= ALLOC_ELTS( quads
*6 );
827 for ( i
= j
-start
; i
< j
-start
+quads
; i
++, elts
+= 2 ) {
828 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
829 EMIT_TWO_ELTS( dest
, 2, elts
[2], elts
[1] );
830 EMIT_TWO_ELTS( dest
, 4, elts
[3], elts
[2] );
839 ELT_INIT( GL_TRIANGLE_STRIP
, HW_TRIANGLE_STRIP_0
);
841 for (j
= start
; j
+ 3 < count
; j
+= nr
- 2 ) {
842 nr
= MIN2( dmasz
, count
- j
);
843 dest
= ALLOC_ELTS( nr
);
844 dest
= TAG(emit_elts
)( ctx
, dest
, elts
+j
, nr
);
852 static void TAG(render_quads_elts
)( GLcontext
*ctx
,
857 if (start
+3 >= count
)
860 if (HAVE_QUADS
&& 0) {
863 GLuint
*elts
= GET_MESA_ELTS();
864 int dmasz
= GET_MAX_HW_ELTS();
867 ELT_INIT( GL_TRIANGLES
, HW_TRIANGLES
);
869 /* Emit whole number of quads in total, and in each buffer.
872 count
-= (count
-start
) & 3;
874 /* Adjust for rendering as triangles:
878 for (j
= start
; j
+ 3 < count
; j
+= nr
) {
879 nr
= MIN2( dmasz
, count
- j
);
883 ELT_TYPE
*dest
= ALLOC_ELTS( quads
* 6 );
886 for ( i
= j
-start
; i
< j
-start
+quads
; i
++, elts
+= 4 ) {
887 EMIT_TWO_ELTS( dest
, 0, elts
[0], elts
[1] );
888 EMIT_TWO_ELTS( dest
, 2, elts
[3], elts
[1] );
889 EMIT_TWO_ELTS( dest
, 4, elts
[2], elts
[3] );
901 static render_func
TAG(render_tab_elts
)[GL_POLYGON
+2] =
903 TAG(render_points_elts
),
904 TAG(render_lines_elts
),
905 TAG(render_line_loop_elts
),
906 TAG(render_line_strip_elts
),
907 TAG(render_triangles_elts
),
908 TAG(render_tri_strip_elts
),
909 TAG(render_tri_fan_elts
),
910 TAG(render_quads_elts
),
911 TAG(render_quad_strip_elts
),
912 TAG(render_poly_elts
),