1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6848b8605Smrg *
7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
8848b8605Smrg * copy of this software and associated documentation files (the "Software"),
9848b8605Smrg * to deal in the Software without restriction, including without limitation
10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
12848b8605Smrg * Software is furnished to do so, subject to the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice shall be included
15848b8605Smrg * in all copies or substantial portions of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
24848b8605Smrg */
25848b8605Smrg
26848b8605Smrg
27848b8605Smrg/**
28848b8605Smrg * \file tnl/t_vb_program.c
29848b8605Smrg * \brief Pipeline stage for executing vertex programs.
30848b8605Smrg * \author Brian Paul,  Keith Whitwell
31848b8605Smrg */
32848b8605Smrg
33848b8605Smrg
34848b8605Smrg#include "main/glheader.h"
35848b8605Smrg#include "main/macros.h"
36848b8605Smrg#include "main/imports.h"
37848b8605Smrg#include "main/samplerobj.h"
38b8e80941Smrg#include "main/state.h"
39848b8605Smrg#include "math/m_xform.h"
40848b8605Smrg#include "program/prog_instruction.h"
41848b8605Smrg#include "program/prog_statevars.h"
42848b8605Smrg#include "program/prog_execute.h"
43848b8605Smrg#include "swrast/s_context.h"
44b8e80941Smrg#include "util/bitscan.h"
45848b8605Smrg
46848b8605Smrg#include "tnl/tnl.h"
47848b8605Smrg#include "tnl/t_context.h"
48848b8605Smrg#include "tnl/t_pipeline.h"
49848b8605Smrg
50848b8605Smrg
51848b8605Smrg#ifdef NAN_CHECK
52848b8605Smrg/** Check for NaNs and very large values */
53848b8605Smrgstatic inline void
54848b8605Smrgcheck_float(float x)
55848b8605Smrg{
56848b8605Smrg   assert(!IS_INF_OR_NAN(x));
57848b8605Smrg   assert(1.0e-15 <= x && x <= 1.0e15);
58848b8605Smrg}
59848b8605Smrg#endif
60848b8605Smrg
61848b8605Smrg
62848b8605Smrg/*!
63848b8605Smrg * Private storage for the vertex program pipeline stage.
64848b8605Smrg */
65848b8605Smrgstruct vp_stage_data {
66848b8605Smrg   /** The results of running the vertex program go into these arrays. */
67848b8605Smrg   GLvector4f results[VARYING_SLOT_MAX];
68848b8605Smrg
69848b8605Smrg   GLvector4f ndcCoords;              /**< normalized device coords */
70848b8605Smrg   GLubyte *clipmask;                 /**< clip flags */
71848b8605Smrg   GLubyte ormask, andmask;           /**< for clipping */
72848b8605Smrg
73848b8605Smrg   GLboolean vertex_textures;
74848b8605Smrg
75848b8605Smrg   struct gl_program_machine machine;
76848b8605Smrg};
77848b8605Smrg
78848b8605Smrg
79848b8605Smrg#define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr))
80848b8605Smrg
81848b8605Smrg
82848b8605Smrgstatic void
83848b8605Smrguserclip( struct gl_context *ctx,
84848b8605Smrg          GLvector4f *clip,
85848b8605Smrg          GLubyte *clipmask,
86848b8605Smrg          GLubyte *clipormask,
87848b8605Smrg          GLubyte *clipandmask )
88848b8605Smrg{
89b8e80941Smrg   GLbitfield mask = ctx->Transform.ClipPlanesEnabled;
90b8e80941Smrg   while (mask) {
91b8e80941Smrg      const int p = u_bit_scan(&mask);
92b8e80941Smrg      GLuint nr, i;
93b8e80941Smrg      const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
94b8e80941Smrg      const GLfloat b = ctx->Transform._ClipUserPlane[p][1];
95b8e80941Smrg      const GLfloat c = ctx->Transform._ClipUserPlane[p][2];
96b8e80941Smrg      const GLfloat d = ctx->Transform._ClipUserPlane[p][3];
97b8e80941Smrg      GLfloat *coord = (GLfloat *)clip->data;
98b8e80941Smrg      GLuint stride = clip->stride;
99b8e80941Smrg      GLuint count = clip->count;
100b8e80941Smrg
101b8e80941Smrg      for (nr = 0, i = 0 ; i < count ; i++) {
102b8e80941Smrg         GLfloat dp = (coord[0] * a +
103b8e80941Smrg                       coord[1] * b +
104b8e80941Smrg                       coord[2] * c +
105b8e80941Smrg                       coord[3] * d);
106b8e80941Smrg
107b8e80941Smrg         if (dp < 0) {
108b8e80941Smrg            nr++;
109b8e80941Smrg            clipmask[i] |= CLIP_USER_BIT;
110b8e80941Smrg         }
111b8e80941Smrg
112b8e80941Smrg         STRIDE_F(coord, stride);
113b8e80941Smrg      }
114848b8605Smrg
115b8e80941Smrg      if (nr > 0) {
116b8e80941Smrg         *clipormask |= CLIP_USER_BIT;
117b8e80941Smrg         if (nr == count) {
118b8e80941Smrg            *clipandmask |= CLIP_USER_BIT;
119b8e80941Smrg            return;
120b8e80941Smrg         }
121848b8605Smrg      }
122848b8605Smrg   }
123848b8605Smrg}
124848b8605Smrg
125848b8605Smrg
126848b8605Smrgstatic GLboolean
127848b8605Smrgdo_ndc_cliptest(struct gl_context *ctx, struct vp_stage_data *store)
128848b8605Smrg{
129848b8605Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
130848b8605Smrg   struct vertex_buffer *VB = &tnl->vb;
131848b8605Smrg   /* Cliptest and perspective divide.  Clip functions must clear
132848b8605Smrg    * the clipmask.
133848b8605Smrg    */
134848b8605Smrg   store->ormask = 0;
135848b8605Smrg   store->andmask = CLIP_FRUSTUM_BITS;
136848b8605Smrg
137848b8605Smrg   tnl_clip_prepare(ctx);
138848b8605Smrg
139848b8605Smrg   if (tnl->NeedNdcCoords) {
140848b8605Smrg      VB->NdcPtr =
141848b8605Smrg         _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
142848b8605Smrg                                            &store->ndcCoords,
143848b8605Smrg                                            store->clipmask,
144848b8605Smrg                                            &store->ormask,
145848b8605Smrg                                            &store->andmask,
146b8e80941Smrg					    !(ctx->Transform.DepthClampNear &&
147b8e80941Smrg                                              ctx->Transform.DepthClampFar) );
148848b8605Smrg   }
149848b8605Smrg   else {
150848b8605Smrg      VB->NdcPtr = NULL;
151848b8605Smrg      _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
152848b8605Smrg                                            NULL,
153848b8605Smrg                                            store->clipmask,
154848b8605Smrg                                            &store->ormask,
155848b8605Smrg                                            &store->andmask,
156b8e80941Smrg					    !(ctx->Transform.DepthClampNear &&
157b8e80941Smrg                                              ctx->Transform.DepthClampFar) );
158848b8605Smrg   }
159848b8605Smrg
160848b8605Smrg   if (store->andmask) {
161848b8605Smrg      /* All vertices are outside the frustum */
162848b8605Smrg      return GL_FALSE;
163848b8605Smrg   }
164848b8605Smrg
165848b8605Smrg   /* Test userclip planes.  This contributes to VB->ClipMask.
166848b8605Smrg    */
167848b8605Smrg   /** XXX NEW_SLANG _Enabled ??? */
168b8e80941Smrg   if (ctx->Transform.ClipPlanesEnabled &&
169b8e80941Smrg       (!_mesa_arb_vertex_program_enabled(ctx) ||
170b8e80941Smrg      ctx->VertexProgram.Current->arb.IsPositionInvariant)) {
171848b8605Smrg      userclip( ctx,
172848b8605Smrg		VB->ClipPtr,
173848b8605Smrg		store->clipmask,
174848b8605Smrg		&store->ormask,
175848b8605Smrg		&store->andmask );
176848b8605Smrg
177848b8605Smrg      if (store->andmask) {
178848b8605Smrg	 return GL_FALSE;
179848b8605Smrg      }
180848b8605Smrg   }
181848b8605Smrg
182848b8605Smrg   VB->ClipAndMask = store->andmask;
183848b8605Smrg   VB->ClipOrMask = store->ormask;
184848b8605Smrg   VB->ClipMask = store->clipmask;
185848b8605Smrg
186848b8605Smrg   return GL_TRUE;
187848b8605Smrg}
188848b8605Smrg
189848b8605Smrg
190848b8605Smrg/**
191848b8605Smrg * XXX the texture sampling code in this module is a bit of a hack.
192848b8605Smrg * The texture sampling code is in swrast, though it doesn't have any
193848b8605Smrg * real dependencies on the rest of swrast.  It should probably be
194848b8605Smrg * moved into main/ someday.
195848b8605Smrg */
196848b8605Smrgstatic void
197848b8605Smrgvp_fetch_texel(struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda,
198848b8605Smrg               GLuint unit, GLfloat color[4])
199848b8605Smrg{
200848b8605Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
201848b8605Smrg
202848b8605Smrg   /* XXX use a float-valued TextureSample routine here!!! */
203848b8605Smrg   swrast->TextureSample[unit](ctx, _mesa_get_samplerobj(ctx, unit),
204848b8605Smrg                               ctx->Texture.Unit[unit]._Current,
205848b8605Smrg                               1, (const GLfloat (*)[4]) texcoord,
206848b8605Smrg                               &lambda,  (GLfloat (*)[4]) color);
207848b8605Smrg}
208848b8605Smrg
209848b8605Smrg
210848b8605Smrg/**
211848b8605Smrg * Called via ctx->Driver.ProgramStringNotify() after a new vertex program
212848b8605Smrg * string has been parsed.
213848b8605Smrg */
214848b8605SmrgGLboolean
215848b8605Smrg_tnl_program_string(struct gl_context *ctx, GLenum target, struct gl_program *program)
216848b8605Smrg{
217848b8605Smrg   /* No-op.
218848b8605Smrg    * If we had derived anything from the program that was private to this
219848b8605Smrg    * stage we'd recompute/validate it here.
220848b8605Smrg    */
221848b8605Smrg   return GL_TRUE;
222848b8605Smrg}
223848b8605Smrg
224848b8605Smrg
225848b8605Smrg/**
226848b8605Smrg * Initialize virtual machine state prior to executing vertex program.
227848b8605Smrg */
228848b8605Smrgstatic void
229848b8605Smrginit_machine(struct gl_context *ctx, struct gl_program_machine *machine,
230848b8605Smrg             GLuint instID)
231848b8605Smrg{
232848b8605Smrg   /* Input registers get initialized from the current vertex attribs */
233848b8605Smrg   memcpy(machine->VertAttribs, ctx->Current.Attrib,
234848b8605Smrg          MAX_VERTEX_GENERIC_ATTRIBS * 4 * sizeof(GLfloat));
235848b8605Smrg
236848b8605Smrg   machine->NumDeriv = 0;
237848b8605Smrg
238848b8605Smrg   /* init call stack */
239848b8605Smrg   machine->StackDepth = 0;
240848b8605Smrg
241848b8605Smrg   machine->FetchTexelLod = vp_fetch_texel;
242848b8605Smrg   machine->FetchTexelDeriv = NULL; /* not used by vertex programs */
243848b8605Smrg
244b8e80941Smrg   machine->Samplers = ctx->VertexProgram._Current->SamplerUnits;
245848b8605Smrg
246848b8605Smrg   machine->SystemValues[SYSTEM_VALUE_INSTANCE_ID][0] = (GLfloat) instID;
247848b8605Smrg}
248848b8605Smrg
249848b8605Smrg
250848b8605Smrg/**
251848b8605Smrg * Map the texture images which the vertex program will access (if any).
252848b8605Smrg */
253848b8605Smrgstatic void
254b8e80941Smrgmap_textures(struct gl_context *ctx, const struct gl_program *vp)
255848b8605Smrg{
256848b8605Smrg   GLuint u;
257848b8605Smrg
258848b8605Smrg   for (u = 0; u < ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits; u++) {
259b8e80941Smrg      if (vp->TexturesUsed[u]) {
260848b8605Smrg         /* Note: _Current *should* correspond to the target indicated
261848b8605Smrg          * in TexturesUsed[u].
262848b8605Smrg          */
263848b8605Smrg         _swrast_map_texture(ctx, ctx->Texture.Unit[u]._Current);
264848b8605Smrg      }
265848b8605Smrg   }
266848b8605Smrg}
267848b8605Smrg
268848b8605Smrg
269848b8605Smrg/**
270848b8605Smrg * Unmap the texture images which were used by the vertex program (if any).
271848b8605Smrg */
272848b8605Smrgstatic void
273b8e80941Smrgunmap_textures(struct gl_context *ctx, const struct gl_program *vp)
274848b8605Smrg{
275848b8605Smrg   GLuint u;
276848b8605Smrg
277848b8605Smrg   for (u = 0; u < ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits; u++) {
278b8e80941Smrg      if (vp->TexturesUsed[u]) {
279848b8605Smrg         /* Note: _Current *should* correspond to the target indicated
280848b8605Smrg          * in TexturesUsed[u].
281848b8605Smrg          */
282848b8605Smrg         _swrast_unmap_texture(ctx, ctx->Texture.Unit[u]._Current);
283848b8605Smrg      }
284848b8605Smrg   }
285848b8605Smrg}
286848b8605Smrg
287848b8605Smrg
288848b8605Smrg/**
289848b8605Smrg * This function executes vertex programs
290848b8605Smrg */
291848b8605Smrgstatic GLboolean
292848b8605Smrgrun_vp( struct gl_context *ctx, struct tnl_pipeline_stage *stage )
293848b8605Smrg{
294848b8605Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
295848b8605Smrg   struct vp_stage_data *store = VP_STAGE_DATA(stage);
296848b8605Smrg   struct vertex_buffer *VB = &tnl->vb;
297b8e80941Smrg   struct gl_program *program = ctx->VertexProgram._Current;
298848b8605Smrg   struct gl_program_machine *machine = &store->machine;
299848b8605Smrg   GLuint outputs[VARYING_SLOT_MAX], numOutputs;
300848b8605Smrg   GLuint i, j;
301848b8605Smrg
302848b8605Smrg   if (!program)
303848b8605Smrg      return GL_TRUE;
304848b8605Smrg
305848b8605Smrg   /* ARB program or vertex shader */
306b8e80941Smrg   _mesa_load_state_parameters(ctx, program->Parameters);
307848b8605Smrg
308848b8605Smrg   /* make list of outputs to save some time below */
309848b8605Smrg   numOutputs = 0;
310848b8605Smrg   for (i = 0; i < VARYING_SLOT_MAX; i++) {
311b8e80941Smrg      if (program->info.outputs_written & BITFIELD64_BIT(i)) {
312848b8605Smrg         outputs[numOutputs++] = i;
313848b8605Smrg      }
314848b8605Smrg   }
315848b8605Smrg
316848b8605Smrg   /* Allocate result vectors.  We delay this until now to avoid allocating
317848b8605Smrg    * memory that would never be used if we don't run the software tnl pipeline.
318848b8605Smrg    */
319848b8605Smrg   if (!store->results[0].storage) {
320848b8605Smrg      for (i = 0; i < VARYING_SLOT_MAX; i++) {
321848b8605Smrg         assert(!store->results[i].storage);
322848b8605Smrg         _mesa_vector4f_alloc( &store->results[i], 0, VB->Size, 32 );
323848b8605Smrg         store->results[i].size = 4;
324848b8605Smrg      }
325848b8605Smrg   }
326848b8605Smrg
327848b8605Smrg   map_textures(ctx, program);
328848b8605Smrg
329848b8605Smrg   for (i = 0; i < VB->Count; i++) {
330848b8605Smrg      GLuint attr;
331848b8605Smrg
332848b8605Smrg      init_machine(ctx, machine, tnl->CurInstance);
333848b8605Smrg
334848b8605Smrg#if 0
335848b8605Smrg      printf("Input  %d: %f, %f, %f, %f\n", i,
336848b8605Smrg             VB->AttribPtr[0]->data[i][0],
337848b8605Smrg             VB->AttribPtr[0]->data[i][1],
338848b8605Smrg             VB->AttribPtr[0]->data[i][2],
339848b8605Smrg             VB->AttribPtr[0]->data[i][3]);
340848b8605Smrg      printf("   color: %f, %f, %f, %f\n",
341848b8605Smrg             VB->AttribPtr[3]->data[i][0],
342848b8605Smrg             VB->AttribPtr[3]->data[i][1],
343848b8605Smrg             VB->AttribPtr[3]->data[i][2],
344848b8605Smrg             VB->AttribPtr[3]->data[i][3]);
345848b8605Smrg      printf("  normal: %f, %f, %f, %f\n",
346848b8605Smrg             VB->AttribPtr[2]->data[i][0],
347848b8605Smrg             VB->AttribPtr[2]->data[i][1],
348848b8605Smrg             VB->AttribPtr[2]->data[i][2],
349848b8605Smrg             VB->AttribPtr[2]->data[i][3]);
350848b8605Smrg#endif
351848b8605Smrg
352848b8605Smrg      /* the vertex array case */
353848b8605Smrg      for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
354b8e80941Smrg	 if (program->info.inputs_read & BITFIELD64_BIT(attr)) {
355848b8605Smrg	    const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data;
356848b8605Smrg	    const GLuint size = VB->AttribPtr[attr]->size;
357848b8605Smrg	    const GLuint stride = VB->AttribPtr[attr]->stride;
358848b8605Smrg	    const GLfloat *data = (GLfloat *) (ptr + stride * i);
359848b8605Smrg#ifdef NAN_CHECK
360848b8605Smrg            check_float(data[0]);
361848b8605Smrg            check_float(data[1]);
362848b8605Smrg            check_float(data[2]);
363848b8605Smrg            check_float(data[3]);
364848b8605Smrg#endif
365848b8605Smrg	    COPY_CLEAN_4V(machine->VertAttribs[attr], size, data);
366848b8605Smrg	 }
367848b8605Smrg      }
368848b8605Smrg
369848b8605Smrg      /* execute the program */
370b8e80941Smrg      _mesa_execute_program(ctx, program, machine);
371848b8605Smrg
372848b8605Smrg      /* copy the output registers into the VB->attribs arrays */
373848b8605Smrg      for (j = 0; j < numOutputs; j++) {
374848b8605Smrg         const GLuint attr = outputs[j];
375848b8605Smrg#ifdef NAN_CHECK
376848b8605Smrg         check_float(machine->Outputs[attr][0]);
377848b8605Smrg         check_float(machine->Outputs[attr][1]);
378848b8605Smrg         check_float(machine->Outputs[attr][2]);
379848b8605Smrg         check_float(machine->Outputs[attr][3]);
380848b8605Smrg#endif
381848b8605Smrg         COPY_4V(store->results[attr].data[i], machine->Outputs[attr]);
382848b8605Smrg      }
383848b8605Smrg
384848b8605Smrg      /* FOGC is a special case.  Fragment shader expects (f,0,0,1) */
385b8e80941Smrg      if (program->info.outputs_written & BITFIELD64_BIT(VARYING_SLOT_FOGC)) {
386848b8605Smrg         store->results[VARYING_SLOT_FOGC].data[i][1] = 0.0;
387848b8605Smrg         store->results[VARYING_SLOT_FOGC].data[i][2] = 0.0;
388848b8605Smrg         store->results[VARYING_SLOT_FOGC].data[i][3] = 1.0;
389848b8605Smrg      }
390848b8605Smrg#ifdef NAN_CHECK
391b8e80941Smrg      assert(machine->Outputs[0][3] != 0.0F);
392848b8605Smrg#endif
393848b8605Smrg#if 0
394848b8605Smrg      printf("HPOS: %f %f %f %f\n",
395848b8605Smrg             machine->Outputs[0][0],
396848b8605Smrg             machine->Outputs[0][1],
397848b8605Smrg             machine->Outputs[0][2],
398848b8605Smrg             machine->Outputs[0][3]);
399848b8605Smrg#endif
400848b8605Smrg   }
401848b8605Smrg
402848b8605Smrg   unmap_textures(ctx, program);
403848b8605Smrg
404b8e80941Smrg   if (program->arb.IsPositionInvariant) {
405848b8605Smrg      /* We need the exact same transform as in the fixed function path here
406848b8605Smrg       * to guarantee invariance, depending on compiler optimization flags
407848b8605Smrg       * results could be different otherwise.
408848b8605Smrg       */
409848b8605Smrg      VB->ClipPtr = TransformRaw( &store->results[0],
410848b8605Smrg				  &ctx->_ModelProjectMatrix,
411848b8605Smrg				  VB->AttribPtr[0] );
412848b8605Smrg
413848b8605Smrg      /* Drivers expect this to be clean to element 4...
414848b8605Smrg       */
415848b8605Smrg      switch (VB->ClipPtr->size) {
416848b8605Smrg      case 1:
417848b8605Smrg	 /* impossible */
418848b8605Smrg      case 2:
419848b8605Smrg	 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 );
420848b8605Smrg	 /* fall-through */
421848b8605Smrg      case 3:
422848b8605Smrg	 _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 );
423848b8605Smrg	 /* fall-through */
424848b8605Smrg      case 4:
425848b8605Smrg	 break;
426848b8605Smrg      }
427848b8605Smrg   }
428848b8605Smrg   else {
429848b8605Smrg      /* Setup the VB pointers so that the next pipeline stages get
430848b8605Smrg       * their data from the right place (the program output arrays).
431848b8605Smrg       */
432848b8605Smrg      VB->ClipPtr = &store->results[VARYING_SLOT_POS];
433848b8605Smrg      VB->ClipPtr->size = 4;
434848b8605Smrg      VB->ClipPtr->count = VB->Count;
435848b8605Smrg   }
436848b8605Smrg
437848b8605Smrg   VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->results[VARYING_SLOT_COL0];
438848b8605Smrg   VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->results[VARYING_SLOT_COL1];
439848b8605Smrg   VB->AttribPtr[VERT_ATTRIB_FOG] = &store->results[VARYING_SLOT_FOGC];
440848b8605Smrg   VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->results[VARYING_SLOT_PSIZ];
441848b8605Smrg   VB->BackfaceColorPtr = &store->results[VARYING_SLOT_BFC0];
442848b8605Smrg   VB->BackfaceSecondaryColorPtr = &store->results[VARYING_SLOT_BFC1];
443848b8605Smrg
444848b8605Smrg   for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
445848b8605Smrg      VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]
446848b8605Smrg         = &store->results[VARYING_SLOT_TEX0 + i];
447848b8605Smrg   }
448848b8605Smrg
449848b8605Smrg   for (i = 0; i < ctx->Const.MaxVarying; i++) {
450b8e80941Smrg      if (program->info.outputs_written &
451b8e80941Smrg          BITFIELD64_BIT(VARYING_SLOT_VAR0 + i)) {
452848b8605Smrg         /* Note: varying results get put into the generic attributes */
453848b8605Smrg	 VB->AttribPtr[VERT_ATTRIB_GENERIC0+i]
454848b8605Smrg            = &store->results[VARYING_SLOT_VAR0 + i];
455848b8605Smrg      }
456848b8605Smrg   }
457848b8605Smrg
458848b8605Smrg
459848b8605Smrg   /* Perform NDC and cliptest operations:
460848b8605Smrg    */
461848b8605Smrg   return do_ndc_cliptest(ctx, store);
462848b8605Smrg}
463848b8605Smrg
464848b8605Smrg
465848b8605Smrg/**
466848b8605Smrg * Called the first time stage->run is called.  In effect, don't
467848b8605Smrg * allocate data until the first time the stage is run.
468848b8605Smrg */
469848b8605Smrgstatic GLboolean
470848b8605Smrginit_vp(struct gl_context *ctx, struct tnl_pipeline_stage *stage)
471848b8605Smrg{
472848b8605Smrg   TNLcontext *tnl = TNL_CONTEXT(ctx);
473848b8605Smrg   struct vertex_buffer *VB = &(tnl->vb);
474848b8605Smrg   struct vp_stage_data *store;
475848b8605Smrg   const GLuint size = VB->Size;
476848b8605Smrg
477848b8605Smrg   stage->privatePtr = calloc(1, sizeof(*store));
478848b8605Smrg   store = VP_STAGE_DATA(stage);
479848b8605Smrg   if (!store)
480848b8605Smrg      return GL_FALSE;
481848b8605Smrg
482848b8605Smrg   /* a few other misc allocations */
483848b8605Smrg   _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 );
484848b8605Smrg   store->clipmask = _mesa_align_malloc(sizeof(GLubyte)*size, 32 );
485848b8605Smrg
486848b8605Smrg   return GL_TRUE;
487848b8605Smrg}
488848b8605Smrg
489848b8605Smrg
490848b8605Smrg/**
491848b8605Smrg * Destructor for this pipeline stage.
492848b8605Smrg */
493848b8605Smrgstatic void
494848b8605Smrgdtr(struct tnl_pipeline_stage *stage)
495848b8605Smrg{
496848b8605Smrg   struct vp_stage_data *store = VP_STAGE_DATA(stage);
497848b8605Smrg
498848b8605Smrg   if (store) {
499848b8605Smrg      GLuint i;
500848b8605Smrg
501848b8605Smrg      /* free the vertex program result arrays */
502848b8605Smrg      for (i = 0; i < VARYING_SLOT_MAX; i++)
503848b8605Smrg         _mesa_vector4f_free( &store->results[i] );
504848b8605Smrg
505848b8605Smrg      /* free misc arrays */
506848b8605Smrg      _mesa_vector4f_free( &store->ndcCoords );
507848b8605Smrg      _mesa_align_free( store->clipmask );
508848b8605Smrg
509848b8605Smrg      free( store );
510848b8605Smrg      stage->privatePtr = NULL;
511848b8605Smrg   }
512848b8605Smrg}
513848b8605Smrg
514848b8605Smrg
515848b8605Smrgstatic void
516848b8605Smrgvalidate_vp_stage(struct gl_context *ctx, struct tnl_pipeline_stage *stage)
517848b8605Smrg{
518848b8605Smrg   if (ctx->VertexProgram._Current) {
519848b8605Smrg      _swrast_update_texture_samplers(ctx);
520848b8605Smrg   }
521848b8605Smrg}
522848b8605Smrg
523848b8605Smrg
524848b8605Smrg
525848b8605Smrg/**
526848b8605Smrg * Public description of this pipeline stage.
527848b8605Smrg */
528848b8605Smrgconst struct tnl_pipeline_stage _tnl_vertex_program_stage =
529848b8605Smrg{
530848b8605Smrg   "vertex-program",
531848b8605Smrg   NULL,			/* private_data */
532848b8605Smrg   init_vp,			/* create */
533848b8605Smrg   dtr,				/* destroy */
534848b8605Smrg   validate_vp_stage, 		/* validate */
535848b8605Smrg   run_vp			/* run -- initially set to ctr */
536848b8605Smrg};
537