• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/imports.h"
37 #include "main/samplerobj.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 
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
check_float(float x)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[VARYING_SLOT_MAX];
67 
68    GLvector4f ndcCoords;              /**< normalized device coords */
69    GLubyte *clipmask;                 /**< clip flags */
70    GLubyte ormask, andmask;           /**< for clipping */
71 
72    GLboolean vertex_textures;
73 
74    struct gl_program_machine machine;
75 };
76 
77 
78 #define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr))
79 
80 
81 static void
userclip(struct gl_context * ctx,GLvector4f * clip,GLubyte * clipmask,GLubyte * clipormask,GLubyte * clipandmask)82 userclip( struct gl_context *ctx,
83           GLvector4f *clip,
84           GLubyte *clipmask,
85           GLubyte *clipormask,
86           GLubyte *clipandmask )
87 {
88    GLbitfield mask = ctx->Transform.ClipPlanesEnabled;
89    while (mask) {
90       const int p = u_bit_scan(&mask);
91       GLuint nr, i;
92       const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
93       const GLfloat b = ctx->Transform._ClipUserPlane[p][1];
94       const GLfloat c = ctx->Transform._ClipUserPlane[p][2];
95       const GLfloat d = ctx->Transform._ClipUserPlane[p][3];
96       GLfloat *coord = (GLfloat *)clip->data;
97       GLuint stride = clip->stride;
98       GLuint count = clip->count;
99 
100       for (nr = 0, i = 0 ; i < count ; i++) {
101          GLfloat dp = (coord[0] * a +
102                        coord[1] * b +
103                        coord[2] * c +
104                        coord[3] * d);
105 
106          if (dp < 0) {
107             nr++;
108             clipmask[i] |= CLIP_USER_BIT;
109          }
110 
111          STRIDE_F(coord, stride);
112       }
113 
114       if (nr > 0) {
115          *clipormask |= CLIP_USER_BIT;
116          if (nr == count) {
117             *clipandmask |= CLIP_USER_BIT;
118             return;
119          }
120       }
121    }
122 }
123 
124 
125 static GLboolean
do_ndc_cliptest(struct gl_context * ctx,struct vp_stage_data * store)126 do_ndc_cliptest(struct gl_context *ctx, struct vp_stage_data *store)
127 {
128    TNLcontext *tnl = TNL_CONTEXT(ctx);
129    struct vertex_buffer *VB = &tnl->vb;
130    /* Cliptest and perspective divide.  Clip functions must clear
131     * the clipmask.
132     */
133    store->ormask = 0;
134    store->andmask = CLIP_FRUSTUM_BITS;
135 
136    tnl_clip_prepare(ctx);
137 
138    if (tnl->NeedNdcCoords) {
139       VB->NdcPtr =
140          _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
141                                             &store->ndcCoords,
142                                             store->clipmask,
143                                             &store->ormask,
144                                             &store->andmask,
145 					    !ctx->Transform.DepthClamp );
146    }
147    else {
148       VB->NdcPtr = NULL;
149       _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
150                                             NULL,
151                                             store->clipmask,
152                                             &store->ormask,
153                                             &store->andmask,
154 					    !ctx->Transform.DepthClamp );
155    }
156 
157    if (store->andmask) {
158       /* All vertices are outside the frustum */
159       return GL_FALSE;
160    }
161 
162    /* Test userclip planes.  This contributes to VB->ClipMask.
163     */
164    /** XXX NEW_SLANG _Enabled ??? */
165    if (ctx->Transform.ClipPlanesEnabled && (!ctx->VertexProgram._Enabled ||
166       ctx->VertexProgram.Current->arb.IsPositionInvariant)) {
167       userclip( ctx,
168 		VB->ClipPtr,
169 		store->clipmask,
170 		&store->ormask,
171 		&store->andmask );
172 
173       if (store->andmask) {
174 	 return GL_FALSE;
175       }
176    }
177 
178    VB->ClipAndMask = store->andmask;
179    VB->ClipOrMask = store->ormask;
180    VB->ClipMask = store->clipmask;
181 
182    return GL_TRUE;
183 }
184 
185 
186 /**
187  * XXX the texture sampling code in this module is a bit of a hack.
188  * The texture sampling code is in swrast, though it doesn't have any
189  * real dependencies on the rest of swrast.  It should probably be
190  * moved into main/ someday.
191  */
192 static void
vp_fetch_texel(struct gl_context * ctx,const GLfloat texcoord[4],GLfloat lambda,GLuint unit,GLfloat color[4])193 vp_fetch_texel(struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda,
194                GLuint unit, GLfloat color[4])
195 {
196    SWcontext *swrast = SWRAST_CONTEXT(ctx);
197 
198    /* XXX use a float-valued TextureSample routine here!!! */
199    swrast->TextureSample[unit](ctx, _mesa_get_samplerobj(ctx, unit),
200                                ctx->Texture.Unit[unit]._Current,
201                                1, (const GLfloat (*)[4]) texcoord,
202                                &lambda,  (GLfloat (*)[4]) color);
203 }
204 
205 
206 /**
207  * Called via ctx->Driver.ProgramStringNotify() after a new vertex program
208  * string has been parsed.
209  */
210 GLboolean
_tnl_program_string(struct gl_context * ctx,GLenum target,struct gl_program * program)211 _tnl_program_string(struct gl_context *ctx, GLenum target, struct gl_program *program)
212 {
213    /* No-op.
214     * If we had derived anything from the program that was private to this
215     * stage we'd recompute/validate it here.
216     */
217    return GL_TRUE;
218 }
219 
220 
221 /**
222  * Initialize virtual machine state prior to executing vertex program.
223  */
224 static void
init_machine(struct gl_context * ctx,struct gl_program_machine * machine,GLuint instID)225 init_machine(struct gl_context *ctx, struct gl_program_machine *machine,
226              GLuint instID)
227 {
228    /* Input registers get initialized from the current vertex attribs */
229    memcpy(machine->VertAttribs, ctx->Current.Attrib,
230           MAX_VERTEX_GENERIC_ATTRIBS * 4 * sizeof(GLfloat));
231 
232    machine->NumDeriv = 0;
233 
234    /* init call stack */
235    machine->StackDepth = 0;
236 
237    machine->FetchTexelLod = vp_fetch_texel;
238    machine->FetchTexelDeriv = NULL; /* not used by vertex programs */
239 
240    machine->Samplers = ctx->VertexProgram._Current->SamplerUnits;
241 
242    machine->SystemValues[SYSTEM_VALUE_INSTANCE_ID][0] = (GLfloat) instID;
243 }
244 
245 
246 /**
247  * Map the texture images which the vertex program will access (if any).
248  */
249 static void
map_textures(struct gl_context * ctx,const struct gl_program * vp)250 map_textures(struct gl_context *ctx, const struct gl_program *vp)
251 {
252    GLuint u;
253 
254    for (u = 0; u < ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits; u++) {
255       if (vp->TexturesUsed[u]) {
256          /* Note: _Current *should* correspond to the target indicated
257           * in TexturesUsed[u].
258           */
259          _swrast_map_texture(ctx, ctx->Texture.Unit[u]._Current);
260       }
261    }
262 }
263 
264 
265 /**
266  * Unmap the texture images which were used by the vertex program (if any).
267  */
268 static void
unmap_textures(struct gl_context * ctx,const struct gl_program * vp)269 unmap_textures(struct gl_context *ctx, const struct gl_program *vp)
270 {
271    GLuint u;
272 
273    for (u = 0; u < ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits; u++) {
274       if (vp->TexturesUsed[u]) {
275          /* Note: _Current *should* correspond to the target indicated
276           * in TexturesUsed[u].
277           */
278          _swrast_unmap_texture(ctx, ctx->Texture.Unit[u]._Current);
279       }
280    }
281 }
282 
283 
284 /**
285  * This function executes vertex programs
286  */
287 static GLboolean
run_vp(struct gl_context * ctx,struct tnl_pipeline_stage * stage)288 run_vp( struct gl_context *ctx, struct tnl_pipeline_stage *stage )
289 {
290    TNLcontext *tnl = TNL_CONTEXT(ctx);
291    struct vp_stage_data *store = VP_STAGE_DATA(stage);
292    struct vertex_buffer *VB = &tnl->vb;
293    struct gl_program *program = ctx->VertexProgram._Current;
294    struct gl_program_machine *machine = &store->machine;
295    GLuint outputs[VARYING_SLOT_MAX], numOutputs;
296    GLuint i, j;
297 
298    if (!program)
299       return GL_TRUE;
300 
301    /* ARB program or vertex shader */
302    _mesa_load_state_parameters(ctx, program->Parameters);
303 
304    /* make list of outputs to save some time below */
305    numOutputs = 0;
306    for (i = 0; i < VARYING_SLOT_MAX; i++) {
307       if (program->info.outputs_written & BITFIELD64_BIT(i)) {
308          outputs[numOutputs++] = i;
309       }
310    }
311 
312    /* Allocate result vectors.  We delay this until now to avoid allocating
313     * memory that would never be used if we don't run the software tnl pipeline.
314     */
315    if (!store->results[0].storage) {
316       for (i = 0; i < VARYING_SLOT_MAX; i++) {
317          assert(!store->results[i].storage);
318          _mesa_vector4f_alloc( &store->results[i], 0, VB->Size, 32 );
319          store->results[i].size = 4;
320       }
321    }
322 
323    map_textures(ctx, program);
324 
325    for (i = 0; i < VB->Count; i++) {
326       GLuint attr;
327 
328       init_machine(ctx, machine, tnl->CurInstance);
329 
330 #if 0
331       printf("Input  %d: %f, %f, %f, %f\n", i,
332              VB->AttribPtr[0]->data[i][0],
333              VB->AttribPtr[0]->data[i][1],
334              VB->AttribPtr[0]->data[i][2],
335              VB->AttribPtr[0]->data[i][3]);
336       printf("   color: %f, %f, %f, %f\n",
337              VB->AttribPtr[3]->data[i][0],
338              VB->AttribPtr[3]->data[i][1],
339              VB->AttribPtr[3]->data[i][2],
340              VB->AttribPtr[3]->data[i][3]);
341       printf("  normal: %f, %f, %f, %f\n",
342              VB->AttribPtr[2]->data[i][0],
343              VB->AttribPtr[2]->data[i][1],
344              VB->AttribPtr[2]->data[i][2],
345              VB->AttribPtr[2]->data[i][3]);
346 #endif
347 
348       /* the vertex array case */
349       for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
350 	 if (program->info.inputs_read & BITFIELD64_BIT(attr)) {
351 	    const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data;
352 	    const GLuint size = VB->AttribPtr[attr]->size;
353 	    const GLuint stride = VB->AttribPtr[attr]->stride;
354 	    const GLfloat *data = (GLfloat *) (ptr + stride * i);
355 #ifdef NAN_CHECK
356             check_float(data[0]);
357             check_float(data[1]);
358             check_float(data[2]);
359             check_float(data[3]);
360 #endif
361 	    COPY_CLEAN_4V(machine->VertAttribs[attr], size, data);
362 	 }
363       }
364 
365       /* execute the program */
366       _mesa_execute_program(ctx, program, machine);
367 
368       /* copy the output registers into the VB->attribs arrays */
369       for (j = 0; j < numOutputs; j++) {
370          const GLuint attr = outputs[j];
371 #ifdef NAN_CHECK
372          check_float(machine->Outputs[attr][0]);
373          check_float(machine->Outputs[attr][1]);
374          check_float(machine->Outputs[attr][2]);
375          check_float(machine->Outputs[attr][3]);
376 #endif
377          COPY_4V(store->results[attr].data[i], machine->Outputs[attr]);
378       }
379 
380       /* FOGC is a special case.  Fragment shader expects (f,0,0,1) */
381       if (program->info.outputs_written & BITFIELD64_BIT(VARYING_SLOT_FOGC)) {
382          store->results[VARYING_SLOT_FOGC].data[i][1] = 0.0;
383          store->results[VARYING_SLOT_FOGC].data[i][2] = 0.0;
384          store->results[VARYING_SLOT_FOGC].data[i][3] = 1.0;
385       }
386 #ifdef NAN_CHECK
387       assert(machine->Outputs[0][3] != 0.0F);
388 #endif
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    if (program->arb.IsPositionInvariant) {
401       /* We need the exact same transform as in the fixed function path here
402        * to guarantee invariance, depending on compiler optimization flags
403        * results could be different otherwise.
404        */
405       VB->ClipPtr = TransformRaw( &store->results[0],
406 				  &ctx->_ModelProjectMatrix,
407 				  VB->AttribPtr[0] );
408 
409       /* Drivers expect this to be clean to element 4...
410        */
411       switch (VB->ClipPtr->size) {
412       case 1:
413 	 /* impossible */
414       case 2:
415 	 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 );
416 	 /* fall-through */
417       case 3:
418 	 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 );
419 	 /* fall-through */
420       case 4:
421 	 break;
422       }
423    }
424    else {
425       /* Setup the VB pointers so that the next pipeline stages get
426        * their data from the right place (the program output arrays).
427        */
428       VB->ClipPtr = &store->results[VARYING_SLOT_POS];
429       VB->ClipPtr->size = 4;
430       VB->ClipPtr->count = VB->Count;
431    }
432 
433    VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->results[VARYING_SLOT_COL0];
434    VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->results[VARYING_SLOT_COL1];
435    VB->AttribPtr[VERT_ATTRIB_FOG] = &store->results[VARYING_SLOT_FOGC];
436    VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->results[VARYING_SLOT_PSIZ];
437    VB->BackfaceColorPtr = &store->results[VARYING_SLOT_BFC0];
438    VB->BackfaceSecondaryColorPtr = &store->results[VARYING_SLOT_BFC1];
439 
440    for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
441       VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]
442          = &store->results[VARYING_SLOT_TEX0 + i];
443    }
444 
445    for (i = 0; i < ctx->Const.MaxVarying; i++) {
446       if (program->info.outputs_written &
447           BITFIELD64_BIT(VARYING_SLOT_VAR0 + i)) {
448          /* Note: varying results get put into the generic attributes */
449 	 VB->AttribPtr[VERT_ATTRIB_GENERIC0+i]
450             = &store->results[VARYING_SLOT_VAR0 + i];
451       }
452    }
453 
454 
455    /* Perform NDC and cliptest operations:
456     */
457    return do_ndc_cliptest(ctx, store);
458 }
459 
460 
461 /**
462  * Called the first time stage->run is called.  In effect, don't
463  * allocate data until the first time the stage is run.
464  */
465 static GLboolean
init_vp(struct gl_context * ctx,struct tnl_pipeline_stage * stage)466 init_vp(struct gl_context *ctx, struct tnl_pipeline_stage *stage)
467 {
468    TNLcontext *tnl = TNL_CONTEXT(ctx);
469    struct vertex_buffer *VB = &(tnl->vb);
470    struct vp_stage_data *store;
471    const GLuint size = VB->Size;
472 
473    stage->privatePtr = calloc(1, sizeof(*store));
474    store = VP_STAGE_DATA(stage);
475    if (!store)
476       return GL_FALSE;
477 
478    /* a few other misc allocations */
479    _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 );
480    store->clipmask = _mesa_align_malloc(sizeof(GLubyte)*size, 32 );
481 
482    return GL_TRUE;
483 }
484 
485 
486 /**
487  * Destructor for this pipeline stage.
488  */
489 static void
dtr(struct tnl_pipeline_stage * stage)490 dtr(struct tnl_pipeline_stage *stage)
491 {
492    struct vp_stage_data *store = VP_STAGE_DATA(stage);
493 
494    if (store) {
495       GLuint i;
496 
497       /* free the vertex program result arrays */
498       for (i = 0; i < VARYING_SLOT_MAX; i++)
499          _mesa_vector4f_free( &store->results[i] );
500 
501       /* free misc arrays */
502       _mesa_vector4f_free( &store->ndcCoords );
503       _mesa_align_free( store->clipmask );
504 
505       free( store );
506       stage->privatePtr = NULL;
507    }
508 }
509 
510 
511 static void
validate_vp_stage(struct gl_context * ctx,struct tnl_pipeline_stage * stage)512 validate_vp_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage)
513 {
514    if (ctx->VertexProgram._Current) {
515       _swrast_update_texture_samplers(ctx);
516    }
517 }
518 
519 
520 
521 /**
522  * Public description of this pipeline stage.
523  */
524 const struct tnl_pipeline_stage _tnl_vertex_program_stage =
525 {
526    "vertex-program",
527    NULL,			/* private_data */
528    init_vp,			/* create */
529    dtr,				/* destroy */
530    validate_vp_stage, 		/* validate */
531    run_vp			/* run -- initially set to ctr */
532 };
533