fragment program execution
[mesa.git] / src / mesa / tnl / t_vb_program.c
1 /* $Id: t_vb_program.c,v 1.17 2003/01/14 04:55:47 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 5.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 /**
29 * \file tnl/t_vb_program.c
30 * \brief Pipeline stage for executing NVIDIA vertex programs.
31 * \author Brian Paul, Keith Whitwell
32 */
33
34
35 #include "glheader.h"
36 #include "api_noop.h"
37 #include "colormac.h"
38 #include "context.h"
39 #include "dlist.h"
40 #include "hash.h"
41 #include "light.h"
42 #include "macros.h"
43 #include "imports.h"
44 #include "mmath.h"
45 #include "simple_list.h"
46 #include "mtypes.h"
47 #include "nvvertprog.h"
48 #include "nvvertexec.h"
49 #include "nvprogram.h"
50
51 #include "math/m_translate.h"
52
53 #include "t_context.h"
54 #include "t_pipeline.h"
55 #include "t_imm_api.h"
56 #include "t_imm_exec.h"
57
58
59 /**
60 * \warning These values _MUST_ match the values in the OutputRegisters[]
61 * array in vpparse.c!!!
62 */
63 #define VERT_RESULT_HPOS 0
64 #define VERT_RESULT_COL0 1
65 #define VERT_RESULT_COL1 2
66 #define VERT_RESULT_BFC0 3
67 #define VERT_RESULT_BFC1 4
68 #define VERT_RESULT_FOGC 5
69 #define VERT_RESULT_PSIZ 6
70 #define VERT_RESULT_TEX0 7
71 #define VERT_RESULT_TEX1 8
72 #define VERT_RESULT_TEX2 9
73 #define VERT_RESULT_TEX3 10
74 #define VERT_RESULT_TEX4 11
75 #define VERT_RESULT_TEX5 12
76 #define VERT_RESULT_TEX6 13
77 #define VERT_RESULT_TEX7 14
78
79
80 /*!
81 * Private storage for the vertex program pipeline stage.
82 */
83 struct vp_stage_data {
84 /** The results of running the vertex program go into these arrays. */
85 GLvector4f attribs[15];
86
87 /* These point to the attribs[VERT_RESULT_COL0, COL1, BFC0, BFC1] arrays */
88 struct gl_client_array color0[2]; /**< diffuse front and back */
89 struct gl_client_array color1[2]; /**< specular front and back */
90
91 GLvector4f ndcCoords; /**< normalized device coords */
92 GLubyte *clipmask; /**< clip flags */
93 GLubyte ormask, andmask; /**< for clipping */
94 };
95
96
97 #define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr))
98
99
100 /**
101 * This function executes vertex programs
102 */
103 static GLboolean run_vp( GLcontext *ctx, struct gl_pipeline_stage *stage )
104 {
105 TNLcontext *tnl = TNL_CONTEXT(ctx);
106 struct vp_stage_data *store = VP_STAGE_DATA(stage);
107 struct vertex_buffer *VB = &tnl->vb;
108 struct vp_machine *machine = &(ctx->VertexProgram.Machine);
109 struct vertex_program *program = ctx->VertexProgram.Current;
110 GLuint i;
111
112 _mesa_init_tracked_matrices(ctx); /* load registers with matrices */
113 _mesa_init_vp_registers(ctx); /* init temp and result regs */
114
115 for (i = 0; i < VB->Count; i++) {
116 GLuint attr;
117
118 #if 0
119 printf("Input %d: %f, %f, %f, %f\n", i,
120 VB->AttribPtr[0]->data[i][0],
121 VB->AttribPtr[0]->data[i][1],
122 VB->AttribPtr[0]->data[i][2],
123 VB->AttribPtr[0]->data[i][3]);
124 printf(" color: %f, %f, %f, %f\n",
125 VB->AttribPtr[3]->data[i][0],
126 VB->AttribPtr[3]->data[i][1],
127 VB->AttribPtr[3]->data[i][2],
128 VB->AttribPtr[3]->data[i][3]);
129 printf(" normal: %f, %f, %f, %f\n",
130 VB->AttribPtr[2]->data[i][0],
131 VB->AttribPtr[2]->data[i][1],
132 VB->AttribPtr[2]->data[i][2],
133 VB->AttribPtr[2]->data[i][3]);
134 #endif
135
136 /* load the input attribute registers */
137 if (VB->Flag) {
138 /* the traditional glBegin/glVertex/glEnd case */
139 for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
140 if (attr == 0 || (VB->Flag[i] & (1 << attr))) {
141 COPY_4V(machine->Registers[VP_INPUT_REG_START + attr],
142 VB->AttribPtr[attr]->data[i]);
143 }
144 }
145 }
146 else {
147 /* the vertex array case */
148 for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
149 if (program->InputsRead & (1 << attr)) {
150 const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data;
151 const GLuint stride = VB->AttribPtr[attr]->stride;
152 const GLfloat *data = (GLfloat *) (ptr + stride * i);
153 COPY_4V(machine->Registers[VP_INPUT_REG_START + attr], data);
154 /*ASSERT(VB->AttribPtr[attr]->size == 4);*/
155 ASSERT(stride == 4 * sizeof(GLfloat) || stride == 0);
156 }
157 }
158 }
159
160 /* execute the program */
161 ASSERT(program);
162 _mesa_exec_vertex_program(ctx, program);
163
164 #if 0
165 printf("Output %d: %f, %f, %f, %f\n", i,
166 machine->Registers[VP_OUTPUT_REG_START + 0][0],
167 machine->Registers[VP_OUTPUT_REG_START + 0][1],
168 machine->Registers[VP_OUTPUT_REG_START + 0][2],
169 machine->Registers[VP_OUTPUT_REG_START + 0][3]);
170 printf(" color: %f, %f, %f, %f\n",
171 machine->Registers[VP_OUTPUT_REG_START +_1][0],
172 machine->Registers[VP_OUTPUT_REG_START + 1][1],
173 machine->Registers[VP_OUTPUT_REG_START + 1][2],
174 machine->Registers[VP_OUTPUT_REG_START + 1][3]);
175 printf("PointSize[%d]: %g\n", i,
176 machine->Registers[VP_OUTPUT_REG_START + VERT_RESULT_PSIZ][0]);
177 #endif
178
179 /* Fixup fog an point size results if needed */
180 if (ctx->Fog.Enabled &&
181 (program->OutputsWritten & (1 << VERT_RESULT_FOGC)) == 0) {
182 machine->Registers[VP_OUTPUT_REG_START + VERT_RESULT_FOGC][0] = 1.0;
183 }
184
185 if (ctx->VertexProgram.PointSizeEnabled &&
186 (program->OutputsWritten & (1 << VERT_RESULT_PSIZ)) == 0) {
187 machine->Registers[VP_OUTPUT_REG_START + VERT_RESULT_PSIZ][0]
188 = ctx->Point.Size;
189 }
190
191 /* copy the output registers into the VB->attribs arrays */
192 /* XXX (optimize) could use a conditional and smaller loop limit here */
193 for (attr = 0; attr < 15; attr++) {
194 COPY_4V( store->attribs[attr].data[i],
195 machine->Registers[VP_OUTPUT_REG_START + attr] );
196 }
197 }
198
199 /* Setup the VB pointers so that the next pipeline stages get
200 * their data from the right place (the program output arrays).
201 */
202 VB->ClipPtr = &store->attribs[VERT_RESULT_HPOS];
203 VB->ClipPtr->size = 4;
204 VB->ClipPtr->count = VB->Count;
205 VB->ColorPtr[0] = &store->color0[0];
206 VB->ColorPtr[1] = &store->color0[1];
207 VB->SecondaryColorPtr[0] = &store->color1[0];
208 VB->SecondaryColorPtr[1] = &store->color1[1];
209 VB->FogCoordPtr = &store->attribs[VERT_RESULT_FOGC];
210 VB->PointSizePtr = &store->attribs[VERT_RESULT_PSIZ];
211 for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
212 VB->TexCoordPtr[i] = &store->attribs[VERT_RESULT_TEX0 + i];
213
214 /* Cliptest and perspective divide. Clip functions must clear
215 * the clipmask.
216 */
217 store->ormask = 0;
218 store->andmask = CLIP_ALL_BITS;
219
220 if (tnl->NeedNdcCoords) {
221 VB->NdcPtr =
222 _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
223 &store->ndcCoords,
224 store->clipmask,
225 &store->ormask,
226 &store->andmask );
227 }
228 else {
229 VB->NdcPtr = 0;
230 _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
231 0,
232 store->clipmask,
233 &store->ormask,
234 &store->andmask );
235 }
236
237 if (store->andmask) /* All vertices are outside the frustum */
238 return GL_FALSE;
239
240
241 /* This is where we'd do clip testing against the user-defined
242 * clipping planes, but they're not supported by vertex programs.
243 */
244
245 VB->ClipOrMask = store->ormask;
246 VB->ClipMask = store->clipmask;
247
248 /* XXXX what's this?
249 if (VB->ClipPtr == VB->ObjPtr && (VB->importable_data & VERT_BIT_POS))
250 VB->importable_data |= VERT_BIT_CLIP;
251 */
252
253 return GL_TRUE;
254 }
255
256
257 /**
258 * This function validates stuff.
259 */
260 static GLboolean run_validate_program( GLcontext *ctx,
261 struct gl_pipeline_stage *stage )
262 {
263 #if 000
264 /* XXX do we need any validation for vertex programs? */
265 GLuint ind = 0;
266 light_func *tab;
267
268 if (ctx->Visual.rgbMode) {
269 if (ctx->Light._NeedVertices) {
270 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
271 tab = _tnl_light_spec_tab;
272 else
273 tab = _tnl_light_tab;
274 }
275 else {
276 if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev)
277 tab = _tnl_light_fast_single_tab;
278 else
279 tab = _tnl_light_fast_tab;
280 }
281 }
282 else
283 tab = _tnl_light_ci_tab;
284
285 if (ctx->Light.ColorMaterialEnabled)
286 ind |= LIGHT_COLORMATERIAL;
287
288 if (ctx->Light.Model.TwoSide)
289 ind |= LIGHT_TWOSIDE;
290
291 VP_STAGE_DATA(stage)->light_func_tab = &tab[ind];
292
293 /* This and the above should only be done on _NEW_LIGHT:
294 */
295 _mesa_validate_all_lighting_tables( ctx );
296 #endif
297
298 /* Now run the stage...
299 */
300 stage->run = run_vp;
301 return stage->run( ctx, stage );
302 }
303
304
305 /**
306 * Initialize a gl_client_array to point into a GLvector4f color vector.
307 */
308 static void init_color_array( struct gl_client_array *a, GLvector4f *vec )
309 {
310 a->Ptr = vec->data;
311 a->Size = 4;
312 a->Type = GL_FLOAT;
313 a->Stride = 0;
314 a->StrideB = sizeof(GLfloat) * 4;
315 a->Enabled = 0;
316 a->Flags = 0;
317 }
318
319
320 /**
321 * Called the first time stage->run is called. In effect, don't
322 * allocate data until the first time the stage is run.
323 */
324 static GLboolean run_init_vp( GLcontext *ctx,
325 struct gl_pipeline_stage *stage )
326 {
327 TNLcontext *tnl = TNL_CONTEXT(ctx);
328 struct vertex_buffer *VB = &(tnl->vb);
329 struct vp_stage_data *store;
330 const GLuint size = VB->Size;
331 GLuint i;
332
333 stage->privatePtr = MALLOC(sizeof(*store));
334 store = VP_STAGE_DATA(stage);
335 if (!store)
336 return GL_FALSE;
337
338 /* Allocate arrays of vertex output values */
339 for (i = 0; i < 15; i++)
340 _mesa_vector4f_alloc( &store->attribs[i], 0, size, 32 );
341
342 /* Make the color0[] and color1[] arrays point into the attribs[] arrays */
343 init_color_array( &store->color0[0], &store->attribs[VERT_RESULT_COL0] );
344 init_color_array( &store->color0[1], &store->attribs[VERT_RESULT_COL1] );
345 init_color_array( &store->color1[0], &store->attribs[VERT_RESULT_BFC0] );
346 init_color_array( &store->color1[1], &store->attribs[VERT_RESULT_BFC1] );
347
348 /* a few other misc allocations */
349 _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 );
350 store->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
351
352 /* Now validate the stage derived data...
353 */
354 stage->run = run_validate_program;
355 return stage->run( ctx, stage );
356 }
357
358
359
360 /**
361 * Check if vertex program mode is enabled.
362 * If so, configure the pipeline stage's type, inputs, and outputs.
363 */
364 static void check_vp( GLcontext *ctx, struct gl_pipeline_stage *stage )
365 {
366 stage->active = ctx->VertexProgram.Enabled;
367
368 if (stage->active) {
369 /* I believe this is right - Keith?
370 * Set stage->inputs equal to the bitmask of vertex attributes
371 * which the program needs for inputs.
372 */
373
374 stage->inputs = ctx->VertexProgram.Current->InputsRead;
375
376 #if 000
377 if (stage->privatePtr)
378 stage->run = run_validate_program;
379 stage->inputs = VERT_BIT_NORMAL|VERT_BIT_MATERIAL;
380 if (ctx->Light._NeedVertices)
381 stage->inputs |= VERT_BIT_EYE; /* effectively, even when lighting in obj */
382 if (ctx->Light.ColorMaterialEnabled)
383 stage->inputs |= VERT_BIT_COLOR0;
384
385 stage->outputs = VERT_BIT_COLOR0;
386 if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
387 stage->outputs |= VERT_BIT_COLOR1;
388 #endif
389 }
390 }
391
392
393 /**
394 * Destructor for this pipeline stage.
395 */
396 static void dtr( struct gl_pipeline_stage *stage )
397 {
398 struct vp_stage_data *store = VP_STAGE_DATA(stage);
399
400 if (store) {
401 GLuint i;
402
403 /* free the vertex program result arrays */
404 for (i = 0; i < 15; i++)
405 _mesa_vector4f_free( &store->attribs[i] );
406
407 /* free misc arrays */
408 _mesa_vector4f_free( &store->ndcCoords );
409 ALIGN_FREE( store->clipmask );
410
411 FREE( store );
412 stage->privatePtr = 0;
413 }
414 }
415
416 /**
417 * Public description of this pipeline stage.
418 */
419 const struct gl_pipeline_stage _tnl_vertex_program_stage =
420 {
421 "vertex-program",
422 _NEW_ALL, /*XXX FIX */ /* recheck */
423 _NEW_ALL, /*XXX FIX */ /* recalc -- modelview dependency
424 * otherwise not captured by inputs
425 * (which may be VERT_BIT_POS) */
426 GL_FALSE, /* active */
427 /*0*/ VERT_BIT_POS, /* inputs XXX OK? */
428 VERT_BIT_CLIP | VERT_BIT_COLOR0, /* outputs XXX OK? */
429 0, /* changed_inputs */
430 NULL, /* private_data */
431 dtr, /* destroy */
432 check_vp, /* check */
433 run_init_vp /* run -- initially set to ctr */
434 };