2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
25 * Keith Whitwell <keithw@vmware.com>
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.
36 * Produces code for both inline triangles and indexed triangles.
37 * Where various primitive types are unaccelerated by hardware, the
38 * code attempts to fallback to other primitive types (quadstrips to
39 * tristrips, lineloops to linestrips), or to indexed vertices.
42 #if !HAVE_TRIANGLES || !HAVE_LINES || !HAVE_LINE_STRIPS || !HAVE_TRI_STRIPS || !HAVE_TRI_FANS
43 #error "must have lines, line strips, triangles, triangle fans, and triangle strips to use render template"
46 #if HAVE_QUAD_STRIPS || HAVE_QUADS || HAVE_ELTS
47 #error "ELTs, quads, and quad strips not supported by render template"
51 /**********************************************************************/
52 /* Render whole begin/end objects */
53 /**********************************************************************/
55 static inline void *TAG(emit_verts
)(struct gl_context
*ctx
, GLuint start
,
56 GLuint count
, void *buf
)
58 return EMIT_VERTS(ctx
, start
, count
, buf
);
61 /***********************************************************************
62 * Render non-indexed primitives.
63 ***********************************************************************/
65 static void TAG(render_points_verts
)(struct gl_context
*ctx
,
72 const unsigned dmasz
= GET_SUBSEQUENT_VB_MAX_VERTS();
78 currentsz
= GET_CURRENT_VB_MAX_VERTS();
82 for (j
= 0; j
< count
; j
+= nr
) {
83 nr
= MIN2(currentsz
, count
- j
);
84 TAG(emit_verts
)(ctx
, start
+ j
, nr
, ALLOC_VERTS(nr
));
88 unreachable("Cannot draw primitive; validate_render should have "
93 static void TAG(render_lines_verts
)(struct gl_context
*ctx
,
99 const unsigned dmasz
= GET_SUBSEQUENT_VB_MAX_VERTS() & ~1;
105 /* Emit whole number of lines in total and in each buffer:
108 currentsz
= GET_CURRENT_VB_MAX_VERTS();
109 currentsz
-= currentsz
& 1;
114 for (j
= 0; j
< count
; j
+= nr
) {
115 nr
= MIN2(currentsz
, count
- j
);
116 TAG(emit_verts
)(ctx
, start
+ j
, nr
, ALLOC_VERTS(nr
));
122 static void TAG(render_line_strip_verts
)(struct gl_context
*ctx
,
128 const unsigned dmasz
= GET_SUBSEQUENT_VB_MAX_VERTS();
134 currentsz
= GET_CURRENT_VB_MAX_VERTS();
138 for (j
= 0; j
+ 1 < count
; j
+= nr
- 1) {
139 nr
= MIN2(currentsz
, count
- j
);
140 TAG(emit_verts
)(ctx
, start
+ j
, nr
, ALLOC_VERTS(nr
));
148 static void TAG(render_line_loop_verts
)(struct gl_context
*ctx
,
154 const unsigned dmasz
= GET_SUBSEQUENT_VB_MAX_VERTS() - 1;
160 j
= (flags
& PRIM_BEGIN
) ? 0 : 1;
162 /* Ensure last vertex won't wrap buffers:
164 currentsz
= GET_CURRENT_VB_MAX_VERTS();
171 for (/* empty */; j
+ 1 < count
; j
+= nr
- 1) {
172 nr
= MIN2(currentsz
, count
- j
);
174 if (j
+ nr
>= count
&&
176 (flags
& PRIM_END
)) {
178 tmp
= ALLOC_VERTS(nr
+1);
179 tmp
= TAG(emit_verts
)(ctx
, start
+ j
, nr
, tmp
);
180 tmp
= TAG(emit_verts
)( ctx
, start
, 1, tmp
);
183 TAG(emit_verts
)(ctx
, start
+ j
, nr
, ALLOC_VERTS(nr
));
187 } else if (count
> 1 && (flags
& PRIM_END
)) {
189 tmp
= ALLOC_VERTS(2);
190 tmp
= TAG(emit_verts
)( ctx
, start
+1, 1, tmp
);
191 tmp
= TAG(emit_verts
)( ctx
, start
, 1, tmp
);
199 static void TAG(render_triangles_verts
)(struct gl_context
*ctx
,
205 const unsigned dmasz
= (GET_SUBSEQUENT_VB_MAX_VERTS() / 3) * 3;
211 currentsz
= (GET_CURRENT_VB_MAX_VERTS() / 3) * 3;
213 /* Emit whole number of tris in total. dmasz is already a multiple
221 for (j
= 0; j
< count
; j
+= nr
) {
222 nr
= MIN2(currentsz
, count
- j
);
223 TAG(emit_verts
)(ctx
, start
+ j
, nr
, ALLOC_VERTS(nr
));
230 static void TAG(render_tri_strip_verts
)(struct gl_context
*ctx
,
237 const unsigned dmasz
= GET_SUBSEQUENT_VB_MAX_VERTS() & ~1;
240 INIT(GL_TRIANGLE_STRIP
);
242 currentsz
= GET_CURRENT_VB_MAX_VERTS();
247 /* From here on emit even numbers of tris when wrapping over buffers:
249 currentsz
-= (currentsz
& 1);
251 for (j
= 0; j
+ 2 < count
; j
+= nr
- 2) {
252 nr
= MIN2(currentsz
, count
- j
);
253 TAG(emit_verts
)(ctx
, start
+ j
, nr
, ALLOC_VERTS(nr
));
260 static void TAG(render_tri_fan_verts
)(struct gl_context
*ctx
,
267 const unsigned dmasz
= GET_SUBSEQUENT_VB_MAX_VERTS();
270 INIT(GL_TRIANGLE_FAN
);
272 currentsz
= GET_CURRENT_VB_MAX_VERTS();
276 for (j
= 1; j
+ 1 < count
; j
+= nr
- 2) {
278 nr
= MIN2(currentsz
, count
- j
+ 1);
279 tmp
= ALLOC_VERTS(nr
);
280 tmp
= TAG(emit_verts
)(ctx
, start
, 1, tmp
);
281 tmp
= TAG(emit_verts
)(ctx
, start
+ j
, nr
- 1, tmp
);
290 static void TAG(render_poly_verts
)(struct gl_context
*ctx
,
298 const unsigned dmasz
= GET_SUBSEQUENT_VB_MAX_VERTS();
303 currentsz
= GET_CURRENT_VB_MAX_VERTS();
308 for (j
= 1; j
+ 1 < count
; j
+= nr
- 2) {
310 nr
= MIN2(currentsz
, count
- j
+ 1);
311 tmp
= ALLOC_VERTS(nr
);
312 tmp
= TAG(emit_verts
)(ctx
, start
, 1, tmp
);
313 tmp
= TAG(emit_verts
)(ctx
, start
+ j
, nr
- 1, tmp
);
319 } else if (ctx
->Light
.ShadeModel
== GL_SMOOTH
||
320 ctx
->Light
.ProvokingVertex
== GL_FIRST_VERTEX_CONVENTION
) {
321 TAG(render_tri_fan_verts
)( ctx
, start
, count
, flags
);
323 unreachable("Cannot draw primitive; validate_render should have "
328 static void TAG(render_quad_strip_verts
)(struct gl_context
*ctx
,
335 if (ctx
->Light
.ShadeModel
== GL_SMOOTH
) {
337 const unsigned dmasz
= GET_SUBSEQUENT_VB_MAX_VERTS() & ~1;
340 /* Emit smooth-shaded quadstrips as tristrips:
343 INIT(GL_TRIANGLE_STRIP
);
345 /* Emit whole number of quads in total, and in each buffer.
347 currentsz
= GET_CURRENT_VB_MAX_VERTS();
348 currentsz
-= currentsz
& 1;
354 for (j
= 0; j
+ 3 < count
; j
+= nr
- 2) {
355 nr
= MIN2(currentsz
, count
- j
);
356 TAG(emit_verts
)(ctx
, start
+ j
, nr
, ALLOC_VERTS(nr
));
362 unreachable("Cannot draw primitive; validate_render should have "
368 static void TAG(render_quads_verts
)(struct gl_context
*ctx
,
376 /* Emit whole number of quads in total. */
379 /* Hardware doesn't have a quad primitive type -- try to simulate it using
380 * triangle primitive. This is a win for gears, but is it useful in the
385 for (j
= 0; j
+ 3 < count
; j
+= 4) {
386 void *tmp
= ALLOC_VERTS(6);
389 tmp
= EMIT_VERTS(ctx
, start
+ j
, 2, tmp
);
390 tmp
= EMIT_VERTS(ctx
, start
+ j
+ 3, 1, tmp
);
393 tmp
= EMIT_VERTS(ctx
, start
+ j
+ 1, 3, tmp
);
398 static void TAG(render_noop
)(struct gl_context
*ctx
,
409 static const tnl_render_func
TAG(render_tab_verts
)[GL_POLYGON
+2] =
411 TAG(render_points_verts
),
412 TAG(render_lines_verts
),
413 TAG(render_line_loop_verts
),
414 TAG(render_line_strip_verts
),
415 TAG(render_triangles_verts
),
416 TAG(render_tri_strip_verts
),
417 TAG(render_tri_fan_verts
),
418 TAG(render_quads_verts
),
419 TAG(render_quad_strip_verts
),
420 TAG(render_poly_verts
),
424 /* Pre-check the primitives in the VB to prevent the need for
425 * fallbacks later on.
427 static bool TAG(validate_render
)(struct gl_context
*ctx
,
428 struct vertex_buffer
*VB
)
432 if (VB
->ClipOrMask
& ~CLIP_CULL_BIT
)
438 for (i
= 0 ; i
< VB
->PrimitiveCount
; i
++) {
439 GLuint prim
= VB
->Primitive
[i
].mode
;
440 GLuint count
= VB
->Primitive
[i
].count
;
446 switch (prim
& PRIM_MODE_MASK
) {
453 ok
= !ctx
->Line
.StippleFlag
;
456 case GL_TRIANGLE_STRIP
:
457 case GL_TRIANGLE_FAN
:
461 ok
= (HAVE_POLYGONS
) || ctx
->Light
.ShadeModel
== GL_SMOOTH
||
462 ctx
->Light
.ProvokingVertex
== GL_FIRST_VERTEX_CONVENTION
;
465 ok
= VB
->Elts
|| ctx
->Light
.ShadeModel
== GL_SMOOTH
;
468 ok
= true; /* flatshading is ok. */
475 /* fprintf(stderr, "not ok %s\n", _mesa_enum_to_string(prim & PRIM_MODE_MASK)); */