t_vb_program.c revision e382efc85d02ee5a0c582e1a9d9bc35ad262e70b
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.3 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 NVIDIA vertex programs. 29 * \author Brian Paul, Keith Whitwell 30 */ 31 32 33#include "glheader.h" 34#include "context.h" 35#include "macros.h" 36#include "imports.h" 37#include "prog_instruction.h" 38#include "prog_statevars.h" 39#include "prog_execute.h" 40 41#include "t_context.h" 42#include "t_pipeline.h" 43 44 45 46/*! 47 * Private storage for the vertex program pipeline stage. 48 */ 49struct vp_stage_data { 50 /** The results of running the vertex program go into these arrays. */ 51 GLvector4f attribs[VERT_RESULT_MAX]; 52 53 GLvector4f ndcCoords; /**< normalized device coords */ 54 GLubyte *clipmask; /**< clip flags */ 55 GLubyte ormask, andmask; /**< for clipping */ 56}; 57 58 59#define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr)) 60 61 62/** 63 * Initialize virtual machine state prior to executing vertex program. 64 */ 65static void 66init_machine(GLcontext *ctx, struct gl_program_machine *machine) 67{ 68 /* Input registers get initialized from the current vertex attribs */ 69 MEMCPY(machine->VertAttribs, ctx->Current.Attrib, 70 MAX_VERTEX_PROGRAM_ATTRIBS * 4 * sizeof(GLfloat)); 71 72 if (ctx->VertexProgram.Current->IsNVProgram) { 73 GLuint i; 74 /* Output/result regs are initialized to [0,0,0,1] */ 75 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_OUTPUTS; i++) { 76 ASSIGN_4V(machine->Outputs[i], 0.0F, 0.0F, 0.0F, 1.0F); 77 } 78 /* Temp regs are initialized to [0,0,0,0] */ 79 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_TEMPS; i++) { 80 ASSIGN_4V(machine->Temporaries[i], 0.0F, 0.0F, 0.0F, 0.0F); 81 } 82 for (i = 0; i < MAX_VERTEX_PROGRAM_ADDRESS_REGS; i++) { 83 ASSIGN_4V(machine->AddressReg[i], 0, 0, 0, 0); 84 } 85 } 86 87 /* init condition codes */ 88 machine->CondCodes[0] = COND_EQ; 89 machine->CondCodes[1] = COND_EQ; 90 machine->CondCodes[2] = COND_EQ; 91 machine->CondCodes[3] = COND_EQ; 92} 93 94 95/** 96 * Copy the 16 elements of a matrix into four consecutive program 97 * registers starting at 'pos'. 98 */ 99static void 100load_matrix(GLfloat registers[][4], GLuint pos, const GLfloat mat[16]) 101{ 102 GLuint i; 103 for (i = 0; i < 4; i++) { 104 registers[pos + i][0] = mat[0 + i]; 105 registers[pos + i][1] = mat[4 + i]; 106 registers[pos + i][2] = mat[8 + i]; 107 registers[pos + i][3] = mat[12 + i]; 108 } 109} 110 111 112/** 113 * As above, but transpose the matrix. 114 */ 115static void 116load_transpose_matrix(GLfloat registers[][4], GLuint pos, 117 const GLfloat mat[16]) 118{ 119 MEMCPY(registers[pos], mat, 16 * sizeof(GLfloat)); 120} 121 122 123/** 124 * Load program parameter registers with tracked matrices (if NV program). 125 * This only needs to be done per glBegin/glEnd, not per-vertex. 126 */ 127static void 128load_program_parameters(GLcontext *ctx) 129{ 130 GLuint i; 131 132 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) { 133 /* point 'mat' at source matrix */ 134 GLmatrix *mat; 135 if (ctx->VertexProgram.TrackMatrix[i] == GL_MODELVIEW) { 136 mat = ctx->ModelviewMatrixStack.Top; 137 } 138 else if (ctx->VertexProgram.TrackMatrix[i] == GL_PROJECTION) { 139 mat = ctx->ProjectionMatrixStack.Top; 140 } 141 else if (ctx->VertexProgram.TrackMatrix[i] == GL_TEXTURE) { 142 mat = ctx->TextureMatrixStack[ctx->Texture.CurrentUnit].Top; 143 } 144 else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) { 145 mat = ctx->ColorMatrixStack.Top; 146 } 147 else if (ctx->VertexProgram.TrackMatrix[i]==GL_MODELVIEW_PROJECTION_NV) { 148 /* XXX verify the combined matrix is up to date */ 149 mat = &ctx->_ModelProjectMatrix; 150 } 151 else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV && 152 ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) { 153 GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV; 154 ASSERT(n < MAX_PROGRAM_MATRICES); 155 mat = ctx->ProgramMatrixStack[n].Top; 156 } 157 else { 158 /* no matrix is tracked, but we leave the register values as-is */ 159 assert(ctx->VertexProgram.TrackMatrix[i] == GL_NONE); 160 continue; 161 } 162 163 /* load the matrix values into sequential registers */ 164 if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_IDENTITY_NV) { 165 load_matrix(ctx->VertexProgram.Parameters, i*4, mat->m); 166 } 167 else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_NV) { 168 _math_matrix_analyse(mat); /* update the inverse */ 169 ASSERT(!_math_matrix_is_dirty(mat)); 170 load_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv); 171 } 172 else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_TRANSPOSE_NV) { 173 load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->m); 174 } 175 else { 176 assert(ctx->VertexProgram.TrackMatrixTransform[i] 177 == GL_INVERSE_TRANSPOSE_NV); 178 _math_matrix_analyse(mat); /* update the inverse */ 179 ASSERT(!_math_matrix_is_dirty(mat)); 180 load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv); 181 } 182 } 183} 184 185 186/** 187 * This function executes vertex programs 188 */ 189static GLboolean 190run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage ) 191{ 192 TNLcontext *tnl = TNL_CONTEXT(ctx); 193 struct vp_stage_data *store = VP_STAGE_DATA(stage); 194 struct vertex_buffer *VB = &tnl->vb; 195 struct gl_vertex_program *program = ctx->VertexProgram._Current; 196 struct gl_program_machine machine; 197 GLuint i; 198 199#define FORCE_PROG_EXECUTE_C 0 200#if FORCE_PROG_EXECUTE_C 201 if (!program) 202 return GL_TRUE; 203#else 204 if (!program || !program->IsNVProgram) 205 return GL_TRUE; 206#endif 207 208 if (ctx->VertexProgram.Current->IsNVProgram) { 209 load_program_parameters(ctx); 210 } 211 else { 212 _mesa_load_state_parameters(ctx, program->Base.Parameters); 213 } 214 215 for (i = 0; i < VB->Count; i++) { 216 GLuint attr; 217 218 init_machine(ctx, &machine); 219 220#if 0 221 printf("Input %d: %f, %f, %f, %f\n", i, 222 VB->AttribPtr[0]->data[i][0], 223 VB->AttribPtr[0]->data[i][1], 224 VB->AttribPtr[0]->data[i][2], 225 VB->AttribPtr[0]->data[i][3]); 226 printf(" color: %f, %f, %f, %f\n", 227 VB->AttribPtr[3]->data[i][0], 228 VB->AttribPtr[3]->data[i][1], 229 VB->AttribPtr[3]->data[i][2], 230 VB->AttribPtr[3]->data[i][3]); 231 printf(" normal: %f, %f, %f, %f\n", 232 VB->AttribPtr[2]->data[i][0], 233 VB->AttribPtr[2]->data[i][1], 234 VB->AttribPtr[2]->data[i][2], 235 VB->AttribPtr[2]->data[i][3]); 236#endif 237 238 /* the vertex array case */ 239 for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { 240 if (program->Base.InputsRead & (1 << attr)) { 241 const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data; 242 const GLuint size = VB->AttribPtr[attr]->size; 243 const GLuint stride = VB->AttribPtr[attr]->stride; 244 const GLfloat *data = (GLfloat *) (ptr + stride * i); 245 COPY_CLEAN_4V(machine.VertAttribs/*Inputs*/[attr], size, data); 246 } 247 } 248 249 /* execute the program */ 250 _mesa_execute_program(ctx, &program->Base, program->Base.NumInstructions, 251 &machine, 0); 252 253 /* Fixup fog an point size results if needed */ 254 if (ctx->Fog.Enabled && 255 (program->Base.OutputsWritten & (1 << VERT_RESULT_FOGC)) == 0) { 256 machine.Outputs[VERT_RESULT_FOGC][0] = 1.0; 257 } 258 259 if (ctx->VertexProgram.PointSizeEnabled && 260 (program->Base.OutputsWritten & (1 << VERT_RESULT_PSIZ)) == 0) { 261 machine.Outputs[VERT_RESULT_PSIZ][0] = ctx->Point.Size; 262 } 263 264 /* copy the output registers into the VB->attribs arrays */ 265 /* XXX (optimize) could use a conditional and smaller loop limit here */ 266 for (attr = 0; attr < VERT_RESULT_MAX; attr++) { 267 COPY_4V(store->attribs[attr].data[i], machine.Outputs[attr]); 268 } 269#if 0 270 printf("HPOS: %f %f %f %f\n", 271 machine.Outputs[0][0], 272 machine.Outputs[0][1], 273 machine.Outputs[0][2], 274 machine.Outputs[0][3]); 275#endif 276 } 277 278 /* Setup the VB pointers so that the next pipeline stages get 279 * their data from the right place (the program output arrays). 280 */ 281 VB->ClipPtr = &store->attribs[VERT_RESULT_HPOS]; 282 VB->ClipPtr->size = 4; 283 VB->ClipPtr->count = VB->Count; 284 VB->ColorPtr[0] = &store->attribs[VERT_RESULT_COL0]; 285 VB->ColorPtr[1] = &store->attribs[VERT_RESULT_BFC0]; 286 VB->SecondaryColorPtr[0] = &store->attribs[VERT_RESULT_COL1]; 287 VB->SecondaryColorPtr[1] = &store->attribs[VERT_RESULT_BFC1]; 288 VB->FogCoordPtr = &store->attribs[VERT_RESULT_FOGC]; 289 290 VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->attribs[VERT_RESULT_COL0]; 291 VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->attribs[VERT_RESULT_COL1]; 292 VB->AttribPtr[VERT_ATTRIB_FOG] = &store->attribs[VERT_RESULT_FOGC]; 293 VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->attribs[VERT_RESULT_PSIZ]; 294 295 for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { 296 VB->TexCoordPtr[i] = 297 VB->AttribPtr[_TNL_ATTRIB_TEX0 + i] 298 = &store->attribs[VERT_RESULT_TEX0 + i]; 299 } 300 301 for (i = 0; i < ctx->Const.MaxVarying; i++) { 302 if (program->Base.OutputsWritten & (1 << (VERT_RESULT_VAR0 + i))) { 303 /* Note: varying results get put into the generic attributes */ 304 VB->AttribPtr[VERT_ATTRIB_GENERIC0+i] 305 = &store->attribs[VERT_RESULT_VAR0 + i]; 306 } 307 } 308 309 /* Cliptest and perspective divide. Clip functions must clear 310 * the clipmask. 311 */ 312 store->ormask = 0; 313 store->andmask = CLIP_FRUSTUM_BITS; 314 315 if (tnl->NeedNdcCoords) { 316 VB->NdcPtr = 317 _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr, 318 &store->ndcCoords, 319 store->clipmask, 320 &store->ormask, 321 &store->andmask ); 322 } 323 else { 324 VB->NdcPtr = NULL; 325 _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr, 326 NULL, 327 store->clipmask, 328 &store->ormask, 329 &store->andmask ); 330 } 331 332 if (store->andmask) /* All vertices are outside the frustum */ 333 return GL_FALSE; 334 335 336 /* This is where we'd do clip testing against the user-defined 337 * clipping planes, but they're not supported by vertex programs. 338 */ 339 340 VB->ClipOrMask = store->ormask; 341 VB->ClipMask = store->clipmask; 342 343 return GL_TRUE; 344} 345 346 347/** 348 * Called the first time stage->run is called. In effect, don't 349 * allocate data until the first time the stage is run. 350 */ 351static GLboolean init_vp( GLcontext *ctx, 352 struct tnl_pipeline_stage *stage ) 353{ 354 TNLcontext *tnl = TNL_CONTEXT(ctx); 355 struct vertex_buffer *VB = &(tnl->vb); 356 struct vp_stage_data *store; 357 const GLuint size = VB->Size; 358 GLuint i; 359 360 stage->privatePtr = MALLOC(sizeof(*store)); 361 store = VP_STAGE_DATA(stage); 362 if (!store) 363 return GL_FALSE; 364 365 /* Allocate arrays of vertex output values */ 366 for (i = 0; i < VERT_RESULT_MAX; i++) { 367 _mesa_vector4f_alloc( &store->attribs[i], 0, size, 32 ); 368 store->attribs[i].size = 4; 369 } 370 371 /* a few other misc allocations */ 372 _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 ); 373 store->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 ); 374 375 return GL_TRUE; 376} 377 378 379/** 380 * Destructor for this pipeline stage. 381 */ 382static void dtr( struct tnl_pipeline_stage *stage ) 383{ 384 struct vp_stage_data *store = VP_STAGE_DATA(stage); 385 386 if (store) { 387 GLuint i; 388 389 /* free the vertex program result arrays */ 390 for (i = 0; i < VERT_RESULT_MAX; i++) 391 _mesa_vector4f_free( &store->attribs[i] ); 392 393 /* free misc arrays */ 394 _mesa_vector4f_free( &store->ndcCoords ); 395 ALIGN_FREE( store->clipmask ); 396 397 FREE( store ); 398 stage->privatePtr = NULL; 399 } 400} 401 402 403/** 404 * Public description of this pipeline stage. 405 */ 406const struct tnl_pipeline_stage _tnl_vertex_program_stage = 407{ 408 "vertex-program", 409 NULL, /* private_data */ 410 init_vp, /* create */ 411 dtr, /* destroy */ 412 NULL, /* validate */ 413 run_vp /* run -- initially set to ctr */ 414}; 415