t_vb_program.c revision 3c63452e64df7e10aa073c6c3b9492b1d7dabbb8
1/* $Id: t_vb_program.c,v 1.15 2002/10/24 23:57:25 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  4.1
6 *
7 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27/*
28 * -------- Regarding NV_vertex_program --------
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions are met:
31 *
32 * o Redistribution of the source code must contain a copyright notice
33 *   and this list of conditions;
34 *
35 * o Redistribution in binary and source code form must contain the
36 *   following Notice in the software and any documentation and/or other
37 *   materials provided with the distribution; and
38 *
39 * o The name of Nvidia may not be used to promote or endorse software
40 *   derived from the software.
41 *
42 * NOTICE: Nvidia hereby grants to each recipient a non-exclusive worldwide
43 * royalty free patent license under patent claims that are licensable by
44 * Nvidia and which are necessarily required and for which no commercially
45 * viable non infringing alternative exists to make, use, sell, offer to sell,
46 * import and otherwise transfer the vertex extension for the Mesa 3D Graphics
47 * Library as distributed in source code and object code form.  No hardware or
48 * hardware implementation (including a semiconductor implementation and chips)
49 * are licensed hereunder. If a recipient makes a patent claim or institutes
50 * patent litigation against Nvidia or Nvidia's customers for use or sale of
51 * Nvidia products, then this license grant as to such recipient shall
52 * immediately terminate and recipient immediately agrees to cease use and
53 * distribution of the Mesa Program and derivatives thereof.
54 *
55 * THE MESA 3D GRAPHICS LIBRARY IS PROVIDED ON AN "AS IS BASIS, WITHOUT
56 * WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
57 * WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-NFRINGEMENT
58 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
59 *
60 * NVIDIA SHALL NOT HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
61 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
62 * LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
63 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64 * ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE MESA 3D GRAPHICS
65 * LIBRARY OR EVIDENCE OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDR, EVEN
66 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 *
68 * If you do not comply with this agreement, then Nvidia may cancel the license
69 * and rights granted herein.
70 * ---------------------------------------------
71 */
72
73/**
74 * \file tnl/t_vb_program.c
75 * \brief Pipeline stage for executing vertex programs
76 * \author Brian Paul,  Keith Whitwell
77 */
78
79
80#include "glheader.h"
81#include "api_noop.h"
82#include "colormac.h"
83#include "context.h"
84#include "dlist.h"
85#include "hash.h"
86#include "light.h"
87#include "macros.h"
88#include "imports.h"
89#include "mmath.h"
90#include "simple_list.h"
91#include "mtypes.h"
92#include "vpexec.h"
93
94#include "math/m_translate.h"
95
96#include "t_context.h"
97#include "t_pipeline.h"
98#include "t_imm_api.h"
99#include "t_imm_exec.h"
100
101
102/**
103 * \warning These values _MUST_ match the values in the OutputRegisters[]
104 * array in vpparse.c!!!
105 */
106#define VERT_RESULT_HPOS 0
107#define VERT_RESULT_COL0 1
108#define VERT_RESULT_COL1 2
109#define VERT_RESULT_BFC0 3
110#define VERT_RESULT_BFC1 4
111#define VERT_RESULT_FOGC 5
112#define VERT_RESULT_PSIZ 6
113#define VERT_RESULT_TEX0 7
114#define VERT_RESULT_TEX1 8
115#define VERT_RESULT_TEX2 9
116#define VERT_RESULT_TEX3 10
117#define VERT_RESULT_TEX4 11
118#define VERT_RESULT_TEX5 12
119#define VERT_RESULT_TEX6 13
120#define VERT_RESULT_TEX7 14
121
122
123/*!
124 * Private storage for the vertex program pipeline stage.
125 */
126struct vp_stage_data {
127   /** The results of running the vertex program go into these arrays. */
128   GLvector4f attribs[15];
129
130   /* These point to the attribs[VERT_RESULT_COL0, COL1, BFC0, BFC1] arrays */
131   struct gl_client_array color0[2];  /**< diffuse front and back */
132   struct gl_client_array color1[2];  /**< specular front and back */
133
134   GLvector4f ndcCoords;              /**< normalized device coords */
135   GLubyte *clipmask;                 /**< clip flags */
136   GLubyte ormask, andmask;           /**< for clipping */
137};
138
139
140#define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr))
141
142
143/**
144 * This function executes vertex programs
145 */
146static GLboolean run_vp( GLcontext *ctx, struct gl_pipeline_stage *stage )
147{
148   TNLcontext *tnl = TNL_CONTEXT(ctx);
149   struct vp_stage_data *store = VP_STAGE_DATA(stage);
150   struct vertex_buffer *VB = &tnl->vb;
151   struct vp_machine *machine = &(ctx->VertexProgram.Machine);
152   struct vp_program *program = ctx->VertexProgram.Current;
153   GLuint i;
154
155   _mesa_init_tracked_matrices(ctx); /* load registers with matrices */
156   _mesa_init_vp_registers(ctx);     /* init temp and result regs */
157
158   for (i = 0; i < VB->Count; i++) {
159      GLuint attr;
160
161#if 0
162      printf("Input  %d: %f, %f, %f, %f\n", i,
163             VB->AttribPtr[0]->data[i][0],
164             VB->AttribPtr[0]->data[i][1],
165             VB->AttribPtr[0]->data[i][2],
166             VB->AttribPtr[0]->data[i][3]);
167      printf("   color: %f, %f, %f, %f\n",
168             VB->AttribPtr[3]->data[i][0],
169             VB->AttribPtr[3]->data[i][1],
170             VB->AttribPtr[3]->data[i][2],
171             VB->AttribPtr[3]->data[i][3]);
172      printf("  normal: %f, %f, %f, %f\n",
173             VB->AttribPtr[2]->data[i][0],
174             VB->AttribPtr[2]->data[i][1],
175             VB->AttribPtr[2]->data[i][2],
176             VB->AttribPtr[2]->data[i][3]);
177#endif
178
179      /* load the input attribute registers */
180      if (VB->Flag) {
181         /* the traditional glBegin/glVertex/glEnd case */
182         for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
183            if (VB->Flag[i] & (1 << attr)) {
184               COPY_4V(machine->Registers[VP_INPUT_REG_START + attr],
185                       VB->AttribPtr[attr]->data[i]);
186            }
187         }
188      }
189      else {
190         /* the vertex array case */
191         for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
192            if (program->InputsRead & (1 << attr)) {
193               const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data;
194               const GLuint stride = VB->AttribPtr[attr]->stride;
195               const GLfloat *data = (GLfloat *) (ptr + stride * i);
196               COPY_4V(machine->Registers[VP_INPUT_REG_START + attr], data);
197               /*ASSERT(VB->AttribPtr[attr]->size == 4);*/
198               ASSERT(stride == 4 * sizeof(GLfloat) || stride == 0);
199            }
200         }
201      }
202
203      /* execute the program */
204      ASSERT(program);
205      _mesa_exec_program(ctx, program);
206
207#if 0
208      printf("Output %d: %f, %f, %f, %f\n", i,
209             machine->Registers[VP_OUTPUT_REG_START + 0][0],
210             machine->Registers[VP_OUTPUT_REG_START + 0][1],
211             machine->Registers[VP_OUTPUT_REG_START + 0][2],
212             machine->Registers[VP_OUTPUT_REG_START + 0][3]);
213      printf("   color: %f, %f, %f, %f\n",
214             machine->Registers[VP_OUTPUT_REG_START +_1][0],
215             machine->Registers[VP_OUTPUT_REG_START + 1][1],
216             machine->Registers[VP_OUTPUT_REG_START + 1][2],
217             machine->Registers[VP_OUTPUT_REG_START + 1][3]);
218      printf("PointSize[%d]: %g\n", i,
219             machine->Registers[VP_OUTPUT_REG_START + VERT_RESULT_PSIZ][0]);
220#endif
221
222      /* Fixup fog an point size results if needed */
223      if (ctx->Fog.Enabled &&
224          (program->OutputsWritten & (1 << VERT_RESULT_FOGC)) == 0) {
225         machine->Registers[VP_OUTPUT_REG_START + VERT_RESULT_FOGC][0] = 1.0;
226      }
227
228      if (ctx->VertexProgram.PointSizeEnabled &&
229          (program->OutputsWritten & (1 << VERT_RESULT_PSIZ)) == 0) {
230         machine->Registers[VP_OUTPUT_REG_START + VERT_RESULT_PSIZ][0]
231            = ctx->Point.Size;
232      }
233
234      /* copy the output registers into the VB->attribs arrays */
235      /* XXX (optimize) could use a conditional and smaller loop limit here */
236      for (attr = 0; attr < 15; attr++) {
237         COPY_4V( store->attribs[attr].data[i],
238                  machine->Registers[VP_OUTPUT_REG_START + attr] );
239      }
240   }
241
242   /* Setup the VB pointers so that the next pipeline stages get
243    * their data from the right place (the program output arrays).
244    */
245   VB->ClipPtr = &store->attribs[VERT_RESULT_HPOS];
246   VB->ClipPtr->size = 4;
247   VB->ClipPtr->count = VB->Count;
248   VB->ColorPtr[0] = &store->color0[0];
249   VB->ColorPtr[1] = &store->color0[1];
250   VB->SecondaryColorPtr[0] = &store->color1[0];
251   VB->SecondaryColorPtr[1] = &store->color1[1];
252   VB->FogCoordPtr = &store->attribs[VERT_RESULT_FOGC];
253   VB->PointSizePtr = &store->attribs[VERT_RESULT_PSIZ];
254   for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
255      VB->TexCoordPtr[i] = &store->attribs[VERT_RESULT_TEX0 + i];
256
257   /* Cliptest and perspective divide.  Clip functions must clear
258    * the clipmask.
259    */
260   store->ormask = 0;
261   store->andmask = CLIP_ALL_BITS;
262
263   if (tnl->NeedNdcCoords) {
264      VB->NdcPtr =
265         _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
266                                            &store->ndcCoords,
267                                            store->clipmask,
268                                            &store->ormask,
269                                            &store->andmask );
270
271   }
272   else {
273      VB->NdcPtr = 0;
274      _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
275                                            0,
276                                            store->clipmask,
277                                            &store->ormask,
278                                            &store->andmask );
279   }
280
281   if (store->andmask)  /* All vertices are outside the frustum */
282      return GL_FALSE;
283
284
285   /* This is where we'd do clip testing against the user-defined
286    * clipping planes, but they're not supported by vertex programs.
287    */
288
289   VB->ClipOrMask = store->ormask;
290   VB->ClipMask = store->clipmask;
291
292   /* XXXX what's this?
293   if (VB->ClipPtr == VB->ObjPtr && (VB->importable_data & VERT_BIT_POS))
294      VB->importable_data |= VERT_BIT_CLIP;
295   */
296
297   return GL_TRUE;
298}
299
300
301/**
302 * This function validates stuff.
303 */
304static GLboolean run_validate_program( GLcontext *ctx,
305					struct gl_pipeline_stage *stage )
306{
307#if 000
308   /* XXX do we need any validation for vertex programs? */
309   GLuint ind = 0;
310   light_func *tab;
311
312   if (ctx->Visual.rgbMode) {
313      if (ctx->Light._NeedVertices) {
314	 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
315	    tab = _tnl_light_spec_tab;
316	 else
317	    tab = _tnl_light_tab;
318      }
319      else {
320	 if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev)
321	    tab = _tnl_light_fast_single_tab;
322	 else
323	    tab = _tnl_light_fast_tab;
324      }
325   }
326   else
327      tab = _tnl_light_ci_tab;
328
329   if (ctx->Light.ColorMaterialEnabled)
330      ind |= LIGHT_COLORMATERIAL;
331
332   if (ctx->Light.Model.TwoSide)
333      ind |= LIGHT_TWOSIDE;
334
335   VP_STAGE_DATA(stage)->light_func_tab = &tab[ind];
336
337   /* This and the above should only be done on _NEW_LIGHT:
338    */
339   _mesa_validate_all_lighting_tables( ctx );
340#endif
341
342   /* Now run the stage...
343    */
344   stage->run = run_vp;
345   return stage->run( ctx, stage );
346}
347
348
349/**
350 * Initialize a gl_client_array to point into a GLvector4f color vector.
351 */
352static void init_color_array( struct gl_client_array *a, GLvector4f *vec )
353{
354   a->Ptr = vec->data;
355   a->Size = 4;
356   a->Type = GL_FLOAT;
357   a->Stride = 0;
358   a->StrideB = sizeof(GLfloat) * 4;
359   a->Enabled = 0;
360   a->Flags = 0;
361}
362
363
364/**
365 * Called the first time stage->run is called.  In effect, don't
366 * allocate data until the first time the stage is run.
367 */
368static GLboolean run_init_vp( GLcontext *ctx,
369                              struct gl_pipeline_stage *stage )
370{
371   TNLcontext *tnl = TNL_CONTEXT(ctx);
372   struct vertex_buffer *VB = &(tnl->vb);
373   struct vp_stage_data *store;
374   const GLuint size = VB->Size;
375   GLuint i;
376
377   stage->privatePtr = MALLOC(sizeof(*store));
378   store = VP_STAGE_DATA(stage);
379   if (!store)
380      return GL_FALSE;
381
382   /* Allocate arrays of vertex output values */
383   for (i = 0; i < 15; i++)
384      _mesa_vector4f_alloc( &store->attribs[i], 0, size, 32 );
385
386   /* Make the color0[] and color1[] arrays point into the attribs[] arrays */
387   init_color_array( &store->color0[0], &store->attribs[VERT_RESULT_COL0] );
388   init_color_array( &store->color0[1], &store->attribs[VERT_RESULT_COL1] );
389   init_color_array( &store->color1[0], &store->attribs[VERT_RESULT_BFC0] );
390   init_color_array( &store->color1[1], &store->attribs[VERT_RESULT_BFC1] );
391
392   /* a few other misc allocations */
393   _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 );
394   store->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
395
396   /* Now validate the stage derived data...
397    */
398   stage->run = run_validate_program;
399   return stage->run( ctx, stage );
400}
401
402
403
404/**
405 * Check if vertex program mode is enabled.
406 * If so, configure the pipeline stage's type, inputs, and outputs.
407 */
408static void check_vp( GLcontext *ctx, struct gl_pipeline_stage *stage )
409{
410   stage->active = ctx->VertexProgram.Enabled;
411
412   if (stage->active) {
413      /* I believe this is right - Keith?
414       * Set stage->inputs equal to the bitmask of vertex attributes
415       * which the program needs for inputs.
416       */
417
418      stage->inputs = ctx->VertexProgram.Current->InputsRead;
419
420#if 000
421      if (stage->privatePtr)
422	 stage->run = run_validate_program;
423      stage->inputs = VERT_BIT_NORMAL|VERT_BIT_MATERIAL;
424      if (ctx->Light._NeedVertices)
425	 stage->inputs |= VERT_BIT_EYE; /* effectively, even when lighting in obj */
426      if (ctx->Light.ColorMaterialEnabled)
427	 stage->inputs |= VERT_BIT_COLOR0;
428
429      stage->outputs = VERT_BIT_COLOR0;
430      if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
431	 stage->outputs |= VERT_BIT_COLOR1;
432#endif
433   }
434}
435
436
437/**
438 * Destructor for this pipeline stage.
439 */
440static void dtr( struct gl_pipeline_stage *stage )
441{
442   struct vp_stage_data *store = VP_STAGE_DATA(stage);
443
444   if (store) {
445      GLuint i;
446
447      /* free the vertex program result arrays */
448      for (i = 0; i < 15; i++)
449         _mesa_vector4f_free( &store->attribs[i] );
450
451      /* free misc arrays */
452      _mesa_vector4f_free( &store->ndcCoords );
453      ALIGN_FREE( store->clipmask );
454
455      FREE( store );
456      stage->privatePtr = 0;
457   }
458}
459
460/**
461 * Public description of this pipeline stage.
462 */
463const struct gl_pipeline_stage _tnl_vertex_program_stage =
464{
465   "vertex-program",
466   _NEW_ALL,	/*XXX FIX */	/* recheck */
467   _NEW_ALL,	/*XXX FIX */    /* recalc -- modelview dependency
468				 * otherwise not captured by inputs
469				 * (which may be VERT_BIT_POS) */
470   GL_FALSE,			/* active */
471   /*0*/ VERT_BIT_POS,				/* inputs  XXX OK? */
472   VERT_BIT_CLIP | VERT_BIT_COLOR0,			/* outputs XXX OK? */
473   0,				/* changed_inputs */
474   NULL,			/* private_data */
475   dtr,				/* destroy */
476   check_vp,			/* check */
477   run_init_vp			/* run -- initially set to ctr */
478};
479