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