17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
44a49301eSmrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
54a49301eSmrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
247117f1b4Smrg */
257117f1b4Smrg
267117f1b4Smrg
277117f1b4Smrg/**
287117f1b4Smrg * \file tnl/t_vb_program.c
297117f1b4Smrg * \brief Pipeline stage for executing vertex programs.
307117f1b4Smrg * \author Brian Paul,  Keith Whitwell
317117f1b4Smrg */
327117f1b4Smrg
337117f1b4Smrg
347117f1b4Smrg#include "main/glheader.h"
357117f1b4Smrg#include "main/macros.h"
36af69d88dSmrg#include "main/samplerobj.h"
3701e04c3fSmrg#include "main/state.h"
383464ebd5Sriastradh#include "math/m_xform.h"
393464ebd5Sriastradh#include "program/prog_instruction.h"
403464ebd5Sriastradh#include "program/prog_statevars.h"
413464ebd5Sriastradh#include "program/prog_execute.h"
427117f1b4Smrg#include "swrast/s_context.h"
4301e04c3fSmrg#include "util/bitscan.h"
447ec681f3Smrg#include "util/u_memory.h"
457117f1b4Smrg
467117f1b4Smrg#include "tnl/tnl.h"
477117f1b4Smrg#include "tnl/t_context.h"
487117f1b4Smrg#include "tnl/t_pipeline.h"
497117f1b4Smrg
507117f1b4Smrg
514a49301eSmrg#ifdef NAN_CHECK
524a49301eSmrg/** Check for NaNs and very large values */
53af69d88dSmrgstatic inline void
544a49301eSmrgcheck_float(float x)
554a49301eSmrg{
567ec681f3Smrg   assert(!util_is_inf_or_nan(x));
574a49301eSmrg   assert(1.0e-15 <= x && x <= 1.0e15);
584a49301eSmrg}
594a49301eSmrg#endif
604a49301eSmrg
617117f1b4Smrg
627117f1b4Smrg/*!
637117f1b4Smrg * Private storage for the vertex program pipeline stage.
647117f1b4Smrg */
657117f1b4Smrgstruct vp_stage_data {
667117f1b4Smrg   /** The results of running the vertex program go into these arrays. */
67af69d88dSmrg   GLvector4f results[VARYING_SLOT_MAX];
687117f1b4Smrg
697117f1b4Smrg   GLvector4f ndcCoords;              /**< normalized device coords */
707117f1b4Smrg   GLubyte *clipmask;                 /**< clip flags */
717117f1b4Smrg   GLubyte ormask, andmask;           /**< for clipping */
723464ebd5Sriastradh
73af69d88dSmrg   GLboolean vertex_textures;
74af69d88dSmrg
753464ebd5Sriastradh   struct gl_program_machine machine;
767117f1b4Smrg};
777117f1b4Smrg
787117f1b4Smrg
797117f1b4Smrg#define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr))
807117f1b4Smrg
817117f1b4Smrg
827117f1b4Smrgstatic void
833464ebd5Sriastradhuserclip( struct gl_context *ctx,
847117f1b4Smrg          GLvector4f *clip,
857117f1b4Smrg          GLubyte *clipmask,
867117f1b4Smrg          GLubyte *clipormask,
877117f1b4Smrg          GLubyte *clipandmask )
887117f1b4Smrg{
8901e04c3fSmrg   GLbitfield mask = ctx->Transform.ClipPlanesEnabled;
9001e04c3fSmrg   while (mask) {
9101e04c3fSmrg      const int p = u_bit_scan(&mask);
9201e04c3fSmrg      GLuint nr, i;
9301e04c3fSmrg      const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
9401e04c3fSmrg      const GLfloat b = ctx->Transform._ClipUserPlane[p][1];
9501e04c3fSmrg      const GLfloat c = ctx->Transform._ClipUserPlane[p][2];
9601e04c3fSmrg      const GLfloat d = ctx->Transform._ClipUserPlane[p][3];
9701e04c3fSmrg      GLfloat *coord = (GLfloat *)clip->data;
9801e04c3fSmrg      GLuint stride = clip->stride;
9901e04c3fSmrg      GLuint count = clip->count;
10001e04c3fSmrg
10101e04c3fSmrg      for (nr = 0, i = 0 ; i < count ; i++) {
10201e04c3fSmrg         GLfloat dp = (coord[0] * a +
10301e04c3fSmrg                       coord[1] * b +
10401e04c3fSmrg                       coord[2] * c +
10501e04c3fSmrg                       coord[3] * d);
10601e04c3fSmrg
10701e04c3fSmrg         if (dp < 0) {
10801e04c3fSmrg            nr++;
10901e04c3fSmrg            clipmask[i] |= CLIP_USER_BIT;
11001e04c3fSmrg         }
11101e04c3fSmrg
11201e04c3fSmrg         STRIDE_F(coord, stride);
11301e04c3fSmrg      }
1147117f1b4Smrg
11501e04c3fSmrg      if (nr > 0) {
11601e04c3fSmrg         *clipormask |= CLIP_USER_BIT;
11701e04c3fSmrg         if (nr == count) {
11801e04c3fSmrg            *clipandmask |= CLIP_USER_BIT;
11901e04c3fSmrg            return;
12001e04c3fSmrg         }
1217117f1b4Smrg      }
1227117f1b4Smrg   }
1237117f1b4Smrg}
1247117f1b4Smrg
1257117f1b4Smrg
1267117f1b4Smrgstatic GLboolean
1273464ebd5Sriastradhdo_ndc_cliptest(struct gl_context *ctx, struct vp_stage_data *store)
1287117f1b4Smrg{
1297117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
1307117f1b4Smrg   struct vertex_buffer *VB = &tnl->vb;
1317117f1b4Smrg   /* Cliptest and perspective divide.  Clip functions must clear
1327117f1b4Smrg    * the clipmask.
1337117f1b4Smrg    */
1347117f1b4Smrg   store->ormask = 0;
1357117f1b4Smrg   store->andmask = CLIP_FRUSTUM_BITS;
1367117f1b4Smrg
1374a49301eSmrg   tnl_clip_prepare(ctx);
1384a49301eSmrg
1397117f1b4Smrg   if (tnl->NeedNdcCoords) {
1407117f1b4Smrg      VB->NdcPtr =
1417117f1b4Smrg         _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
1427117f1b4Smrg                                            &store->ndcCoords,
1437117f1b4Smrg                                            store->clipmask,
1447117f1b4Smrg                                            &store->ormask,
1454a49301eSmrg                                            &store->andmask,
14601e04c3fSmrg					    !(ctx->Transform.DepthClampNear &&
14701e04c3fSmrg                                              ctx->Transform.DepthClampFar) );
1487117f1b4Smrg   }
1497117f1b4Smrg   else {
1507117f1b4Smrg      VB->NdcPtr = NULL;
1517117f1b4Smrg      _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
1527117f1b4Smrg                                            NULL,
1537117f1b4Smrg                                            store->clipmask,
1547117f1b4Smrg                                            &store->ormask,
1554a49301eSmrg                                            &store->andmask,
15601e04c3fSmrg					    !(ctx->Transform.DepthClampNear &&
15701e04c3fSmrg                                              ctx->Transform.DepthClampFar) );
1587117f1b4Smrg   }
1597117f1b4Smrg
1607117f1b4Smrg   if (store->andmask) {
1617117f1b4Smrg      /* All vertices are outside the frustum */
1627117f1b4Smrg      return GL_FALSE;
1637117f1b4Smrg   }
1647117f1b4Smrg
1657117f1b4Smrg   /* Test userclip planes.  This contributes to VB->ClipMask.
1667117f1b4Smrg    */
1677117f1b4Smrg   /** XXX NEW_SLANG _Enabled ??? */
16801e04c3fSmrg   if (ctx->Transform.ClipPlanesEnabled &&
16901e04c3fSmrg       (!_mesa_arb_vertex_program_enabled(ctx) ||
17001e04c3fSmrg      ctx->VertexProgram.Current->arb.IsPositionInvariant)) {
1717117f1b4Smrg      userclip( ctx,
1727117f1b4Smrg		VB->ClipPtr,
1737117f1b4Smrg		store->clipmask,
1747117f1b4Smrg		&store->ormask,
1757117f1b4Smrg		&store->andmask );
1767117f1b4Smrg
1777117f1b4Smrg      if (store->andmask) {
1787117f1b4Smrg	 return GL_FALSE;
1797117f1b4Smrg      }
1807117f1b4Smrg   }
1817117f1b4Smrg
1827117f1b4Smrg   VB->ClipAndMask = store->andmask;
1837117f1b4Smrg   VB->ClipOrMask = store->ormask;
1847117f1b4Smrg   VB->ClipMask = store->clipmask;
1857117f1b4Smrg
1867117f1b4Smrg   return GL_TRUE;
1877117f1b4Smrg}
1887117f1b4Smrg
1897117f1b4Smrg
1907117f1b4Smrg/**
1917117f1b4Smrg * XXX the texture sampling code in this module is a bit of a hack.
1927117f1b4Smrg * The texture sampling code is in swrast, though it doesn't have any
1937117f1b4Smrg * real dependencies on the rest of swrast.  It should probably be
1947117f1b4Smrg * moved into main/ someday.
1957117f1b4Smrg */
1967117f1b4Smrgstatic void
1973464ebd5Sriastradhvp_fetch_texel(struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda,
1987117f1b4Smrg               GLuint unit, GLfloat color[4])
1997117f1b4Smrg{
2007117f1b4Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
2017117f1b4Smrg
2027117f1b4Smrg   /* XXX use a float-valued TextureSample routine here!!! */
203af69d88dSmrg   swrast->TextureSample[unit](ctx, _mesa_get_samplerobj(ctx, unit),
204af69d88dSmrg                               ctx->Texture.Unit[unit]._Current,
2057117f1b4Smrg                               1, (const GLfloat (*)[4]) texcoord,
2064a49301eSmrg                               &lambda,  (GLfloat (*)[4]) color);
2077117f1b4Smrg}
2087117f1b4Smrg
2097117f1b4Smrg
2107117f1b4Smrg/**
2117117f1b4Smrg * Called via ctx->Driver.ProgramStringNotify() after a new vertex program
2127117f1b4Smrg * string has been parsed.
2137117f1b4Smrg */
214cdc920a0SmrgGLboolean
2153464ebd5Sriastradh_tnl_program_string(struct gl_context *ctx, GLenum target, struct gl_program *program)
2167117f1b4Smrg{
2177117f1b4Smrg   /* No-op.
2187117f1b4Smrg    * If we had derived anything from the program that was private to this
2197117f1b4Smrg    * stage we'd recompute/validate it here.
2207117f1b4Smrg    */
221cdc920a0Smrg   return GL_TRUE;
2227117f1b4Smrg}
2237117f1b4Smrg
2247117f1b4Smrg
2257117f1b4Smrg/**
2267117f1b4Smrg * Initialize virtual machine state prior to executing vertex program.
2277117f1b4Smrg */
2287117f1b4Smrgstatic void
2293464ebd5Sriastradhinit_machine(struct gl_context *ctx, struct gl_program_machine *machine,
2303464ebd5Sriastradh             GLuint instID)
2317117f1b4Smrg{
2327117f1b4Smrg   /* Input registers get initialized from the current vertex attribs */
233cdc920a0Smrg   memcpy(machine->VertAttribs, ctx->Current.Attrib,
2344a49301eSmrg          MAX_VERTEX_GENERIC_ATTRIBS * 4 * sizeof(GLfloat));
2357117f1b4Smrg
2367117f1b4Smrg   machine->NumDeriv = 0;
2377117f1b4Smrg
2387117f1b4Smrg   /* init call stack */
2397117f1b4Smrg   machine->StackDepth = 0;
2407117f1b4Smrg
2417117f1b4Smrg   machine->FetchTexelLod = vp_fetch_texel;
2427117f1b4Smrg   machine->FetchTexelDeriv = NULL; /* not used by vertex programs */
243c1f859d4Smrg
24401e04c3fSmrg   machine->Samplers = ctx->VertexProgram._Current->SamplerUnits;
2453464ebd5Sriastradh
2463464ebd5Sriastradh   machine->SystemValues[SYSTEM_VALUE_INSTANCE_ID][0] = (GLfloat) instID;
2477117f1b4Smrg}
2487117f1b4Smrg
2497117f1b4Smrg
2507117f1b4Smrg/**
2517117f1b4Smrg * Map the texture images which the vertex program will access (if any).
2527117f1b4Smrg */
2537117f1b4Smrgstatic void
25401e04c3fSmrgmap_textures(struct gl_context *ctx, const struct gl_program *vp)
2557117f1b4Smrg{
2567117f1b4Smrg   GLuint u;
2577117f1b4Smrg
258af69d88dSmrg   for (u = 0; u < ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits; u++) {
25901e04c3fSmrg      if (vp->TexturesUsed[u]) {
2607117f1b4Smrg         /* Note: _Current *should* correspond to the target indicated
2617117f1b4Smrg          * in TexturesUsed[u].
2627117f1b4Smrg          */
263af69d88dSmrg         _swrast_map_texture(ctx, ctx->Texture.Unit[u]._Current);
2647117f1b4Smrg      }
2657117f1b4Smrg   }
2667117f1b4Smrg}
2677117f1b4Smrg
2687117f1b4Smrg
2697117f1b4Smrg/**
2707117f1b4Smrg * Unmap the texture images which were used by the vertex program (if any).
2717117f1b4Smrg */
2727117f1b4Smrgstatic void
27301e04c3fSmrgunmap_textures(struct gl_context *ctx, const struct gl_program *vp)
2747117f1b4Smrg{
2757117f1b4Smrg   GLuint u;
2767117f1b4Smrg
277af69d88dSmrg   for (u = 0; u < ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits; u++) {
27801e04c3fSmrg      if (vp->TexturesUsed[u]) {
2797117f1b4Smrg         /* Note: _Current *should* correspond to the target indicated
2807117f1b4Smrg          * in TexturesUsed[u].
2817117f1b4Smrg          */
282af69d88dSmrg         _swrast_unmap_texture(ctx, ctx->Texture.Unit[u]._Current);
2837117f1b4Smrg      }
2847117f1b4Smrg   }
2857117f1b4Smrg}
2867117f1b4Smrg
2877117f1b4Smrg
2887117f1b4Smrg/**
2897117f1b4Smrg * This function executes vertex programs
2907117f1b4Smrg */
2917117f1b4Smrgstatic GLboolean
2923464ebd5Sriastradhrun_vp( struct gl_context *ctx, struct tnl_pipeline_stage *stage )
2937117f1b4Smrg{
2947117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
2957117f1b4Smrg   struct vp_stage_data *store = VP_STAGE_DATA(stage);
2967117f1b4Smrg   struct vertex_buffer *VB = &tnl->vb;
29701e04c3fSmrg   struct gl_program *program = ctx->VertexProgram._Current;
2983464ebd5Sriastradh   struct gl_program_machine *machine = &store->machine;
299af69d88dSmrg   GLuint outputs[VARYING_SLOT_MAX], numOutputs;
3007117f1b4Smrg   GLuint i, j;
3017117f1b4Smrg
3027117f1b4Smrg   if (!program)
3037117f1b4Smrg      return GL_TRUE;
3047117f1b4Smrg
305af69d88dSmrg   /* ARB program or vertex shader */
30601e04c3fSmrg   _mesa_load_state_parameters(ctx, program->Parameters);
3077117f1b4Smrg
3087117f1b4Smrg   /* make list of outputs to save some time below */
3097117f1b4Smrg   numOutputs = 0;
310af69d88dSmrg   for (i = 0; i < VARYING_SLOT_MAX; i++) {
31101e04c3fSmrg      if (program->info.outputs_written & BITFIELD64_BIT(i)) {
3127117f1b4Smrg         outputs[numOutputs++] = i;
3137117f1b4Smrg      }
3147117f1b4Smrg   }
3157117f1b4Smrg
316af69d88dSmrg   /* Allocate result vectors.  We delay this until now to avoid allocating
317af69d88dSmrg    * memory that would never be used if we don't run the software tnl pipeline.
318af69d88dSmrg    */
319af69d88dSmrg   if (!store->results[0].storage) {
320af69d88dSmrg      for (i = 0; i < VARYING_SLOT_MAX; i++) {
321af69d88dSmrg         assert(!store->results[i].storage);
322af69d88dSmrg         _mesa_vector4f_alloc( &store->results[i], 0, VB->Size, 32 );
323af69d88dSmrg         store->results[i].size = 4;
324af69d88dSmrg      }
325af69d88dSmrg   }
326af69d88dSmrg
3277117f1b4Smrg   map_textures(ctx, program);
3287117f1b4Smrg
3297117f1b4Smrg   for (i = 0; i < VB->Count; i++) {
3307117f1b4Smrg      GLuint attr;
3317117f1b4Smrg
3323464ebd5Sriastradh      init_machine(ctx, machine, tnl->CurInstance);
3337117f1b4Smrg
3347117f1b4Smrg#if 0
3357117f1b4Smrg      printf("Input  %d: %f, %f, %f, %f\n", i,
3367117f1b4Smrg             VB->AttribPtr[0]->data[i][0],
3377117f1b4Smrg             VB->AttribPtr[0]->data[i][1],
3387117f1b4Smrg             VB->AttribPtr[0]->data[i][2],
3397117f1b4Smrg             VB->AttribPtr[0]->data[i][3]);
3407117f1b4Smrg      printf("   color: %f, %f, %f, %f\n",
3417117f1b4Smrg             VB->AttribPtr[3]->data[i][0],
3427117f1b4Smrg             VB->AttribPtr[3]->data[i][1],
3437117f1b4Smrg             VB->AttribPtr[3]->data[i][2],
3447117f1b4Smrg             VB->AttribPtr[3]->data[i][3]);
3457117f1b4Smrg      printf("  normal: %f, %f, %f, %f\n",
3467117f1b4Smrg             VB->AttribPtr[2]->data[i][0],
3477117f1b4Smrg             VB->AttribPtr[2]->data[i][1],
3487117f1b4Smrg             VB->AttribPtr[2]->data[i][2],
3497117f1b4Smrg             VB->AttribPtr[2]->data[i][3]);
3507117f1b4Smrg#endif
3517117f1b4Smrg
3527117f1b4Smrg      /* the vertex array case */
3537117f1b4Smrg      for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
35401e04c3fSmrg	 if (program->info.inputs_read & BITFIELD64_BIT(attr)) {
3557117f1b4Smrg	    const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data;
3567117f1b4Smrg	    const GLuint size = VB->AttribPtr[attr]->size;
3577117f1b4Smrg	    const GLuint stride = VB->AttribPtr[attr]->stride;
3587117f1b4Smrg	    const GLfloat *data = (GLfloat *) (ptr + stride * i);
3594a49301eSmrg#ifdef NAN_CHECK
3604a49301eSmrg            check_float(data[0]);
3614a49301eSmrg            check_float(data[1]);
3624a49301eSmrg            check_float(data[2]);
3634a49301eSmrg            check_float(data[3]);
3644a49301eSmrg#endif
3653464ebd5Sriastradh	    COPY_CLEAN_4V(machine->VertAttribs[attr], size, data);
3667117f1b4Smrg	 }
3677117f1b4Smrg      }
3687117f1b4Smrg
3697117f1b4Smrg      /* execute the program */
37001e04c3fSmrg      _mesa_execute_program(ctx, program, machine);
3717117f1b4Smrg
3727117f1b4Smrg      /* copy the output registers into the VB->attribs arrays */
3737117f1b4Smrg      for (j = 0; j < numOutputs; j++) {
3747117f1b4Smrg         const GLuint attr = outputs[j];
3754a49301eSmrg#ifdef NAN_CHECK
3763464ebd5Sriastradh         check_float(machine->Outputs[attr][0]);
3773464ebd5Sriastradh         check_float(machine->Outputs[attr][1]);
3783464ebd5Sriastradh         check_float(machine->Outputs[attr][2]);
3793464ebd5Sriastradh         check_float(machine->Outputs[attr][3]);
3804a49301eSmrg#endif
3813464ebd5Sriastradh         COPY_4V(store->results[attr].data[i], machine->Outputs[attr]);
3827117f1b4Smrg      }
3834a49301eSmrg
3844a49301eSmrg      /* FOGC is a special case.  Fragment shader expects (f,0,0,1) */
38501e04c3fSmrg      if (program->info.outputs_written & BITFIELD64_BIT(VARYING_SLOT_FOGC)) {
386af69d88dSmrg         store->results[VARYING_SLOT_FOGC].data[i][1] = 0.0;
387af69d88dSmrg         store->results[VARYING_SLOT_FOGC].data[i][2] = 0.0;
388af69d88dSmrg         store->results[VARYING_SLOT_FOGC].data[i][3] = 1.0;
3894a49301eSmrg      }
3904a49301eSmrg#ifdef NAN_CHECK
39101e04c3fSmrg      assert(machine->Outputs[0][3] != 0.0F);
3924a49301eSmrg#endif
3937117f1b4Smrg#if 0
3947117f1b4Smrg      printf("HPOS: %f %f %f %f\n",
3957ec681f3Smrg             machine->Outputs[0][0],
3967ec681f3Smrg             machine->Outputs[0][1],
3977ec681f3Smrg             machine->Outputs[0][2],
3983464ebd5Sriastradh             machine->Outputs[0][3]);
3997117f1b4Smrg#endif
4007117f1b4Smrg   }
4017117f1b4Smrg
4027117f1b4Smrg   unmap_textures(ctx, program);
4037117f1b4Smrg
40401e04c3fSmrg   if (program->arb.IsPositionInvariant) {
4057ec681f3Smrg      /* make sure the inverse is up to date */
4067ec681f3Smrg      _math_matrix_analyse(&ctx->_ModelProjectMatrix);
4077ec681f3Smrg
4087117f1b4Smrg      /* We need the exact same transform as in the fixed function path here
4097117f1b4Smrg       * to guarantee invariance, depending on compiler optimization flags
4107117f1b4Smrg       * results could be different otherwise.
4117117f1b4Smrg       */
4127117f1b4Smrg      VB->ClipPtr = TransformRaw( &store->results[0],
4137117f1b4Smrg				  &ctx->_ModelProjectMatrix,
4147117f1b4Smrg				  VB->AttribPtr[0] );
4157117f1b4Smrg
4167117f1b4Smrg      /* Drivers expect this to be clean to element 4...
4177117f1b4Smrg       */
4187117f1b4Smrg      switch (VB->ClipPtr->size) {
4197117f1b4Smrg      case 1:
4207117f1b4Smrg	 /* impossible */
4217117f1b4Smrg      case 2:
4227117f1b4Smrg	 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 );
4237ec681f3Smrg	 FALLTHROUGH;
4247117f1b4Smrg      case 3:
4257117f1b4Smrg	 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 );
4267ec681f3Smrg	 FALLTHROUGH;
4277117f1b4Smrg      case 4:
4287117f1b4Smrg	 break;
4297117f1b4Smrg      }
4307117f1b4Smrg   }
4317117f1b4Smrg   else {
4327117f1b4Smrg      /* Setup the VB pointers so that the next pipeline stages get
4337117f1b4Smrg       * their data from the right place (the program output arrays).
4347117f1b4Smrg       */
435af69d88dSmrg      VB->ClipPtr = &store->results[VARYING_SLOT_POS];
4367117f1b4Smrg      VB->ClipPtr->size = 4;
4377117f1b4Smrg      VB->ClipPtr->count = VB->Count;
4387117f1b4Smrg   }
4397117f1b4Smrg
440af69d88dSmrg   VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->results[VARYING_SLOT_COL0];
441af69d88dSmrg   VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->results[VARYING_SLOT_COL1];
442af69d88dSmrg   VB->AttribPtr[VERT_ATTRIB_FOG] = &store->results[VARYING_SLOT_FOGC];
443af69d88dSmrg   VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->results[VARYING_SLOT_PSIZ];
444af69d88dSmrg   VB->BackfaceColorPtr = &store->results[VARYING_SLOT_BFC0];
445af69d88dSmrg   VB->BackfaceSecondaryColorPtr = &store->results[VARYING_SLOT_BFC1];
4467117f1b4Smrg
4477117f1b4Smrg   for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
4487117f1b4Smrg      VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]
449af69d88dSmrg         = &store->results[VARYING_SLOT_TEX0 + i];
4507117f1b4Smrg   }
4517117f1b4Smrg
4527117f1b4Smrg   for (i = 0; i < ctx->Const.MaxVarying; i++) {
45301e04c3fSmrg      if (program->info.outputs_written &
45401e04c3fSmrg          BITFIELD64_BIT(VARYING_SLOT_VAR0 + i)) {
4557117f1b4Smrg         /* Note: varying results get put into the generic attributes */
4567117f1b4Smrg	 VB->AttribPtr[VERT_ATTRIB_GENERIC0+i]
457af69d88dSmrg            = &store->results[VARYING_SLOT_VAR0 + i];
4587117f1b4Smrg      }
4597117f1b4Smrg   }
4607117f1b4Smrg
4617117f1b4Smrg
4627117f1b4Smrg   /* Perform NDC and cliptest operations:
4637117f1b4Smrg    */
4647117f1b4Smrg   return do_ndc_cliptest(ctx, store);
4657117f1b4Smrg}
4667117f1b4Smrg
4677117f1b4Smrg
4687117f1b4Smrg/**
4697117f1b4Smrg * Called the first time stage->run is called.  In effect, don't
4707117f1b4Smrg * allocate data until the first time the stage is run.
4717117f1b4Smrg */
4727117f1b4Smrgstatic GLboolean
4733464ebd5Sriastradhinit_vp(struct gl_context *ctx, struct tnl_pipeline_stage *stage)
4747117f1b4Smrg{
4757117f1b4Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
4767117f1b4Smrg   struct vertex_buffer *VB = &(tnl->vb);
4777117f1b4Smrg   struct vp_stage_data *store;
4787117f1b4Smrg   const GLuint size = VB->Size;
4797117f1b4Smrg
480af69d88dSmrg   stage->privatePtr = calloc(1, sizeof(*store));
4817117f1b4Smrg   store = VP_STAGE_DATA(stage);
4827117f1b4Smrg   if (!store)
4837117f1b4Smrg      return GL_FALSE;
4847117f1b4Smrg
4857117f1b4Smrg   /* a few other misc allocations */
4867117f1b4Smrg   _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 );
4877ec681f3Smrg   store->clipmask = align_malloc(sizeof(GLubyte)*size, 32 );
4887117f1b4Smrg
4897117f1b4Smrg   return GL_TRUE;
4907117f1b4Smrg}
4917117f1b4Smrg
4927117f1b4Smrg
4937117f1b4Smrg/**
4947117f1b4Smrg * Destructor for this pipeline stage.
4957117f1b4Smrg */
4967117f1b4Smrgstatic void
4977117f1b4Smrgdtr(struct tnl_pipeline_stage *stage)
4987117f1b4Smrg{
4997117f1b4Smrg   struct vp_stage_data *store = VP_STAGE_DATA(stage);
5007117f1b4Smrg
5017117f1b4Smrg   if (store) {
5027117f1b4Smrg      GLuint i;
5037117f1b4Smrg
5047117f1b4Smrg      /* free the vertex program result arrays */
505af69d88dSmrg      for (i = 0; i < VARYING_SLOT_MAX; i++)
5067117f1b4Smrg         _mesa_vector4f_free( &store->results[i] );
5077117f1b4Smrg
5087117f1b4Smrg      /* free misc arrays */
5097117f1b4Smrg      _mesa_vector4f_free( &store->ndcCoords );
5107ec681f3Smrg      align_free( store->clipmask );
5117117f1b4Smrg
512af69d88dSmrg      free( store );
5137117f1b4Smrg      stage->privatePtr = NULL;
5147117f1b4Smrg   }
5157117f1b4Smrg}
5167117f1b4Smrg
5177117f1b4Smrg
5187117f1b4Smrgstatic void
5193464ebd5Sriastradhvalidate_vp_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage)
5207117f1b4Smrg{
5217117f1b4Smrg   if (ctx->VertexProgram._Current) {
5227117f1b4Smrg      _swrast_update_texture_samplers(ctx);
5237117f1b4Smrg   }
5247117f1b4Smrg}
5257117f1b4Smrg
5267117f1b4Smrg
5277117f1b4Smrg
5287117f1b4Smrg/**
5297117f1b4Smrg * Public description of this pipeline stage.
5307117f1b4Smrg */
5317117f1b4Smrgconst struct tnl_pipeline_stage _tnl_vertex_program_stage =
5327117f1b4Smrg{
5337117f1b4Smrg   "vertex-program",
5347117f1b4Smrg   NULL,			/* private_data */
5357117f1b4Smrg   init_vp,			/* create */
5367117f1b4Smrg   dtr,				/* destroy */
5377117f1b4Smrg   validate_vp_stage, 		/* validate */
5387117f1b4Smrg   run_vp			/* run -- initially set to ctr */
5397117f1b4Smrg};
540