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