t_vb_program.c revision af69d88d
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5 * Copyright (C) 2009 VMware, Inc. 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 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * 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 */ 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[VARYING_SLOT_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 81static void 82userclip( 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 127static GLboolean 128do_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 */ 194static void 195vp_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 */ 212GLboolean 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 */ 226static void 227init_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 machine->NumDeriv = 0; 235 236 /* init condition codes */ 237 machine->CondCodes[0] = COND_EQ; 238 machine->CondCodes[1] = COND_EQ; 239 machine->CondCodes[2] = COND_EQ; 240 machine->CondCodes[3] = COND_EQ; 241 242 /* init call stack */ 243 machine->StackDepth = 0; 244 245 machine->FetchTexelLod = vp_fetch_texel; 246 machine->FetchTexelDeriv = NULL; /* not used by vertex programs */ 247 248 machine->Samplers = ctx->VertexProgram._Current->Base.SamplerUnits; 249 250 machine->SystemValues[SYSTEM_VALUE_INSTANCE_ID][0] = (GLfloat) instID; 251} 252 253 254/** 255 * Map the texture images which the vertex program will access (if any). 256 */ 257static void 258map_textures(struct gl_context *ctx, const struct gl_vertex_program *vp) 259{ 260 GLuint u; 261 262 for (u = 0; u < ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits; u++) { 263 if (vp->Base.TexturesUsed[u]) { 264 /* Note: _Current *should* correspond to the target indicated 265 * in TexturesUsed[u]. 266 */ 267 _swrast_map_texture(ctx, ctx->Texture.Unit[u]._Current); 268 } 269 } 270} 271 272 273/** 274 * Unmap the texture images which were used by the vertex program (if any). 275 */ 276static void 277unmap_textures(struct gl_context *ctx, const struct gl_vertex_program *vp) 278{ 279 GLuint u; 280 281 for (u = 0; u < ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits; u++) { 282 if (vp->Base.TexturesUsed[u]) { 283 /* Note: _Current *should* correspond to the target indicated 284 * in TexturesUsed[u]. 285 */ 286 _swrast_unmap_texture(ctx, ctx->Texture.Unit[u]._Current); 287 } 288 } 289} 290 291 292/** 293 * This function executes vertex programs 294 */ 295static GLboolean 296run_vp( struct gl_context *ctx, struct tnl_pipeline_stage *stage ) 297{ 298 TNLcontext *tnl = TNL_CONTEXT(ctx); 299 struct vp_stage_data *store = VP_STAGE_DATA(stage); 300 struct vertex_buffer *VB = &tnl->vb; 301 struct gl_vertex_program *program = ctx->VertexProgram._Current; 302 struct gl_program_machine *machine = &store->machine; 303 GLuint outputs[VARYING_SLOT_MAX], numOutputs; 304 GLuint i, j; 305 306 if (!program) 307 return GL_TRUE; 308 309 /* ARB program or vertex shader */ 310 _mesa_load_state_parameters(ctx, program->Base.Parameters); 311 312 /* make list of outputs to save some time below */ 313 numOutputs = 0; 314 for (i = 0; i < VARYING_SLOT_MAX; i++) { 315 if (program->Base.OutputsWritten & BITFIELD64_BIT(i)) { 316 outputs[numOutputs++] = i; 317 } 318 } 319 320 /* Allocate result vectors. We delay this until now to avoid allocating 321 * memory that would never be used if we don't run the software tnl pipeline. 322 */ 323 if (!store->results[0].storage) { 324 for (i = 0; i < VARYING_SLOT_MAX; i++) { 325 assert(!store->results[i].storage); 326 _mesa_vector4f_alloc( &store->results[i], 0, VB->Size, 32 ); 327 store->results[i].size = 4; 328 } 329 } 330 331 map_textures(ctx, program); 332 333 for (i = 0; i < VB->Count; i++) { 334 GLuint attr; 335 336 init_machine(ctx, machine, tnl->CurInstance); 337 338#if 0 339 printf("Input %d: %f, %f, %f, %f\n", i, 340 VB->AttribPtr[0]->data[i][0], 341 VB->AttribPtr[0]->data[i][1], 342 VB->AttribPtr[0]->data[i][2], 343 VB->AttribPtr[0]->data[i][3]); 344 printf(" color: %f, %f, %f, %f\n", 345 VB->AttribPtr[3]->data[i][0], 346 VB->AttribPtr[3]->data[i][1], 347 VB->AttribPtr[3]->data[i][2], 348 VB->AttribPtr[3]->data[i][3]); 349 printf(" normal: %f, %f, %f, %f\n", 350 VB->AttribPtr[2]->data[i][0], 351 VB->AttribPtr[2]->data[i][1], 352 VB->AttribPtr[2]->data[i][2], 353 VB->AttribPtr[2]->data[i][3]); 354#endif 355 356 /* the vertex array case */ 357 for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { 358 if (program->Base.InputsRead & BITFIELD64_BIT(attr)) { 359 const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data; 360 const GLuint size = VB->AttribPtr[attr]->size; 361 const GLuint stride = VB->AttribPtr[attr]->stride; 362 const GLfloat *data = (GLfloat *) (ptr + stride * i); 363#ifdef NAN_CHECK 364 check_float(data[0]); 365 check_float(data[1]); 366 check_float(data[2]); 367 check_float(data[3]); 368#endif 369 COPY_CLEAN_4V(machine->VertAttribs[attr], size, data); 370 } 371 } 372 373 /* execute the program */ 374 _mesa_execute_program(ctx, &program->Base, machine); 375 376 /* copy the output registers into the VB->attribs arrays */ 377 for (j = 0; j < numOutputs; j++) { 378 const GLuint attr = outputs[j]; 379#ifdef NAN_CHECK 380 check_float(machine->Outputs[attr][0]); 381 check_float(machine->Outputs[attr][1]); 382 check_float(machine->Outputs[attr][2]); 383 check_float(machine->Outputs[attr][3]); 384#endif 385 COPY_4V(store->results[attr].data[i], machine->Outputs[attr]); 386 } 387 388 /* FOGC is a special case. Fragment shader expects (f,0,0,1) */ 389 if (program->Base.OutputsWritten & BITFIELD64_BIT(VARYING_SLOT_FOGC)) { 390 store->results[VARYING_SLOT_FOGC].data[i][1] = 0.0; 391 store->results[VARYING_SLOT_FOGC].data[i][2] = 0.0; 392 store->results[VARYING_SLOT_FOGC].data[i][3] = 1.0; 393 } 394#ifdef NAN_CHECK 395 ASSERT(machine->Outputs[0][3] != 0.0F); 396#endif 397#if 0 398 printf("HPOS: %f %f %f %f\n", 399 machine->Outputs[0][0], 400 machine->Outputs[0][1], 401 machine->Outputs[0][2], 402 machine->Outputs[0][3]); 403#endif 404 } 405 406 unmap_textures(ctx, program); 407 408 if (program->IsPositionInvariant) { 409 /* We need the exact same transform as in the fixed function path here 410 * to guarantee invariance, depending on compiler optimization flags 411 * results could be different otherwise. 412 */ 413 VB->ClipPtr = TransformRaw( &store->results[0], 414 &ctx->_ModelProjectMatrix, 415 VB->AttribPtr[0] ); 416 417 /* Drivers expect this to be clean to element 4... 418 */ 419 switch (VB->ClipPtr->size) { 420 case 1: 421 /* impossible */ 422 case 2: 423 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 ); 424 /* fall-through */ 425 case 3: 426 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 ); 427 /* fall-through */ 428 case 4: 429 break; 430 } 431 } 432 else { 433 /* Setup the VB pointers so that the next pipeline stages get 434 * their data from the right place (the program output arrays). 435 */ 436 VB->ClipPtr = &store->results[VARYING_SLOT_POS]; 437 VB->ClipPtr->size = 4; 438 VB->ClipPtr->count = VB->Count; 439 } 440 441 VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->results[VARYING_SLOT_COL0]; 442 VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->results[VARYING_SLOT_COL1]; 443 VB->AttribPtr[VERT_ATTRIB_FOG] = &store->results[VARYING_SLOT_FOGC]; 444 VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->results[VARYING_SLOT_PSIZ]; 445 VB->BackfaceColorPtr = &store->results[VARYING_SLOT_BFC0]; 446 VB->BackfaceSecondaryColorPtr = &store->results[VARYING_SLOT_BFC1]; 447 448 for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { 449 VB->AttribPtr[_TNL_ATTRIB_TEX0 + i] 450 = &store->results[VARYING_SLOT_TEX0 + i]; 451 } 452 453 for (i = 0; i < ctx->Const.MaxVarying; i++) { 454 if (program->Base.OutputsWritten & BITFIELD64_BIT(VARYING_SLOT_VAR0 + i)) { 455 /* Note: varying results get put into the generic attributes */ 456 VB->AttribPtr[VERT_ATTRIB_GENERIC0+i] 457 = &store->results[VARYING_SLOT_VAR0 + i]; 458 } 459 } 460 461 462 /* Perform NDC and cliptest operations: 463 */ 464 return do_ndc_cliptest(ctx, store); 465} 466 467 468/** 469 * Called the first time stage->run is called. In effect, don't 470 * allocate data until the first time the stage is run. 471 */ 472static GLboolean 473init_vp(struct gl_context *ctx, struct tnl_pipeline_stage *stage) 474{ 475 TNLcontext *tnl = TNL_CONTEXT(ctx); 476 struct vertex_buffer *VB = &(tnl->vb); 477 struct vp_stage_data *store; 478 const GLuint size = VB->Size; 479 480 stage->privatePtr = calloc(1, sizeof(*store)); 481 store = VP_STAGE_DATA(stage); 482 if (!store) 483 return GL_FALSE; 484 485 /* a few other misc allocations */ 486 _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 ); 487 store->clipmask = _mesa_align_malloc(sizeof(GLubyte)*size, 32 ); 488 489 return GL_TRUE; 490} 491 492 493/** 494 * Destructor for this pipeline stage. 495 */ 496static void 497dtr(struct tnl_pipeline_stage *stage) 498{ 499 struct vp_stage_data *store = VP_STAGE_DATA(stage); 500 501 if (store) { 502 GLuint i; 503 504 /* free the vertex program result arrays */ 505 for (i = 0; i < VARYING_SLOT_MAX; i++) 506 _mesa_vector4f_free( &store->results[i] ); 507 508 /* free misc arrays */ 509 _mesa_vector4f_free( &store->ndcCoords ); 510 _mesa_align_free( store->clipmask ); 511 512 free( store ); 513 stage->privatePtr = NULL; 514 } 515} 516 517 518static void 519validate_vp_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage) 520{ 521 if (ctx->VertexProgram._Current) { 522 _swrast_update_texture_samplers(ctx); 523 } 524} 525 526 527 528/** 529 * Public description of this pipeline stage. 530 */ 531const struct tnl_pipeline_stage _tnl_vertex_program_stage = 532{ 533 "vertex-program", 534 NULL, /* private_data */ 535 init_vp, /* create */ 536 dtr, /* destroy */ 537 validate_vp_stage, /* validate */ 538 run_vp /* run -- initially set to ctr */ 539}; 540