Merge branch 'mesa_7_5_branch'
[mesa.git] / src / mesa / tnl / t_vb_program.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.6
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR 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/context.h"
37 #include "main/macros.h"
38 #include "main/imports.h"
39 #include "shader/prog_instruction.h"
40 #include "shader/prog_statevars.h"
41 #include "shader/prog_execute.h"
42 #include "swrast/s_context.h"
43 #include "swrast/s_texfilter.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 */
52 static INLINE void
53 check_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 */
64 struct vp_stage_data {
65 /** The results of running the vertex program go into these arrays. */
66 GLvector4f results[VERT_RESULT_MAX];
67
68 GLvector4f ndcCoords; /**< normalized device coords */
69 GLubyte *clipmask; /**< clip flags */
70 GLubyte ormask, andmask; /**< for clipping */
71 };
72
73
74 #define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr))
75
76
77 static void
78 userclip( GLcontext *ctx,
79 GLvector4f *clip,
80 GLubyte *clipmask,
81 GLubyte *clipormask,
82 GLubyte *clipandmask )
83 {
84 GLuint p;
85
86 for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
87 if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
88 GLuint nr, i;
89 const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
90 const GLfloat b = ctx->Transform._ClipUserPlane[p][1];
91 const GLfloat c = ctx->Transform._ClipUserPlane[p][2];
92 const GLfloat d = ctx->Transform._ClipUserPlane[p][3];
93 GLfloat *coord = (GLfloat *)clip->data;
94 GLuint stride = clip->stride;
95 GLuint count = clip->count;
96
97 for (nr = 0, i = 0 ; i < count ; i++) {
98 GLfloat dp = (coord[0] * a +
99 coord[1] * b +
100 coord[2] * c +
101 coord[3] * d);
102
103 if (dp < 0) {
104 nr++;
105 clipmask[i] |= CLIP_USER_BIT;
106 }
107
108 STRIDE_F(coord, stride);
109 }
110
111 if (nr > 0) {
112 *clipormask |= CLIP_USER_BIT;
113 if (nr == count) {
114 *clipandmask |= CLIP_USER_BIT;
115 return;
116 }
117 }
118 }
119 }
120 }
121
122
123 static GLboolean
124 do_ndc_cliptest(GLcontext *ctx, struct vp_stage_data *store)
125 {
126 TNLcontext *tnl = TNL_CONTEXT(ctx);
127 struct vertex_buffer *VB = &tnl->vb;
128 /* Cliptest and perspective divide. Clip functions must clear
129 * the clipmask.
130 */
131 store->ormask = 0;
132 store->andmask = CLIP_FRUSTUM_BITS;
133
134 if (tnl->NeedNdcCoords) {
135 VB->NdcPtr =
136 _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
137 &store->ndcCoords,
138 store->clipmask,
139 &store->ormask,
140 &store->andmask );
141 }
142 else {
143 VB->NdcPtr = NULL;
144 _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
145 NULL,
146 store->clipmask,
147 &store->ormask,
148 &store->andmask );
149 }
150
151 if (store->andmask) {
152 /* All vertices are outside the frustum */
153 return GL_FALSE;
154 }
155
156 /* Test userclip planes. This contributes to VB->ClipMask.
157 */
158 /** XXX NEW_SLANG _Enabled ??? */
159 if (ctx->Transform.ClipPlanesEnabled && (!ctx->VertexProgram._Enabled ||
160 ctx->VertexProgram.Current->IsPositionInvariant)) {
161 userclip( ctx,
162 VB->ClipPtr,
163 store->clipmask,
164 &store->ormask,
165 &store->andmask );
166
167 if (store->andmask) {
168 return GL_FALSE;
169 }
170 }
171
172 VB->ClipAndMask = store->andmask;
173 VB->ClipOrMask = store->ormask;
174 VB->ClipMask = store->clipmask;
175
176 return GL_TRUE;
177 }
178
179
180 /**
181 * XXX the texture sampling code in this module is a bit of a hack.
182 * The texture sampling code is in swrast, though it doesn't have any
183 * real dependencies on the rest of swrast. It should probably be
184 * moved into main/ someday.
185 */
186 static void
187 vp_fetch_texel(GLcontext *ctx, const GLfloat texcoord[4], GLfloat lambda,
188 GLuint unit, GLfloat color[4])
189 {
190 SWcontext *swrast = SWRAST_CONTEXT(ctx);
191
192 /* XXX use a float-valued TextureSample routine here!!! */
193 swrast->TextureSample[unit](ctx, ctx->Texture.Unit[unit]._Current,
194 1, (const GLfloat (*)[4]) texcoord,
195 &lambda, (GLfloat (*)[4]) color);
196 }
197
198
199 /**
200 * Called via ctx->Driver.ProgramStringNotify() after a new vertex program
201 * string has been parsed.
202 */
203 void
204 _tnl_program_string(GLcontext *ctx, GLenum target, struct gl_program *program)
205 {
206 /* No-op.
207 * If we had derived anything from the program that was private to this
208 * stage we'd recompute/validate it here.
209 */
210 }
211
212
213 /**
214 * Initialize virtual machine state prior to executing vertex program.
215 */
216 static void
217 init_machine(GLcontext *ctx, struct gl_program_machine *machine)
218 {
219 /* Input registers get initialized from the current vertex attribs */
220 MEMCPY(machine->VertAttribs, ctx->Current.Attrib,
221 MAX_VERTEX_GENERIC_ATTRIBS * 4 * sizeof(GLfloat));
222
223 if (ctx->VertexProgram._Current->IsNVProgram) {
224 GLuint i;
225 /* Output/result regs are initialized to [0,0,0,1] */
226 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_OUTPUTS; i++) {
227 ASSIGN_4V(machine->Outputs[i], 0.0F, 0.0F, 0.0F, 1.0F);
228 }
229 /* Temp regs are initialized to [0,0,0,0] */
230 for (i = 0; i < MAX_NV_VERTEX_PROGRAM_TEMPS; i++) {
231 ASSIGN_4V(machine->Temporaries[i], 0.0F, 0.0F, 0.0F, 0.0F);
232 }
233 for (i = 0; i < MAX_VERTEX_PROGRAM_ADDRESS_REGS; i++) {
234 ASSIGN_4V(machine->AddressReg[i], 0, 0, 0, 0);
235 }
236 }
237
238 machine->NumDeriv = 0;
239
240 /* init condition codes */
241 machine->CondCodes[0] = COND_EQ;
242 machine->CondCodes[1] = COND_EQ;
243 machine->CondCodes[2] = COND_EQ;
244 machine->CondCodes[3] = COND_EQ;
245
246 /* init call stack */
247 machine->StackDepth = 0;
248
249 machine->FetchTexelLod = vp_fetch_texel;
250 machine->FetchTexelDeriv = NULL; /* not used by vertex programs */
251
252 machine->Samplers = ctx->VertexProgram._Current->Base.SamplerUnits;
253 }
254
255
256 /**
257 * Map the texture images which the vertex program will access (if any).
258 */
259 static void
260 map_textures(GLcontext *ctx, const struct gl_vertex_program *vp)
261 {
262 GLuint u;
263
264 if (!ctx->Driver.MapTexture)
265 return;
266
267 for (u = 0; u < ctx->Const.MaxVertexTextureImageUnits; u++) {
268 if (vp->Base.TexturesUsed[u]) {
269 /* Note: _Current *should* correspond to the target indicated
270 * in TexturesUsed[u].
271 */
272 ctx->Driver.MapTexture(ctx, ctx->Texture.Unit[u]._Current);
273 }
274 }
275 }
276
277
278 /**
279 * Unmap the texture images which were used by the vertex program (if any).
280 */
281 static void
282 unmap_textures(GLcontext *ctx, const struct gl_vertex_program *vp)
283 {
284 GLuint u;
285
286 if (!ctx->Driver.MapTexture)
287 return;
288
289 for (u = 0; u < ctx->Const.MaxVertexTextureImageUnits; u++) {
290 if (vp->Base.TexturesUsed[u]) {
291 /* Note: _Current *should* correspond to the target indicated
292 * in TexturesUsed[u].
293 */
294 ctx->Driver.UnmapTexture(ctx, ctx->Texture.Unit[u]._Current);
295 }
296 }
297 }
298
299
300 /**
301 * This function executes vertex programs
302 */
303 static GLboolean
304 run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
305 {
306 TNLcontext *tnl = TNL_CONTEXT(ctx);
307 struct vp_stage_data *store = VP_STAGE_DATA(stage);
308 struct vertex_buffer *VB = &tnl->vb;
309 struct gl_vertex_program *program = ctx->VertexProgram._Current;
310 struct gl_program_machine machine;
311 GLuint outputs[VERT_RESULT_MAX], numOutputs;
312 GLuint i, j;
313
314 if (!program)
315 return GL_TRUE;
316
317 if (program->IsNVProgram) {
318 _mesa_load_tracked_matrices(ctx);
319 }
320 else {
321 /* ARB program or vertex shader */
322 _mesa_load_state_parameters(ctx, program->Base.Parameters);
323 }
324
325 /* make list of outputs to save some time below */
326 numOutputs = 0;
327 for (i = 0; i < VERT_RESULT_MAX; i++) {
328 if (program->Base.OutputsWritten & (1 << i)) {
329 outputs[numOutputs++] = i;
330 }
331 }
332
333 map_textures(ctx, program);
334
335 for (i = 0; i < VB->Count; i++) {
336 GLuint attr;
337
338 init_machine(ctx, &machine);
339
340 #if 0
341 printf("Input %d: %f, %f, %f, %f\n", i,
342 VB->AttribPtr[0]->data[i][0],
343 VB->AttribPtr[0]->data[i][1],
344 VB->AttribPtr[0]->data[i][2],
345 VB->AttribPtr[0]->data[i][3]);
346 printf(" color: %f, %f, %f, %f\n",
347 VB->AttribPtr[3]->data[i][0],
348 VB->AttribPtr[3]->data[i][1],
349 VB->AttribPtr[3]->data[i][2],
350 VB->AttribPtr[3]->data[i][3]);
351 printf(" normal: %f, %f, %f, %f\n",
352 VB->AttribPtr[2]->data[i][0],
353 VB->AttribPtr[2]->data[i][1],
354 VB->AttribPtr[2]->data[i][2],
355 VB->AttribPtr[2]->data[i][3]);
356 #endif
357
358 /* the vertex array case */
359 for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
360 if (program->Base.InputsRead & (1 << attr)) {
361 const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data;
362 const GLuint size = VB->AttribPtr[attr]->size;
363 const GLuint stride = VB->AttribPtr[attr]->stride;
364 const GLfloat *data = (GLfloat *) (ptr + stride * i);
365 #ifdef NAN_CHECK
366 check_float(data[0]);
367 check_float(data[1]);
368 check_float(data[2]);
369 check_float(data[3]);
370 #endif
371 COPY_CLEAN_4V(machine.VertAttribs[attr], size, data);
372 }
373 }
374
375 /* execute the program */
376 _mesa_execute_program(ctx, &program->Base, &machine);
377
378 /* copy the output registers into the VB->attribs arrays */
379 for (j = 0; j < numOutputs; j++) {
380 const GLuint attr = outputs[j];
381 #ifdef NAN_CHECK
382 check_float(machine.Outputs[attr][0]);
383 check_float(machine.Outputs[attr][1]);
384 check_float(machine.Outputs[attr][2]);
385 check_float(machine.Outputs[attr][3]);
386 #endif
387 COPY_4V(store->results[attr].data[i], machine.Outputs[attr]);
388 }
389 #if 0
390 printf("HPOS: %f %f %f %f\n",
391 machine.Outputs[0][0],
392 machine.Outputs[0][1],
393 machine.Outputs[0][2],
394 machine.Outputs[0][3]);
395 #endif
396 }
397
398 unmap_textures(ctx, program);
399
400 /* Fixup fog and point size results if needed */
401 if (program->IsNVProgram) {
402 if (ctx->Fog.Enabled &&
403 (program->Base.OutputsWritten & (1 << VERT_RESULT_FOGC)) == 0) {
404 for (i = 0; i < VB->Count; i++) {
405 store->results[VERT_RESULT_FOGC].data[i][0] = 1.0;
406 }
407 }
408
409 if (ctx->VertexProgram.PointSizeEnabled &&
410 (program->Base.OutputsWritten & (1 << VERT_RESULT_PSIZ)) == 0) {
411 for (i = 0; i < VB->Count; i++) {
412 store->results[VERT_RESULT_PSIZ].data[i][0] = ctx->Point.Size;
413 }
414 }
415 }
416
417 if (program->IsPositionInvariant) {
418 /* We need the exact same transform as in the fixed function path here
419 * to guarantee invariance, depending on compiler optimization flags
420 * results could be different otherwise.
421 */
422 VB->ClipPtr = TransformRaw( &store->results[0],
423 &ctx->_ModelProjectMatrix,
424 VB->AttribPtr[0] );
425
426 /* Drivers expect this to be clean to element 4...
427 */
428 switch (VB->ClipPtr->size) {
429 case 1:
430 /* impossible */
431 case 2:
432 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 );
433 /* fall-through */
434 case 3:
435 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 );
436 /* fall-through */
437 case 4:
438 break;
439 }
440 }
441 else {
442 /* Setup the VB pointers so that the next pipeline stages get
443 * their data from the right place (the program output arrays).
444 */
445 VB->ClipPtr = &store->results[VERT_RESULT_HPOS];
446 VB->ClipPtr->size = 4;
447 VB->ClipPtr->count = VB->Count;
448 }
449
450 VB->ColorPtr[0] = &store->results[VERT_RESULT_COL0];
451 VB->ColorPtr[1] = &store->results[VERT_RESULT_BFC0];
452 VB->SecondaryColorPtr[0] = &store->results[VERT_RESULT_COL1];
453 VB->SecondaryColorPtr[1] = &store->results[VERT_RESULT_BFC1];
454 VB->FogCoordPtr = &store->results[VERT_RESULT_FOGC];
455
456 VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->results[VERT_RESULT_COL0];
457 VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->results[VERT_RESULT_COL1];
458 VB->AttribPtr[VERT_ATTRIB_FOG] = &store->results[VERT_RESULT_FOGC];
459 VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->results[VERT_RESULT_PSIZ];
460
461 for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
462 VB->TexCoordPtr[i] =
463 VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]
464 = &store->results[VERT_RESULT_TEX0 + i];
465 }
466
467 for (i = 0; i < ctx->Const.MaxVarying; i++) {
468 if (program->Base.OutputsWritten & (1 << (VERT_RESULT_VAR0 + i))) {
469 /* Note: varying results get put into the generic attributes */
470 VB->AttribPtr[VERT_ATTRIB_GENERIC0+i]
471 = &store->results[VERT_RESULT_VAR0 + i];
472 }
473 }
474
475
476 /* Perform NDC and cliptest operations:
477 */
478 return do_ndc_cliptest(ctx, store);
479 }
480
481
482 /**
483 * Called the first time stage->run is called. In effect, don't
484 * allocate data until the first time the stage is run.
485 */
486 static GLboolean
487 init_vp(GLcontext *ctx, struct tnl_pipeline_stage *stage)
488 {
489 TNLcontext *tnl = TNL_CONTEXT(ctx);
490 struct vertex_buffer *VB = &(tnl->vb);
491 struct vp_stage_data *store;
492 const GLuint size = VB->Size;
493 GLuint i;
494
495 stage->privatePtr = MALLOC(sizeof(*store));
496 store = VP_STAGE_DATA(stage);
497 if (!store)
498 return GL_FALSE;
499
500 /* Allocate arrays of vertex output values */
501 for (i = 0; i < VERT_RESULT_MAX; i++) {
502 _mesa_vector4f_alloc( &store->results[i], 0, size, 32 );
503 store->results[i].size = 4;
504 }
505
506 /* a few other misc allocations */
507 _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 );
508 store->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
509
510 return GL_TRUE;
511 }
512
513
514 /**
515 * Destructor for this pipeline stage.
516 */
517 static void
518 dtr(struct tnl_pipeline_stage *stage)
519 {
520 struct vp_stage_data *store = VP_STAGE_DATA(stage);
521
522 if (store) {
523 GLuint i;
524
525 /* free the vertex program result arrays */
526 for (i = 0; i < VERT_RESULT_MAX; i++)
527 _mesa_vector4f_free( &store->results[i] );
528
529 /* free misc arrays */
530 _mesa_vector4f_free( &store->ndcCoords );
531 ALIGN_FREE( store->clipmask );
532
533 FREE( store );
534 stage->privatePtr = NULL;
535 }
536 }
537
538
539 static void
540 validate_vp_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
541 {
542 if (ctx->VertexProgram._Current) {
543 _swrast_update_texture_samplers(ctx);
544 }
545 }
546
547
548
549 /**
550 * Public description of this pipeline stage.
551 */
552 const struct tnl_pipeline_stage _tnl_vertex_program_stage =
553 {
554 "vertex-program",
555 NULL, /* private_data */
556 init_vp, /* create */
557 dtr, /* destroy */
558 validate_vp_stage, /* validate */
559 run_vp /* run -- initially set to ctr */
560 };