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