1 /* $Id: t_vb_render.c,v 1.19 2001/04/28 08:39:18 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Keith Whitwell <keithw@valinux.com>
32 * Render whole vertex buffers, including projection of vertices from
33 * clip space and clipping of primitives.
35 * This file makes calls to project vertices and to the point, line
36 * and triangle rasterizers via the function pointers:
38 * context->Driver.BuildProjectedVertices()
40 * context->Driver.PointsFunc()
41 * context->Driver.LineFunc()
42 * context->Driver.TriangleFunc()
43 * context->Driver.QuadFunc()
45 * context->Driver.RenderTabVerts[]
46 * context->Driver.RenderTabElts[]
48 * None of these may be null.
59 #include "math/m_matrix.h"
60 #include "math/m_xform.h"
62 #include "t_pipeline.h"
66 /**********************************************************************/
67 /* Clip single primitives */
68 /**********************************************************************/
72 #define NEGATIVE(x) ((*(GLuint *)&x) & (1<<31))
73 #define DIFFERENT_SIGNS(x,y) (((*(GLuint *)&x)^(*(GLuint *)&y)) & (1<<31))
75 #define NEGATIVE(x) (x < 0)
76 #define DIFFERENT_SIGNS(x,y) (x * y <= 0 && x - y != 0)
77 /* Could just use (x*y<0) except for the flatshading requirements.
78 * Maybe there's a better way?
83 #define W(i) coord[i][3]
84 #define Z(i) coord[i][2]
85 #define Y(i) coord[i][1]
86 #define X(i) coord[i][0]
89 #include "t_vb_cliptmp.h"
93 /**********************************************************************/
94 /* Clip and render whole begin/end objects */
95 /**********************************************************************/
97 #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED)
98 #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
99 #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
102 /* Vertices, with the possibility of clipping.
104 #define RENDER_POINTS( start, count ) \
105 tnl->Driver.PointsFunc( ctx, start, count )
107 #define RENDER_LINE( v1, v2 ) \
109 GLubyte c1 = mask[v1], c2 = mask[v2]; \
110 GLubyte ormask = c1|c2; \
112 LineFunc( ctx, v1, v2 ); \
113 else if (!(c1 & c2 & 0x3f)) \
114 clip_line_4( ctx, v1, v2, ormask ); \
117 #define RENDER_TRI( v1, v2, v3 ) \
119 GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \
120 GLubyte ormask = c1|c2|c3; \
122 TriangleFunc( ctx, v1, v2, v3 ); \
123 else if (!(c1 & c2 & c3 & 0x3f)) \
124 clip_tri_4( ctx, v1, v2, v3, ormask ); \
127 #define RENDER_QUAD( v1, v2, v3, v4 ) \
129 GLubyte c1 = mask[v1], c2 = mask[v2]; \
130 GLubyte c3 = mask[v3], c4 = mask[v4]; \
131 GLubyte ormask = c1|c2|c3|c4; \
133 QuadFunc( ctx, v1, v2, v3, v4 ); \
134 else if (!(c1 & c2 & c3 & c4 & 0x3f)) \
135 clip_quad_4( ctx, v1, v2, v3, v4, ormask ); \
140 TNLcontext *tnl = TNL_CONTEXT(ctx); \
141 struct vertex_buffer *VB = &tnl->vb; \
142 const GLuint * const elt = VB->Elts; \
143 const GLubyte *mask = VB->ClipMask; \
144 const GLuint sz = VB->ClipPtr->size; \
145 const line_func LineFunc = tnl->Driver.LineFunc; \
146 const triangle_func TriangleFunc = tnl->Driver.TriangleFunc; \
147 const quad_func QuadFunc = tnl->Driver.QuadFunc; \
148 const GLboolean stipple = ctx->Line.StippleFlag; \
149 (void) (LineFunc && TriangleFunc && QuadFunc); \
150 (void) elt; (void) mask; (void) sz; (void) stipple;
152 #define TAG(x) clip_##x##_verts
153 #define INIT(x) tnl->Driver.RenderPrimitive( ctx, x )
154 #define RESET_STIPPLE if (stipple) tnl->Driver.ResetLineStipple( ctx )
155 #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE
156 #define PRESERVE_VB_DEFS
157 #include "t_vb_rendertmp.h"
161 /* Elts, with the possibility of clipping.
165 #define ELT(x) elt[x]
166 #define TAG(x) clip_##x##_elts
167 #include "t_vb_rendertmp.h"
169 /* TODO: do this for all primitives, verts and elts:
171 static void clip_elt_triangles( GLcontext
*ctx
,
176 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
177 render_func render_tris
= tnl
->Driver
.RenderTabElts
[GL_TRIANGLES
];
178 struct vertex_buffer
*VB
= &tnl
->vb
;
179 const GLuint
* const elt
= VB
->Elts
;
180 GLubyte
*mask
= VB
->ClipMask
;
181 GLuint last
= count
-2;
185 tnl
->Driver
.RenderPrimitive( ctx
, GL_TRIANGLES
);
187 for (j
=start
; j
< last
; j
+=3 ) {
188 GLubyte c1
= mask
[elt
[j
]];
189 GLubyte c2
= mask
[elt
[j
+1]];
190 GLubyte c3
= mask
[elt
[j
+2]];
191 GLubyte ormask
= c1
|c2
|c3
;
194 render_tris( ctx
, start
, j
, 0 );
195 if (!(c1
&c2
&c3
&0x3f))
196 clip_tri_4( ctx
, elt
[j
], elt
[j
+1], elt
[j
+2], ormask
);
202 render_tris( ctx
, start
, j
, 0 );
205 /**********************************************************************/
206 /* Render whole begin/end objects */
207 /**********************************************************************/
209 #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED)
210 #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
211 #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
214 /* Vertices, no clipping.
216 #define RENDER_POINTS( start, count ) \
217 tnl->Driver.PointsFunc( ctx, start, count )
219 #define RENDER_LINE( v1, v2 ) \
220 LineFunc( ctx, v1, v2 )
222 #define RENDER_TRI( v1, v2, v3 ) \
223 TriangleFunc( ctx, v1, v2, v3 )
225 #define RENDER_QUAD( v1, v2, v3, v4 ) \
226 QuadFunc( ctx, v1, v2, v3, v4 )
228 #define TAG(x) _tnl_##x##_verts
231 TNLcontext *tnl = TNL_CONTEXT(ctx); \
232 struct vertex_buffer *VB = &tnl->vb; \
233 const GLuint * const elt = VB->Elts; \
234 const line_func LineFunc = tnl->Driver.LineFunc; \
235 const triangle_func TriangleFunc = tnl->Driver.TriangleFunc; \
236 const quad_func QuadFunc = tnl->Driver.QuadFunc; \
237 (void) (LineFunc && TriangleFunc && QuadFunc); \
240 #define RESET_STIPPLE tnl->Driver.ResetLineStipple( ctx )
241 #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE
242 #define INIT(x) tnl->Driver.RenderPrimitive( ctx, x )
243 #define RENDER_TAB_QUALIFIER
244 #define PRESERVE_VB_DEFS
245 #include "t_vb_rendertmp.h"
248 /* Elts, no clipping.
251 #define TAG(x) _tnl_##x##_elts
252 #define ELT(x) elt[x]
253 #include "t_vb_rendertmp.h"
258 /**********************************************************************/
259 /* Clip and render whole vertex buffers */
260 /**********************************************************************/
263 static GLboolean
run_render( GLcontext
*ctx
,
264 struct gl_pipeline_stage
*stage
)
266 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
267 struct vertex_buffer
*VB
= &tnl
->vb
;
268 GLuint new_inputs
= stage
->changed_inputs
;
273 /* Allow the drivers to lock before projected verts are built so
274 * that window coordinates are guarenteed not to change before
277 ASSERT(tnl
->Driver
.RenderStart
);
279 tnl
->Driver
.RenderStart( ctx
);
281 ASSERT(tnl
->Driver
.BuildProjectedVertices
);
282 ASSERT(tnl
->Driver
.RenderPrimitive
);
283 ASSERT(tnl
->Driver
.PointsFunc
);
284 ASSERT(tnl
->Driver
.LineFunc
);
285 ASSERT(tnl
->Driver
.TriangleFunc
);
286 ASSERT(tnl
->Driver
.QuadFunc
);
287 ASSERT(tnl
->Driver
.ResetLineStipple
);
288 ASSERT(tnl
->Driver
.RenderInterp
);
289 ASSERT(tnl
->Driver
.RenderCopyPV
);
290 ASSERT(tnl
->Driver
.RenderClippedLine
);
291 ASSERT(tnl
->Driver
.RenderClippedPolygon
);
292 ASSERT(tnl
->Driver
.RenderFinish
);
294 tnl
->Driver
.BuildProjectedVertices( ctx
, 0, VB
->Count
, new_inputs
);
296 if (VB
->ClipOrMask
) {
297 tab
= VB
->Elts
? clip_render_tab_elts
: clip_render_tab_verts
;
298 clip_render_tab_elts
[GL_TRIANGLES
] = clip_elt_triangles
;
301 tab
= VB
->Elts
? tnl
->Driver
.RenderTabElts
: tnl
->Driver
.RenderTabVerts
;
306 GLuint i
, length
, flags
= 0;
307 for (i
= 0 ; !(flags
& PRIM_LAST
) ; i
+= length
)
309 flags
= VB
->Primitive
[i
];
310 length
= VB
->PrimitiveLength
[i
];
311 ASSERT(length
|| (flags
& PRIM_LAST
));
312 ASSERT((flags
& PRIM_MODE_MASK
) <= GL_POLYGON
+1);
314 tab
[flags
& PRIM_MODE_MASK
]( ctx
, i
, i
+ length
, flags
);
316 } while (tnl
->Driver
.MultipassFunc
&&
317 tnl
->Driver
.MultipassFunc( ctx
, ++pass
));
320 tnl
->Driver
.RenderFinish( ctx
);
321 /* usleep(100000); */
322 return GL_FALSE
; /* finished the pipe */
326 /**********************************************************************/
327 /* Render pipeline stage */
328 /**********************************************************************/
332 /* Quite a bit of work involved in finding out the inputs for the
335 static void check_render( GLcontext
*ctx
, struct gl_pipeline_stage
*stage
)
337 GLuint inputs
= VERT_CLIP
;
340 if (ctx
->Visual
.rgbMode
) {
343 if (ctx
->_TriangleCaps
& DD_SEPARATE_SPECULAR
)
344 inputs
|= VERT_SPEC_RGB
;
346 if (ctx
->Texture
._ReallyEnabled
) {
347 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++) {
348 if (ctx
->Texture
.Unit
[i
]._ReallyEnabled
)
349 inputs
|= VERT_TEX(i
);
354 inputs
|= VERT_INDEX
;
357 if (ctx
->Point
._Attenuated
)
358 inputs
|= VERT_POINT_SIZE
;
360 /* How do drivers turn this off?
362 if (ctx
->Fog
.Enabled
)
363 inputs
|= VERT_FOG_COORD
;
365 if (ctx
->_TriangleCaps
& DD_TRI_UNFILLED
)
368 if (ctx
->RenderMode
==GL_FEEDBACK
)
369 inputs
|= VERT_TEX_ANY
;
371 stage
->inputs
= inputs
;
377 static void dtr( struct gl_pipeline_stage
*stage
)
382 const struct gl_pipeline_stage _tnl_render_stage
=
386 _DD_NEW_SEPARATE_SPECULAR
|
392 _DD_NEW_TRI_UNFILLED
|
393 _NEW_RENDERMODE
), /* re-check (new inputs, interp function) */
394 0, /* re-run (always runs) */
395 GL_TRUE
, /* active */
396 0, 0, /* inputs (set in check_render), outputs */
397 0, 0, /* changed_inputs, private */
398 dtr
, /* destructor */
399 check_render
, /* check */