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 (at) 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 ) \ 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 */ 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 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 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 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