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