mesa: Prefix main includes with dir to avoid conflicts.
[mesa.git] / src / mesa / tnl / t_vb_program.c
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 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.h"
45 #include "t_context.h"
46 #include "t_pipeline.h"
47
48
49 /**
50 * XXX the texture sampling code in this module is a bit of a hack.
51 * The texture sampling code is in swrast, though it doesn't have any
52 * real dependencies on the rest of swrast. It should probably be
53 * moved into main/ someday.
54 */
55
56 static void
57 vp_fetch_texel(GLcontext *ctx, const GLfloat texcoord[4], GLfloat lambda,
58 GLuint unit, GLfloat color[4])
59 {
60 GLchan rgba[4];
61 SWcontext *swrast = SWRAST_CONTEXT(ctx);
62
63 /* XXX use a float-valued TextureSample routine here!!! */
64 swrast->TextureSample[unit](ctx, ctx->Texture.Unit[unit]._Current,
65 1, (const GLfloat (*)[4]) texcoord,
66 &lambda, &rgba);
67 color[0] = CHAN_TO_FLOAT(rgba[0]);
68 color[1] = CHAN_TO_FLOAT(rgba[1]);
69 color[2] = CHAN_TO_FLOAT(rgba[2]);
70 color[3] = CHAN_TO_FLOAT(rgba[3]);
71 }
72
73
74 /**
75 * Called via ctx->Driver.ProgramStringNotify() after a new vertex program
76 * string has been parsed.
77 */
78 void
79 _tnl_program_string(GLcontext *ctx, GLenum target, struct gl_program *program)
80 {
81 /* No-op.
82 * If we had derived anything from the program that was private to this
83 * stage we'd recompute/validate it here.
84 */
85 }
86
87
88 /*!
89 * Private storage for the vertex program pipeline stage.
90 */
91 struct vp_stage_data {
92 /** The results of running the vertex program go into these arrays. */
93 GLvector4f results[VERT_RESULT_MAX];
94
95 GLvector4f ndcCoords; /**< normalized device coords */
96 GLubyte *clipmask; /**< clip flags */
97 GLubyte ormask, andmask; /**< for clipping */
98 };
99
100
101 #define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr))
102
103
104 /**
105 * Initialize virtual machine state prior to executing vertex program.
106 */
107 static void
108 init_machine(GLcontext *ctx, struct gl_program_machine *machine)
109 {
110 /* Input registers get initialized from the current vertex attribs */
111 MEMCPY(machine->VertAttribs, ctx->Current.Attrib,
112 MAX_VERTEX_PROGRAM_ATTRIBS * 4 * sizeof(GLfloat));
113
114 if (ctx->VertexProgram._Current->IsNVProgram) {
115 GLuint i;
116 /* Output/result regs are initialized to [0,0,0,1] */
117 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_OUTPUTS; i++) {
118 ASSIGN_4V(machine->Outputs[i], 0.0F, 0.0F, 0.0F, 1.0F);
119 }
120 /* Temp regs are initialized to [0,0,0,0] */
121 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_TEMPS; i++) {
122 ASSIGN_4V(machine->Temporaries[i], 0.0F, 0.0F, 0.0F, 0.0F);
123 }
124 for (i = 0; i < MAX_VERTEX_PROGRAM_ADDRESS_REGS; i++) {
125 ASSIGN_4V(machine->AddressReg[i], 0, 0, 0, 0);
126 }
127 }
128
129 machine->NumDeriv = 0;
130
131 /* init condition codes */
132 machine->CondCodes[0] = COND_EQ;
133 machine->CondCodes[1] = COND_EQ;
134 machine->CondCodes[2] = COND_EQ;
135 machine->CondCodes[3] = COND_EQ;
136
137 /* init call stack */
138 machine->StackDepth = 0;
139
140 machine->FetchTexelLod = vp_fetch_texel;
141 machine->FetchTexelDeriv = NULL; /* not used by vertex programs */
142 }
143
144
145 /**
146 * Copy the 16 elements of a matrix into four consecutive program
147 * registers starting at 'pos'.
148 */
149 static void
150 load_matrix(GLfloat registers[][4], GLuint pos, const GLfloat mat[16])
151 {
152 GLuint i;
153 for (i = 0; i < 4; i++) {
154 registers[pos + i][0] = mat[0 + i];
155 registers[pos + i][1] = mat[4 + i];
156 registers[pos + i][2] = mat[8 + i];
157 registers[pos + i][3] = mat[12 + i];
158 }
159 }
160
161
162 /**
163 * As above, but transpose the matrix.
164 */
165 static void
166 load_transpose_matrix(GLfloat registers[][4], GLuint pos,
167 const GLfloat mat[16])
168 {
169 MEMCPY(registers[pos], mat, 16 * sizeof(GLfloat));
170 }
171
172
173 /**
174 * Load current vertex program's parameter registers with tracked
175 * matrices (if NV program). This only needs to be done per
176 * glBegin/glEnd, not per-vertex.
177 */
178 void
179 _mesa_load_tracked_matrices(GLcontext *ctx)
180 {
181 GLuint i;
182
183 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
184 /* point 'mat' at source matrix */
185 GLmatrix *mat;
186 if (ctx->VertexProgram.TrackMatrix[i] == GL_MODELVIEW) {
187 mat = ctx->ModelviewMatrixStack.Top;
188 }
189 else if (ctx->VertexProgram.TrackMatrix[i] == GL_PROJECTION) {
190 mat = ctx->ProjectionMatrixStack.Top;
191 }
192 else if (ctx->VertexProgram.TrackMatrix[i] == GL_TEXTURE) {
193 mat = ctx->TextureMatrixStack[ctx->Texture.CurrentUnit].Top;
194 }
195 else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) {
196 mat = ctx->ColorMatrixStack.Top;
197 }
198 else if (ctx->VertexProgram.TrackMatrix[i]==GL_MODELVIEW_PROJECTION_NV) {
199 /* XXX verify the combined matrix is up to date */
200 mat = &ctx->_ModelProjectMatrix;
201 }
202 else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV &&
203 ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) {
204 GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV;
205 ASSERT(n < MAX_PROGRAM_MATRICES);
206 mat = ctx->ProgramMatrixStack[n].Top;
207 }
208 else {
209 /* no matrix is tracked, but we leave the register values as-is */
210 assert(ctx->VertexProgram.TrackMatrix[i] == GL_NONE);
211 continue;
212 }
213
214 /* load the matrix values into sequential registers */
215 if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_IDENTITY_NV) {
216 load_matrix(ctx->VertexProgram.Parameters, i*4, mat->m);
217 }
218 else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_NV) {
219 _math_matrix_analyse(mat); /* update the inverse */
220 ASSERT(!_math_matrix_is_dirty(mat));
221 load_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv);
222 }
223 else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_TRANSPOSE_NV) {
224 load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->m);
225 }
226 else {
227 assert(ctx->VertexProgram.TrackMatrixTransform[i]
228 == GL_INVERSE_TRANSPOSE_NV);
229 _math_matrix_analyse(mat); /* update the inverse */
230 ASSERT(!_math_matrix_is_dirty(mat));
231 load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv);
232 }
233 }
234 }
235
236
237 /**
238 * This function executes vertex programs
239 */
240 static GLboolean
241 run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
242 {
243 TNLcontext *tnl = TNL_CONTEXT(ctx);
244 struct vp_stage_data *store = VP_STAGE_DATA(stage);
245 struct vertex_buffer *VB = &tnl->vb;
246 struct gl_vertex_program *program = ctx->VertexProgram._Current;
247 struct gl_program_machine machine;
248 GLuint outputs[VERT_RESULT_MAX], numOutputs;
249 GLuint i, j;
250
251 if (!program)
252 return GL_TRUE;
253
254 if (program->IsNVProgram) {
255 _mesa_load_tracked_matrices(ctx);
256 }
257 else {
258 /* ARB program or vertex shader */
259 _mesa_load_state_parameters(ctx, program->Base.Parameters);
260 }
261
262 numOutputs = 0;
263 for (i = 0; i < VERT_RESULT_MAX; i++) {
264 if (program->Base.OutputsWritten & (1 << i)) {
265 outputs[numOutputs++] = i;
266 }
267 }
268
269 for (i = 0; i < VB->Count; i++) {
270 GLuint attr;
271
272 init_machine(ctx, &machine);
273
274 #if 0
275 printf("Input %d: %f, %f, %f, %f\n", i,
276 VB->AttribPtr[0]->data[i][0],
277 VB->AttribPtr[0]->data[i][1],
278 VB->AttribPtr[0]->data[i][2],
279 VB->AttribPtr[0]->data[i][3]);
280 printf(" color: %f, %f, %f, %f\n",
281 VB->AttribPtr[3]->data[i][0],
282 VB->AttribPtr[3]->data[i][1],
283 VB->AttribPtr[3]->data[i][2],
284 VB->AttribPtr[3]->data[i][3]);
285 printf(" normal: %f, %f, %f, %f\n",
286 VB->AttribPtr[2]->data[i][0],
287 VB->AttribPtr[2]->data[i][1],
288 VB->AttribPtr[2]->data[i][2],
289 VB->AttribPtr[2]->data[i][3]);
290 #endif
291
292 /* the vertex array case */
293 for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
294 if (program->Base.InputsRead & (1 << attr)) {
295 const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data;
296 const GLuint size = VB->AttribPtr[attr]->size;
297 const GLuint stride = VB->AttribPtr[attr]->stride;
298 const GLfloat *data = (GLfloat *) (ptr + stride * i);
299 COPY_CLEAN_4V(machine.VertAttribs[attr], size, data);
300 }
301 }
302
303 /* execute the program */
304 _mesa_execute_program(ctx, &program->Base, &machine);
305
306 /* copy the output registers into the VB->attribs arrays */
307 for (j = 0; j < numOutputs; j++) {
308 const GLuint attr = outputs[j];
309 COPY_4V(store->results[attr].data[i], machine.Outputs[attr]);
310 }
311 #if 0
312 printf("HPOS: %f %f %f %f\n",
313 machine.Outputs[0][0],
314 machine.Outputs[0][1],
315 machine.Outputs[0][2],
316 machine.Outputs[0][3]);
317 #endif
318 }
319
320 /* Fixup fog and point size results if needed */
321 if (program->IsNVProgram) {
322 if (ctx->Fog.Enabled &&
323 (program->Base.OutputsWritten & (1 << VERT_RESULT_FOGC)) == 0) {
324 for (i = 0; i < VB->Count; i++) {
325 store->results[VERT_RESULT_FOGC].data[i][0] = 1.0;
326 }
327 }
328
329 if (ctx->VertexProgram.PointSizeEnabled &&
330 (program->Base.OutputsWritten & (1 << VERT_RESULT_PSIZ)) == 0) {
331 for (i = 0; i < VB->Count; i++) {
332 store->results[VERT_RESULT_PSIZ].data[i][0] = ctx->Point.Size;
333 }
334 }
335 }
336
337 /* Setup the VB pointers so that the next pipeline stages get
338 * their data from the right place (the program output arrays).
339 */
340 VB->ClipPtr = &store->results[VERT_RESULT_HPOS];
341 VB->ClipPtr->size = 4;
342 VB->ClipPtr->count = VB->Count;
343 VB->ColorPtr[0] = &store->results[VERT_RESULT_COL0];
344 VB->ColorPtr[1] = &store->results[VERT_RESULT_BFC0];
345 VB->SecondaryColorPtr[0] = &store->results[VERT_RESULT_COL1];
346 VB->SecondaryColorPtr[1] = &store->results[VERT_RESULT_BFC1];
347 VB->FogCoordPtr = &store->results[VERT_RESULT_FOGC];
348
349 VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->results[VERT_RESULT_COL0];
350 VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->results[VERT_RESULT_COL1];
351 VB->AttribPtr[VERT_ATTRIB_FOG] = &store->results[VERT_RESULT_FOGC];
352 VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->results[VERT_RESULT_PSIZ];
353
354 for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
355 VB->TexCoordPtr[i] =
356 VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]
357 = &store->results[VERT_RESULT_TEX0 + i];
358 }
359
360 for (i = 0; i < ctx->Const.MaxVarying; i++) {
361 if (program->Base.OutputsWritten & (1 << (VERT_RESULT_VAR0 + i))) {
362 /* Note: varying results get put into the generic attributes */
363 VB->AttribPtr[VERT_ATTRIB_GENERIC0+i]
364 = &store->results[VERT_RESULT_VAR0 + i];
365 }
366 }
367
368 /* Cliptest and perspective divide. Clip functions must clear
369 * the clipmask.
370 */
371 store->ormask = 0;
372 store->andmask = CLIP_FRUSTUM_BITS;
373
374 if (tnl->NeedNdcCoords) {
375 VB->NdcPtr =
376 _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
377 &store->ndcCoords,
378 store->clipmask,
379 &store->ormask,
380 &store->andmask );
381 }
382 else {
383 VB->NdcPtr = NULL;
384 _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
385 NULL,
386 store->clipmask,
387 &store->ormask,
388 &store->andmask );
389 }
390
391 if (store->andmask) /* All vertices are outside the frustum */
392 return GL_FALSE;
393
394
395 /* This is where we'd do clip testing against the user-defined
396 * clipping planes, but they're not supported by vertex programs.
397 */
398
399 VB->ClipOrMask = store->ormask;
400 VB->ClipMask = store->clipmask;
401
402 return GL_TRUE;
403 }
404
405
406 /**
407 * Called the first time stage->run is called. In effect, don't
408 * allocate data until the first time the stage is run.
409 */
410 static GLboolean
411 init_vp(GLcontext *ctx, struct tnl_pipeline_stage *stage)
412 {
413 TNLcontext *tnl = TNL_CONTEXT(ctx);
414 struct vertex_buffer *VB = &(tnl->vb);
415 struct vp_stage_data *store;
416 const GLuint size = VB->Size;
417 GLuint i;
418
419 stage->privatePtr = MALLOC(sizeof(*store));
420 store = VP_STAGE_DATA(stage);
421 if (!store)
422 return GL_FALSE;
423
424 /* Allocate arrays of vertex output values */
425 for (i = 0; i < VERT_RESULT_MAX; i++) {
426 _mesa_vector4f_alloc( &store->results[i], 0, size, 32 );
427 store->results[i].size = 4;
428 }
429
430 /* a few other misc allocations */
431 _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 );
432 store->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
433
434 return GL_TRUE;
435 }
436
437
438 /**
439 * Destructor for this pipeline stage.
440 */
441 static void
442 dtr(struct tnl_pipeline_stage *stage)
443 {
444 struct vp_stage_data *store = VP_STAGE_DATA(stage);
445
446 if (store) {
447 GLuint i;
448
449 /* free the vertex program result arrays */
450 for (i = 0; i < VERT_RESULT_MAX; i++)
451 _mesa_vector4f_free( &store->results[i] );
452
453 /* free misc arrays */
454 _mesa_vector4f_free( &store->ndcCoords );
455 ALIGN_FREE( store->clipmask );
456
457 FREE( store );
458 stage->privatePtr = NULL;
459 }
460 }
461
462
463 static void
464 validate_vp_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
465 {
466 if (ctx->VertexProgram._Current) {
467 _swrast_update_texture_samplers(ctx);
468 }
469 }
470
471
472
473 /**
474 * Public description of this pipeline stage.
475 */
476 const struct tnl_pipeline_stage _tnl_vertex_program_stage =
477 {
478 "vertex-program",
479 NULL, /* private_data */
480 init_vp, /* create */
481 dtr, /* destroy */
482 validate_vp_stage, /* validate */
483 run_vp /* run -- initially set to ctr */
484 };