change an assertion
[mesa.git] / src / mesa / tnl / t_vb_render.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Keith Whitwell <keith@tungstengraphics.com>
26 */
27
28
29 /*
30 * Render whole vertex buffers, including projection of vertices from
31 * clip space and clipping of primitives.
32 *
33 * This file makes calls to project vertices and to the point, line
34 * and triangle rasterizers via the function pointers:
35 *
36 * context->Driver.Render.*
37 *
38 */
39
40
41 #include "glheader.h"
42 #include "context.h"
43 #include "enums.h"
44 #include "macros.h"
45 #include "imports.h"
46 #include "mtypes.h"
47
48 #include "t_pipeline.h"
49
50
51
52 /**********************************************************************/
53 /* Clip single primitives */
54 /**********************************************************************/
55
56
57 #define W(i) coord[i][3]
58 #define Z(i) coord[i][2]
59 #define Y(i) coord[i][1]
60 #define X(i) coord[i][0]
61 #define SIZE 4
62 #define TAG(x) x##_4
63 #include "t_vb_cliptmp.h"
64
65
66
67 /**********************************************************************/
68 /* Clip and render whole begin/end objects */
69 /**********************************************************************/
70
71 #define NEED_EDGEFLAG_SETUP (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL)
72 #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
73 #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
74
75
76 #define CLIPMASK (CLIP_ALL_BITS|CLIP_CULL_BIT)
77
78
79 /* Vertices, with the possibility of clipping.
80 */
81 #define RENDER_POINTS( start, count ) \
82 tnl->Driver.Render.Points( ctx, start, count )
83
84 #define RENDER_LINE( v1, v2 ) \
85 do { \
86 GLubyte c1 = mask[v1], c2 = mask[v2]; \
87 GLubyte ormask = c1|c2; \
88 if (!ormask) \
89 LineFunc( ctx, v1, v2 ); \
90 else if (!(c1 & c2 & CLIPMASK)) \
91 clip_line_4( ctx, v1, v2, ormask ); \
92 } while (0)
93
94 #define RENDER_TRI( v1, v2, v3 ) \
95 do { \
96 GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \
97 GLubyte ormask = c1|c2|c3; \
98 if (!ormask) \
99 TriangleFunc( ctx, v1, v2, v3 ); \
100 else if (!(c1 & c2 & c3 & CLIPMASK)) \
101 clip_tri_4( ctx, v1, v2, v3, ormask ); \
102 } while (0)
103
104 #define RENDER_QUAD( v1, v2, v3, v4 ) \
105 do { \
106 GLubyte c1 = mask[v1], c2 = mask[v2]; \
107 GLubyte c3 = mask[v3], c4 = mask[v4]; \
108 GLubyte ormask = c1|c2|c3|c4; \
109 if (!ormask) \
110 QuadFunc( ctx, v1, v2, v3, v4 ); \
111 else if (!(c1 & c2 & c3 & c4 & CLIPMASK)) \
112 clip_quad_4( ctx, v1, v2, v3, v4, ormask ); \
113 } while (0)
114
115
116 #define LOCAL_VARS \
117 TNLcontext *tnl = TNL_CONTEXT(ctx); \
118 struct vertex_buffer *VB = &tnl->vb; \
119 const GLuint * const elt = VB->Elts; \
120 const GLubyte *mask = VB->ClipMask; \
121 const GLuint sz = VB->ClipPtr->size; \
122 const tnl_line_func LineFunc = tnl->Driver.Render.Line; \
123 const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \
124 const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \
125 const GLboolean stipple = ctx->Line.StippleFlag; \
126 (void) (LineFunc && TriangleFunc && QuadFunc); \
127 (void) elt; (void) mask; (void) sz; (void) stipple;
128
129 #define TAG(x) clip_##x##_verts
130 #define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x )
131 #define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx )
132 #define PRESERVE_VB_DEFS
133 #include "t_vb_rendertmp.h"
134
135
136
137 /* Elts, with the possibility of clipping.
138 */
139 #undef ELT
140 #undef TAG
141 #define ELT(x) elt[x]
142 #define TAG(x) clip_##x##_elts
143 #include "t_vb_rendertmp.h"
144
145 /* TODO: do this for all primitives, verts and elts:
146 */
147 static void clip_elt_triangles( GLcontext *ctx,
148 GLuint start,
149 GLuint count,
150 GLuint flags )
151 {
152 TNLcontext *tnl = TNL_CONTEXT(ctx);
153 tnl_render_func render_tris = tnl->Driver.Render.PrimTabElts[GL_TRIANGLES];
154 struct vertex_buffer *VB = &tnl->vb;
155 const GLuint * const elt = VB->Elts;
156 GLubyte *mask = VB->ClipMask;
157 GLuint last = count-2;
158 GLuint j;
159 (void) flags;
160
161 tnl->Driver.Render.PrimitiveNotify( ctx, GL_TRIANGLES );
162
163 for (j=start; j < last; j+=3 ) {
164 GLubyte c1 = mask[elt[j]];
165 GLubyte c2 = mask[elt[j+1]];
166 GLubyte c3 = mask[elt[j+2]];
167 GLubyte ormask = c1|c2|c3;
168 if (ormask) {
169 if (start < j)
170 render_tris( ctx, start, j, 0 );
171 if (!(c1&c2&c3&CLIPMASK))
172 clip_tri_4( ctx, elt[j], elt[j+1], elt[j+2], ormask );
173 start = j+3;
174 }
175 }
176
177 if (start < j)
178 render_tris( ctx, start, j, 0 );
179 }
180
181 /**********************************************************************/
182 /* Render whole begin/end objects */
183 /**********************************************************************/
184
185 #define NEED_EDGEFLAG_SETUP (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL)
186 #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
187 #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
188
189
190 /* Vertices, no clipping.
191 */
192 #define RENDER_POINTS( start, count ) \
193 tnl->Driver.Render.Points( ctx, start, count )
194
195 #define RENDER_LINE( v1, v2 ) \
196 LineFunc( ctx, v1, v2 )
197
198 #define RENDER_TRI( v1, v2, v3 ) \
199 TriangleFunc( ctx, v1, v2, v3 )
200
201 #define RENDER_QUAD( v1, v2, v3, v4 ) \
202 QuadFunc( ctx, v1, v2, v3, v4 )
203
204 #define TAG(x) _tnl_##x##_verts
205
206 #define LOCAL_VARS \
207 TNLcontext *tnl = TNL_CONTEXT(ctx); \
208 struct vertex_buffer *VB = &tnl->vb; \
209 const GLuint * const elt = VB->Elts; \
210 const tnl_line_func LineFunc = tnl->Driver.Render.Line; \
211 const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \
212 const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \
213 const GLboolean stipple = ctx->Line.StippleFlag; \
214 (void) (LineFunc && TriangleFunc && QuadFunc); \
215 (void) elt; (void) stipple
216
217 #define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx )
218 #define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x )
219 #define RENDER_TAB_QUALIFIER
220 #define PRESERVE_VB_DEFS
221 #include "t_vb_rendertmp.h"
222
223
224 /* Elts, no clipping.
225 */
226 #undef ELT
227 #define TAG(x) _tnl_##x##_elts
228 #define ELT(x) elt[x]
229 #include "t_vb_rendertmp.h"
230
231
232 /**********************************************************************/
233 /* Helper functions for drivers */
234 /**********************************************************************/
235
236 void _tnl_RenderClippedPolygon( GLcontext *ctx, const GLuint *elts, GLuint n )
237 {
238 TNLcontext *tnl = TNL_CONTEXT(ctx);
239 struct vertex_buffer *VB = &tnl->vb;
240 GLuint *tmp = VB->Elts;
241
242 VB->Elts = (GLuint *)elts;
243 tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END );
244 VB->Elts = tmp;
245 }
246
247 void _tnl_RenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj )
248 {
249 TNLcontext *tnl = TNL_CONTEXT(ctx);
250 tnl->Driver.Render.Line( ctx, ii, jj );
251 }
252
253
254
255 /**********************************************************************/
256 /* Clip and render whole vertex buffers */
257 /**********************************************************************/
258
259
260 static GLboolean run_render( GLcontext *ctx,
261 struct tnl_pipeline_stage *stage )
262 {
263 TNLcontext *tnl = TNL_CONTEXT(ctx);
264 struct vertex_buffer *VB = &tnl->vb;
265 tnl_render_func *tab;
266 GLint pass = 0;
267
268 /* Allow the drivers to lock before projected verts are built so
269 * that window coordinates are guarenteed not to change before
270 * rendering.
271 */
272 ASSERT(tnl->Driver.Render.Start);
273
274 tnl->Driver.Render.Start( ctx );
275
276 ASSERT(tnl->Driver.Render.BuildVertices);
277 ASSERT(tnl->Driver.Render.PrimitiveNotify);
278 ASSERT(tnl->Driver.Render.Points);
279 ASSERT(tnl->Driver.Render.Line);
280 ASSERT(tnl->Driver.Render.Triangle);
281 ASSERT(tnl->Driver.Render.Quad);
282 ASSERT(tnl->Driver.Render.ResetLineStipple);
283 ASSERT(tnl->Driver.Render.Interp);
284 ASSERT(tnl->Driver.Render.CopyPV);
285 ASSERT(tnl->Driver.Render.ClippedLine);
286 ASSERT(tnl->Driver.Render.ClippedPolygon);
287 ASSERT(tnl->Driver.Render.Finish);
288
289 tnl->Driver.Render.BuildVertices( ctx, 0, VB->Count, ~0 );
290
291 if (VB->ClipOrMask) {
292 tab = VB->Elts ? clip_render_tab_elts : clip_render_tab_verts;
293 clip_render_tab_elts[GL_TRIANGLES] = clip_elt_triangles;
294 }
295 else {
296 tab = (VB->Elts ?
297 tnl->Driver.Render.PrimTabElts :
298 tnl->Driver.Render.PrimTabVerts);
299 }
300
301 do
302 {
303 GLuint i;
304
305 for (i = 0 ; i < VB->PrimitiveCount ; i++)
306 {
307 GLuint prim = VB->Primitive[i].mode;
308 GLuint start = VB->Primitive[i].start;
309 GLuint length = VB->Primitive[i].count;
310
311 assert((prim & PRIM_MODE_MASK) <= GL_POLYGON);
312
313 if (MESA_VERBOSE & VERBOSE_PRIMS)
314 _mesa_debug(NULL, "MESA prim %s %d..%d\n",
315 _mesa_lookup_enum_by_nr(prim & PRIM_MODE_MASK),
316 start, start+length);
317
318 if (length)
319 tab[prim & PRIM_MODE_MASK]( ctx, start, start + length, prim );
320 }
321 } while (tnl->Driver.Render.Multipass &&
322 tnl->Driver.Render.Multipass( ctx, ++pass ));
323
324 tnl->Driver.Render.Finish( ctx );
325
326 return GL_FALSE; /* finished the pipe */
327 }
328
329
330 /**********************************************************************/
331 /* Render pipeline stage */
332 /**********************************************************************/
333
334
335
336
337
338 const struct tnl_pipeline_stage _tnl_render_stage =
339 {
340 "render", /* name */
341 NULL, /* private data */
342 NULL, /* creator */
343 NULL, /* destructor */
344 NULL, /* validate */
345 run_render /* run */
346 };