2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
27 * \file tnl/t_vb_program.c
28 * \brief Pipeline stage for executing NVIDIA vertex programs.
29 * \author Brian Paul, Keith Whitwell
37 #include "prog_instruction.h"
38 #include "prog_statevars.h"
39 #include "prog_execute.h"
42 #include "t_context.h"
43 #include "t_pipeline.h"
48 * Called via ctx->Driver.ProgramStringNotify() after a new vertex program
49 * string has been parsed.
52 _tnl_program_string(GLcontext
*ctx
, GLenum target
, struct gl_program
*program
)
55 * If we had derived anything from the program that was private to this
56 * stage we'd recompute/validate it here.
62 * Private storage for the vertex program pipeline stage.
64 struct vp_stage_data
{
65 /** The results of running the vertex program go into these arrays. */
66 GLvector4f results
[VERT_RESULT_MAX
];
68 GLvector4f ndcCoords
; /**< normalized device coords */
69 GLubyte
*clipmask
; /**< clip flags */
70 GLubyte ormask
, andmask
; /**< for clipping */
74 #define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr))
78 * Initialize virtual machine state prior to executing vertex program.
81 init_machine(GLcontext
*ctx
, struct gl_program_machine
*machine
)
83 /* Input registers get initialized from the current vertex attribs */
84 MEMCPY(machine
->VertAttribs
, ctx
->Current
.Attrib
,
85 MAX_VERTEX_PROGRAM_ATTRIBS
* 4 * sizeof(GLfloat
));
87 if (ctx
->VertexProgram
._Current
->IsNVProgram
) {
89 /* Output/result regs are initialized to [0,0,0,1] */
90 for (i
= 0; i
< MAX_NV_VERTEX_PROGRAM_OUTPUTS
; i
++) {
91 ASSIGN_4V(machine
->Outputs
[i
], 0.0F
, 0.0F
, 0.0F
, 1.0F
);
93 /* Temp regs are initialized to [0,0,0,0] */
94 for (i
= 0; i
< MAX_NV_VERTEX_PROGRAM_TEMPS
; i
++) {
95 ASSIGN_4V(machine
->Temporaries
[i
], 0.0F
, 0.0F
, 0.0F
, 0.0F
);
97 for (i
= 0; i
< MAX_VERTEX_PROGRAM_ADDRESS_REGS
; i
++) {
98 ASSIGN_4V(machine
->AddressReg
[i
], 0, 0, 0, 0);
102 /* init condition codes */
103 machine
->CondCodes
[0] = COND_EQ
;
104 machine
->CondCodes
[1] = COND_EQ
;
105 machine
->CondCodes
[2] = COND_EQ
;
106 machine
->CondCodes
[3] = COND_EQ
;
108 /* init call stack */
109 machine
->StackDepth
= 0;
114 * Copy the 16 elements of a matrix into four consecutive program
115 * registers starting at 'pos'.
118 load_matrix(GLfloat registers
[][4], GLuint pos
, const GLfloat mat
[16])
121 for (i
= 0; i
< 4; i
++) {
122 registers
[pos
+ i
][0] = mat
[0 + i
];
123 registers
[pos
+ i
][1] = mat
[4 + i
];
124 registers
[pos
+ i
][2] = mat
[8 + i
];
125 registers
[pos
+ i
][3] = mat
[12 + i
];
131 * As above, but transpose the matrix.
134 load_transpose_matrix(GLfloat registers
[][4], GLuint pos
,
135 const GLfloat mat
[16])
137 MEMCPY(registers
[pos
], mat
, 16 * sizeof(GLfloat
));
142 * Load current vertex program's parameter registers with tracked
143 * matrices (if NV program). This only needs to be done per
144 * glBegin/glEnd, not per-vertex.
147 _mesa_load_tracked_matrices(GLcontext
*ctx
)
151 for (i
= 0; i
< MAX_NV_VERTEX_PROGRAM_PARAMS
/ 4; i
++) {
152 /* point 'mat' at source matrix */
154 if (ctx
->VertexProgram
.TrackMatrix
[i
] == GL_MODELVIEW
) {
155 mat
= ctx
->ModelviewMatrixStack
.Top
;
157 else if (ctx
->VertexProgram
.TrackMatrix
[i
] == GL_PROJECTION
) {
158 mat
= ctx
->ProjectionMatrixStack
.Top
;
160 else if (ctx
->VertexProgram
.TrackMatrix
[i
] == GL_TEXTURE
) {
161 mat
= ctx
->TextureMatrixStack
[ctx
->Texture
.CurrentUnit
].Top
;
163 else if (ctx
->VertexProgram
.TrackMatrix
[i
] == GL_COLOR
) {
164 mat
= ctx
->ColorMatrixStack
.Top
;
166 else if (ctx
->VertexProgram
.TrackMatrix
[i
]==GL_MODELVIEW_PROJECTION_NV
) {
167 /* XXX verify the combined matrix is up to date */
168 mat
= &ctx
->_ModelProjectMatrix
;
170 else if (ctx
->VertexProgram
.TrackMatrix
[i
] >= GL_MATRIX0_NV
&&
171 ctx
->VertexProgram
.TrackMatrix
[i
] <= GL_MATRIX7_NV
) {
172 GLuint n
= ctx
->VertexProgram
.TrackMatrix
[i
] - GL_MATRIX0_NV
;
173 ASSERT(n
< MAX_PROGRAM_MATRICES
);
174 mat
= ctx
->ProgramMatrixStack
[n
].Top
;
177 /* no matrix is tracked, but we leave the register values as-is */
178 assert(ctx
->VertexProgram
.TrackMatrix
[i
] == GL_NONE
);
182 /* load the matrix values into sequential registers */
183 if (ctx
->VertexProgram
.TrackMatrixTransform
[i
] == GL_IDENTITY_NV
) {
184 load_matrix(ctx
->VertexProgram
.Parameters
, i
*4, mat
->m
);
186 else if (ctx
->VertexProgram
.TrackMatrixTransform
[i
] == GL_INVERSE_NV
) {
187 _math_matrix_analyse(mat
); /* update the inverse */
188 ASSERT(!_math_matrix_is_dirty(mat
));
189 load_matrix(ctx
->VertexProgram
.Parameters
, i
*4, mat
->inv
);
191 else if (ctx
->VertexProgram
.TrackMatrixTransform
[i
] == GL_TRANSPOSE_NV
) {
192 load_transpose_matrix(ctx
->VertexProgram
.Parameters
, i
*4, mat
->m
);
195 assert(ctx
->VertexProgram
.TrackMatrixTransform
[i
]
196 == GL_INVERSE_TRANSPOSE_NV
);
197 _math_matrix_analyse(mat
); /* update the inverse */
198 ASSERT(!_math_matrix_is_dirty(mat
));
199 load_transpose_matrix(ctx
->VertexProgram
.Parameters
, i
*4, mat
->inv
);
206 * This function executes vertex programs
209 run_vp( GLcontext
*ctx
, struct tnl_pipeline_stage
*stage
)
211 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
212 struct vp_stage_data
*store
= VP_STAGE_DATA(stage
);
213 struct vertex_buffer
*VB
= &tnl
->vb
;
214 struct gl_vertex_program
*program
= ctx
->VertexProgram
._Current
;
215 struct gl_program_machine machine
;
216 GLuint outputs
[VERT_RESULT_MAX
], numOutputs
;
219 #define FORCE_PROG_EXECUTE_C 1
220 #if FORCE_PROG_EXECUTE_C
224 if (!program
|| !program
->IsNVProgram
)
228 if (program
->IsNVProgram
) {
229 _mesa_load_tracked_matrices(ctx
);
232 _mesa_load_state_parameters(ctx
, program
->Base
.Parameters
);
236 for (i
= 0; i
< VERT_RESULT_MAX
; i
++) {
237 if (program
->Base
.OutputsWritten
& (1 << i
)) {
238 outputs
[numOutputs
++] = i
;
242 for (i
= 0; i
< VB
->Count
; i
++) {
245 init_machine(ctx
, &machine
);
248 printf("Input %d: %f, %f, %f, %f\n", i
,
249 VB
->AttribPtr
[0]->data
[i
][0],
250 VB
->AttribPtr
[0]->data
[i
][1],
251 VB
->AttribPtr
[0]->data
[i
][2],
252 VB
->AttribPtr
[0]->data
[i
][3]);
253 printf(" color: %f, %f, %f, %f\n",
254 VB
->AttribPtr
[3]->data
[i
][0],
255 VB
->AttribPtr
[3]->data
[i
][1],
256 VB
->AttribPtr
[3]->data
[i
][2],
257 VB
->AttribPtr
[3]->data
[i
][3]);
258 printf(" normal: %f, %f, %f, %f\n",
259 VB
->AttribPtr
[2]->data
[i
][0],
260 VB
->AttribPtr
[2]->data
[i
][1],
261 VB
->AttribPtr
[2]->data
[i
][2],
262 VB
->AttribPtr
[2]->data
[i
][3]);
265 /* the vertex array case */
266 for (attr
= 0; attr
< VERT_ATTRIB_MAX
; attr
++) {
267 if (program
->Base
.InputsRead
& (1 << attr
)) {
268 const GLubyte
*ptr
= (const GLubyte
*) VB
->AttribPtr
[attr
]->data
;
269 const GLuint size
= VB
->AttribPtr
[attr
]->size
;
270 const GLuint stride
= VB
->AttribPtr
[attr
]->stride
;
271 const GLfloat
*data
= (GLfloat
*) (ptr
+ stride
* i
);
272 COPY_CLEAN_4V(machine
.VertAttribs
[attr
], size
, data
);
276 /* execute the program */
277 _mesa_execute_program(ctx
, &program
->Base
, &machine
);
279 /* copy the output registers into the VB->attribs arrays */
280 for (j
= 0; j
< numOutputs
; j
++) {
281 const GLuint attr
= outputs
[j
];
282 COPY_4V(store
->results
[attr
].data
[i
], machine
.Outputs
[attr
]);
285 printf("HPOS: %f %f %f %f\n",
286 machine
.Outputs
[0][0],
287 machine
.Outputs
[0][1],
288 machine
.Outputs
[0][2],
289 machine
.Outputs
[0][3]);
293 /* Fixup fog and point size results if needed */
294 if (program
->IsNVProgram
) {
295 if (ctx
->Fog
.Enabled
&&
296 (program
->Base
.OutputsWritten
& (1 << VERT_RESULT_FOGC
)) == 0) {
297 for (i
= 0; i
< VB
->Count
; i
++) {
298 store
->results
[VERT_RESULT_FOGC
].data
[i
][0] = 1.0;
302 if (ctx
->VertexProgram
.PointSizeEnabled
&&
303 (program
->Base
.OutputsWritten
& (1 << VERT_RESULT_PSIZ
)) == 0) {
304 for (i
= 0; i
< VB
->Count
; i
++) {
305 store
->results
[VERT_RESULT_PSIZ
].data
[i
][0] = ctx
->Point
.Size
;
310 /* Setup the VB pointers so that the next pipeline stages get
311 * their data from the right place (the program output arrays).
313 VB
->ClipPtr
= &store
->results
[VERT_RESULT_HPOS
];
314 VB
->ClipPtr
->size
= 4;
315 VB
->ClipPtr
->count
= VB
->Count
;
316 VB
->ColorPtr
[0] = &store
->results
[VERT_RESULT_COL0
];
317 VB
->ColorPtr
[1] = &store
->results
[VERT_RESULT_BFC0
];
318 VB
->SecondaryColorPtr
[0] = &store
->results
[VERT_RESULT_COL1
];
319 VB
->SecondaryColorPtr
[1] = &store
->results
[VERT_RESULT_BFC1
];
320 VB
->FogCoordPtr
= &store
->results
[VERT_RESULT_FOGC
];
322 VB
->AttribPtr
[VERT_ATTRIB_COLOR0
] = &store
->results
[VERT_RESULT_COL0
];
323 VB
->AttribPtr
[VERT_ATTRIB_COLOR1
] = &store
->results
[VERT_RESULT_COL1
];
324 VB
->AttribPtr
[VERT_ATTRIB_FOG
] = &store
->results
[VERT_RESULT_FOGC
];
325 VB
->AttribPtr
[_TNL_ATTRIB_POINTSIZE
] = &store
->results
[VERT_RESULT_PSIZ
];
327 for (i
= 0; i
< ctx
->Const
.MaxTextureCoordUnits
; i
++) {
329 VB
->AttribPtr
[_TNL_ATTRIB_TEX0
+ i
]
330 = &store
->results
[VERT_RESULT_TEX0
+ i
];
333 for (i
= 0; i
< ctx
->Const
.MaxVarying
; i
++) {
334 if (program
->Base
.OutputsWritten
& (1 << (VERT_RESULT_VAR0
+ i
))) {
335 /* Note: varying results get put into the generic attributes */
336 VB
->AttribPtr
[VERT_ATTRIB_GENERIC0
+i
]
337 = &store
->results
[VERT_RESULT_VAR0
+ i
];
341 /* Cliptest and perspective divide. Clip functions must clear
345 store
->andmask
= CLIP_FRUSTUM_BITS
;
347 if (tnl
->NeedNdcCoords
) {
349 _mesa_clip_tab
[VB
->ClipPtr
->size
]( VB
->ClipPtr
,
357 _mesa_clip_np_tab
[VB
->ClipPtr
->size
]( VB
->ClipPtr
,
364 if (store
->andmask
) /* All vertices are outside the frustum */
368 /* This is where we'd do clip testing against the user-defined
369 * clipping planes, but they're not supported by vertex programs.
372 VB
->ClipOrMask
= store
->ormask
;
373 VB
->ClipMask
= store
->clipmask
;
380 * Called the first time stage->run is called. In effect, don't
381 * allocate data until the first time the stage is run.
383 static GLboolean
init_vp( GLcontext
*ctx
,
384 struct tnl_pipeline_stage
*stage
)
386 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
387 struct vertex_buffer
*VB
= &(tnl
->vb
);
388 struct vp_stage_data
*store
;
389 const GLuint size
= VB
->Size
;
392 stage
->privatePtr
= MALLOC(sizeof(*store
));
393 store
= VP_STAGE_DATA(stage
);
397 /* Allocate arrays of vertex output values */
398 for (i
= 0; i
< VERT_RESULT_MAX
; i
++) {
399 _mesa_vector4f_alloc( &store
->results
[i
], 0, size
, 32 );
400 store
->results
[i
].size
= 4;
403 /* a few other misc allocations */
404 _mesa_vector4f_alloc( &store
->ndcCoords
, 0, size
, 32 );
405 store
->clipmask
= (GLubyte
*) ALIGN_MALLOC(sizeof(GLubyte
)*size
, 32 );
412 * Destructor for this pipeline stage.
414 static void dtr( struct tnl_pipeline_stage
*stage
)
416 struct vp_stage_data
*store
= VP_STAGE_DATA(stage
);
421 /* free the vertex program result arrays */
422 for (i
= 0; i
< VERT_RESULT_MAX
; i
++)
423 _mesa_vector4f_free( &store
->results
[i
] );
425 /* free misc arrays */
426 _mesa_vector4f_free( &store
->ndcCoords
);
427 ALIGN_FREE( store
->clipmask
);
430 stage
->privatePtr
= NULL
;
436 * Public description of this pipeline stage.
438 const struct tnl_pipeline_stage _tnl_vertex_program_stage
=
441 NULL
, /* private_data */
442 init_vp
, /* create */
445 run_vp
/* run -- initially set to ctr */