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@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 ) \ 87do { \ 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 ) \ 97do { \ 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 ) \ 107do { \ 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 */ 149static 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 238void _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 249void _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 262static 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 340const 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