17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
47117f1b4Smrg * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
57117f1b4Smrg *
67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
87117f1b4Smrg * to deal in the Software without restriction, including without limitation
97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
117117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
127117f1b4Smrg *
137117f1b4Smrg * The above copyright notice and this permission notice shall be included
147117f1b4Smrg * in all copies or substantial portions of the Software.
157117f1b4Smrg *
167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg *
247117f1b4Smrg * Authors:
25af69d88dSmrg *    Keith Whitwell <keithw@vmware.com>
267117f1b4Smrg */
277117f1b4Smrg
287117f1b4Smrg
297117f1b4Smrg/*
307117f1b4Smrg * Render whole vertex buffers, including projection of vertices from
317117f1b4Smrg * clip space and clipping of primitives.
327117f1b4Smrg *
337117f1b4Smrg * This file makes calls to project vertices and to the point, line
347117f1b4Smrg * and triangle rasterizers via the function pointers:
357117f1b4Smrg *
367117f1b4Smrg *    context->Driver.Render.*
377117f1b4Smrg *
387117f1b4Smrg */
397117f1b4Smrg
407117f1b4Smrg
4101e04c3fSmrg#include <stdio.h>
42c1f859d4Smrg#include "main/glheader.h"
43c1f859d4Smrg#include "main/context.h"
44c1f859d4Smrg#include "main/enums.h"
45c1f859d4Smrg#include "main/macros.h"
467ec681f3Smrg
47c1f859d4Smrg#include "main/mtypes.h"
483464ebd5Sriastradh#include "math/m_xform.h"
4901e04c3fSmrg#include "util/bitscan.h"
507117f1b4Smrg
517117f1b4Smrg#include "t_pipeline.h"
527117f1b4Smrg
537117f1b4Smrg
547117f1b4Smrg
557117f1b4Smrg/**********************************************************************/
567117f1b4Smrg/*                        Clip single primitives                      */
577117f1b4Smrg/**********************************************************************/
587117f1b4Smrg
597117f1b4Smrg
607117f1b4Smrg#define W(i) coord[i][3]
617117f1b4Smrg#define Z(i) coord[i][2]
627117f1b4Smrg#define Y(i) coord[i][1]
637117f1b4Smrg#define X(i) coord[i][0]
647117f1b4Smrg#define SIZE 4
657117f1b4Smrg#define TAG(x) x##_4
667117f1b4Smrg#include "t_vb_cliptmp.h"
677117f1b4Smrg
687117f1b4Smrg
697117f1b4Smrg
707117f1b4Smrg/**********************************************************************/
717117f1b4Smrg/*              Clip and render whole begin/end objects               */
727117f1b4Smrg/**********************************************************************/
737117f1b4Smrg
747117f1b4Smrg#define NEED_EDGEFLAG_SETUP (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL)
757117f1b4Smrg#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
767117f1b4Smrg#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
777117f1b4Smrg
787117f1b4Smrg
797117f1b4Smrg/* This does NOT include the CLIP_USER_BIT! */
807117f1b4Smrg#define CLIPMASK (CLIP_FRUSTUM_BITS | CLIP_CULL_BIT)
817117f1b4Smrg
827117f1b4Smrg
837117f1b4Smrg/* Vertices, with the possibility of clipping.
847117f1b4Smrg */
857117f1b4Smrg#define RENDER_POINTS( start, count ) \
867117f1b4Smrg   tnl->Driver.Render.Points( ctx, start, count )
877117f1b4Smrg
887117f1b4Smrg#define RENDER_LINE( v1, v2 )			\
897117f1b4Smrgdo {						\
907117f1b4Smrg   GLubyte c1 = mask[v1], c2 = mask[v2];	\
917117f1b4Smrg   GLubyte ormask = c1|c2;			\
927117f1b4Smrg   if (!ormask)					\
937117f1b4Smrg      LineFunc( ctx, v1, v2 );			\
947117f1b4Smrg   else if (!(c1 & c2 & CLIPMASK))			\
957117f1b4Smrg      clip_line_4( ctx, v1, v2, ormask );	\
967117f1b4Smrg} while (0)
977117f1b4Smrg
987117f1b4Smrg#define RENDER_TRI( v1, v2, v3 )			\
997117f1b4Smrgdo {							\
1007117f1b4Smrg   GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3];	\
1017117f1b4Smrg   GLubyte ormask = c1|c2|c3;				\
1027117f1b4Smrg   if (!ormask)						\
1037117f1b4Smrg      TriangleFunc( ctx, v1, v2, v3 );			\
1047117f1b4Smrg   else if (!(c1 & c2 & c3 & CLIPMASK)) 			\
1057117f1b4Smrg      clip_tri_4( ctx, v1, v2, v3, ormask );    	\
1067117f1b4Smrg} while (0)
1077117f1b4Smrg
1087117f1b4Smrg#define RENDER_QUAD( v1, v2, v3, v4 )			\
1097117f1b4Smrgdo {							\
1107117f1b4Smrg   GLubyte c1 = mask[v1], c2 = mask[v2];		\
1117117f1b4Smrg   GLubyte c3 = mask[v3], c4 = mask[v4];		\
1127117f1b4Smrg   GLubyte ormask = c1|c2|c3|c4;			\
1137117f1b4Smrg   if (!ormask)						\
1147117f1b4Smrg      QuadFunc( ctx, v1, v2, v3, v4 );			\
1157117f1b4Smrg   else if (!(c1 & c2 & c3 & c4 & CLIPMASK)) 		\
1167117f1b4Smrg      clip_quad_4( ctx, v1, v2, v3, v4, ormask );	\
1177117f1b4Smrg} while (0)
1187117f1b4Smrg
1197117f1b4Smrg
1207117f1b4Smrg#define LOCAL_VARS						\
1217117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);				\
1227117f1b4Smrg   struct vertex_buffer *VB = &tnl->vb;				\
1237117f1b4Smrg   const GLuint * const elt = VB->Elts;				\
1247117f1b4Smrg   const GLubyte *mask = VB->ClipMask;				\
1257117f1b4Smrg   const GLuint sz = VB->ClipPtr->size;				\
1267117f1b4Smrg   const tnl_line_func LineFunc = tnl->Driver.Render.Line;		\
1277117f1b4Smrg   const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle;	\
1287117f1b4Smrg   const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad;		\
1297117f1b4Smrg   const GLboolean stipple = ctx->Line.StippleFlag;		\
1307117f1b4Smrg   (void) (LineFunc && TriangleFunc && QuadFunc);		\
1317117f1b4Smrg   (void) elt; (void) mask; (void) sz; (void) stipple;
1327117f1b4Smrg
1337117f1b4Smrg#define TAG(x) clip_##x##_verts
1347117f1b4Smrg#define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x )
1357117f1b4Smrg#define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx )
1367117f1b4Smrg#define PRESERVE_VB_DEFS
1377117f1b4Smrg#include "t_vb_rendertmp.h"
1387117f1b4Smrg
1397117f1b4Smrg
1407117f1b4Smrg
1417117f1b4Smrg/* Elts, with the possibility of clipping.
1427117f1b4Smrg */
1437117f1b4Smrg#undef ELT
1447117f1b4Smrg#undef TAG
1457117f1b4Smrg#define ELT(x) elt[x]
1467117f1b4Smrg#define TAG(x) clip_##x##_elts
1477117f1b4Smrg#include "t_vb_rendertmp.h"
1487117f1b4Smrg
1497117f1b4Smrg/* TODO: do this for all primitives, verts and elts:
1507117f1b4Smrg */
1513464ebd5Sriastradhstatic void clip_elt_triangles( struct gl_context *ctx,
1527117f1b4Smrg				GLuint start,
1537117f1b4Smrg				GLuint count,
1547117f1b4Smrg				GLuint flags )
1557117f1b4Smrg{
1567117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
1577117f1b4Smrg   tnl_render_func render_tris = tnl->Driver.Render.PrimTabElts[GL_TRIANGLES];
1587117f1b4Smrg   struct vertex_buffer *VB = &tnl->vb;
1597117f1b4Smrg   const GLuint * const elt = VB->Elts;
1607117f1b4Smrg   GLubyte *mask = VB->ClipMask;
1617117f1b4Smrg   GLuint last = count-2;
1627117f1b4Smrg   GLuint j;
1637117f1b4Smrg   (void) flags;
1647117f1b4Smrg
1657117f1b4Smrg   tnl->Driver.Render.PrimitiveNotify( ctx, GL_TRIANGLES );
1667117f1b4Smrg
1677117f1b4Smrg   for (j=start; j < last; j+=3 ) {
1687117f1b4Smrg      GLubyte c1 = mask[elt[j]];
1697117f1b4Smrg      GLubyte c2 = mask[elt[j+1]];
1707117f1b4Smrg      GLubyte c3 = mask[elt[j+2]];
1717117f1b4Smrg      GLubyte ormask = c1|c2|c3;
1727117f1b4Smrg      if (ormask) {
1737117f1b4Smrg	 if (start < j)
1747117f1b4Smrg	    render_tris( ctx, start, j, 0 );
1757117f1b4Smrg	 if (!(c1&c2&c3&CLIPMASK))
1767117f1b4Smrg	    clip_tri_4( ctx, elt[j], elt[j+1], elt[j+2], ormask );
1777117f1b4Smrg	 start = j+3;
1787117f1b4Smrg      }
1797117f1b4Smrg   }
1807117f1b4Smrg
1817117f1b4Smrg   if (start < j)
1827117f1b4Smrg      render_tris( ctx, start, j, 0 );
1837117f1b4Smrg}
1847117f1b4Smrg
1857117f1b4Smrg/**********************************************************************/
1867117f1b4Smrg/*                  Render whole begin/end objects                    */
1877117f1b4Smrg/**********************************************************************/
1887117f1b4Smrg
1897117f1b4Smrg#define NEED_EDGEFLAG_SETUP (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL)
1907117f1b4Smrg#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
1917117f1b4Smrg#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
1927117f1b4Smrg
1937117f1b4Smrg
1947117f1b4Smrg/* Vertices, no clipping.
1957117f1b4Smrg */
1967117f1b4Smrg#define RENDER_POINTS( start, count ) \
1977117f1b4Smrg   tnl->Driver.Render.Points( ctx, start, count )
1987117f1b4Smrg
1997117f1b4Smrg#define RENDER_LINE( v1, v2 ) \
2007117f1b4Smrg   LineFunc( ctx, v1, v2 )
2017117f1b4Smrg
2027117f1b4Smrg#define RENDER_TRI( v1, v2, v3 ) \
2037117f1b4Smrg   TriangleFunc( ctx, v1, v2, v3 )
2047117f1b4Smrg
2057117f1b4Smrg#define RENDER_QUAD( v1, v2, v3, v4 ) \
2067117f1b4Smrg   QuadFunc( ctx, v1, v2, v3, v4 )
2077117f1b4Smrg
2087117f1b4Smrg#define TAG(x) _tnl_##x##_verts
2097117f1b4Smrg
2107117f1b4Smrg#define LOCAL_VARS						\
2117117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);				\
2127117f1b4Smrg   struct vertex_buffer *VB = &tnl->vb;				\
2137117f1b4Smrg   const GLuint * const elt = VB->Elts;				\
2147117f1b4Smrg   const tnl_line_func LineFunc = tnl->Driver.Render.Line;		\
2157117f1b4Smrg   const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle;	\
2167117f1b4Smrg   const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad;		\
2177117f1b4Smrg   const GLboolean stipple = ctx->Line.StippleFlag;		\
2187117f1b4Smrg   (void) (LineFunc && TriangleFunc && QuadFunc);		\
2197117f1b4Smrg   (void) elt; (void) stipple
2207117f1b4Smrg
2217117f1b4Smrg#define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx )
2227117f1b4Smrg#define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x )
2237117f1b4Smrg#define RENDER_TAB_QUALIFIER
2247117f1b4Smrg#define PRESERVE_VB_DEFS
2257117f1b4Smrg#include "t_vb_rendertmp.h"
2267117f1b4Smrg
2277117f1b4Smrg
2287117f1b4Smrg/* Elts, no clipping.
2297117f1b4Smrg */
2307117f1b4Smrg#undef ELT
2317117f1b4Smrg#define TAG(x) _tnl_##x##_elts
2327117f1b4Smrg#define ELT(x) elt[x]
2337117f1b4Smrg#include "t_vb_rendertmp.h"
2347117f1b4Smrg
2357117f1b4Smrg
2367117f1b4Smrg/**********************************************************************/
2377117f1b4Smrg/*              Helper functions for drivers                  */
2387117f1b4Smrg/**********************************************************************/
2397117f1b4Smrg
2403464ebd5Sriastradhvoid _tnl_RenderClippedPolygon( struct gl_context *ctx, const GLuint *elts, GLuint n )
2417117f1b4Smrg{
2427117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
2437117f1b4Smrg   struct vertex_buffer *VB = &tnl->vb;
2447117f1b4Smrg   GLuint *tmp = VB->Elts;
2457117f1b4Smrg
2467117f1b4Smrg   VB->Elts = (GLuint *)elts;
2477117f1b4Smrg   tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END );
2487117f1b4Smrg   VB->Elts = tmp;
2497117f1b4Smrg}
2507117f1b4Smrg
2513464ebd5Sriastradhvoid _tnl_RenderClippedLine( struct gl_context *ctx, GLuint ii, GLuint jj )
2527117f1b4Smrg{
2537117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
2547117f1b4Smrg   tnl->Driver.Render.Line( ctx, ii, jj );
2557117f1b4Smrg}
2567117f1b4Smrg
2577117f1b4Smrg
2587117f1b4Smrg
2597117f1b4Smrg/**********************************************************************/
2607117f1b4Smrg/*              Clip and render whole vertex buffers                  */
2617117f1b4Smrg/**********************************************************************/
2627117f1b4Smrg
2637117f1b4Smrg
2643464ebd5Sriastradhstatic GLboolean run_render( struct gl_context *ctx,
2657117f1b4Smrg			     struct tnl_pipeline_stage *stage )
2667117f1b4Smrg{
2677117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
2687117f1b4Smrg   struct vertex_buffer *VB = &tnl->vb;
2697117f1b4Smrg   tnl_render_func *tab;
2707117f1b4Smrg   GLint pass = 0;
2717117f1b4Smrg
2727117f1b4Smrg   /* Allow the drivers to lock before projected verts are built so
2737117f1b4Smrg    * that window coordinates are guarenteed not to change before
2747117f1b4Smrg    * rendering.
2757117f1b4Smrg    */
27601e04c3fSmrg   assert(tnl->Driver.Render.Start);
2777117f1b4Smrg
2787117f1b4Smrg   tnl->Driver.Render.Start( ctx );
2797117f1b4Smrg
28001e04c3fSmrg   assert(tnl->Driver.Render.BuildVertices);
28101e04c3fSmrg   assert(tnl->Driver.Render.PrimitiveNotify);
28201e04c3fSmrg   assert(tnl->Driver.Render.Points);
28301e04c3fSmrg   assert(tnl->Driver.Render.Line);
28401e04c3fSmrg   assert(tnl->Driver.Render.Triangle);
28501e04c3fSmrg   assert(tnl->Driver.Render.Quad);
28601e04c3fSmrg   assert(tnl->Driver.Render.ResetLineStipple);
28701e04c3fSmrg   assert(tnl->Driver.Render.Interp);
28801e04c3fSmrg   assert(tnl->Driver.Render.CopyPV);
28901e04c3fSmrg   assert(tnl->Driver.Render.ClippedLine);
29001e04c3fSmrg   assert(tnl->Driver.Render.ClippedPolygon);
29101e04c3fSmrg   assert(tnl->Driver.Render.Finish);
2927117f1b4Smrg
2937117f1b4Smrg   tnl->Driver.Render.BuildVertices( ctx, 0, VB->Count, ~0 );
2947117f1b4Smrg
2957117f1b4Smrg   if (VB->ClipOrMask) {
2967117f1b4Smrg      tab = VB->Elts ? clip_render_tab_elts : clip_render_tab_verts;
2977117f1b4Smrg      clip_render_tab_elts[GL_TRIANGLES] = clip_elt_triangles;
2987117f1b4Smrg   }
2997117f1b4Smrg   else {
3007ec681f3Smrg      tab = (VB->Elts ?
3017ec681f3Smrg	     tnl->Driver.Render.PrimTabElts :
3027117f1b4Smrg	     tnl->Driver.Render.PrimTabVerts);
3037117f1b4Smrg   }
3047117f1b4Smrg
3057117f1b4Smrg   do
3067117f1b4Smrg   {
3077117f1b4Smrg      GLuint i;
3087117f1b4Smrg
3097117f1b4Smrg      for (i = 0 ; i < VB->PrimitiveCount ; i++)
3107117f1b4Smrg      {
3117117f1b4Smrg	 GLuint prim = _tnl_translate_prim(&VB->Primitive[i]);
3127117f1b4Smrg	 GLuint start = VB->Primitive[i].start;
3137117f1b4Smrg	 GLuint length = VB->Primitive[i].count;
3147117f1b4Smrg
3157117f1b4Smrg	 assert((prim & PRIM_MODE_MASK) <= GL_POLYGON);
3167117f1b4Smrg
3177ec681f3Smrg	 if (MESA_VERBOSE & VERBOSE_PRIMS)
3187ec681f3Smrg	    _mesa_debug(NULL, "MESA prim %s %d..%d\n",
3197ec681f3Smrg			_mesa_enum_to_string(prim & PRIM_MODE_MASK),
3207117f1b4Smrg			start, start+length);
3217117f1b4Smrg
3227117f1b4Smrg	 if (length)
3237117f1b4Smrg	    tab[prim & PRIM_MODE_MASK]( ctx, start, start + length, prim );
3247117f1b4Smrg      }
3257117f1b4Smrg   } while (tnl->Driver.Render.Multipass &&
3267117f1b4Smrg	    tnl->Driver.Render.Multipass( ctx, ++pass ));
3277117f1b4Smrg
3287117f1b4Smrg   tnl->Driver.Render.Finish( ctx );
3297117f1b4Smrg
3307117f1b4Smrg   return GL_FALSE;		/* finished the pipe */
3317117f1b4Smrg}
3327117f1b4Smrg
3337117f1b4Smrg
3347117f1b4Smrg/**********************************************************************/
3357117f1b4Smrg/*                          Render pipeline stage                     */
3367117f1b4Smrg/**********************************************************************/
3377117f1b4Smrg
3387117f1b4Smrg
3397117f1b4Smrg
3407117f1b4Smrg
3417117f1b4Smrg
3427117f1b4Smrgconst struct tnl_pipeline_stage _tnl_render_stage =
3437117f1b4Smrg{
3447117f1b4Smrg   "render",			/* name */
3457117f1b4Smrg   NULL,			/* private data */
3467117f1b4Smrg   NULL,			/* creator */
3477117f1b4Smrg   NULL,			/* destructor */
3487117f1b4Smrg   NULL,			/* validate */
3497117f1b4Smrg   run_render			/* run */
3507117f1b4Smrg};
351