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