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