t_vb_render.c revision 0ad64faec79770ad97044257ab1baf0675187aea
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 "glheader.h" 42#include "context.h" 43#include "enums.h" 44#include "macros.h" 45#include "imports.h" 46#include "mtypes.h" 47 48#include "t_pipeline.h" 49 50 51 52/**********************************************************************/ 53/* Clip single primitives */ 54/**********************************************************************/ 55 56 57#define W(i) coord[i][3] 58#define Z(i) coord[i][2] 59#define Y(i) coord[i][1] 60#define X(i) coord[i][0] 61#define SIZE 4 62#define TAG(x) x##_4 63#include "t_vb_cliptmp.h" 64 65 66 67/**********************************************************************/ 68/* Clip and render whole begin/end objects */ 69/**********************************************************************/ 70 71#define NEED_EDGEFLAG_SETUP (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL) 72#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx] 73#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val 74 75 76#define CLIPMASK (CLIP_ALL_BITS|CLIP_CULL_BIT) 77 78 79/* Vertices, with the possibility of clipping. 80 */ 81#define RENDER_POINTS( start, count ) \ 82 tnl->Driver.Render.Points( ctx, start, count ) 83 84#define RENDER_LINE( v1, v2 ) \ 85do { \ 86 GLubyte c1 = mask[v1], c2 = mask[v2]; \ 87 GLubyte ormask = c1|c2; \ 88 if (!ormask) \ 89 LineFunc( ctx, v1, v2 ); \ 90 else if (!(c1 & c2 & CLIPMASK)) \ 91 clip_line_4( ctx, v1, v2, ormask ); \ 92} while (0) 93 94#define RENDER_TRI( v1, v2, v3 ) \ 95do { \ 96 GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \ 97 GLubyte ormask = c1|c2|c3; \ 98 if (!ormask) \ 99 TriangleFunc( ctx, v1, v2, v3 ); \ 100 else if (!(c1 & c2 & c3 & CLIPMASK)) \ 101 clip_tri_4( ctx, v1, v2, v3, ormask ); \ 102} while (0) 103 104#define RENDER_QUAD( v1, v2, v3, v4 ) \ 105do { \ 106 GLubyte c1 = mask[v1], c2 = mask[v2]; \ 107 GLubyte c3 = mask[v3], c4 = mask[v4]; \ 108 GLubyte ormask = c1|c2|c3|c4; \ 109 if (!ormask) \ 110 QuadFunc( ctx, v1, v2, v3, v4 ); \ 111 else if (!(c1 & c2 & c3 & c4 & CLIPMASK)) \ 112 clip_quad_4( ctx, v1, v2, v3, v4, ormask ); \ 113} while (0) 114 115 116#define LOCAL_VARS \ 117 TNLcontext *tnl = TNL_CONTEXT(ctx); \ 118 struct vertex_buffer *VB = &tnl->vb; \ 119 const GLuint * const elt = VB->Elts; \ 120 const GLubyte *mask = VB->ClipMask; \ 121 const GLuint sz = VB->ClipPtr->size; \ 122 const tnl_line_func LineFunc = tnl->Driver.Render.Line; \ 123 const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \ 124 const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \ 125 const GLboolean stipple = ctx->Line.StippleFlag; \ 126 (void) (LineFunc && TriangleFunc && QuadFunc); \ 127 (void) elt; (void) mask; (void) sz; (void) stipple; 128 129#define TAG(x) clip_##x##_verts 130#define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x ) 131#define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx ) 132#define PRESERVE_VB_DEFS 133#include "t_vb_rendertmp.h" 134 135 136 137/* Elts, with the possibility of clipping. 138 */ 139#undef ELT 140#undef TAG 141#define ELT(x) elt[x] 142#define TAG(x) clip_##x##_elts 143#include "t_vb_rendertmp.h" 144 145/* TODO: do this for all primitives, verts and elts: 146 */ 147static void clip_elt_triangles( GLcontext *ctx, 148 GLuint start, 149 GLuint count, 150 GLuint flags ) 151{ 152 TNLcontext *tnl = TNL_CONTEXT(ctx); 153 tnl_render_func render_tris = tnl->Driver.Render.PrimTabElts[GL_TRIANGLES]; 154 struct vertex_buffer *VB = &tnl->vb; 155 const GLuint * const elt = VB->Elts; 156 GLubyte *mask = VB->ClipMask; 157 GLuint last = count-2; 158 GLuint j; 159 (void) flags; 160 161 tnl->Driver.Render.PrimitiveNotify( ctx, GL_TRIANGLES ); 162 163 for (j=start; j < last; j+=3 ) { 164 GLubyte c1 = mask[elt[j]]; 165 GLubyte c2 = mask[elt[j+1]]; 166 GLubyte c3 = mask[elt[j+2]]; 167 GLubyte ormask = c1|c2|c3; 168 if (ormask) { 169 if (start < j) 170 render_tris( ctx, start, j, 0 ); 171 if (!(c1&c2&c3&CLIPMASK)) 172 clip_tri_4( ctx, elt[j], elt[j+1], elt[j+2], ormask ); 173 start = j+3; 174 } 175 } 176 177 if (start < j) 178 render_tris( ctx, start, j, 0 ); 179} 180 181/**********************************************************************/ 182/* Render whole begin/end objects */ 183/**********************************************************************/ 184 185#define NEED_EDGEFLAG_SETUP (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL) 186#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx] 187#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val 188 189 190/* Vertices, no clipping. 191 */ 192#define RENDER_POINTS( start, count ) \ 193 tnl->Driver.Render.Points( ctx, start, count ) 194 195#define RENDER_LINE( v1, v2 ) \ 196 LineFunc( ctx, v1, v2 ) 197 198#define RENDER_TRI( v1, v2, v3 ) \ 199 TriangleFunc( ctx, v1, v2, v3 ) 200 201#define RENDER_QUAD( v1, v2, v3, v4 ) \ 202 QuadFunc( ctx, v1, v2, v3, v4 ) 203 204#define TAG(x) _tnl_##x##_verts 205 206#define LOCAL_VARS \ 207 TNLcontext *tnl = TNL_CONTEXT(ctx); \ 208 struct vertex_buffer *VB = &tnl->vb; \ 209 const GLuint * const elt = VB->Elts; \ 210 const tnl_line_func LineFunc = tnl->Driver.Render.Line; \ 211 const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \ 212 const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \ 213 const GLboolean stipple = ctx->Line.StippleFlag; \ 214 (void) (LineFunc && TriangleFunc && QuadFunc); \ 215 (void) elt; (void) stipple 216 217#define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx ) 218#define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x ) 219#define RENDER_TAB_QUALIFIER 220#define PRESERVE_VB_DEFS 221#include "t_vb_rendertmp.h" 222 223 224/* Elts, no clipping. 225 */ 226#undef ELT 227#define TAG(x) _tnl_##x##_elts 228#define ELT(x) elt[x] 229#include "t_vb_rendertmp.h" 230 231 232/**********************************************************************/ 233/* Helper functions for drivers */ 234/**********************************************************************/ 235 236void _tnl_RenderClippedPolygon( GLcontext *ctx, const GLuint *elts, GLuint n ) 237{ 238 TNLcontext *tnl = TNL_CONTEXT(ctx); 239 struct vertex_buffer *VB = &tnl->vb; 240 GLuint *tmp = VB->Elts; 241 242 VB->Elts = (GLuint *)elts; 243 tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END ); 244 VB->Elts = tmp; 245} 246 247void _tnl_RenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj ) 248{ 249 TNLcontext *tnl = TNL_CONTEXT(ctx); 250 tnl->Driver.Render.Line( ctx, ii, jj ); 251} 252 253 254 255/**********************************************************************/ 256/* Clip and render whole vertex buffers */ 257/**********************************************************************/ 258 259 260static GLboolean run_render( GLcontext *ctx, 261 struct tnl_pipeline_stage *stage ) 262{ 263 TNLcontext *tnl = TNL_CONTEXT(ctx); 264 struct vertex_buffer *VB = &tnl->vb; 265 tnl_render_func *tab; 266 GLint pass = 0; 267 268 /* Allow the drivers to lock before projected verts are built so 269 * that window coordinates are guarenteed not to change before 270 * rendering. 271 */ 272 ASSERT(tnl->Driver.Render.Start); 273 274 tnl->Driver.Render.Start( ctx ); 275 276 ASSERT(tnl->Driver.Render.BuildVertices); 277 ASSERT(tnl->Driver.Render.PrimitiveNotify); 278 ASSERT(tnl->Driver.Render.Points); 279 ASSERT(tnl->Driver.Render.Line); 280 ASSERT(tnl->Driver.Render.Triangle); 281 ASSERT(tnl->Driver.Render.Quad); 282 ASSERT(tnl->Driver.Render.ResetLineStipple); 283 ASSERT(tnl->Driver.Render.Interp); 284 ASSERT(tnl->Driver.Render.CopyPV); 285 ASSERT(tnl->Driver.Render.ClippedLine); 286 ASSERT(tnl->Driver.Render.ClippedPolygon); 287 ASSERT(tnl->Driver.Render.Finish); 288 289 tnl->Driver.Render.BuildVertices( ctx, 0, VB->Count, ~0 ); 290 291 if (VB->ClipOrMask) { 292 tab = VB->Elts ? clip_render_tab_elts : clip_render_tab_verts; 293 clip_render_tab_elts[GL_TRIANGLES] = clip_elt_triangles; 294 } 295 else { 296 tab = (VB->Elts ? 297 tnl->Driver.Render.PrimTabElts : 298 tnl->Driver.Render.PrimTabVerts); 299 } 300 301 do 302 { 303 GLuint i; 304 305 for (i = 0 ; i < VB->PrimitiveCount ; i++) 306 { 307 GLuint prim = VB->Primitive[i].mode; 308 GLuint start = VB->Primitive[i].start; 309 GLuint length = VB->Primitive[i].count; 310 311 assert((prim & PRIM_MODE_MASK) <= GL_POLYGON); 312 313 if (MESA_VERBOSE & VERBOSE_PRIMS) 314 _mesa_debug(NULL, "MESA prim %s %d..%d\n", 315 _mesa_lookup_enum_by_nr(prim & PRIM_MODE_MASK), 316 start, start+length); 317 318 if (length) 319 tab[prim & PRIM_MODE_MASK]( ctx, start, start + length, prim ); 320 } 321 } while (tnl->Driver.Render.Multipass && 322 tnl->Driver.Render.Multipass( ctx, ++pass )); 323 324 tnl->Driver.Render.Finish( ctx ); 325 326 return GL_FALSE; /* finished the pipe */ 327} 328 329 330/**********************************************************************/ 331/* Render pipeline stage */ 332/**********************************************************************/ 333 334 335 336 337 338const struct tnl_pipeline_stage _tnl_render_stage = 339{ 340 "render", /* name */ 341 NULL, /* private data */ 342 NULL, /* creator */ 343 NULL, /* destructor */ 344 NULL, /* validate */ 345 run_render /* run */ 346}; 347