t_vb_program.c revision 6577f753b278878eeb965964b381812c7b950083
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.6 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27/** 28 * \file tnl/t_vb_program.c 29 * \brief Pipeline stage for executing vertex programs. 30 * \author Brian Paul, Keith Whitwell 31 */ 32 33 34#include "main/glheader.h" 35#include "main/colormac.h" 36#include "main/macros.h" 37#include "main/imports.h" 38#include "math/m_xform.h" 39#include "program/prog_instruction.h" 40#include "program/prog_statevars.h" 41#include "program/prog_execute.h" 42#include "swrast/s_context.h" 43 44#include "tnl/tnl.h" 45#include "tnl/t_context.h" 46#include "tnl/t_pipeline.h" 47 48 49#ifdef NAN_CHECK 50/** Check for NaNs and very large values */ 51static INLINE void 52check_float(float x) 53{ 54 assert(!IS_INF_OR_NAN(x)); 55 assert(1.0e-15 <= x && x <= 1.0e15); 56} 57#endif 58 59 60/*! 61 * Private storage for the vertex program pipeline stage. 62 */ 63struct vp_stage_data { 64 /** The results of running the vertex program go into these arrays. */ 65 GLvector4f results[VERT_RESULT_MAX]; 66 67 GLvector4f ndcCoords; /**< normalized device coords */ 68 GLubyte *clipmask; /**< clip flags */ 69 GLubyte ormask, andmask; /**< for clipping */ 70 71 struct gl_program_machine machine; 72}; 73 74 75#define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr)) 76 77 78static void 79userclip( struct gl_context *ctx, 80 GLvector4f *clip, 81 GLubyte *clipmask, 82 GLubyte *clipormask, 83 GLubyte *clipandmask ) 84{ 85 GLuint p; 86 87 for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { 88 if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { 89 GLuint nr, i; 90 const GLfloat a = ctx->Transform._ClipUserPlane[p][0]; 91 const GLfloat b = ctx->Transform._ClipUserPlane[p][1]; 92 const GLfloat c = ctx->Transform._ClipUserPlane[p][2]; 93 const GLfloat d = ctx->Transform._ClipUserPlane[p][3]; 94 GLfloat *coord = (GLfloat *)clip->data; 95 GLuint stride = clip->stride; 96 GLuint count = clip->count; 97 98 for (nr = 0, i = 0 ; i < count ; i++) { 99 GLfloat dp = (coord[0] * a + 100 coord[1] * b + 101 coord[2] * c + 102 coord[3] * d); 103 104 if (dp < 0) { 105 nr++; 106 clipmask[i] |= CLIP_USER_BIT; 107 } 108 109 STRIDE_F(coord, stride); 110 } 111 112 if (nr > 0) { 113 *clipormask |= CLIP_USER_BIT; 114 if (nr == count) { 115 *clipandmask |= CLIP_USER_BIT; 116 return; 117 } 118 } 119 } 120 } 121} 122 123 124static GLboolean 125do_ndc_cliptest(struct gl_context *ctx, struct vp_stage_data *store) 126{ 127 TNLcontext *tnl = TNL_CONTEXT(ctx); 128 struct vertex_buffer *VB = &tnl->vb; 129 /* Cliptest and perspective divide. Clip functions must clear 130 * the clipmask. 131 */ 132 store->ormask = 0; 133 store->andmask = CLIP_FRUSTUM_BITS; 134 135 tnl_clip_prepare(ctx); 136 137 if (tnl->NeedNdcCoords) { 138 VB->NdcPtr = 139 _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr, 140 &store->ndcCoords, 141 store->clipmask, 142 &store->ormask, 143 &store->andmask, 144 !ctx->Transform.DepthClamp ); 145 } 146 else { 147 VB->NdcPtr = NULL; 148 _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr, 149 NULL, 150 store->clipmask, 151 &store->ormask, 152 &store->andmask, 153 !ctx->Transform.DepthClamp ); 154 } 155 156 if (store->andmask) { 157 /* All vertices are outside the frustum */ 158 return GL_FALSE; 159 } 160 161 /* Test userclip planes. This contributes to VB->ClipMask. 162 */ 163 /** XXX NEW_SLANG _Enabled ??? */ 164 if (ctx->Transform.ClipPlanesEnabled && (!ctx->VertexProgram._Enabled || 165 ctx->VertexProgram.Current->IsPositionInvariant)) { 166 userclip( ctx, 167 VB->ClipPtr, 168 store->clipmask, 169 &store->ormask, 170 &store->andmask ); 171 172 if (store->andmask) { 173 return GL_FALSE; 174 } 175 } 176 177 VB->ClipAndMask = store->andmask; 178 VB->ClipOrMask = store->ormask; 179 VB->ClipMask = store->clipmask; 180 181 return GL_TRUE; 182} 183 184 185/** 186 * XXX the texture sampling code in this module is a bit of a hack. 187 * The texture sampling code is in swrast, though it doesn't have any 188 * real dependencies on the rest of swrast. It should probably be 189 * moved into main/ someday. 190 */ 191static void 192vp_fetch_texel(struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda, 193 GLuint unit, GLfloat color[4]) 194{ 195 SWcontext *swrast = SWRAST_CONTEXT(ctx); 196 197 /* XXX use a float-valued TextureSample routine here!!! */ 198 swrast->TextureSample[unit](ctx, ctx->Texture.Unit[unit]._Current, 199 1, (const GLfloat (*)[4]) texcoord, 200 &lambda, (GLfloat (*)[4]) color); 201} 202 203 204/** 205 * Called via ctx->Driver.ProgramStringNotify() after a new vertex program 206 * string has been parsed. 207 */ 208GLboolean 209_tnl_program_string(struct gl_context *ctx, GLenum target, struct gl_program *program) 210{ 211 /* No-op. 212 * If we had derived anything from the program that was private to this 213 * stage we'd recompute/validate it here. 214 */ 215 return GL_TRUE; 216} 217 218 219/** 220 * Initialize virtual machine state prior to executing vertex program. 221 */ 222static void 223init_machine(struct gl_context *ctx, struct gl_program_machine *machine) 224{ 225 /* Input registers get initialized from the current vertex attribs */ 226 memcpy(machine->VertAttribs, ctx->Current.Attrib, 227 MAX_VERTEX_GENERIC_ATTRIBS * 4 * sizeof(GLfloat)); 228 229 if (ctx->VertexProgram._Current->IsNVProgram) { 230 GLuint i; 231 /* Output/result regs are initialized to [0,0,0,1] */ 232 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_OUTPUTS; i++) { 233 ASSIGN_4V(machine->Outputs[i], 0.0F, 0.0F, 0.0F, 1.0F); 234 } 235 /* Temp regs are initialized to [0,0,0,0] */ 236 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_TEMPS; i++) { 237 ASSIGN_4V(machine->Temporaries[i], 0.0F, 0.0F, 0.0F, 0.0F); 238 } 239 for (i = 0; i < MAX_VERTEX_PROGRAM_ADDRESS_REGS; i++) { 240 ASSIGN_4V(machine->AddressReg[i], 0, 0, 0, 0); 241 } 242 } 243 244 machine->NumDeriv = 0; 245 246 /* init condition codes */ 247 machine->CondCodes[0] = COND_EQ; 248 machine->CondCodes[1] = COND_EQ; 249 machine->CondCodes[2] = COND_EQ; 250 machine->CondCodes[3] = COND_EQ; 251 252 /* init call stack */ 253 machine->StackDepth = 0; 254 255 machine->FetchTexelLod = vp_fetch_texel; 256 machine->FetchTexelDeriv = NULL; /* not used by vertex programs */ 257 258 machine->Samplers = ctx->VertexProgram._Current->Base.SamplerUnits; 259} 260 261 262/** 263 * Map the texture images which the vertex program will access (if any). 264 */ 265static void 266map_textures(struct gl_context *ctx, const struct gl_vertex_program *vp) 267{ 268 GLuint u; 269 270 if (!ctx->Driver.MapTexture) 271 return; 272 273 for (u = 0; u < ctx->Const.MaxVertexTextureImageUnits; u++) { 274 if (vp->Base.TexturesUsed[u]) { 275 /* Note: _Current *should* correspond to the target indicated 276 * in TexturesUsed[u]. 277 */ 278 ctx->Driver.MapTexture(ctx, ctx->Texture.Unit[u]._Current); 279 } 280 } 281} 282 283 284/** 285 * Unmap the texture images which were used by the vertex program (if any). 286 */ 287static void 288unmap_textures(struct gl_context *ctx, const struct gl_vertex_program *vp) 289{ 290 GLuint u; 291 292 if (!ctx->Driver.MapTexture) 293 return; 294 295 for (u = 0; u < ctx->Const.MaxVertexTextureImageUnits; u++) { 296 if (vp->Base.TexturesUsed[u]) { 297 /* Note: _Current *should* correspond to the target indicated 298 * in TexturesUsed[u]. 299 */ 300 ctx->Driver.UnmapTexture(ctx, ctx->Texture.Unit[u]._Current); 301 } 302 } 303} 304 305 306/** 307 * This function executes vertex programs 308 */ 309static GLboolean 310run_vp( struct gl_context *ctx, struct tnl_pipeline_stage *stage ) 311{ 312 TNLcontext *tnl = TNL_CONTEXT(ctx); 313 struct vp_stage_data *store = VP_STAGE_DATA(stage); 314 struct vertex_buffer *VB = &tnl->vb; 315 struct gl_vertex_program *program = ctx->VertexProgram._Current; 316 struct gl_program_machine *machine = &store->machine; 317 GLuint outputs[VERT_RESULT_MAX], numOutputs; 318 GLuint i, j; 319 320 if (!program) 321 return GL_TRUE; 322 323 if (program->IsNVProgram) { 324 _mesa_load_tracked_matrices(ctx); 325 } 326 else { 327 /* ARB program or vertex shader */ 328 _mesa_load_state_parameters(ctx, program->Base.Parameters); 329 } 330 331 /* make list of outputs to save some time below */ 332 numOutputs = 0; 333 for (i = 0; i < VERT_RESULT_MAX; i++) { 334 if (program->Base.OutputsWritten & BITFIELD64_BIT(i)) { 335 outputs[numOutputs++] = i; 336 } 337 } 338 339 map_textures(ctx, program); 340 341 for (i = 0; i < VB->Count; i++) { 342 GLuint attr; 343 344 init_machine(ctx, machine); 345 346#if 0 347 printf("Input %d: %f, %f, %f, %f\n", i, 348 VB->AttribPtr[0]->data[i][0], 349 VB->AttribPtr[0]->data[i][1], 350 VB->AttribPtr[0]->data[i][2], 351 VB->AttribPtr[0]->data[i][3]); 352 printf(" color: %f, %f, %f, %f\n", 353 VB->AttribPtr[3]->data[i][0], 354 VB->AttribPtr[3]->data[i][1], 355 VB->AttribPtr[3]->data[i][2], 356 VB->AttribPtr[3]->data[i][3]); 357 printf(" normal: %f, %f, %f, %f\n", 358 VB->AttribPtr[2]->data[i][0], 359 VB->AttribPtr[2]->data[i][1], 360 VB->AttribPtr[2]->data[i][2], 361 VB->AttribPtr[2]->data[i][3]); 362#endif 363 364 /* the vertex array case */ 365 for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { 366 if (program->Base.InputsRead & (1 << attr)) { 367 const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data; 368 const GLuint size = VB->AttribPtr[attr]->size; 369 const GLuint stride = VB->AttribPtr[attr]->stride; 370 const GLfloat *data = (GLfloat *) (ptr + stride * i); 371#ifdef NAN_CHECK 372 check_float(data[0]); 373 check_float(data[1]); 374 check_float(data[2]); 375 check_float(data[3]); 376#endif 377 COPY_CLEAN_4V(machine->VertAttribs[attr], size, data); 378 } 379 } 380 381 /* execute the program */ 382 _mesa_execute_program(ctx, &program->Base, machine); 383 384 /* copy the output registers into the VB->attribs arrays */ 385 for (j = 0; j < numOutputs; j++) { 386 const GLuint attr = outputs[j]; 387#ifdef NAN_CHECK 388 check_float(machine->Outputs[attr][0]); 389 check_float(machine->Outputs[attr][1]); 390 check_float(machine->Outputs[attr][2]); 391 check_float(machine->Outputs[attr][3]); 392#endif 393 COPY_4V(store->results[attr].data[i], machine->Outputs[attr]); 394 } 395 396 /* FOGC is a special case. Fragment shader expects (f,0,0,1) */ 397 if (program->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_FOGC)) { 398 store->results[VERT_RESULT_FOGC].data[i][1] = 0.0; 399 store->results[VERT_RESULT_FOGC].data[i][2] = 0.0; 400 store->results[VERT_RESULT_FOGC].data[i][3] = 1.0; 401 } 402#ifdef NAN_CHECK 403 ASSERT(machine->Outputs[0][3] != 0.0F); 404#endif 405#if 0 406 printf("HPOS: %f %f %f %f\n", 407 machine->Outputs[0][0], 408 machine->Outputs[0][1], 409 machine->Outputs[0][2], 410 machine->Outputs[0][3]); 411#endif 412 } 413 414 unmap_textures(ctx, program); 415 416 /* Fixup fog and point size results if needed */ 417 if (program->IsNVProgram) { 418 if (ctx->Fog.Enabled && 419 (program->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_FOGC)) == 0) { 420 for (i = 0; i < VB->Count; i++) { 421 store->results[VERT_RESULT_FOGC].data[i][0] = 1.0; 422 } 423 } 424 425 if (ctx->VertexProgram.PointSizeEnabled && 426 (program->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_PSIZ)) == 0) { 427 for (i = 0; i < VB->Count; i++) { 428 store->results[VERT_RESULT_PSIZ].data[i][0] = ctx->Point.Size; 429 } 430 } 431 } 432 433 if (program->IsPositionInvariant) { 434 /* We need the exact same transform as in the fixed function path here 435 * to guarantee invariance, depending on compiler optimization flags 436 * results could be different otherwise. 437 */ 438 VB->ClipPtr = TransformRaw( &store->results[0], 439 &ctx->_ModelProjectMatrix, 440 VB->AttribPtr[0] ); 441 442 /* Drivers expect this to be clean to element 4... 443 */ 444 switch (VB->ClipPtr->size) { 445 case 1: 446 /* impossible */ 447 case 2: 448 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 ); 449 /* fall-through */ 450 case 3: 451 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 ); 452 /* fall-through */ 453 case 4: 454 break; 455 } 456 } 457 else { 458 /* Setup the VB pointers so that the next pipeline stages get 459 * their data from the right place (the program output arrays). 460 */ 461 VB->ClipPtr = &store->results[VERT_RESULT_HPOS]; 462 VB->ClipPtr->size = 4; 463 VB->ClipPtr->count = VB->Count; 464 } 465 466 VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->results[VERT_RESULT_COL0]; 467 VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->results[VERT_RESULT_COL1]; 468 VB->AttribPtr[VERT_ATTRIB_FOG] = &store->results[VERT_RESULT_FOGC]; 469 VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->results[VERT_RESULT_PSIZ]; 470 VB->BackfaceColorPtr = &store->results[VERT_RESULT_BFC0]; 471 VB->BackfaceSecondaryColorPtr = &store->results[VERT_RESULT_BFC1]; 472 473 for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { 474 VB->AttribPtr[_TNL_ATTRIB_TEX0 + i] 475 = &store->results[VERT_RESULT_TEX0 + i]; 476 } 477 478 for (i = 0; i < ctx->Const.MaxVarying; i++) { 479 if (program->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_VAR0 + i)) { 480 /* Note: varying results get put into the generic attributes */ 481 VB->AttribPtr[VERT_ATTRIB_GENERIC0+i] 482 = &store->results[VERT_RESULT_VAR0 + i]; 483 } 484 } 485 486 487 /* Perform NDC and cliptest operations: 488 */ 489 return do_ndc_cliptest(ctx, store); 490} 491 492 493/** 494 * Called the first time stage->run is called. In effect, don't 495 * allocate data until the first time the stage is run. 496 */ 497static GLboolean 498init_vp(struct gl_context *ctx, struct tnl_pipeline_stage *stage) 499{ 500 TNLcontext *tnl = TNL_CONTEXT(ctx); 501 struct vertex_buffer *VB = &(tnl->vb); 502 struct vp_stage_data *store; 503 const GLuint size = VB->Size; 504 GLuint i; 505 506 stage->privatePtr = CALLOC(sizeof(*store)); 507 store = VP_STAGE_DATA(stage); 508 if (!store) 509 return GL_FALSE; 510 511 /* Allocate arrays of vertex output values */ 512 for (i = 0; i < VERT_RESULT_MAX; i++) { 513 _mesa_vector4f_alloc( &store->results[i], 0, size, 32 ); 514 store->results[i].size = 4; 515 } 516 517 /* a few other misc allocations */ 518 _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 ); 519 store->clipmask = (GLubyte *) _mesa_align_malloc(sizeof(GLubyte)*size, 32 ); 520 521 return GL_TRUE; 522} 523 524 525/** 526 * Destructor for this pipeline stage. 527 */ 528static void 529dtr(struct tnl_pipeline_stage *stage) 530{ 531 struct vp_stage_data *store = VP_STAGE_DATA(stage); 532 533 if (store) { 534 GLuint i; 535 536 /* free the vertex program result arrays */ 537 for (i = 0; i < VERT_RESULT_MAX; i++) 538 _mesa_vector4f_free( &store->results[i] ); 539 540 /* free misc arrays */ 541 _mesa_vector4f_free( &store->ndcCoords ); 542 _mesa_align_free( store->clipmask ); 543 544 FREE( store ); 545 stage->privatePtr = NULL; 546 } 547} 548 549 550static void 551validate_vp_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage) 552{ 553 if (ctx->VertexProgram._Current) { 554 _swrast_update_texture_samplers(ctx); 555 } 556} 557 558 559 560/** 561 * Public description of this pipeline stage. 562 */ 563const struct tnl_pipeline_stage _tnl_vertex_program_stage = 564{ 565 "vertex-program", 566 NULL, /* private_data */ 567 init_vp, /* create */ 568 dtr, /* destroy */ 569 validate_vp_stage, /* validate */ 570 run_vp /* run -- initially set to ctr */ 571}; 572