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/macros.h" 36#include "main/samplerobj.h" 37#include "main/state.h" 38#include "math/m_xform.h" 39#include "program/prog_instruction.h" 40#include "program/prog_statevars.h" 41#include "program/prog_execute.h" 42#include "swrast/s_context.h" 43#include "util/bitscan.h" 44#include "util/u_memory.h" 45 46#include "tnl/tnl.h" 47#include "tnl/t_context.h" 48#include "tnl/t_pipeline.h" 49 50 51#ifdef NAN_CHECK 52/** Check for NaNs and very large values */ 53static inline void 54check_float(float x) 55{ 56 assert(!util_is_inf_or_nan(x)); 57 assert(1.0e-15 <= x && x <= 1.0e15); 58} 59#endif 60 61 62/*! 63 * Private storage for the vertex program pipeline stage. 64 */ 65struct vp_stage_data { 66 /** The results of running the vertex program go into these arrays. */ 67 GLvector4f results[VARYING_SLOT_MAX]; 68 69 GLvector4f ndcCoords; /**< normalized device coords */ 70 GLubyte *clipmask; /**< clip flags */ 71 GLubyte ormask, andmask; /**< for clipping */ 72 73 GLboolean vertex_textures; 74 75 struct gl_program_machine machine; 76}; 77 78 79#define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr)) 80 81 82static void 83userclip( struct gl_context *ctx, 84 GLvector4f *clip, 85 GLubyte *clipmask, 86 GLubyte *clipormask, 87 GLubyte *clipandmask ) 88{ 89 GLbitfield mask = ctx->Transform.ClipPlanesEnabled; 90 while (mask) { 91 const int p = u_bit_scan(&mask); 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 126static GLboolean 127do_ndc_cliptest(struct gl_context *ctx, struct vp_stage_data *store) 128{ 129 TNLcontext *tnl = TNL_CONTEXT(ctx); 130 struct vertex_buffer *VB = &tnl->vb; 131 /* Cliptest and perspective divide. Clip functions must clear 132 * the clipmask. 133 */ 134 store->ormask = 0; 135 store->andmask = CLIP_FRUSTUM_BITS; 136 137 tnl_clip_prepare(ctx); 138 139 if (tnl->NeedNdcCoords) { 140 VB->NdcPtr = 141 _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr, 142 &store->ndcCoords, 143 store->clipmask, 144 &store->ormask, 145 &store->andmask, 146 !(ctx->Transform.DepthClampNear && 147 ctx->Transform.DepthClampFar) ); 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.DepthClampNear && 157 ctx->Transform.DepthClampFar) ); 158 } 159 160 if (store->andmask) { 161 /* All vertices are outside the frustum */ 162 return GL_FALSE; 163 } 164 165 /* Test userclip planes. This contributes to VB->ClipMask. 166 */ 167 /** XXX NEW_SLANG _Enabled ??? */ 168 if (ctx->Transform.ClipPlanesEnabled && 169 (!_mesa_arb_vertex_program_enabled(ctx) || 170 ctx->VertexProgram.Current->arb.IsPositionInvariant)) { 171 userclip( ctx, 172 VB->ClipPtr, 173 store->clipmask, 174 &store->ormask, 175 &store->andmask ); 176 177 if (store->andmask) { 178 return GL_FALSE; 179 } 180 } 181 182 VB->ClipAndMask = store->andmask; 183 VB->ClipOrMask = store->ormask; 184 VB->ClipMask = store->clipmask; 185 186 return GL_TRUE; 187} 188 189 190/** 191 * XXX the texture sampling code in this module is a bit of a hack. 192 * The texture sampling code is in swrast, though it doesn't have any 193 * real dependencies on the rest of swrast. It should probably be 194 * moved into main/ someday. 195 */ 196static void 197vp_fetch_texel(struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda, 198 GLuint unit, GLfloat color[4]) 199{ 200 SWcontext *swrast = SWRAST_CONTEXT(ctx); 201 202 /* XXX use a float-valued TextureSample routine here!!! */ 203 swrast->TextureSample[unit](ctx, _mesa_get_samplerobj(ctx, unit), 204 ctx->Texture.Unit[unit]._Current, 205 1, (const GLfloat (*)[4]) texcoord, 206 &lambda, (GLfloat (*)[4]) color); 207} 208 209 210/** 211 * Called via ctx->Driver.ProgramStringNotify() after a new vertex program 212 * string has been parsed. 213 */ 214GLboolean 215_tnl_program_string(struct gl_context *ctx, GLenum target, struct gl_program *program) 216{ 217 /* No-op. 218 * If we had derived anything from the program that was private to this 219 * stage we'd recompute/validate it here. 220 */ 221 return GL_TRUE; 222} 223 224 225/** 226 * Initialize virtual machine state prior to executing vertex program. 227 */ 228static void 229init_machine(struct gl_context *ctx, struct gl_program_machine *machine, 230 GLuint instID) 231{ 232 /* Input registers get initialized from the current vertex attribs */ 233 memcpy(machine->VertAttribs, ctx->Current.Attrib, 234 MAX_VERTEX_GENERIC_ATTRIBS * 4 * sizeof(GLfloat)); 235 236 machine->NumDeriv = 0; 237 238 /* init call stack */ 239 machine->StackDepth = 0; 240 241 machine->FetchTexelLod = vp_fetch_texel; 242 machine->FetchTexelDeriv = NULL; /* not used by vertex programs */ 243 244 machine->Samplers = ctx->VertexProgram._Current->SamplerUnits; 245 246 machine->SystemValues[SYSTEM_VALUE_INSTANCE_ID][0] = (GLfloat) instID; 247} 248 249 250/** 251 * Map the texture images which the vertex program will access (if any). 252 */ 253static void 254map_textures(struct gl_context *ctx, const struct gl_program *vp) 255{ 256 GLuint u; 257 258 for (u = 0; u < ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits; u++) { 259 if (vp->TexturesUsed[u]) { 260 /* Note: _Current *should* correspond to the target indicated 261 * in TexturesUsed[u]. 262 */ 263 _swrast_map_texture(ctx, ctx->Texture.Unit[u]._Current); 264 } 265 } 266} 267 268 269/** 270 * Unmap the texture images which were used by the vertex program (if any). 271 */ 272static void 273unmap_textures(struct gl_context *ctx, const struct gl_program *vp) 274{ 275 GLuint u; 276 277 for (u = 0; u < ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits; u++) { 278 if (vp->TexturesUsed[u]) { 279 /* Note: _Current *should* correspond to the target indicated 280 * in TexturesUsed[u]. 281 */ 282 _swrast_unmap_texture(ctx, ctx->Texture.Unit[u]._Current); 283 } 284 } 285} 286 287 288/** 289 * This function executes vertex programs 290 */ 291static GLboolean 292run_vp( struct gl_context *ctx, struct tnl_pipeline_stage *stage ) 293{ 294 TNLcontext *tnl = TNL_CONTEXT(ctx); 295 struct vp_stage_data *store = VP_STAGE_DATA(stage); 296 struct vertex_buffer *VB = &tnl->vb; 297 struct gl_program *program = ctx->VertexProgram._Current; 298 struct gl_program_machine *machine = &store->machine; 299 GLuint outputs[VARYING_SLOT_MAX], numOutputs; 300 GLuint i, j; 301 302 if (!program) 303 return GL_TRUE; 304 305 /* ARB program or vertex shader */ 306 _mesa_load_state_parameters(ctx, program->Parameters); 307 308 /* make list of outputs to save some time below */ 309 numOutputs = 0; 310 for (i = 0; i < VARYING_SLOT_MAX; i++) { 311 if (program->info.outputs_written & BITFIELD64_BIT(i)) { 312 outputs[numOutputs++] = i; 313 } 314 } 315 316 /* Allocate result vectors. We delay this until now to avoid allocating 317 * memory that would never be used if we don't run the software tnl pipeline. 318 */ 319 if (!store->results[0].storage) { 320 for (i = 0; i < VARYING_SLOT_MAX; i++) { 321 assert(!store->results[i].storage); 322 _mesa_vector4f_alloc( &store->results[i], 0, VB->Size, 32 ); 323 store->results[i].size = 4; 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, tnl->CurInstance); 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->info.inputs_read & BITFIELD64_BIT(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#ifdef NAN_CHECK 360 check_float(data[0]); 361 check_float(data[1]); 362 check_float(data[2]); 363 check_float(data[3]); 364#endif 365 COPY_CLEAN_4V(machine->VertAttribs[attr], size, data); 366 } 367 } 368 369 /* execute the program */ 370 _mesa_execute_program(ctx, program, machine); 371 372 /* copy the output registers into the VB->attribs arrays */ 373 for (j = 0; j < numOutputs; j++) { 374 const GLuint attr = outputs[j]; 375#ifdef NAN_CHECK 376 check_float(machine->Outputs[attr][0]); 377 check_float(machine->Outputs[attr][1]); 378 check_float(machine->Outputs[attr][2]); 379 check_float(machine->Outputs[attr][3]); 380#endif 381 COPY_4V(store->results[attr].data[i], machine->Outputs[attr]); 382 } 383 384 /* FOGC is a special case. Fragment shader expects (f,0,0,1) */ 385 if (program->info.outputs_written & BITFIELD64_BIT(VARYING_SLOT_FOGC)) { 386 store->results[VARYING_SLOT_FOGC].data[i][1] = 0.0; 387 store->results[VARYING_SLOT_FOGC].data[i][2] = 0.0; 388 store->results[VARYING_SLOT_FOGC].data[i][3] = 1.0; 389 } 390#ifdef NAN_CHECK 391 assert(machine->Outputs[0][3] != 0.0F); 392#endif 393#if 0 394 printf("HPOS: %f %f %f %f\n", 395 machine->Outputs[0][0], 396 machine->Outputs[0][1], 397 machine->Outputs[0][2], 398 machine->Outputs[0][3]); 399#endif 400 } 401 402 unmap_textures(ctx, program); 403 404 if (program->arb.IsPositionInvariant) { 405 /* make sure the inverse is up to date */ 406 _math_matrix_analyse(&ctx->_ModelProjectMatrix); 407 408 /* We need the exact same transform as in the fixed function path here 409 * to guarantee invariance, depending on compiler optimization flags 410 * results could be different otherwise. 411 */ 412 VB->ClipPtr = TransformRaw( &store->results[0], 413 &ctx->_ModelProjectMatrix, 414 VB->AttribPtr[0] ); 415 416 /* Drivers expect this to be clean to element 4... 417 */ 418 switch (VB->ClipPtr->size) { 419 case 1: 420 /* impossible */ 421 case 2: 422 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 ); 423 FALLTHROUGH; 424 case 3: 425 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 ); 426 FALLTHROUGH; 427 case 4: 428 break; 429 } 430 } 431 else { 432 /* Setup the VB pointers so that the next pipeline stages get 433 * their data from the right place (the program output arrays). 434 */ 435 VB->ClipPtr = &store->results[VARYING_SLOT_POS]; 436 VB->ClipPtr->size = 4; 437 VB->ClipPtr->count = VB->Count; 438 } 439 440 VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->results[VARYING_SLOT_COL0]; 441 VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->results[VARYING_SLOT_COL1]; 442 VB->AttribPtr[VERT_ATTRIB_FOG] = &store->results[VARYING_SLOT_FOGC]; 443 VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->results[VARYING_SLOT_PSIZ]; 444 VB->BackfaceColorPtr = &store->results[VARYING_SLOT_BFC0]; 445 VB->BackfaceSecondaryColorPtr = &store->results[VARYING_SLOT_BFC1]; 446 447 for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { 448 VB->AttribPtr[_TNL_ATTRIB_TEX0 + i] 449 = &store->results[VARYING_SLOT_TEX0 + i]; 450 } 451 452 for (i = 0; i < ctx->Const.MaxVarying; i++) { 453 if (program->info.outputs_written & 454 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 = 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 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