t_vb_render.c revision 51c0c71811508b6658e0d5dcff8426b618322a73
1/* $Id: t_vb_render.c,v 1.19 2001/04/28 08:39:18 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
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]
87#define SIZE 4
88#define TAG(x) x##_4
89#include "t_vb_cliptmp.h"
90
91
92
93/**********************************************************************/
94/*              Clip and render whole begin/end objects               */
95/**********************************************************************/
96
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
100
101
102/* Vertices, with the possibility of clipping.
103 */
104#define RENDER_POINTS( start, count ) \
105   tnl->Driver.PointsFunc( ctx, start, count )
106
107#define RENDER_LINE( v1, v2 )			\
108do {						\
109   GLubyte c1 = mask[v1], c2 = mask[v2];	\
110   GLubyte ormask = c1|c2;			\
111   if (!ormask)					\
112      LineFunc( ctx, v1, v2 );			\
113   else if (!(c1 & c2 & 0x3f))			\
114      clip_line_4( ctx, v1, v2, ormask );	\
115} while (0)
116
117#define RENDER_TRI( v1, v2, v3 )			\
118do {							\
119   GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3];	\
120   GLubyte ormask = c1|c2|c3;				\
121   if (!ormask)						\
122      TriangleFunc( ctx, v1, v2, v3 );			\
123   else if (!(c1 & c2 & c3 & 0x3f)) 			\
124      clip_tri_4( ctx, v1, v2, v3, ormask );    	\
125} while (0)
126
127#define RENDER_QUAD( v1, v2, v3, v4 )			\
128do {							\
129   GLubyte c1 = mask[v1], c2 = mask[v2];		\
130   GLubyte c3 = mask[v3], c4 = mask[v4];		\
131   GLubyte ormask = c1|c2|c3|c4;			\
132   if (!ormask)						\
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 );	\
136} while (0)
137
138
139#define LOCAL_VARS						\
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;
151
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"
158
159
160
161/* Elts, with the possibility of clipping.
162 */
163#undef ELT
164#undef TAG
165#define ELT(x) elt[x]
166#define TAG(x) clip_##x##_elts
167#include "t_vb_rendertmp.h"
168
169/* TODO: do this for all primitives, verts and elts:
170 */
171static void clip_elt_triangles( GLcontext *ctx,
172				GLuint start,
173				GLuint count,
174				GLuint flags )
175{
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;
182   GLuint j;
183   (void) flags;
184
185   tnl->Driver.RenderPrimitive( ctx, GL_TRIANGLES );
186
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;
192      if (ormask) {
193	 if (start < j)
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 );
197	 start = j+3;
198      }
199   }
200
201   if (start < j)
202      render_tris( ctx, start, j, 0 );
203}
204
205/**********************************************************************/
206/*                  Render whole begin/end objects                    */
207/**********************************************************************/
208
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
212
213
214/* Vertices, no clipping.
215 */
216#define RENDER_POINTS( start, count ) \
217   tnl->Driver.PointsFunc( ctx, start, count )
218
219#define RENDER_LINE( v1, v2 ) \
220   LineFunc( ctx, v1, v2 )
221
222#define RENDER_TRI( v1, v2, v3 ) \
223   TriangleFunc( ctx, v1, v2, v3 )
224
225#define RENDER_QUAD( v1, v2, v3, v4 ) \
226   QuadFunc( ctx, v1, v2, v3, v4 )
227
228#define TAG(x) _tnl_##x##_verts
229
230#define LOCAL_VARS						\
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);		\
238   (void) elt;
239
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"
246
247
248/* Elts, no clipping.
249 */
250#undef ELT
251#define TAG(x) _tnl_##x##_elts
252#define ELT(x) elt[x]
253#include "t_vb_rendertmp.h"
254
255
256
257
258/**********************************************************************/
259/*              Clip and render whole vertex buffers                  */
260/**********************************************************************/
261
262
263static GLboolean run_render( GLcontext *ctx,
264			     struct gl_pipeline_stage *stage )
265{
266   TNLcontext *tnl = TNL_CONTEXT(ctx);
267   struct vertex_buffer *VB = &tnl->vb;
268   GLuint new_inputs = stage->changed_inputs;
269   render_func *tab;
270   GLint pass = 0;
271
272
273   /* Allow the drivers to lock before projected verts are built so
274    * that window coordinates are guarenteed not to change before
275    * rendering.
276    */
277   ASSERT(tnl->Driver.RenderStart);
278
279   tnl->Driver.RenderStart( ctx );
280
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);
293
294   tnl->Driver.BuildProjectedVertices( ctx, 0, VB->Count, new_inputs );
295
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;
299   }
300   else {
301      tab = VB->Elts ? tnl->Driver.RenderTabElts : tnl->Driver.RenderTabVerts;
302   }
303
304   do
305   {
306      GLuint i, length, flags = 0;
307      for (i = 0 ; !(flags & PRIM_LAST) ; i += length)
308      {
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);
313	 if (length)
314	    tab[flags & PRIM_MODE_MASK]( ctx, i, i + length, flags );
315      }
316   } while (tnl->Driver.MultipassFunc &&
317	    tnl->Driver.MultipassFunc( ctx, ++pass ));
318
319
320   tnl->Driver.RenderFinish( ctx );
321/*     usleep(100000); */
322   return GL_FALSE;		/* finished the pipe */
323}
324
325
326/**********************************************************************/
327/*                          Render pipeline stage                     */
328/**********************************************************************/
329
330
331
332/* Quite a bit of work involved in finding out the inputs for the
333 * render stage.
334 */
335static void check_render( GLcontext *ctx, struct gl_pipeline_stage *stage )
336{
337   GLuint inputs = VERT_CLIP;
338   GLuint i;
339
340   if (ctx->Visual.rgbMode) {
341      inputs |= VERT_RGBA;
342
343      if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)
344	 inputs |= VERT_SPEC_RGB;
345
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);
350	 }
351      }
352   }
353   else {
354      inputs |= VERT_INDEX;
355   }
356
357   if (ctx->Point._Attenuated)
358      inputs |= VERT_POINT_SIZE;
359
360   /* How do drivers turn this off?
361    */
362   if (ctx->Fog.Enabled)
363      inputs |= VERT_FOG_COORD;
364
365   if (ctx->_TriangleCaps & DD_TRI_UNFILLED)
366      inputs |= VERT_EDGE;
367
368   if (ctx->RenderMode==GL_FEEDBACK)
369      inputs |= VERT_TEX_ANY;
370
371   stage->inputs = inputs;
372}
373
374
375
376
377static void dtr( struct gl_pipeline_stage *stage )
378{
379}
380
381
382const struct gl_pipeline_stage _tnl_render_stage =
383{
384   "render",
385   (_NEW_BUFFERS |
386    _DD_NEW_SEPARATE_SPECULAR |
387    _DD_NEW_FLATSHADE |
388    _NEW_TEXTURE|
389    _NEW_LIGHT|
390    _NEW_POINT|
391    _NEW_FOG|
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 */
400   run_render			/* run */
401};
402