t_vb_render.c revision 908be619fdba608b057ae512834dcc7a76aa3224
1/* $Id: t_vb_render.c,v 1.18 2001/04/26 14:53:48 keithw Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.5
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 <keithw@valinux.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.BuildProjectedVertices()
39 *
40 *    context->Driver.PointsFunc()
41 *    context->Driver.LineFunc()
42 *    context->Driver.TriangleFunc()
43 *    context->Driver.QuadFunc()
44 *
45 *    context->Driver.RenderTabVerts[]
46 *    context->Driver.RenderTabElts[]
47 *
48 * None of these may be null.
49 */
50
51
52#include "glheader.h"
53#include "context.h"
54#include "macros.h"
55#include "mem.h"
56#include "mtypes.h"
57#include "mmath.h"
58
59#include "math/m_matrix.h"
60#include "math/m_xform.h"
61
62#include "t_pipeline.h"
63
64
65
66/**********************************************************************/
67/*                        Clip single primitives                      */
68/**********************************************************************/
69
70
71#if defined(USE_IEEE)
72#define NEGATIVE(x) ((*(GLuint *)&x) & (1<<31))
73#define DIFFERENT_SIGNS(x,y) (((*(GLuint *)&x)^(*(GLuint *)&y)) & (1<<31))
74#else
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?
79 */
80#endif
81
82#define LINTERP_SZ( t, vec, to, a, b, sz )			\
83do {								\
84   switch (sz) {						\
85   case 2: vec[to][2] = 0.0;					\
86   case 3: vec[to][3] = 1.0;					\
87   }      							\
88   switch (sz) {						\
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] );	\
93   }								\
94} while(0)
95
96#define LINTERP_4F( t, vec, to, a, b, sz )		\
97do {							\
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] );	\
102} while (0)
103
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]
108#define SIZE 4
109#define TAG(x) x##_4
110#include "t_vb_cliptmp.h"
111
112
113
114/**********************************************************************/
115/*              Clip and render whole begin/end objects               */
116/**********************************************************************/
117
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
121
122
123/* Vertices, with the possibility of clipping.
124 */
125#define RENDER_POINTS( start, count ) \
126   tnl->Driver.PointsFunc( ctx, start, count )
127
128#define RENDER_LINE( v1, v2 )			\
129do {						\
130   GLubyte c1 = mask[v1], c2 = mask[v2];	\
131   GLubyte ormask = c1|c2;			\
132   if (!ormask)					\
133      LineFunc( ctx, v1, v2 );			\
134   else if (!(c1 & c2 & 0x3f))			\
135      clip_line_4( ctx, v1, v2, ormask );	\
136} while (0)
137
138#define RENDER_TRI( v1, v2, v3 )			\
139do {							\
140   GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3];	\
141   GLubyte ormask = c1|c2|c3;				\
142   if (!ormask)						\
143      TriangleFunc( ctx, v1, v2, v3 );			\
144   else if (!(c1 & c2 & c3 & 0x3f)) 			\
145      clip_tri_4( ctx, v1, v2, v3, ormask );    	\
146} while (0)
147
148#define RENDER_QUAD( v1, v2, v3, v4 )			\
149do {							\
150   GLubyte c1 = mask[v1], c2 = mask[v2];		\
151   GLubyte c3 = mask[v3], c4 = mask[v4];		\
152   GLubyte ormask = c1|c2|c3|c4;			\
153   if (!ormask)						\
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 );	\
157} while (0)
158
159
160#define LOCAL_VARS						\
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;
172
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"
179
180
181
182/* Elts, with the possibility of clipping.
183 */
184#undef ELT
185#undef TAG
186#define ELT(x) elt[x]
187#define TAG(x) clip_##x##_elts
188#include "t_vb_rendertmp.h"
189
190/* TODO: do this for all primitives, verts and elts:
191 */
192static void clip_elt_triangles( GLcontext *ctx,
193				GLuint start,
194				GLuint count,
195				GLuint flags )
196{
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;
203   GLuint j;
204   (void) flags;
205
206   tnl->Driver.RenderPrimitive( ctx, GL_TRIANGLES );
207
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;
213      if (ormask) {
214	 if (start < j)
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 );
218	 start = j+3;
219      }
220   }
221
222   if (start < j)
223      render_tris( ctx, start, j, 0 );
224}
225
226/**********************************************************************/
227/*                  Render whole begin/end objects                    */
228/**********************************************************************/
229
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
233
234
235/* Vertices, no clipping.
236 */
237#define RENDER_POINTS( start, count ) \
238   tnl->Driver.PointsFunc( ctx, start, count )
239
240#define RENDER_LINE( v1, v2 ) \
241   LineFunc( ctx, v1, v2 )
242
243#define RENDER_TRI( v1, v2, v3 ) \
244   TriangleFunc( ctx, v1, v2, v3 )
245
246#define RENDER_QUAD( v1, v2, v3, v4 ) \
247   QuadFunc( ctx, v1, v2, v3, v4 )
248
249#define TAG(x) _tnl_##x##_verts
250
251#define LOCAL_VARS						\
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);		\
259   (void) elt;
260
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"
267
268
269/* Elts, no clipping.
270 */
271#undef ELT
272#define TAG(x) _tnl_##x##_elts
273#define ELT(x) elt[x]
274#include "t_vb_rendertmp.h"
275
276
277
278
279/**********************************************************************/
280/*              Clip and render whole vertex buffers                  */
281/**********************************************************************/
282
283
284static GLboolean run_render( GLcontext *ctx,
285			     struct gl_pipeline_stage *stage )
286{
287   TNLcontext *tnl = TNL_CONTEXT(ctx);
288   struct vertex_buffer *VB = &tnl->vb;
289   GLuint new_inputs = stage->changed_inputs;
290   render_func *tab;
291   GLint pass = 0;
292
293
294   /* Allow the drivers to lock before projected verts are built so
295    * that window coordinates are guarenteed not to change before
296    * rendering.
297    */
298   ASSERT(tnl->Driver.RenderStart);
299
300   tnl->Driver.RenderStart( ctx );
301
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);
314
315   tnl->Driver.BuildProjectedVertices( ctx, 0, VB->Count, new_inputs );
316
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;
320   }
321   else {
322      tab = VB->Elts ? tnl->Driver.RenderTabElts : tnl->Driver.RenderTabVerts;
323   }
324
325   do
326   {
327      GLuint i, length, flags = 0;
328      for (i = 0 ; !(flags & PRIM_LAST) ; i += length)
329      {
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);
334	 if (length)
335	    tab[flags & PRIM_MODE_MASK]( ctx, i, i + length, flags );
336      }
337   } while (tnl->Driver.MultipassFunc &&
338	    tnl->Driver.MultipassFunc( ctx, ++pass ));
339
340
341   tnl->Driver.RenderFinish( ctx );
342/*     usleep(100000); */
343   return GL_FALSE;		/* finished the pipe */
344}
345
346
347/**********************************************************************/
348/*                          Render pipeline stage                     */
349/**********************************************************************/
350
351
352
353/* Quite a bit of work involved in finding out the inputs for the
354 * render stage.
355 */
356static void check_render( GLcontext *ctx, struct gl_pipeline_stage *stage )
357{
358   GLuint inputs = VERT_CLIP;
359   GLuint i;
360
361   if (ctx->Visual.rgbMode) {
362      inputs |= VERT_RGBA;
363
364      if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)
365	 inputs |= VERT_SPEC_RGB;
366
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);
371	 }
372      }
373   }
374   else {
375      inputs |= VERT_INDEX;
376   }
377
378   if (ctx->Point._Attenuated)
379      inputs |= VERT_POINT_SIZE;
380
381   /* How do drivers turn this off?
382    */
383   if (ctx->Fog.Enabled)
384      inputs |= VERT_FOG_COORD;
385
386   if (ctx->_TriangleCaps & DD_TRI_UNFILLED)
387      inputs |= VERT_EDGE;
388
389   if (ctx->RenderMode==GL_FEEDBACK)
390      inputs |= VERT_TEX_ANY;
391
392   stage->inputs = inputs;
393}
394
395
396
397
398static void dtr( struct gl_pipeline_stage *stage )
399{
400}
401
402
403const struct gl_pipeline_stage _tnl_render_stage =
404{
405   "render",
406   (_NEW_BUFFERS |
407    _DD_NEW_SEPARATE_SPECULAR |
408    _DD_NEW_FLATSHADE |
409    _NEW_TEXTURE|
410    _NEW_LIGHT|
411    _NEW_POINT|
412    _NEW_FOG|
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 */
421   run_render			/* run */
422};
423