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 
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 )			\
89 do {						\
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 )			\
99 do {							\
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 )			\
109 do {							\
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  */
clip_elt_triangles(struct gl_context * ctx,GLuint start,GLuint count,GLuint flags)151 static 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 
_tnl_RenderClippedPolygon(struct gl_context * ctx,const GLuint * elts,GLuint n)240 void _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 
_tnl_RenderClippedLine(struct gl_context * ctx,GLuint ii,GLuint jj)251 void _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 
run_render(struct gl_context * ctx,struct tnl_pipeline_stage * stage)264 static 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 
342 const 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