t_vb_render.c revision 908be619fdba608b057ae512834dcc7a76aa3224
1/* $Id: t_vb_render.c,v 1.18 2001/04/26 14:53:48 keithw Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.5 6 * 7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * Authors: 27 * Keith Whitwell <keithw@valinux.com> 28 */ 29 30 31/* 32 * Render whole vertex buffers, including projection of vertices from 33 * clip space and clipping of primitives. 34 * 35 * This file makes calls to project vertices and to the point, line 36 * and triangle rasterizers via the function pointers: 37 * 38 * context->Driver.BuildProjectedVertices() 39 * 40 * context->Driver.PointsFunc() 41 * context->Driver.LineFunc() 42 * context->Driver.TriangleFunc() 43 * context->Driver.QuadFunc() 44 * 45 * context->Driver.RenderTabVerts[] 46 * context->Driver.RenderTabElts[] 47 * 48 * None of these may be null. 49 */ 50 51 52#include "glheader.h" 53#include "context.h" 54#include "macros.h" 55#include "mem.h" 56#include "mtypes.h" 57#include "mmath.h" 58 59#include "math/m_matrix.h" 60#include "math/m_xform.h" 61 62#include "t_pipeline.h" 63 64 65 66/**********************************************************************/ 67/* Clip single primitives */ 68/**********************************************************************/ 69 70 71#if defined(USE_IEEE) 72#define NEGATIVE(x) ((*(GLuint *)&x) & (1<<31)) 73#define DIFFERENT_SIGNS(x,y) (((*(GLuint *)&x)^(*(GLuint *)&y)) & (1<<31)) 74#else 75#define NEGATIVE(x) (x < 0) 76#define DIFFERENT_SIGNS(x,y) (x * y <= 0 && x - y != 0) 77/* Could just use (x*y<0) except for the flatshading requirements. 78 * Maybe there's a better way? 79 */ 80#endif 81 82#define LINTERP_SZ( t, vec, to, a, b, sz ) \ 83do { \ 84 switch (sz) { \ 85 case 2: vec[to][2] = 0.0; \ 86 case 3: vec[to][3] = 1.0; \ 87 } \ 88 switch (sz) { \ 89 case 4: vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \ 90 case 3: vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \ 91 case 2: vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \ 92 vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \ 93 } \ 94} while(0) 95 96#define LINTERP_4F( t, vec, to, a, b, sz ) \ 97do { \ 98 vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \ 99 vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \ 100 vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \ 101 vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \ 102} while (0) 103 104#define W(i) coord[i][3] 105#define Z(i) coord[i][2] 106#define Y(i) coord[i][1] 107#define X(i) coord[i][0] 108#define SIZE 4 109#define TAG(x) x##_4 110#include "t_vb_cliptmp.h" 111 112 113 114/**********************************************************************/ 115/* Clip and render whole begin/end objects */ 116/**********************************************************************/ 117 118#define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED) 119#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx] 120#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val 121 122 123/* Vertices, with the possibility of clipping. 124 */ 125#define RENDER_POINTS( start, count ) \ 126 tnl->Driver.PointsFunc( ctx, start, count ) 127 128#define RENDER_LINE( v1, v2 ) \ 129do { \ 130 GLubyte c1 = mask[v1], c2 = mask[v2]; \ 131 GLubyte ormask = c1|c2; \ 132 if (!ormask) \ 133 LineFunc( ctx, v1, v2 ); \ 134 else if (!(c1 & c2 & 0x3f)) \ 135 clip_line_4( ctx, v1, v2, ormask ); \ 136} while (0) 137 138#define RENDER_TRI( v1, v2, v3 ) \ 139do { \ 140 GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \ 141 GLubyte ormask = c1|c2|c3; \ 142 if (!ormask) \ 143 TriangleFunc( ctx, v1, v2, v3 ); \ 144 else if (!(c1 & c2 & c3 & 0x3f)) \ 145 clip_tri_4( ctx, v1, v2, v3, ormask ); \ 146} while (0) 147 148#define RENDER_QUAD( v1, v2, v3, v4 ) \ 149do { \ 150 GLubyte c1 = mask[v1], c2 = mask[v2]; \ 151 GLubyte c3 = mask[v3], c4 = mask[v4]; \ 152 GLubyte ormask = c1|c2|c3|c4; \ 153 if (!ormask) \ 154 QuadFunc( ctx, v1, v2, v3, v4 ); \ 155 else if (!(c1 & c2 & c3 & c4 & 0x3f)) \ 156 clip_quad_4( ctx, v1, v2, v3, v4, ormask ); \ 157} while (0) 158 159 160#define LOCAL_VARS \ 161 TNLcontext *tnl = TNL_CONTEXT(ctx); \ 162 struct vertex_buffer *VB = &tnl->vb; \ 163 const GLuint * const elt = VB->Elts; \ 164 const GLubyte *mask = VB->ClipMask; \ 165 const GLuint sz = VB->ClipPtr->size; \ 166 const line_func LineFunc = tnl->Driver.LineFunc; \ 167 const triangle_func TriangleFunc = tnl->Driver.TriangleFunc; \ 168 const quad_func QuadFunc = tnl->Driver.QuadFunc; \ 169 const GLboolean stipple = ctx->Line.StippleFlag; \ 170 (void) (LineFunc && TriangleFunc && QuadFunc); \ 171 (void) elt; (void) mask; (void) sz; (void) stipple; 172 173#define TAG(x) clip_##x##_verts 174#define INIT(x) tnl->Driver.RenderPrimitive( ctx, x ) 175#define RESET_STIPPLE if (stipple) tnl->Driver.ResetLineStipple( ctx ) 176#define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE 177#define PRESERVE_VB_DEFS 178#include "t_vb_rendertmp.h" 179 180 181 182/* Elts, with the possibility of clipping. 183 */ 184#undef ELT 185#undef TAG 186#define ELT(x) elt[x] 187#define TAG(x) clip_##x##_elts 188#include "t_vb_rendertmp.h" 189 190/* TODO: do this for all primitives, verts and elts: 191 */ 192static void clip_elt_triangles( GLcontext *ctx, 193 GLuint start, 194 GLuint count, 195 GLuint flags ) 196{ 197 TNLcontext *tnl = TNL_CONTEXT(ctx); 198 render_func render_tris = tnl->Driver.RenderTabElts[GL_TRIANGLES]; 199 struct vertex_buffer *VB = &tnl->vb; 200 const GLuint * const elt = VB->Elts; 201 GLubyte *mask = VB->ClipMask; 202 GLuint last = count-2; 203 GLuint j; 204 (void) flags; 205 206 tnl->Driver.RenderPrimitive( ctx, GL_TRIANGLES ); 207 208 for (j=start; j < last; j+=3 ) { 209 GLubyte c1 = mask[elt[j]]; 210 GLubyte c2 = mask[elt[j+1]]; 211 GLubyte c3 = mask[elt[j+2]]; 212 GLubyte ormask = c1|c2|c3; 213 if (ormask) { 214 if (start < j) 215 render_tris( ctx, start, j, 0 ); 216 if (!(c1&c2&c3&0x3f)) 217 clip_tri_4( ctx, elt[j], elt[j+1], elt[j+2], ormask ); 218 start = j+3; 219 } 220 } 221 222 if (start < j) 223 render_tris( ctx, start, j, 0 ); 224} 225 226/**********************************************************************/ 227/* Render whole begin/end objects */ 228/**********************************************************************/ 229 230#define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED) 231#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx] 232#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val 233 234 235/* Vertices, no clipping. 236 */ 237#define RENDER_POINTS( start, count ) \ 238 tnl->Driver.PointsFunc( ctx, start, count ) 239 240#define RENDER_LINE( v1, v2 ) \ 241 LineFunc( ctx, v1, v2 ) 242 243#define RENDER_TRI( v1, v2, v3 ) \ 244 TriangleFunc( ctx, v1, v2, v3 ) 245 246#define RENDER_QUAD( v1, v2, v3, v4 ) \ 247 QuadFunc( ctx, v1, v2, v3, v4 ) 248 249#define TAG(x) _tnl_##x##_verts 250 251#define LOCAL_VARS \ 252 TNLcontext *tnl = TNL_CONTEXT(ctx); \ 253 struct vertex_buffer *VB = &tnl->vb; \ 254 const GLuint * const elt = VB->Elts; \ 255 const line_func LineFunc = tnl->Driver.LineFunc; \ 256 const triangle_func TriangleFunc = tnl->Driver.TriangleFunc; \ 257 const quad_func QuadFunc = tnl->Driver.QuadFunc; \ 258 (void) (LineFunc && TriangleFunc && QuadFunc); \ 259 (void) elt; 260 261#define RESET_STIPPLE tnl->Driver.ResetLineStipple( ctx ) 262#define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE 263#define INIT(x) tnl->Driver.RenderPrimitive( ctx, x ) 264#define RENDER_TAB_QUALIFIER 265#define PRESERVE_VB_DEFS 266#include "t_vb_rendertmp.h" 267 268 269/* Elts, no clipping. 270 */ 271#undef ELT 272#define TAG(x) _tnl_##x##_elts 273#define ELT(x) elt[x] 274#include "t_vb_rendertmp.h" 275 276 277 278 279/**********************************************************************/ 280/* Clip and render whole vertex buffers */ 281/**********************************************************************/ 282 283 284static GLboolean run_render( GLcontext *ctx, 285 struct gl_pipeline_stage *stage ) 286{ 287 TNLcontext *tnl = TNL_CONTEXT(ctx); 288 struct vertex_buffer *VB = &tnl->vb; 289 GLuint new_inputs = stage->changed_inputs; 290 render_func *tab; 291 GLint pass = 0; 292 293 294 /* Allow the drivers to lock before projected verts are built so 295 * that window coordinates are guarenteed not to change before 296 * rendering. 297 */ 298 ASSERT(tnl->Driver.RenderStart); 299 300 tnl->Driver.RenderStart( ctx ); 301 302 ASSERT(tnl->Driver.BuildProjectedVertices); 303 ASSERT(tnl->Driver.RenderPrimitive); 304 ASSERT(tnl->Driver.PointsFunc); 305 ASSERT(tnl->Driver.LineFunc); 306 ASSERT(tnl->Driver.TriangleFunc); 307 ASSERT(tnl->Driver.QuadFunc); 308 ASSERT(tnl->Driver.ResetLineStipple); 309 ASSERT(tnl->Driver.RenderInterp); 310 ASSERT(tnl->Driver.RenderCopyPV); 311 ASSERT(tnl->Driver.RenderClippedLine); 312 ASSERT(tnl->Driver.RenderClippedPolygon); 313 ASSERT(tnl->Driver.RenderFinish); 314 315 tnl->Driver.BuildProjectedVertices( ctx, 0, VB->Count, new_inputs ); 316 317 if (VB->ClipOrMask) { 318 tab = VB->Elts ? clip_render_tab_elts : clip_render_tab_verts; 319 clip_render_tab_elts[GL_TRIANGLES] = clip_elt_triangles; 320 } 321 else { 322 tab = VB->Elts ? tnl->Driver.RenderTabElts : tnl->Driver.RenderTabVerts; 323 } 324 325 do 326 { 327 GLuint i, length, flags = 0; 328 for (i = 0 ; !(flags & PRIM_LAST) ; i += length) 329 { 330 flags = VB->Primitive[i]; 331 length= VB->PrimitiveLength[i]; 332 ASSERT(length || (flags & PRIM_LAST)); 333 ASSERT((flags & PRIM_MODE_MASK) <= GL_POLYGON+1); 334 if (length) 335 tab[flags & PRIM_MODE_MASK]( ctx, i, i + length, flags ); 336 } 337 } while (tnl->Driver.MultipassFunc && 338 tnl->Driver.MultipassFunc( ctx, ++pass )); 339 340 341 tnl->Driver.RenderFinish( ctx ); 342/* usleep(100000); */ 343 return GL_FALSE; /* finished the pipe */ 344} 345 346 347/**********************************************************************/ 348/* Render pipeline stage */ 349/**********************************************************************/ 350 351 352 353/* Quite a bit of work involved in finding out the inputs for the 354 * render stage. 355 */ 356static void check_render( GLcontext *ctx, struct gl_pipeline_stage *stage ) 357{ 358 GLuint inputs = VERT_CLIP; 359 GLuint i; 360 361 if (ctx->Visual.rgbMode) { 362 inputs |= VERT_RGBA; 363 364 if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) 365 inputs |= VERT_SPEC_RGB; 366 367 if (ctx->Texture._ReallyEnabled) { 368 for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { 369 if (ctx->Texture.Unit[i]._ReallyEnabled) 370 inputs |= VERT_TEX(i); 371 } 372 } 373 } 374 else { 375 inputs |= VERT_INDEX; 376 } 377 378 if (ctx->Point._Attenuated) 379 inputs |= VERT_POINT_SIZE; 380 381 /* How do drivers turn this off? 382 */ 383 if (ctx->Fog.Enabled) 384 inputs |= VERT_FOG_COORD; 385 386 if (ctx->_TriangleCaps & DD_TRI_UNFILLED) 387 inputs |= VERT_EDGE; 388 389 if (ctx->RenderMode==GL_FEEDBACK) 390 inputs |= VERT_TEX_ANY; 391 392 stage->inputs = inputs; 393} 394 395 396 397 398static void dtr( struct gl_pipeline_stage *stage ) 399{ 400} 401 402 403const struct gl_pipeline_stage _tnl_render_stage = 404{ 405 "render", 406 (_NEW_BUFFERS | 407 _DD_NEW_SEPARATE_SPECULAR | 408 _DD_NEW_FLATSHADE | 409 _NEW_TEXTURE| 410 _NEW_LIGHT| 411 _NEW_POINT| 412 _NEW_FOG| 413 _DD_NEW_TRI_UNFILLED | 414 _NEW_RENDERMODE), /* re-check (new inputs, interp function) */ 415 0, /* re-run (always runs) */ 416 GL_TRUE, /* active */ 417 0, 0, /* inputs (set in check_render), outputs */ 418 0, 0, /* changed_inputs, private */ 419 dtr, /* destructor */ 420 check_render, /* check */ 421 run_render /* run */ 422}; 423