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