1 /* $Id: t_vb_render.c,v 1.18 2001/04/26 14:53:48 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?
82 #define LINTERP_SZ( t, vec, to, a, b, sz ) \
85 case 2: vec[to][2] = 0.0; \
86 case 3: vec[to][3] = 1.0; \
89 case 4: vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \
90 case 3: vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \
91 case 2: vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \
92 vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \
96 #define LINTERP_4F( t, vec, to, a, b, sz ) \
98 vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \
99 vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \
100 vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \
101 vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \
104 #define W(i) coord[i][3]
105 #define Z(i) coord[i][2]
106 #define Y(i) coord[i][1]
107 #define X(i) coord[i][0]
110 #include "t_vb_cliptmp.h"
114 /**********************************************************************/
115 /* Clip and render whole begin/end objects */
116 /**********************************************************************/
118 #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED)
119 #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
120 #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
123 /* Vertices, with the possibility of clipping.
125 #define RENDER_POINTS( start, count ) \
126 tnl->Driver.PointsFunc( ctx, start, count )
128 #define RENDER_LINE( v1, v2 ) \
130 GLubyte c1 = mask[v1], c2 = mask[v2]; \
131 GLubyte ormask = c1|c2; \
133 LineFunc( ctx, v1, v2 ); \
134 else if (!(c1 & c2 & 0x3f)) \
135 clip_line_4( ctx, v1, v2, ormask ); \
138 #define RENDER_TRI( v1, v2, v3 ) \
140 GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \
141 GLubyte ormask = c1|c2|c3; \
143 TriangleFunc( ctx, v1, v2, v3 ); \
144 else if (!(c1 & c2 & c3 & 0x3f)) \
145 clip_tri_4( ctx, v1, v2, v3, ormask ); \
148 #define RENDER_QUAD( v1, v2, v3, v4 ) \
150 GLubyte c1 = mask[v1], c2 = mask[v2]; \
151 GLubyte c3 = mask[v3], c4 = mask[v4]; \
152 GLubyte ormask = c1|c2|c3|c4; \
154 QuadFunc( ctx, v1, v2, v3, v4 ); \
155 else if (!(c1 & c2 & c3 & c4 & 0x3f)) \
156 clip_quad_4( ctx, v1, v2, v3, v4, ormask ); \
161 TNLcontext *tnl = TNL_CONTEXT(ctx); \
162 struct vertex_buffer *VB = &tnl->vb; \
163 const GLuint * const elt = VB->Elts; \
164 const GLubyte *mask = VB->ClipMask; \
165 const GLuint sz = VB->ClipPtr->size; \
166 const line_func LineFunc = tnl->Driver.LineFunc; \
167 const triangle_func TriangleFunc = tnl->Driver.TriangleFunc; \
168 const quad_func QuadFunc = tnl->Driver.QuadFunc; \
169 const GLboolean stipple = ctx->Line.StippleFlag; \
170 (void) (LineFunc && TriangleFunc && QuadFunc); \
171 (void) elt; (void) mask; (void) sz; (void) stipple;
173 #define TAG(x) clip_##x##_verts
174 #define INIT(x) tnl->Driver.RenderPrimitive( ctx, x )
175 #define RESET_STIPPLE if (stipple) tnl->Driver.ResetLineStipple( ctx )
176 #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE
177 #define PRESERVE_VB_DEFS
178 #include "t_vb_rendertmp.h"
182 /* Elts, with the possibility of clipping.
186 #define ELT(x) elt[x]
187 #define TAG(x) clip_##x##_elts
188 #include "t_vb_rendertmp.h"
190 /* TODO: do this for all primitives, verts and elts:
192 static void clip_elt_triangles( GLcontext
*ctx
,
197 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
198 render_func render_tris
= tnl
->Driver
.RenderTabElts
[GL_TRIANGLES
];
199 struct vertex_buffer
*VB
= &tnl
->vb
;
200 const GLuint
* const elt
= VB
->Elts
;
201 GLubyte
*mask
= VB
->ClipMask
;
202 GLuint last
= count
-2;
206 tnl
->Driver
.RenderPrimitive( ctx
, GL_TRIANGLES
);
208 for (j
=start
; j
< last
; j
+=3 ) {
209 GLubyte c1
= mask
[elt
[j
]];
210 GLubyte c2
= mask
[elt
[j
+1]];
211 GLubyte c3
= mask
[elt
[j
+2]];
212 GLubyte ormask
= c1
|c2
|c3
;
215 render_tris( ctx
, start
, j
, 0 );
216 if (!(c1
&c2
&c3
&0x3f))
217 clip_tri_4( ctx
, elt
[j
], elt
[j
+1], elt
[j
+2], ormask
);
223 render_tris( ctx
, start
, j
, 0 );
226 /**********************************************************************/
227 /* Render whole begin/end objects */
228 /**********************************************************************/
230 #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED)
231 #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
232 #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
235 /* Vertices, no clipping.
237 #define RENDER_POINTS( start, count ) \
238 tnl->Driver.PointsFunc( ctx, start, count )
240 #define RENDER_LINE( v1, v2 ) \
241 LineFunc( ctx, v1, v2 )
243 #define RENDER_TRI( v1, v2, v3 ) \
244 TriangleFunc( ctx, v1, v2, v3 )
246 #define RENDER_QUAD( v1, v2, v3, v4 ) \
247 QuadFunc( ctx, v1, v2, v3, v4 )
249 #define TAG(x) _tnl_##x##_verts
252 TNLcontext *tnl = TNL_CONTEXT(ctx); \
253 struct vertex_buffer *VB = &tnl->vb; \
254 const GLuint * const elt = VB->Elts; \
255 const line_func LineFunc = tnl->Driver.LineFunc; \
256 const triangle_func TriangleFunc = tnl->Driver.TriangleFunc; \
257 const quad_func QuadFunc = tnl->Driver.QuadFunc; \
258 (void) (LineFunc && TriangleFunc && QuadFunc); \
261 #define RESET_STIPPLE tnl->Driver.ResetLineStipple( ctx )
262 #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE
263 #define INIT(x) tnl->Driver.RenderPrimitive( ctx, x )
264 #define RENDER_TAB_QUALIFIER
265 #define PRESERVE_VB_DEFS
266 #include "t_vb_rendertmp.h"
269 /* Elts, no clipping.
272 #define TAG(x) _tnl_##x##_elts
273 #define ELT(x) elt[x]
274 #include "t_vb_rendertmp.h"
279 /**********************************************************************/
280 /* Clip and render whole vertex buffers */
281 /**********************************************************************/
284 static GLboolean
run_render( GLcontext
*ctx
,
285 struct gl_pipeline_stage
*stage
)
287 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
288 struct vertex_buffer
*VB
= &tnl
->vb
;
289 GLuint new_inputs
= stage
->changed_inputs
;
294 /* Allow the drivers to lock before projected verts are built so
295 * that window coordinates are guarenteed not to change before
298 ASSERT(tnl
->Driver
.RenderStart
);
300 tnl
->Driver
.RenderStart( ctx
);
302 ASSERT(tnl
->Driver
.BuildProjectedVertices
);
303 ASSERT(tnl
->Driver
.RenderPrimitive
);
304 ASSERT(tnl
->Driver
.PointsFunc
);
305 ASSERT(tnl
->Driver
.LineFunc
);
306 ASSERT(tnl
->Driver
.TriangleFunc
);
307 ASSERT(tnl
->Driver
.QuadFunc
);
308 ASSERT(tnl
->Driver
.ResetLineStipple
);
309 ASSERT(tnl
->Driver
.RenderInterp
);
310 ASSERT(tnl
->Driver
.RenderCopyPV
);
311 ASSERT(tnl
->Driver
.RenderClippedLine
);
312 ASSERT(tnl
->Driver
.RenderClippedPolygon
);
313 ASSERT(tnl
->Driver
.RenderFinish
);
315 tnl
->Driver
.BuildProjectedVertices( ctx
, 0, VB
->Count
, new_inputs
);
317 if (VB
->ClipOrMask
) {
318 tab
= VB
->Elts
? clip_render_tab_elts
: clip_render_tab_verts
;
319 clip_render_tab_elts
[GL_TRIANGLES
] = clip_elt_triangles
;
322 tab
= VB
->Elts
? tnl
->Driver
.RenderTabElts
: tnl
->Driver
.RenderTabVerts
;
327 GLuint i
, length
, flags
= 0;
328 for (i
= 0 ; !(flags
& PRIM_LAST
) ; i
+= length
)
330 flags
= VB
->Primitive
[i
];
331 length
= VB
->PrimitiveLength
[i
];
332 ASSERT(length
|| (flags
& PRIM_LAST
));
333 ASSERT((flags
& PRIM_MODE_MASK
) <= GL_POLYGON
+1);
335 tab
[flags
& PRIM_MODE_MASK
]( ctx
, i
, i
+ length
, flags
);
337 } while (tnl
->Driver
.MultipassFunc
&&
338 tnl
->Driver
.MultipassFunc( ctx
, ++pass
));
341 tnl
->Driver
.RenderFinish( ctx
);
342 /* usleep(100000); */
343 return GL_FALSE
; /* finished the pipe */
347 /**********************************************************************/
348 /* Render pipeline stage */
349 /**********************************************************************/
353 /* Quite a bit of work involved in finding out the inputs for the
356 static void check_render( GLcontext
*ctx
, struct gl_pipeline_stage
*stage
)
358 GLuint inputs
= VERT_CLIP
;
361 if (ctx
->Visual
.rgbMode
) {
364 if (ctx
->_TriangleCaps
& DD_SEPARATE_SPECULAR
)
365 inputs
|= VERT_SPEC_RGB
;
367 if (ctx
->Texture
._ReallyEnabled
) {
368 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++) {
369 if (ctx
->Texture
.Unit
[i
]._ReallyEnabled
)
370 inputs
|= VERT_TEX(i
);
375 inputs
|= VERT_INDEX
;
378 if (ctx
->Point
._Attenuated
)
379 inputs
|= VERT_POINT_SIZE
;
381 /* How do drivers turn this off?
383 if (ctx
->Fog
.Enabled
)
384 inputs
|= VERT_FOG_COORD
;
386 if (ctx
->_TriangleCaps
& DD_TRI_UNFILLED
)
389 if (ctx
->RenderMode
==GL_FEEDBACK
)
390 inputs
|= VERT_TEX_ANY
;
392 stage
->inputs
= inputs
;
398 static void dtr( struct gl_pipeline_stage
*stage
)
403 const struct gl_pipeline_stage _tnl_render_stage
=
407 _DD_NEW_SEPARATE_SPECULAR
|
413 _DD_NEW_TRI_UNFILLED
|
414 _NEW_RENDERMODE
), /* re-check (new inputs, interp function) */
415 0, /* re-run (always runs) */
416 GL_TRUE
, /* active */
417 0, 0, /* inputs (set in check_render), outputs */
418 0, 0, /* changed_inputs, private */
419 dtr
, /* destructor */
420 check_render
, /* check */