t_vb_render.c revision 51c0c71811508b6658e0d5dcff8426b618322a73
1/* $Id: t_vb_render.c,v 1.19 2001/04/28 08:39:18 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 83#define W(i) coord[i][3] 84#define Z(i) coord[i][2] 85#define Y(i) coord[i][1] 86#define X(i) coord[i][0] 87#define SIZE 4 88#define TAG(x) x##_4 89#include "t_vb_cliptmp.h" 90 91 92 93/**********************************************************************/ 94/* Clip and render whole begin/end objects */ 95/**********************************************************************/ 96 97#define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED) 98#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx] 99#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val 100 101 102/* Vertices, with the possibility of clipping. 103 */ 104#define RENDER_POINTS( start, count ) \ 105 tnl->Driver.PointsFunc( ctx, start, count ) 106 107#define RENDER_LINE( v1, v2 ) \ 108do { \ 109 GLubyte c1 = mask[v1], c2 = mask[v2]; \ 110 GLubyte ormask = c1|c2; \ 111 if (!ormask) \ 112 LineFunc( ctx, v1, v2 ); \ 113 else if (!(c1 & c2 & 0x3f)) \ 114 clip_line_4( ctx, v1, v2, ormask ); \ 115} while (0) 116 117#define RENDER_TRI( v1, v2, v3 ) \ 118do { \ 119 GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \ 120 GLubyte ormask = c1|c2|c3; \ 121 if (!ormask) \ 122 TriangleFunc( ctx, v1, v2, v3 ); \ 123 else if (!(c1 & c2 & c3 & 0x3f)) \ 124 clip_tri_4( ctx, v1, v2, v3, ormask ); \ 125} while (0) 126 127#define RENDER_QUAD( v1, v2, v3, v4 ) \ 128do { \ 129 GLubyte c1 = mask[v1], c2 = mask[v2]; \ 130 GLubyte c3 = mask[v3], c4 = mask[v4]; \ 131 GLubyte ormask = c1|c2|c3|c4; \ 132 if (!ormask) \ 133 QuadFunc( ctx, v1, v2, v3, v4 ); \ 134 else if (!(c1 & c2 & c3 & c4 & 0x3f)) \ 135 clip_quad_4( ctx, v1, v2, v3, v4, ormask ); \ 136} while (0) 137 138 139#define LOCAL_VARS \ 140 TNLcontext *tnl = TNL_CONTEXT(ctx); \ 141 struct vertex_buffer *VB = &tnl->vb; \ 142 const GLuint * const elt = VB->Elts; \ 143 const GLubyte *mask = VB->ClipMask; \ 144 const GLuint sz = VB->ClipPtr->size; \ 145 const line_func LineFunc = tnl->Driver.LineFunc; \ 146 const triangle_func TriangleFunc = tnl->Driver.TriangleFunc; \ 147 const quad_func QuadFunc = tnl->Driver.QuadFunc; \ 148 const GLboolean stipple = ctx->Line.StippleFlag; \ 149 (void) (LineFunc && TriangleFunc && QuadFunc); \ 150 (void) elt; (void) mask; (void) sz; (void) stipple; 151 152#define TAG(x) clip_##x##_verts 153#define INIT(x) tnl->Driver.RenderPrimitive( ctx, x ) 154#define RESET_STIPPLE if (stipple) tnl->Driver.ResetLineStipple( ctx ) 155#define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE 156#define PRESERVE_VB_DEFS 157#include "t_vb_rendertmp.h" 158 159 160 161/* Elts, with the possibility of clipping. 162 */ 163#undef ELT 164#undef TAG 165#define ELT(x) elt[x] 166#define TAG(x) clip_##x##_elts 167#include "t_vb_rendertmp.h" 168 169/* TODO: do this for all primitives, verts and elts: 170 */ 171static void clip_elt_triangles( GLcontext *ctx, 172 GLuint start, 173 GLuint count, 174 GLuint flags ) 175{ 176 TNLcontext *tnl = TNL_CONTEXT(ctx); 177 render_func render_tris = tnl->Driver.RenderTabElts[GL_TRIANGLES]; 178 struct vertex_buffer *VB = &tnl->vb; 179 const GLuint * const elt = VB->Elts; 180 GLubyte *mask = VB->ClipMask; 181 GLuint last = count-2; 182 GLuint j; 183 (void) flags; 184 185 tnl->Driver.RenderPrimitive( ctx, GL_TRIANGLES ); 186 187 for (j=start; j < last; j+=3 ) { 188 GLubyte c1 = mask[elt[j]]; 189 GLubyte c2 = mask[elt[j+1]]; 190 GLubyte c3 = mask[elt[j+2]]; 191 GLubyte ormask = c1|c2|c3; 192 if (ormask) { 193 if (start < j) 194 render_tris( ctx, start, j, 0 ); 195 if (!(c1&c2&c3&0x3f)) 196 clip_tri_4( ctx, elt[j], elt[j+1], elt[j+2], ormask ); 197 start = j+3; 198 } 199 } 200 201 if (start < j) 202 render_tris( ctx, start, j, 0 ); 203} 204 205/**********************************************************************/ 206/* Render whole begin/end objects */ 207/**********************************************************************/ 208 209#define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED) 210#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx] 211#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val 212 213 214/* Vertices, no clipping. 215 */ 216#define RENDER_POINTS( start, count ) \ 217 tnl->Driver.PointsFunc( ctx, start, count ) 218 219#define RENDER_LINE( v1, v2 ) \ 220 LineFunc( ctx, v1, v2 ) 221 222#define RENDER_TRI( v1, v2, v3 ) \ 223 TriangleFunc( ctx, v1, v2, v3 ) 224 225#define RENDER_QUAD( v1, v2, v3, v4 ) \ 226 QuadFunc( ctx, v1, v2, v3, v4 ) 227 228#define TAG(x) _tnl_##x##_verts 229 230#define LOCAL_VARS \ 231 TNLcontext *tnl = TNL_CONTEXT(ctx); \ 232 struct vertex_buffer *VB = &tnl->vb; \ 233 const GLuint * const elt = VB->Elts; \ 234 const line_func LineFunc = tnl->Driver.LineFunc; \ 235 const triangle_func TriangleFunc = tnl->Driver.TriangleFunc; \ 236 const quad_func QuadFunc = tnl->Driver.QuadFunc; \ 237 (void) (LineFunc && TriangleFunc && QuadFunc); \ 238 (void) elt; 239 240#define RESET_STIPPLE tnl->Driver.ResetLineStipple( ctx ) 241#define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE 242#define INIT(x) tnl->Driver.RenderPrimitive( ctx, x ) 243#define RENDER_TAB_QUALIFIER 244#define PRESERVE_VB_DEFS 245#include "t_vb_rendertmp.h" 246 247 248/* Elts, no clipping. 249 */ 250#undef ELT 251#define TAG(x) _tnl_##x##_elts 252#define ELT(x) elt[x] 253#include "t_vb_rendertmp.h" 254 255 256 257 258/**********************************************************************/ 259/* Clip and render whole vertex buffers */ 260/**********************************************************************/ 261 262 263static GLboolean run_render( GLcontext *ctx, 264 struct gl_pipeline_stage *stage ) 265{ 266 TNLcontext *tnl = TNL_CONTEXT(ctx); 267 struct vertex_buffer *VB = &tnl->vb; 268 GLuint new_inputs = stage->changed_inputs; 269 render_func *tab; 270 GLint pass = 0; 271 272 273 /* Allow the drivers to lock before projected verts are built so 274 * that window coordinates are guarenteed not to change before 275 * rendering. 276 */ 277 ASSERT(tnl->Driver.RenderStart); 278 279 tnl->Driver.RenderStart( ctx ); 280 281 ASSERT(tnl->Driver.BuildProjectedVertices); 282 ASSERT(tnl->Driver.RenderPrimitive); 283 ASSERT(tnl->Driver.PointsFunc); 284 ASSERT(tnl->Driver.LineFunc); 285 ASSERT(tnl->Driver.TriangleFunc); 286 ASSERT(tnl->Driver.QuadFunc); 287 ASSERT(tnl->Driver.ResetLineStipple); 288 ASSERT(tnl->Driver.RenderInterp); 289 ASSERT(tnl->Driver.RenderCopyPV); 290 ASSERT(tnl->Driver.RenderClippedLine); 291 ASSERT(tnl->Driver.RenderClippedPolygon); 292 ASSERT(tnl->Driver.RenderFinish); 293 294 tnl->Driver.BuildProjectedVertices( ctx, 0, VB->Count, new_inputs ); 295 296 if (VB->ClipOrMask) { 297 tab = VB->Elts ? clip_render_tab_elts : clip_render_tab_verts; 298 clip_render_tab_elts[GL_TRIANGLES] = clip_elt_triangles; 299 } 300 else { 301 tab = VB->Elts ? tnl->Driver.RenderTabElts : tnl->Driver.RenderTabVerts; 302 } 303 304 do 305 { 306 GLuint i, length, flags = 0; 307 for (i = 0 ; !(flags & PRIM_LAST) ; i += length) 308 { 309 flags = VB->Primitive[i]; 310 length= VB->PrimitiveLength[i]; 311 ASSERT(length || (flags & PRIM_LAST)); 312 ASSERT((flags & PRIM_MODE_MASK) <= GL_POLYGON+1); 313 if (length) 314 tab[flags & PRIM_MODE_MASK]( ctx, i, i + length, flags ); 315 } 316 } while (tnl->Driver.MultipassFunc && 317 tnl->Driver.MultipassFunc( ctx, ++pass )); 318 319 320 tnl->Driver.RenderFinish( ctx ); 321/* usleep(100000); */ 322 return GL_FALSE; /* finished the pipe */ 323} 324 325 326/**********************************************************************/ 327/* Render pipeline stage */ 328/**********************************************************************/ 329 330 331 332/* Quite a bit of work involved in finding out the inputs for the 333 * render stage. 334 */ 335static void check_render( GLcontext *ctx, struct gl_pipeline_stage *stage ) 336{ 337 GLuint inputs = VERT_CLIP; 338 GLuint i; 339 340 if (ctx->Visual.rgbMode) { 341 inputs |= VERT_RGBA; 342 343 if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) 344 inputs |= VERT_SPEC_RGB; 345 346 if (ctx->Texture._ReallyEnabled) { 347 for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { 348 if (ctx->Texture.Unit[i]._ReallyEnabled) 349 inputs |= VERT_TEX(i); 350 } 351 } 352 } 353 else { 354 inputs |= VERT_INDEX; 355 } 356 357 if (ctx->Point._Attenuated) 358 inputs |= VERT_POINT_SIZE; 359 360 /* How do drivers turn this off? 361 */ 362 if (ctx->Fog.Enabled) 363 inputs |= VERT_FOG_COORD; 364 365 if (ctx->_TriangleCaps & DD_TRI_UNFILLED) 366 inputs |= VERT_EDGE; 367 368 if (ctx->RenderMode==GL_FEEDBACK) 369 inputs |= VERT_TEX_ANY; 370 371 stage->inputs = inputs; 372} 373 374 375 376 377static void dtr( struct gl_pipeline_stage *stage ) 378{ 379} 380 381 382const struct gl_pipeline_stage _tnl_render_stage = 383{ 384 "render", 385 (_NEW_BUFFERS | 386 _DD_NEW_SEPARATE_SPECULAR | 387 _DD_NEW_FLATSHADE | 388 _NEW_TEXTURE| 389 _NEW_LIGHT| 390 _NEW_POINT| 391 _NEW_FOG| 392 _DD_NEW_TRI_UNFILLED | 393 _NEW_RENDERMODE), /* re-check (new inputs, interp function) */ 394 0, /* re-run (always runs) */ 395 GL_TRUE, /* active */ 396 0, 0, /* inputs (set in check_render), outputs */ 397 0, 0, /* changed_inputs, private */ 398 dtr, /* destructor */ 399 check_render, /* check */ 400 run_render /* run */ 401}; 402