Rev 56 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
56 | pj | 1 | /* $Id: t_vb_render.c,v 1.1 2003-02-28 11:48:07 pj Exp $ */ |
2 | |||
3 | /* |
||
4 | * Mesa 3-D graphics library |
||
5 | * Version: 4.0.1 |
||
6 | * |
||
7 | * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. |
||
8 | * |
||
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: |
||
15 | * |
||
16 | * The above copyright notice and this permission notice shall be included |
||
17 | * in all copies or substantial portions of the Software. |
||
18 | * |
||
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. |
||
25 | * |
||
26 | * Authors: |
||
27 | * Keith Whitwell <keith@tungstengraphics.com> |
||
28 | */ |
||
29 | |||
30 | |||
31 | /* |
||
32 | * Render whole vertex buffers, including projection of vertices from |
||
33 | * clip space and clipping of primitives. |
||
34 | * |
||
35 | * This file makes calls to project vertices and to the point, line |
||
36 | * and triangle rasterizers via the function pointers: |
||
37 | * |
||
38 | * context->Driver.Render.* |
||
39 | * |
||
40 | */ |
||
41 | |||
42 | |||
43 | #include "glheader.h" |
||
44 | #include "context.h" |
||
45 | #include "enums.h" |
||
46 | #include "macros.h" |
||
47 | #include "imports.h" |
||
48 | #include "mtypes.h" |
||
49 | #include "mmath.h" |
||
50 | |||
51 | #include "math/m_matrix.h" |
||
52 | #include "math/m_xform.h" |
||
53 | |||
54 | #include "t_pipeline.h" |
||
55 | |||
56 | |||
57 | |||
58 | /**********************************************************************/ |
||
59 | /* Clip single primitives */ |
||
60 | /**********************************************************************/ |
||
61 | |||
62 | |||
63 | #if defined(USE_IEEE) |
||
64 | #define NEGATIVE(x) (GET_FLOAT_BITS(x) & (1<<31)) |
||
65 | #define DIFFERENT_SIGNS(x,y) ((GET_FLOAT_BITS(x) ^ GET_FLOAT_BITS(y)) & (1<<31)) |
||
66 | #else |
||
67 | #define NEGATIVE(x) (x < 0) |
||
68 | #define DIFFERENT_SIGNS(x,y) (x * y <= 0 && x - y != 0) |
||
69 | /* Could just use (x*y<0) except for the flatshading requirements. |
||
70 | * Maybe there's a better way? |
||
71 | */ |
||
72 | #endif |
||
73 | |||
74 | |||
75 | #define W(i) coord[i][3] |
||
76 | #define Z(i) coord[i][2] |
||
77 | #define Y(i) coord[i][1] |
||
78 | #define X(i) coord[i][0] |
||
79 | #define SIZE 4 |
||
80 | #define TAG(x) x##_4 |
||
81 | #include "t_vb_cliptmp.h" |
||
82 | |||
83 | |||
84 | |||
85 | /**********************************************************************/ |
||
86 | /* Clip and render whole begin/end objects */ |
||
87 | /**********************************************************************/ |
||
88 | |||
89 | #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED) |
||
90 | #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx] |
||
91 | #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val |
||
92 | |||
93 | |||
94 | /* Vertices, with the possibility of clipping. |
||
95 | */ |
||
96 | #define RENDER_POINTS( start, count ) \ |
||
97 | tnl->Driver.Render.Points( ctx, start, count ) |
||
98 | |||
99 | #define RENDER_LINE( v1, v2 ) \ |
||
100 | do { \ |
||
101 | GLubyte c1 = mask[v1], c2 = mask[v2]; \ |
||
102 | GLubyte ormask = c1|c2; \ |
||
103 | if (!ormask) \ |
||
104 | LineFunc( ctx, v1, v2 ); \ |
||
105 | else if (!(c1 & c2 & 0x3f)) \ |
||
106 | clip_line_4( ctx, v1, v2, ormask ); \ |
||
107 | } while (0) |
||
108 | |||
109 | #define RENDER_TRI( v1, v2, v3 ) \ |
||
110 | do { \ |
||
111 | GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \ |
||
112 | GLubyte ormask = c1|c2|c3; \ |
||
113 | if (!ormask) \ |
||
114 | TriangleFunc( ctx, v1, v2, v3 ); \ |
||
115 | else if (!(c1 & c2 & c3 & 0x3f)) \ |
||
116 | clip_tri_4( ctx, v1, v2, v3, ormask ); \ |
||
117 | } while (0) |
||
118 | |||
119 | #define RENDER_QUAD( v1, v2, v3, v4 ) \ |
||
120 | do { \ |
||
121 | GLubyte c1 = mask[v1], c2 = mask[v2]; \ |
||
122 | GLubyte c3 = mask[v3], c4 = mask[v4]; \ |
||
123 | GLubyte ormask = c1|c2|c3|c4; \ |
||
124 | if (!ormask) \ |
||
125 | QuadFunc( ctx, v1, v2, v3, v4 ); \ |
||
126 | else if (!(c1 & c2 & c3 & c4 & 0x3f)) \ |
||
127 | clip_quad_4( ctx, v1, v2, v3, v4, ormask ); \ |
||
128 | } while (0) |
||
129 | |||
130 | |||
131 | #define LOCAL_VARS \ |
||
132 | TNLcontext *tnl = TNL_CONTEXT(ctx); \ |
||
133 | struct vertex_buffer *VB = &tnl->vb; \ |
||
134 | const GLuint * const elt = VB->Elts; \ |
||
135 | const GLubyte *mask = VB->ClipMask; \ |
||
136 | const GLuint sz = VB->ClipPtr->size; \ |
||
137 | const line_func LineFunc = tnl->Driver.Render.Line; \ |
||
138 | const triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \ |
||
139 | const quad_func QuadFunc = tnl->Driver.Render.Quad; \ |
||
140 | const GLboolean stipple = ctx->Line.StippleFlag; \ |
||
141 | (void) (LineFunc && TriangleFunc && QuadFunc); \ |
||
142 | (void) elt; (void) mask; (void) sz; (void) stipple; |
||
143 | |||
144 | #define TAG(x) clip_##x##_verts |
||
145 | #define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x ) |
||
146 | #define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx ) |
||
147 | #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE |
||
148 | #define PRESERVE_VB_DEFS |
||
149 | #include "t_vb_rendertmp.h" |
||
150 | |||
151 | |||
152 | |||
153 | /* Elts, with the possibility of clipping. |
||
154 | */ |
||
155 | #undef ELT |
||
156 | #undef TAG |
||
157 | #define ELT(x) elt[x] |
||
158 | #define TAG(x) clip_##x##_elts |
||
159 | #include "t_vb_rendertmp.h" |
||
160 | |||
161 | /* TODO: do this for all primitives, verts and elts: |
||
162 | */ |
||
163 | static void clip_elt_triangles( GLcontext *ctx, |
||
164 | GLuint start, |
||
165 | GLuint count, |
||
166 | GLuint flags ) |
||
167 | { |
||
168 | TNLcontext *tnl = TNL_CONTEXT(ctx); |
||
169 | render_func render_tris = tnl->Driver.Render.PrimTabElts[GL_TRIANGLES]; |
||
170 | struct vertex_buffer *VB = &tnl->vb; |
||
171 | const GLuint * const elt = VB->Elts; |
||
172 | GLubyte *mask = VB->ClipMask; |
||
173 | GLuint last = count-2; |
||
174 | GLuint j; |
||
175 | (void) flags; |
||
176 | |||
177 | tnl->Driver.Render.PrimitiveNotify( ctx, GL_TRIANGLES ); |
||
178 | |||
179 | for (j=start; j < last; j+=3 ) { |
||
180 | GLubyte c1 = mask[elt[j]]; |
||
181 | GLubyte c2 = mask[elt[j+1]]; |
||
182 | GLubyte c3 = mask[elt[j+2]]; |
||
183 | GLubyte ormask = c1|c2|c3; |
||
184 | if (ormask) { |
||
185 | if (start < j) |
||
186 | render_tris( ctx, start, j, 0 ); |
||
187 | if (!(c1&c2&c3&0x3f)) |
||
188 | clip_tri_4( ctx, elt[j], elt[j+1], elt[j+2], ormask ); |
||
189 | start = j+3; |
||
190 | } |
||
191 | } |
||
192 | |||
193 | if (start < j) |
||
194 | render_tris( ctx, start, j, 0 ); |
||
195 | } |
||
196 | |||
197 | /**********************************************************************/ |
||
198 | /* Render whole begin/end objects */ |
||
199 | /**********************************************************************/ |
||
200 | |||
201 | #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED) |
||
202 | #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx] |
||
203 | #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val |
||
204 | |||
205 | |||
206 | /* Vertices, no clipping. |
||
207 | */ |
||
208 | #define RENDER_POINTS( start, count ) \ |
||
209 | tnl->Driver.Render.Points( ctx, start, count ) |
||
210 | |||
211 | #define RENDER_LINE( v1, v2 ) \ |
||
212 | LineFunc( ctx, v1, v2 ) |
||
213 | |||
214 | #define RENDER_TRI( v1, v2, v3 ) \ |
||
215 | TriangleFunc( ctx, v1, v2, v3 ) |
||
216 | |||
217 | #define RENDER_QUAD( v1, v2, v3, v4 ) \ |
||
218 | QuadFunc( ctx, v1, v2, v3, v4 ) |
||
219 | |||
220 | #define TAG(x) _tnl_##x##_verts |
||
221 | |||
222 | #define LOCAL_VARS \ |
||
223 | TNLcontext *tnl = TNL_CONTEXT(ctx); \ |
||
224 | struct vertex_buffer *VB = &tnl->vb; \ |
||
225 | const GLuint * const elt = VB->Elts; \ |
||
226 | const line_func LineFunc = tnl->Driver.Render.Line; \ |
||
227 | const triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \ |
||
228 | const quad_func QuadFunc = tnl->Driver.Render.Quad; \ |
||
229 | const GLboolean stipple = ctx->Line.StippleFlag; \ |
||
230 | (void) (LineFunc && TriangleFunc && QuadFunc); \ |
||
231 | (void) elt; (void) stipple |
||
232 | |||
233 | #define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx ) |
||
234 | #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE |
||
235 | #define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x ) |
||
236 | #define RENDER_TAB_QUALIFIER |
||
237 | #define PRESERVE_VB_DEFS |
||
238 | #include "t_vb_rendertmp.h" |
||
239 | |||
240 | |||
241 | /* Elts, no clipping. |
||
242 | */ |
||
243 | #undef ELT |
||
244 | #define TAG(x) _tnl_##x##_elts |
||
245 | #define ELT(x) elt[x] |
||
246 | #include "t_vb_rendertmp.h" |
||
247 | |||
248 | |||
249 | /**********************************************************************/ |
||
250 | /* Helper functions for drivers */ |
||
251 | /**********************************************************************/ |
||
252 | |||
253 | void _tnl_RenderClippedPolygon( GLcontext *ctx, const GLuint *elts, GLuint n ) |
||
254 | { |
||
255 | TNLcontext *tnl = TNL_CONTEXT(ctx); |
||
256 | struct vertex_buffer *VB = &tnl->vb; |
||
257 | GLuint *tmp = VB->Elts; |
||
258 | |||
259 | VB->Elts = (GLuint *)elts; |
||
260 | tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END ); |
||
261 | VB->Elts = tmp; |
||
262 | } |
||
263 | |||
264 | void _tnl_RenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj ) |
||
265 | { |
||
266 | TNLcontext *tnl = TNL_CONTEXT(ctx); |
||
267 | tnl->Driver.Render.Line( ctx, ii, jj ); |
||
268 | } |
||
269 | |||
270 | |||
271 | |||
272 | /**********************************************************************/ |
||
273 | /* Clip and render whole vertex buffers */ |
||
274 | /**********************************************************************/ |
||
275 | |||
276 | |||
277 | static GLboolean run_render( GLcontext *ctx, |
||
278 | struct gl_pipeline_stage *stage ) |
||
279 | { |
||
280 | TNLcontext *tnl = TNL_CONTEXT(ctx); |
||
281 | struct vertex_buffer *VB = &tnl->vb; |
||
282 | GLuint new_inputs = stage->changed_inputs; |
||
283 | render_func *tab; |
||
284 | GLint pass = 0; |
||
285 | |||
286 | /* Allow the drivers to lock before projected verts are built so |
||
287 | * that window coordinates are guarenteed not to change before |
||
288 | * rendering. |
||
289 | */ |
||
290 | ASSERT(tnl->Driver.Render.Start); |
||
291 | |||
292 | tnl->Driver.Render.Start( ctx ); |
||
293 | |||
294 | ASSERT(tnl->Driver.Render.BuildVertices); |
||
295 | ASSERT(tnl->Driver.Render.PrimitiveNotify); |
||
296 | ASSERT(tnl->Driver.Render.Points); |
||
297 | ASSERT(tnl->Driver.Render.Line); |
||
298 | ASSERT(tnl->Driver.Render.Triangle); |
||
299 | ASSERT(tnl->Driver.Render.Quad); |
||
300 | ASSERT(tnl->Driver.Render.ResetLineStipple); |
||
301 | ASSERT(tnl->Driver.Render.Interp); |
||
302 | ASSERT(tnl->Driver.Render.CopyPV); |
||
303 | ASSERT(tnl->Driver.Render.ClippedLine); |
||
304 | ASSERT(tnl->Driver.Render.ClippedPolygon); |
||
305 | ASSERT(tnl->Driver.Render.Finish); |
||
306 | |||
307 | tnl->Driver.Render.BuildVertices( ctx, 0, VB->Count, new_inputs ); |
||
308 | |||
309 | if (VB->ClipOrMask) { |
||
310 | tab = VB->Elts ? clip_render_tab_elts : clip_render_tab_verts; |
||
311 | clip_render_tab_elts[GL_TRIANGLES] = clip_elt_triangles; |
||
312 | } |
||
313 | else { |
||
314 | tab = (VB->Elts ? |
||
315 | tnl->Driver.Render.PrimTabElts : |
||
316 | tnl->Driver.Render.PrimTabVerts); |
||
317 | } |
||
318 | |||
319 | do |
||
320 | { |
||
321 | GLuint i, length, flags = 0; |
||
322 | for (i = VB->FirstPrimitive ; !(flags & PRIM_LAST) ; i += length) |
||
323 | { |
||
324 | flags = VB->Primitive[i]; |
||
325 | length= VB->PrimitiveLength[i]; |
||
326 | ASSERT(length || (flags & PRIM_LAST)); |
||
327 | ASSERT((flags & PRIM_MODE_MASK) <= GL_POLYGON+1); |
||
328 | |||
329 | if (MESA_VERBOSE & VERBOSE_PRIMS) |
||
330 | _mesa_debug(NULL, "MESA prim %s %d..%d\n", |
||
331 | _mesa_lookup_enum_by_nr(flags & PRIM_MODE_MASK), |
||
332 | i, i+length); |
||
333 | |||
334 | if (length) |
||
335 | tab[flags & PRIM_MODE_MASK]( ctx, i, i + length, flags ); |
||
336 | } |
||
337 | } while (tnl->Driver.Render.Multipass && |
||
338 | tnl->Driver.Render.Multipass( ctx, ++pass )); |
||
339 | |||
340 | |||
341 | tnl->Driver.Render.Finish( ctx ); |
||
342 | /* _swrast_flush(ctx); */ |
||
343 | /* usleep(1000000); */ |
||
344 | return GL_FALSE; /* finished the pipe */ |
||
345 | } |
||
346 | |||
347 | |||
348 | /**********************************************************************/ |
||
349 | /* Render pipeline stage */ |
||
350 | /**********************************************************************/ |
||
351 | |||
352 | |||
353 | |||
354 | /* Quite a bit of work involved in finding out the inputs for the |
||
355 | * render stage. |
||
356 | */ |
||
357 | static void check_render( GLcontext *ctx, struct gl_pipeline_stage *stage ) |
||
358 | { |
||
359 | GLuint inputs = VERT_BIT_CLIP; |
||
360 | GLuint i; |
||
361 | |||
362 | if (ctx->Visual.rgbMode) { |
||
363 | inputs |= VERT_BIT_COLOR0; |
||
364 | |||
365 | if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) |
||
366 | inputs |= VERT_BIT_COLOR1; |
||
367 | |||
368 | if (ctx->Texture._EnabledUnits) { |
||
369 | for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { |
||
370 | if (ctx->Texture.Unit[i]._ReallyEnabled) |
||
371 | inputs |= VERT_BIT_TEX(i); |
||
372 | } |
||
373 | } |
||
374 | } |
||
375 | else { |
||
376 | inputs |= VERT_BIT_INDEX; |
||
377 | } |
||
378 | |||
379 | if (ctx->Point._Attenuated) |
||
380 | inputs |= VERT_BIT_POINT_SIZE; |
||
381 | |||
382 | /* How do drivers turn this off? |
||
383 | */ |
||
384 | if (ctx->Fog.Enabled) |
||
385 | inputs |= VERT_BIT_FOG; |
||
386 | |||
387 | if (ctx->_TriangleCaps & DD_TRI_UNFILLED) |
||
388 | inputs |= VERT_BIT_EDGEFLAG; |
||
389 | |||
390 | if (ctx->RenderMode==GL_FEEDBACK) |
||
391 | inputs |= VERT_BITS_TEX_ANY; |
||
392 | |||
393 | stage->inputs = inputs; |
||
394 | } |
||
395 | |||
396 | |||
397 | |||
398 | |||
399 | static void dtr( struct gl_pipeline_stage *stage ) |
||
400 | { |
||
401 | } |
||
402 | |||
403 | |||
404 | const struct gl_pipeline_stage _tnl_render_stage = |
||
405 | { |
||
406 | "render", /* name */ |
||
407 | (_NEW_BUFFERS | |
||
408 | _DD_NEW_SEPARATE_SPECULAR | |
||
409 | _DD_NEW_FLATSHADE | |
||
410 | _NEW_TEXTURE| |
||
411 | _NEW_LIGHT| |
||
412 | _NEW_POINT| |
||
413 | _NEW_FOG| |
||
414 | _DD_NEW_TRI_UNFILLED | |
||
415 | _NEW_RENDERMODE), /* re-check (new inputs, interp function) */ |
||
416 | 0, /* re-run (always runs) */ |
||
417 | GL_TRUE, /* active? */ |
||
418 | 0, /* inputs (set in check_render) */ |
||
419 | 0, /* outputs */ |
||
420 | 0, /* changed_inputs */ |
||
421 | NULL, /* private data */ |
||
422 | dtr, /* destructor */ |
||
423 | check_render, /* check */ |
||
424 | run_render /* run */ |
||
425 | }; |