Follow suggestion by Aapo Tahkola to fix giant memory leak from forgetting to free...
[mesa.git] / src / mesa / tnl / t_vb_arbprogram.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.3
4 *
5 * Copyright (C) 1999-2004 Brian Paul 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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file t_arb_program.c
27 * Compile vertex programs to an intermediate representation.
28 * Execute vertex programs over a buffer of vertices.
29 * \author Keith Whitwell, Brian Paul
30 */
31
32 #include "glheader.h"
33 #include "context.h"
34 #include "imports.h"
35 #include "macros.h"
36 #include "mtypes.h"
37 #include "arbprogparse.h"
38 #include "light.h"
39 #include "program.h"
40 #include "math/m_matrix.h"
41 #include "math/m_translate.h"
42 #include "t_context.h"
43 #include "t_pipeline.h"
44 #include "t_vb_arbprogram.h"
45
46 #define DISASSEM 0
47
48 /*--------------------------------------------------------------------------- */
49
50 struct opcode_info {
51 GLuint nr_args;
52 const char *string;
53 void (*print)( union instruction , const struct opcode_info * );
54 };
55
56 struct compilation {
57 GLuint reg_active;
58 union instruction *csr;
59 };
60
61
62 #define ARB_VP_MACHINE(stage) ((struct arb_vp_machine *)(stage->privatePtr))
63
64 #define PUFF(x) ((x)[1] = (x)[2] = (x)[3] = (x)[0])
65
66
67
68 /* Lower precision functions for the EXP, LOG and LIT opcodes. The
69 * LOG2() implementation is probably not accurate enough, and the
70 * attempted optimization for Exp2 is definitely not accurate
71 * enough - it discards all of t's fractional bits!
72 */
73 static GLfloat RoughApproxLog2(GLfloat t)
74 {
75 return LOG2(t);
76 }
77
78 static GLfloat RoughApproxExp2(GLfloat t)
79 {
80 #if 0
81 fi_type fi;
82 fi.i = (GLint) t;
83 fi.i = (fi.i << 23) + 0x3f800000;
84 return fi.f;
85 #else
86 return (GLfloat) _mesa_pow(2.0, t);
87 #endif
88 }
89
90 static GLfloat RoughApproxPower(GLfloat x, GLfloat y)
91 {
92 return RoughApproxExp2(y * RoughApproxLog2(x));
93 }
94
95
96 /* Higher precision functions for the EX2, LG2 and POW opcodes:
97 */
98 static GLfloat ApproxLog2(GLfloat t)
99 {
100 return (GLfloat) (log(t) * 1.442695F);
101 }
102
103 static GLfloat ApproxExp2(GLfloat t)
104 {
105 return (GLfloat) _mesa_pow(2.0, t);
106 }
107
108 static GLfloat ApproxPower(GLfloat x, GLfloat y)
109 {
110 return (GLfloat) _mesa_pow(x, y);
111 }
112
113 static GLfloat rough_approx_log2_0_1(GLfloat x)
114 {
115 return LOG2(x);
116 }
117
118
119
120
121 /**
122 * Perform a reduced swizzle:
123 */
124 static void do_RSW( struct arb_vp_machine *m, union instruction op )
125 {
126 GLfloat *result = m->File[0][op.rsw.dst];
127 const GLfloat *arg0 = m->File[op.rsw.file0][op.rsw.idx0];
128 GLuint swz = op.rsw.swz;
129 GLuint neg = op.rsw.neg;
130
131 result[0] = arg0[GET_RSW(swz, 0)];
132 result[1] = arg0[GET_RSW(swz, 1)];
133 result[2] = arg0[GET_RSW(swz, 2)];
134 result[3] = arg0[GET_RSW(swz, 3)];
135
136 if (neg) {
137 if (neg & 0x1) result[0] = -result[0];
138 if (neg & 0x2) result[1] = -result[1];
139 if (neg & 0x4) result[2] = -result[2];
140 if (neg & 0x8) result[3] = -result[3];
141 }
142 }
143
144 /* Used to implement write masking. To make things easier for the sse
145 * generator I've gone back to a 1 argument version of this function
146 * (dst.msk = arg), rather than the semantically cleaner (dst = SEL
147 * arg0, arg1, msk)
148 *
149 * That means this is the only instruction which doesn't write a full
150 * 4 dwords out. This would make such a program harder to analyse,
151 * but it looks like analysis is going to take place on a higher level
152 * anyway.
153 */
154 static void do_MSK( struct arb_vp_machine *m, union instruction op )
155 {
156 GLfloat *dst = m->File[0][op.msk.dst];
157 const GLfloat *arg = m->File[op.msk.file][op.msk.idx];
158
159 if (op.msk.mask & 0x1) dst[0] = arg[0];
160 if (op.msk.mask & 0x2) dst[1] = arg[1];
161 if (op.msk.mask & 0x4) dst[2] = arg[2];
162 if (op.msk.mask & 0x8) dst[3] = arg[3];
163 }
164
165
166 static void do_PRT( struct arb_vp_machine *m, union instruction op )
167 {
168 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
169
170 _mesa_printf("%d: %f %f %f %f\n", m->vtx_nr,
171 arg0[0], arg0[1], arg0[2], arg0[3]);
172 }
173
174
175 /**
176 * The traditional ALU and texturing instructions. All operate on
177 * internal registers and ignore write masks and swizzling issues.
178 */
179
180 static void do_ABS( struct arb_vp_machine *m, union instruction op )
181 {
182 GLfloat *result = m->File[0][op.alu.dst];
183 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
184
185 result[0] = (arg0[0] < 0.0) ? -arg0[0] : arg0[0];
186 result[1] = (arg0[1] < 0.0) ? -arg0[1] : arg0[1];
187 result[2] = (arg0[2] < 0.0) ? -arg0[2] : arg0[2];
188 result[3] = (arg0[3] < 0.0) ? -arg0[3] : arg0[3];
189 }
190
191 static void do_ADD( struct arb_vp_machine *m, union instruction op )
192 {
193 GLfloat *result = m->File[0][op.alu.dst];
194 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
195 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
196
197 result[0] = arg0[0] + arg1[0];
198 result[1] = arg0[1] + arg1[1];
199 result[2] = arg0[2] + arg1[2];
200 result[3] = arg0[3] + arg1[3];
201 }
202
203
204 static void do_DP3( struct arb_vp_machine *m, union instruction op )
205 {
206 GLfloat *result = m->File[0][op.alu.dst];
207 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
208 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
209
210 result[0] = (arg0[0] * arg1[0] +
211 arg0[1] * arg1[1] +
212 arg0[2] * arg1[2]);
213
214 PUFF(result);
215 }
216
217
218
219 static void do_DP4( struct arb_vp_machine *m, union instruction op )
220 {
221 GLfloat *result = m->File[0][op.alu.dst];
222 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
223 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
224
225 result[0] = (arg0[0] * arg1[0] +
226 arg0[1] * arg1[1] +
227 arg0[2] * arg1[2] +
228 arg0[3] * arg1[3]);
229
230 PUFF(result);
231 }
232
233 static void do_DPH( struct arb_vp_machine *m, union instruction op )
234 {
235 GLfloat *result = m->File[0][op.alu.dst];
236 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
237 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
238
239 result[0] = (arg0[0] * arg1[0] +
240 arg0[1] * arg1[1] +
241 arg0[2] * arg1[2] +
242 1.0 * arg1[3]);
243
244 PUFF(result);
245 }
246
247 static void do_DST( struct arb_vp_machine *m, union instruction op )
248 {
249 GLfloat *result = m->File[0][op.alu.dst];
250 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
251 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
252
253 result[0] = 1.0F;
254 result[1] = arg0[1] * arg1[1];
255 result[2] = arg0[2];
256 result[3] = arg1[3];
257 }
258
259
260 /* Intended to be high precision:
261 */
262 static void do_EX2( struct arb_vp_machine *m, union instruction op )
263 {
264 GLfloat *result = m->File[0][op.alu.dst];
265 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
266
267 result[0] = (GLfloat)ApproxExp2(arg0[0]);
268 PUFF(result);
269 }
270
271
272 /* Allowed to be lower precision:
273 */
274 static void do_EXP( struct arb_vp_machine *m, union instruction op )
275 {
276 GLfloat *result = m->File[0][op.alu.dst];
277 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
278 GLfloat tmp = arg0[0];
279 GLfloat flr_tmp = FLOORF(tmp);
280 GLfloat frac_tmp = tmp - flr_tmp;
281
282 result[0] = LDEXPF(1.0, (int)flr_tmp);
283 result[1] = frac_tmp;
284 result[2] = LDEXPF(rough_approx_log2_0_1(frac_tmp), (int)flr_tmp);
285 result[3] = 1.0F;
286 }
287
288 static void do_FLR( struct arb_vp_machine *m, union instruction op )
289 {
290 GLfloat *result = m->File[0][op.alu.dst];
291 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
292
293 result[0] = FLOORF(arg0[0]);
294 result[1] = FLOORF(arg0[1]);
295 result[2] = FLOORF(arg0[2]);
296 result[3] = FLOORF(arg0[3]);
297 }
298
299 static void do_FRC( struct arb_vp_machine *m, union instruction op )
300 {
301 GLfloat *result = m->File[0][op.alu.dst];
302 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
303
304 result[0] = arg0[0] - FLOORF(arg0[0]);
305 result[1] = arg0[1] - FLOORF(arg0[1]);
306 result[2] = arg0[2] - FLOORF(arg0[2]);
307 result[3] = arg0[3] - FLOORF(arg0[3]);
308 }
309
310 /* High precision log base 2:
311 */
312 static void do_LG2( struct arb_vp_machine *m, union instruction op )
313 {
314 GLfloat *result = m->File[0][op.alu.dst];
315 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
316
317 result[0] = ApproxLog2(arg0[0]);
318 PUFF(result);
319 }
320
321
322
323 static void do_LIT( struct arb_vp_machine *m, union instruction op )
324 {
325 GLfloat *result = m->File[0][op.alu.dst];
326 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
327 GLfloat tmp[4];
328
329 tmp[0] = 1.0;
330 tmp[1] = 0.0;
331 tmp[2] = 0.0;
332 tmp[3] = 1.0;
333
334 if (arg0[0] > 0.0) {
335 tmp[1] = arg0[0];
336
337 if (arg0[1] > 0.0) {
338 tmp[2] = RoughApproxPower(arg0[1], arg0[3]);
339 }
340 }
341
342 COPY_4V(result, tmp);
343 }
344
345
346 /* Intended to allow a lower precision than required for LG2 above.
347 */
348 static void do_LOG( struct arb_vp_machine *m, union instruction op )
349 {
350 GLfloat *result = m->File[0][op.alu.dst];
351 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
352 GLfloat tmp = FABSF(arg0[0]);
353 int exponent;
354 #ifdef _WIN32
355 GLfloat mantissa = (GLfloat) frexp((double)tmp, &exponent);
356 #else
357 GLfloat mantissa = frexpf(tmp, &exponent);
358 #endif
359
360 result[0] = (GLfloat) (exponent - 1);
361 result[1] = 2.0 * mantissa; /* map [.5, 1) -> [1, 2) */
362 result[2] = exponent + LOG2(mantissa);
363 result[3] = 1.0;
364 }
365
366 static void do_MAX( struct arb_vp_machine *m, union instruction op )
367 {
368 GLfloat *result = m->File[0][op.alu.dst];
369 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
370 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
371
372 result[0] = (arg0[0] > arg1[0]) ? arg0[0] : arg1[0];
373 result[1] = (arg0[1] > arg1[1]) ? arg0[1] : arg1[1];
374 result[2] = (arg0[2] > arg1[2]) ? arg0[2] : arg1[2];
375 result[3] = (arg0[3] > arg1[3]) ? arg0[3] : arg1[3];
376 }
377
378
379 static void do_MIN( struct arb_vp_machine *m, union instruction op )
380 {
381 GLfloat *result = m->File[0][op.alu.dst];
382 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
383 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
384
385 result[0] = (arg0[0] < arg1[0]) ? arg0[0] : arg1[0];
386 result[1] = (arg0[1] < arg1[1]) ? arg0[1] : arg1[1];
387 result[2] = (arg0[2] < arg1[2]) ? arg0[2] : arg1[2];
388 result[3] = (arg0[3] < arg1[3]) ? arg0[3] : arg1[3];
389 }
390
391 static void do_MOV( struct arb_vp_machine *m, union instruction op )
392 {
393 GLfloat *result = m->File[0][op.alu.dst];
394 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
395
396 result[0] = arg0[0];
397 result[1] = arg0[1];
398 result[2] = arg0[2];
399 result[3] = arg0[3];
400 }
401
402 static void do_MUL( struct arb_vp_machine *m, union instruction op )
403 {
404 GLfloat *result = m->File[0][op.alu.dst];
405 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
406 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
407
408 result[0] = arg0[0] * arg1[0];
409 result[1] = arg0[1] * arg1[1];
410 result[2] = arg0[2] * arg1[2];
411 result[3] = arg0[3] * arg1[3];
412 }
413
414
415 /* Intended to be "high" precision
416 */
417 static void do_POW( struct arb_vp_machine *m, union instruction op )
418 {
419 GLfloat *result = m->File[0][op.alu.dst];
420 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
421 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
422
423 result[0] = (GLfloat)ApproxPower(arg0[0], arg1[0]);
424 PUFF(result);
425 }
426
427 static void do_REL( struct arb_vp_machine *m, union instruction op )
428 {
429 GLfloat *result = m->File[0][op.alu.dst];
430 GLuint idx = (op.alu.idx0 + (GLint)m->File[0][REG_ADDR][0]) & (MAX_NV_VERTEX_PROGRAM_PARAMS-1);
431 const GLfloat *arg0 = m->File[op.alu.file0][idx];
432
433 result[0] = arg0[0];
434 result[1] = arg0[1];
435 result[2] = arg0[2];
436 result[3] = arg0[3];
437 }
438
439 static void do_RCP( struct arb_vp_machine *m, union instruction op )
440 {
441 GLfloat *result = m->File[0][op.alu.dst];
442 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
443
444 result[0] = 1.0F / arg0[0];
445 PUFF(result);
446 }
447
448 static void do_RSQ( struct arb_vp_machine *m, union instruction op )
449 {
450 GLfloat *result = m->File[0][op.alu.dst];
451 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
452
453 result[0] = INV_SQRTF(FABSF(arg0[0]));
454 PUFF(result);
455 }
456
457
458 static void do_SGE( struct arb_vp_machine *m, union instruction op )
459 {
460 GLfloat *result = m->File[0][op.alu.dst];
461 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
462 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
463
464 result[0] = (arg0[0] >= arg1[0]) ? 1.0F : 0.0F;
465 result[1] = (arg0[1] >= arg1[1]) ? 1.0F : 0.0F;
466 result[2] = (arg0[2] >= arg1[2]) ? 1.0F : 0.0F;
467 result[3] = (arg0[3] >= arg1[3]) ? 1.0F : 0.0F;
468 }
469
470
471 static void do_SLT( struct arb_vp_machine *m, union instruction op )
472 {
473 GLfloat *result = m->File[0][op.alu.dst];
474 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
475 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
476
477 result[0] = (arg0[0] < arg1[0]) ? 1.0F : 0.0F;
478 result[1] = (arg0[1] < arg1[1]) ? 1.0F : 0.0F;
479 result[2] = (arg0[2] < arg1[2]) ? 1.0F : 0.0F;
480 result[3] = (arg0[3] < arg1[3]) ? 1.0F : 0.0F;
481 }
482
483 static void do_SUB( struct arb_vp_machine *m, union instruction op )
484 {
485 GLfloat *result = m->File[0][op.alu.dst];
486 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
487 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
488
489 result[0] = arg0[0] - arg1[0];
490 result[1] = arg0[1] - arg1[1];
491 result[2] = arg0[2] - arg1[2];
492 result[3] = arg0[3] - arg1[3];
493 }
494
495
496 static void do_XPD( struct arb_vp_machine *m, union instruction op )
497 {
498 GLfloat *result = m->File[0][op.alu.dst];
499 const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
500 const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
501
502 result[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1];
503 result[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2];
504 result[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0];
505 }
506
507 static void do_NOP( struct arb_vp_machine *m, union instruction op )
508 {
509 }
510
511 /* Some useful debugging functions:
512 */
513 static void print_mask( GLuint mask )
514 {
515 _mesa_printf(".");
516 if (mask&0x1) _mesa_printf("x");
517 if (mask&0x2) _mesa_printf("y");
518 if (mask&0x4) _mesa_printf("z");
519 if (mask&0x8) _mesa_printf("w");
520 }
521
522 static void print_reg( GLuint file, GLuint reg )
523 {
524 static const char *reg_file[] = {
525 "REG",
526 "LOCAL_PARAM",
527 "ENV_PARAM",
528 "STATE_VAR",
529 };
530
531 if (file == 0) {
532 if (reg == REG_RES)
533 _mesa_printf("RES");
534 else if (reg >= REG_ARG0 && reg <= REG_ARG1)
535 _mesa_printf("ARG%d", reg - REG_ARG0);
536 else if (reg >= REG_TMP0 && reg <= REG_TMP11)
537 _mesa_printf("TMP%d", reg - REG_TMP0);
538 else if (reg >= REG_IN0 && reg <= REG_IN31)
539 _mesa_printf("IN%d", reg - REG_IN0);
540 else if (reg >= REG_OUT0 && reg <= REG_OUT14)
541 _mesa_printf("OUT%d", reg - REG_OUT0);
542 else if (reg == REG_ADDR)
543 _mesa_printf("ADDR");
544 else if (reg == REG_ID)
545 _mesa_printf("ID");
546 else
547 _mesa_printf("REG%d", reg);
548 }
549 else
550 _mesa_printf("%s:%d", reg_file[file], reg);
551 }
552
553
554 static void print_RSW( union instruction op, const struct opcode_info *info )
555 {
556 GLuint swz = op.rsw.swz;
557 GLuint neg = op.rsw.neg;
558 GLuint i;
559
560 _mesa_printf("%s ", info->string);
561 print_reg(0, op.rsw.dst);
562 _mesa_printf(", ");
563 print_reg(op.rsw.file0, op.rsw.idx0);
564 _mesa_printf(".");
565 for (i = 0; i < 4; i++, swz >>= 2) {
566 const char *cswz = "xyzw";
567 if (neg & (1<<i))
568 _mesa_printf("-");
569 _mesa_printf("%c", cswz[swz&0x3]);
570 }
571 _mesa_printf("\n");
572 }
573
574
575 static void print_ALU( union instruction op, const struct opcode_info *info )
576 {
577 _mesa_printf("%s ", info->string);
578 print_reg(0, op.alu.dst);
579 _mesa_printf(", ");
580 print_reg(op.alu.file0, op.alu.idx0);
581 if (info->nr_args > 1) {
582 _mesa_printf(", ");
583 print_reg(op.alu.file1, op.alu.idx1);
584 }
585 _mesa_printf("\n");
586 }
587
588 static void print_MSK( union instruction op, const struct opcode_info *info )
589 {
590 _mesa_printf("%s ", info->string);
591 print_reg(0, op.msk.dst);
592 print_mask(op.msk.mask);
593 _mesa_printf(", ");
594 print_reg(op.msk.file, op.msk.idx);
595 _mesa_printf("\n");
596 }
597
598
599 static void print_NOP( union instruction op, const struct opcode_info *info )
600 {
601 }
602
603 #define NOP 0
604 #define ALU 1
605 #define SWZ 2
606
607 static const struct opcode_info opcode_info[] =
608 {
609 { 1, "ABS", print_ALU },
610 { 2, "ADD", print_ALU },
611 { 1, "ARL", print_NOP },
612 { 2, "DP3", print_ALU },
613 { 2, "DP4", print_ALU },
614 { 2, "DPH", print_ALU },
615 { 2, "DST", print_ALU },
616 { 0, "END", print_NOP },
617 { 1, "EX2", print_ALU },
618 { 1, "EXP", print_ALU },
619 { 1, "FLR", print_ALU },
620 { 1, "FRC", print_ALU },
621 { 1, "LG2", print_ALU },
622 { 1, "LIT", print_ALU },
623 { 1, "LOG", print_ALU },
624 { 3, "MAD", print_NOP },
625 { 2, "MAX", print_ALU },
626 { 2, "MIN", print_ALU },
627 { 1, "MOV", print_ALU },
628 { 2, "MUL", print_ALU },
629 { 2, "POW", print_ALU },
630 { 1, "PRT", print_ALU }, /* PRINT */
631 { 1, "RCC", print_NOP },
632 { 1, "RCP", print_ALU },
633 { 1, "RSQ", print_ALU },
634 { 2, "SGE", print_ALU },
635 { 2, "SLT", print_ALU },
636 { 2, "SUB", print_ALU },
637 { 1, "SWZ", print_NOP },
638 { 2, "XPD", print_ALU },
639 { 1, "RSW", print_RSW },
640 { 2, "MSK", print_MSK },
641 { 1, "REL", print_ALU },
642 };
643
644 void _tnl_disassem_vba_insn( union instruction op )
645 {
646 const struct opcode_info *info = &opcode_info[op.alu.opcode];
647 info->print( op, info );
648 }
649
650
651 static void (* const opcode_func[])(struct arb_vp_machine *, union instruction) =
652 {
653 do_ABS,
654 do_ADD,
655 do_NOP,
656 do_DP3,
657 do_DP4,
658 do_DPH,
659 do_DST,
660 do_NOP,
661 do_EX2,
662 do_EXP,
663 do_FLR,
664 do_FRC,
665 do_LG2,
666 do_LIT,
667 do_LOG,
668 do_NOP,
669 do_MAX,
670 do_MIN,
671 do_MOV,
672 do_MUL,
673 do_POW,
674 do_PRT,
675 do_NOP,
676 do_RCP,
677 do_RSQ,
678 do_SGE,
679 do_SLT,
680 do_SUB,
681 do_RSW,
682 do_XPD,
683 do_RSW,
684 do_MSK,
685 do_REL,
686 };
687
688 static union instruction *cvp_next_instruction( struct compilation *cp )
689 {
690 union instruction *op = cp->csr++;
691 op->dword = 0;
692 return op;
693 }
694
695 static struct reg cvp_make_reg( GLuint file, GLuint idx )
696 {
697 struct reg reg;
698 reg.file = file;
699 reg.idx = idx;
700 return reg;
701 }
702
703 static struct reg cvp_emit_rel( struct compilation *cp,
704 struct reg reg,
705 struct reg tmpreg )
706 {
707 union instruction *op = cvp_next_instruction(cp);
708 op->alu.opcode = REL;
709 op->alu.file0 = reg.file;
710 op->alu.idx0 = reg.idx;
711 op->alu.dst = tmpreg.idx;
712 return tmpreg;
713 }
714
715
716 static struct reg cvp_load_reg( struct compilation *cp,
717 GLuint file,
718 GLuint index,
719 GLuint rel,
720 GLuint tmpidx )
721 {
722 struct reg tmpreg = cvp_make_reg(FILE_REG, tmpidx);
723 struct reg reg;
724
725 switch (file) {
726 case PROGRAM_TEMPORARY:
727 return cvp_make_reg(FILE_REG, REG_TMP0 + index);
728
729 case PROGRAM_INPUT:
730 return cvp_make_reg(FILE_REG, REG_IN0 + index);
731
732 case PROGRAM_OUTPUT:
733 return cvp_make_reg(FILE_REG, REG_OUT0 + index);
734
735 /* These two aren't populated by the parser?
736 */
737 case PROGRAM_LOCAL_PARAM:
738 reg = cvp_make_reg(FILE_LOCAL_PARAM, index);
739 if (rel)
740 return cvp_emit_rel(cp, reg, tmpreg);
741 else
742 return reg;
743
744 case PROGRAM_ENV_PARAM:
745 reg = cvp_make_reg(FILE_ENV_PARAM, index);
746 if (rel)
747 return cvp_emit_rel(cp, reg, tmpreg);
748 else
749 return reg;
750
751 case PROGRAM_STATE_VAR:
752 reg = cvp_make_reg(FILE_STATE_PARAM, index);
753 if (rel)
754 return cvp_emit_rel(cp, reg, tmpreg);
755 else
756 return reg;
757
758 /* Invalid values:
759 */
760 case PROGRAM_WRITE_ONLY:
761 case PROGRAM_ADDRESS:
762 default:
763 assert(0);
764 return tmpreg; /* can't happen */
765 }
766 }
767
768 static struct reg cvp_emit_arg( struct compilation *cp,
769 const struct vp_src_register *src,
770 GLuint arg )
771 {
772 struct reg reg = cvp_load_reg( cp, src->File, src->Index, src->RelAddr, arg );
773 union instruction rsw, noop;
774
775 /* Emit any necessary swizzling.
776 */
777 rsw.dword = 0;
778 rsw.rsw.neg = src->Negate ? WRITEMASK_XYZW : 0;
779 rsw.rsw.swz = ((GET_SWZ(src->Swizzle, 0) << 0) |
780 (GET_SWZ(src->Swizzle, 1) << 2) |
781 (GET_SWZ(src->Swizzle, 2) << 4) |
782 (GET_SWZ(src->Swizzle, 3) << 6));
783
784 noop.dword = 0;
785 noop.rsw.neg = 0;
786 noop.rsw.swz = RSW_NOOP;
787
788 if (rsw.dword != noop.dword) {
789 union instruction *op = cvp_next_instruction(cp);
790 struct reg rsw_reg = cvp_make_reg(FILE_REG, REG_ARG0 + arg);
791 op->dword = rsw.dword;
792 op->rsw.opcode = RSW;
793 op->rsw.file0 = reg.file;
794 op->rsw.idx0 = reg.idx;
795 op->rsw.dst = rsw_reg.idx;
796 return rsw_reg;
797 }
798 else
799 return reg;
800 }
801
802 static GLuint cvp_choose_result( struct compilation *cp,
803 const struct vp_dst_register *dst,
804 union instruction *fixup )
805 {
806 GLuint mask = dst->WriteMask;
807 GLuint idx;
808
809 switch (dst->File) {
810 case PROGRAM_TEMPORARY:
811 idx = REG_TMP0 + dst->Index;
812 break;
813 case PROGRAM_OUTPUT:
814 idx = REG_OUT0 + dst->Index;
815 break;
816 default:
817 assert(0);
818 return REG_RES; /* can't happen */
819 }
820
821 /* Optimization: When writing (with a writemask) to an undefined
822 * value for the first time, the writemask may be ignored.
823 */
824 if (mask != WRITEMASK_XYZW && (cp->reg_active & (1 << idx))) {
825 fixup->msk.opcode = MSK;
826 fixup->msk.dst = idx;
827 fixup->msk.file = FILE_REG;
828 fixup->msk.idx = REG_RES;
829 fixup->msk.mask = mask;
830 cp->reg_active |= 1 << idx;
831 return REG_RES;
832 }
833 else {
834 fixup->dword = 0;
835 cp->reg_active |= 1 << idx;
836 return idx;
837 }
838 }
839
840 static struct reg cvp_emit_rsw( struct compilation *cp,
841 GLuint dst,
842 struct reg src,
843 GLuint neg,
844 GLuint swz,
845 GLboolean force)
846 {
847 struct reg retval;
848
849 if (swz != RSW_NOOP || neg != 0) {
850 union instruction *op = cvp_next_instruction(cp);
851 op->rsw.opcode = RSW;
852 op->rsw.dst = dst;
853 op->rsw.file0 = src.file;
854 op->rsw.idx0 = src.idx;
855 op->rsw.neg = neg;
856 op->rsw.swz = swz;
857
858 retval.file = FILE_REG;
859 retval.idx = dst;
860 return retval;
861 }
862 else if (force) {
863 /* Oops. Degenerate case:
864 */
865 union instruction *op = cvp_next_instruction(cp);
866 op->alu.opcode = VP_OPCODE_MOV;
867 op->alu.dst = dst;
868 op->alu.file0 = src.file;
869 op->alu.idx0 = src.idx;
870
871 retval.file = FILE_REG;
872 retval.idx = dst;
873 return retval;
874 }
875 else {
876 return src;
877 }
878 }
879
880
881 static void cvp_emit_inst( struct compilation *cp,
882 const struct vp_instruction *inst )
883 {
884 const struct opcode_info *info = &opcode_info[inst->Opcode];
885 union instruction *op;
886 union instruction fixup;
887 struct reg reg[3];
888 GLuint result, i;
889
890 assert(sizeof(*op) == sizeof(GLuint));
891
892 /* Need to handle SWZ, ARL specially.
893 */
894 switch (inst->Opcode) {
895 /* Split into mul and add:
896 */
897 case VP_OPCODE_MAD:
898 result = cvp_choose_result( cp, &inst->DstReg, &fixup );
899 for (i = 0; i < 3; i++)
900 reg[i] = cvp_emit_arg( cp, &inst->SrcReg[i], REG_ARG0+i );
901
902 op = cvp_next_instruction(cp);
903 op->alu.opcode = VP_OPCODE_MUL;
904 op->alu.file0 = reg[0].file;
905 op->alu.idx0 = reg[0].idx;
906 op->alu.file1 = reg[1].file;
907 op->alu.idx1 = reg[1].idx;
908 op->alu.dst = REG_ARG0;
909
910 op = cvp_next_instruction(cp);
911 op->alu.opcode = VP_OPCODE_ADD;
912 op->alu.file0 = FILE_REG;
913 op->alu.idx0 = REG_ARG0;
914 op->alu.file1 = reg[2].file;
915 op->alu.idx1 = reg[2].idx;
916 op->alu.dst = result;
917
918 if (result == REG_RES) {
919 op = cvp_next_instruction(cp);
920 op->dword = fixup.dword;
921 }
922 break;
923
924 case VP_OPCODE_ARL:
925 reg[0] = cvp_emit_arg( cp, &inst->SrcReg[0], REG_ARG0 );
926
927 op = cvp_next_instruction(cp);
928 op->alu.opcode = VP_OPCODE_FLR;
929 op->alu.dst = REG_ADDR;
930 op->alu.file0 = reg[0].file;
931 op->alu.idx0 = reg[0].idx;
932 break;
933
934 case VP_OPCODE_SWZ: {
935 GLuint swz0 = 0, swz1 = 0;
936 GLuint neg0 = 0, neg1 = 0;
937 GLuint mask = 0;
938
939 /* Translate 3-bit-per-element swizzle into two 2-bit swizzles,
940 * one from the source register the other from a constant
941 * {0,0,0,1}.
942 */
943 for (i = 0; i < 4; i++) {
944 GLuint swzelt = GET_SWZ(inst->SrcReg[0].Swizzle, i);
945 if (swzelt >= SWIZZLE_ZERO) {
946 neg0 |= inst->SrcReg[0].Negate & (1<<i);
947 if (swzelt == SWIZZLE_ONE)
948 swz0 |= SWIZZLE_W << (i*2);
949 else if (i < SWIZZLE_W)
950 swz0 |= i << (i*2);
951 }
952 else {
953 mask |= 1<<i;
954 neg1 |= inst->SrcReg[0].Negate & (1<<i);
955 swz1 |= swzelt << (i*2);
956 }
957 }
958
959 result = cvp_choose_result( cp, &inst->DstReg, &fixup );
960 reg[0].file = FILE_REG;
961 reg[0].idx = REG_ID;
962 reg[1] = cvp_emit_arg( cp, &inst->SrcReg[0], REG_ARG0 );
963
964 if (mask == WRITEMASK_XYZW) {
965 cvp_emit_rsw(cp, result, reg[0], neg0, swz0, GL_TRUE);
966
967 }
968 else if (mask == 0) {
969 cvp_emit_rsw(cp, result, reg[1], neg1, swz1, GL_TRUE);
970 }
971 else {
972 cvp_emit_rsw(cp, result, reg[0], neg0, swz0, GL_TRUE);
973 reg[1] = cvp_emit_rsw(cp, REG_ARG0, reg[1], neg1, swz1, GL_FALSE);
974
975 op = cvp_next_instruction(cp);
976 op->msk.opcode = MSK;
977 op->msk.dst = result;
978 op->msk.file = reg[1].file;
979 op->msk.idx = reg[1].idx;
980 op->msk.mask = mask;
981 }
982
983 if (result == REG_RES) {
984 op = cvp_next_instruction(cp);
985 op->dword = fixup.dword;
986 }
987 break;
988 }
989
990 case VP_OPCODE_END:
991 break;
992
993 default:
994 result = cvp_choose_result( cp, &inst->DstReg, &fixup );
995 for (i = 0; i < info->nr_args; i++)
996 reg[i] = cvp_emit_arg( cp, &inst->SrcReg[i], REG_ARG0 + i );
997
998 op = cvp_next_instruction(cp);
999 op->alu.opcode = inst->Opcode;
1000 op->alu.file0 = reg[0].file;
1001 op->alu.idx0 = reg[0].idx;
1002 op->alu.file1 = reg[1].file;
1003 op->alu.idx1 = reg[1].idx;
1004 op->alu.dst = result;
1005
1006 if (result == REG_RES) {
1007 op = cvp_next_instruction(cp);
1008 op->dword = fixup.dword;
1009 }
1010 break;
1011 }
1012 }
1013
1014 static void free_tnl_data( struct vertex_program *program )
1015 {
1016 struct tnl_compiled_program *p = program->TnlData;
1017 if (p->compiled_func)
1018 _mesa_free((void *)p->compiled_func);
1019 _mesa_free(p);
1020 program->TnlData = NULL;
1021 }
1022
1023 static void compile_vertex_program( struct vertex_program *program,
1024 GLboolean try_codegen )
1025 {
1026 struct compilation cp;
1027 struct tnl_compiled_program *p = CALLOC_STRUCT(tnl_compiled_program);
1028 GLuint i;
1029
1030 if (program->TnlData)
1031 free_tnl_data( program );
1032
1033 program->TnlData = p;
1034
1035 /* Initialize cp. Note that ctx and VB aren't used in compilation
1036 * so we don't have to worry about statechanges:
1037 */
1038 memset(&cp, 0, sizeof(cp));
1039 cp.csr = p->instructions;
1040
1041 /* Compile instructions:
1042 */
1043 for (i = 0; i < program->Base.NumInstructions; i++) {
1044 cvp_emit_inst(&cp, &program->Instructions[i]);
1045 }
1046
1047 /* Finish up:
1048 */
1049 p->nr_instructions = cp.csr - p->instructions;
1050
1051 /* Print/disassemble:
1052 */
1053 if (DISASSEM) {
1054 for (i = 0; i < p->nr_instructions; i++) {
1055 _tnl_disassem_vba_insn(p->instructions[i]);
1056 }
1057 _mesa_printf("\n\n");
1058 }
1059
1060 #ifdef USE_SSE_ASM
1061 if (try_codegen)
1062 _tnl_sse_codegen_vertex_program(p);
1063 #endif
1064
1065 }
1066
1067
1068
1069
1070 /* ----------------------------------------------------------------------
1071 * Execution
1072 */
1073 static void userclip( GLcontext *ctx,
1074 GLvector4f *clip,
1075 GLubyte *clipmask,
1076 GLubyte *clipormask,
1077 GLubyte *clipandmask )
1078 {
1079 GLuint p;
1080
1081 for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
1082 if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
1083 GLuint nr, i;
1084 const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
1085 const GLfloat b = ctx->Transform._ClipUserPlane[p][1];
1086 const GLfloat c = ctx->Transform._ClipUserPlane[p][2];
1087 const GLfloat d = ctx->Transform._ClipUserPlane[p][3];
1088 GLfloat *coord = (GLfloat *)clip->data;
1089 GLuint stride = clip->stride;
1090 GLuint count = clip->count;
1091
1092 for (nr = 0, i = 0 ; i < count ; i++) {
1093 GLfloat dp = (coord[0] * a +
1094 coord[1] * b +
1095 coord[2] * c +
1096 coord[3] * d);
1097
1098 if (dp < 0) {
1099 nr++;
1100 clipmask[i] |= CLIP_USER_BIT;
1101 }
1102
1103 STRIDE_F(coord, stride);
1104 }
1105
1106 if (nr > 0) {
1107 *clipormask |= CLIP_USER_BIT;
1108 if (nr == count) {
1109 *clipandmask |= CLIP_USER_BIT;
1110 return;
1111 }
1112 }
1113 }
1114 }
1115 }
1116
1117
1118 static GLboolean do_ndc_cliptest( struct arb_vp_machine *m )
1119 {
1120 GLcontext *ctx = m->ctx;
1121 TNLcontext *tnl = TNL_CONTEXT(ctx);
1122 struct vertex_buffer *VB = m->VB;
1123
1124 /* Cliptest and perspective divide. Clip functions must clear
1125 * the clipmask.
1126 */
1127 m->ormask = 0;
1128 m->andmask = CLIP_ALL_BITS;
1129
1130 if (tnl->NeedNdcCoords) {
1131 VB->NdcPtr =
1132 _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
1133 &m->ndcCoords,
1134 m->clipmask,
1135 &m->ormask,
1136 &m->andmask );
1137 }
1138 else {
1139 VB->NdcPtr = NULL;
1140 _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
1141 NULL,
1142 m->clipmask,
1143 &m->ormask,
1144 &m->andmask );
1145 }
1146
1147 if (m->andmask) {
1148 /* All vertices are outside the frustum */
1149 return GL_FALSE;
1150 }
1151
1152 /* Test userclip planes. This contributes to VB->ClipMask.
1153 */
1154 if (ctx->Transform.ClipPlanesEnabled && !ctx->VertexProgram._Enabled) {
1155 userclip( ctx,
1156 VB->ClipPtr,
1157 m->clipmask,
1158 &m->ormask,
1159 &m->andmask );
1160
1161 if (m->andmask) {
1162 return GL_FALSE;
1163 }
1164 }
1165
1166 VB->ClipAndMask = m->andmask;
1167 VB->ClipOrMask = m->ormask;
1168 VB->ClipMask = m->clipmask;
1169
1170 return GL_TRUE;
1171 }
1172
1173
1174 static INLINE void call_func( struct tnl_compiled_program *p,
1175 struct arb_vp_machine *m )
1176 {
1177 p->compiled_func(m);
1178 }
1179
1180 /**
1181 * Execute the given vertex program.
1182 *
1183 * TODO: Integrate the t_vertex.c code here, to build machine vertices
1184 * directly at this point.
1185 *
1186 * TODO: Eliminate the VB struct entirely and just use
1187 * struct arb_vertex_machine.
1188 */
1189 static GLboolean
1190 run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
1191 {
1192 struct vertex_program *program = (ctx->VertexProgram._Enabled ?
1193 ctx->VertexProgram.Current :
1194 ctx->_TnlProgram);
1195 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
1196 struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
1197 struct tnl_compiled_program *p;
1198 GLuint i, j, outputs;
1199
1200 if (!program || program->IsNVProgram)
1201 return GL_TRUE;
1202
1203 if (program->Parameters) {
1204 _mesa_load_state_parameters(ctx, program->Parameters);
1205 }
1206
1207 p = (struct tnl_compiled_program *)program->TnlData;
1208 assert(p);
1209
1210
1211 m->nr_inputs = m->nr_outputs = 0;
1212
1213 for (i = 0; i < _TNL_ATTRIB_MAX; i++) {
1214 if (program->InputsRead & (1<<i)) {
1215 GLuint j = m->nr_inputs++;
1216 m->input[j].idx = i;
1217 m->input[j].data = (GLfloat *)m->VB->AttribPtr[i]->data;
1218 m->input[j].stride = m->VB->AttribPtr[i]->stride;
1219 m->input[j].size = m->VB->AttribPtr[i]->size;
1220 ASSIGN_4V(m->File[0][REG_IN0 + i], 0, 0, 0, 1);
1221 }
1222 }
1223
1224 for (i = 0; i < 15; i++) {
1225 if (program->OutputsWritten & (1<<i)) {
1226 GLuint j = m->nr_outputs++;
1227 m->output[j].idx = i;
1228 m->output[j].data = (GLfloat *)m->attribs[i].data;
1229 }
1230 }
1231
1232
1233 /* Run the actual program:
1234 */
1235 for (m->vtx_nr = 0; m->vtx_nr < VB->Count; m->vtx_nr++) {
1236 for (j = 0; j < m->nr_inputs; j++) {
1237 GLuint idx = REG_IN0 + m->input[j].idx;
1238 switch (m->input[j].size) {
1239 case 4: m->File[0][idx][3] = m->input[j].data[3];
1240 case 3: m->File[0][idx][2] = m->input[j].data[2];
1241 case 2: m->File[0][idx][1] = m->input[j].data[1];
1242 case 1: m->File[0][idx][0] = m->input[j].data[0];
1243 }
1244
1245 STRIDE_F(m->input[j].data, m->input[j].stride);
1246 }
1247
1248 if (p->compiled_func) {
1249 call_func( p, m );
1250 }
1251 else {
1252 for (j = 0; j < p->nr_instructions; j++) {
1253 union instruction inst = p->instructions[j];
1254 opcode_func[inst.alu.opcode]( m, inst );
1255 }
1256 }
1257
1258 for (j = 0; j < m->nr_outputs; j++) {
1259 GLuint idx = REG_OUT0 + m->output[j].idx;
1260 m->output[j].data[0] = m->File[0][idx][0];
1261 m->output[j].data[1] = m->File[0][idx][1];
1262 m->output[j].data[2] = m->File[0][idx][2];
1263 m->output[j].data[3] = m->File[0][idx][3];
1264 m->output[j].data += 4;
1265 }
1266 }
1267
1268 /* Setup the VB pointers so that the next pipeline stages get
1269 * their data from the right place (the program output arrays).
1270 *
1271 * TODO: 1) Have tnl use these RESULT values for outputs rather
1272 * than trying to shoe-horn inputs and outputs into one set of
1273 * values.
1274 *
1275 * TODO: 2) Integrate t_vertex.c so that we just go straight ahead
1276 * and build machine vertices here.
1277 */
1278 VB->ClipPtr = &m->attribs[VERT_RESULT_HPOS];
1279 VB->ClipPtr->count = VB->Count;
1280
1281 outputs = program->OutputsWritten;
1282
1283 if (outputs & (1<<VERT_RESULT_COL0)) {
1284 VB->ColorPtr[0] = &m->attribs[VERT_RESULT_COL0];
1285 VB->AttribPtr[VERT_ATTRIB_COLOR0] = VB->ColorPtr[0];
1286 }
1287
1288 if (outputs & (1<<VERT_RESULT_BFC0)) {
1289 VB->ColorPtr[1] = &m->attribs[VERT_RESULT_BFC0];
1290 }
1291
1292 if (outputs & (1<<VERT_RESULT_COL1)) {
1293 VB->SecondaryColorPtr[0] = &m->attribs[VERT_RESULT_COL1];
1294 VB->AttribPtr[VERT_ATTRIB_COLOR1] = VB->SecondaryColorPtr[0];
1295 }
1296
1297 if (outputs & (1<<VERT_RESULT_BFC1)) {
1298 VB->SecondaryColorPtr[1] = &m->attribs[VERT_RESULT_BFC1];
1299 }
1300
1301 if (outputs & (1<<VERT_RESULT_FOGC)) {
1302 VB->FogCoordPtr = &m->attribs[VERT_RESULT_FOGC];
1303 VB->AttribPtr[VERT_ATTRIB_FOG] = VB->FogCoordPtr;
1304 }
1305
1306 if (outputs & (1<<VERT_RESULT_PSIZ)) {
1307 VB->PointSizePtr = &m->attribs[VERT_RESULT_PSIZ];
1308 VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &m->attribs[VERT_RESULT_PSIZ];
1309 }
1310
1311 for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
1312 if (outputs & (1<<(VERT_RESULT_TEX0+i))) {
1313 VB->TexCoordPtr[i] = &m->attribs[VERT_RESULT_TEX0 + i];
1314 VB->AttribPtr[VERT_ATTRIB_TEX0+i] = VB->TexCoordPtr[i];
1315 }
1316 }
1317
1318 #if 0
1319 for (i = 0; i < VB->Count; i++) {
1320 printf("Out %d: %f %f %f %f %f %f %f %f\n", i,
1321 VEC_ELT(VB->ClipPtr, GLfloat, i)[0],
1322 VEC_ELT(VB->ClipPtr, GLfloat, i)[1],
1323 VEC_ELT(VB->ClipPtr, GLfloat, i)[2],
1324 VEC_ELT(VB->ClipPtr, GLfloat, i)[3],
1325 VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[0],
1326 VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[1],
1327 VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[2],
1328 VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[3]);
1329 }
1330 #endif
1331
1332 /* Perform NDC and cliptest operations:
1333 */
1334 return do_ndc_cliptest(m);
1335 }
1336
1337
1338 static void
1339 validate_vertex_program( GLcontext *ctx, struct tnl_pipeline_stage *stage )
1340 {
1341 struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
1342 struct vertex_program *program =
1343 (ctx->VertexProgram._Enabled ? ctx->VertexProgram.Current : 0);
1344
1345 if (!program && ctx->_MaintainTnlProgram) {
1346 program = ctx->_TnlProgram;
1347 }
1348
1349 if (program) {
1350 if (!program->TnlData)
1351 compile_vertex_program( program, m->try_codegen );
1352
1353 /* Grab the state GL state and put into registers:
1354 */
1355 m->File[FILE_LOCAL_PARAM] = program->Base.LocalParams;
1356 m->File[FILE_ENV_PARAM] = ctx->VertexProgram.Parameters;
1357 /* GL_NV_vertex_programs can't reference GL state */
1358 if (program->Parameters)
1359 m->File[FILE_STATE_PARAM] = program->Parameters->ParameterValues;
1360 else
1361 m->File[FILE_STATE_PARAM] = NULL;
1362 }
1363 }
1364
1365
1366
1367
1368
1369
1370
1371 /**
1372 * Called the first time stage->run is called. In effect, don't
1373 * allocate data until the first time the stage is run.
1374 */
1375 static GLboolean init_vertex_program( GLcontext *ctx,
1376 struct tnl_pipeline_stage *stage )
1377 {
1378 TNLcontext *tnl = TNL_CONTEXT(ctx);
1379 struct vertex_buffer *VB = &(tnl->vb);
1380 struct arb_vp_machine *m;
1381 const GLuint size = VB->Size;
1382 GLuint i;
1383
1384 stage->privatePtr = _mesa_malloc(sizeof(*m));
1385 m = ARB_VP_MACHINE(stage);
1386 if (!m)
1387 return GL_FALSE;
1388
1389 /* arb_vertex_machine struct should subsume the VB:
1390 */
1391 m->VB = VB;
1392 m->ctx = ctx;
1393
1394 m->File[0] = ALIGN_MALLOC(REG_MAX * sizeof(GLfloat) * 4, 16);
1395
1396 /* Initialize regs where necessary:
1397 */
1398 ASSIGN_4V(m->File[0][REG_ID], 0, 0, 0, 1);
1399 ASSIGN_4V(m->File[0][REG_ONES], 1, 1, 1, 1);
1400 ASSIGN_4V(m->File[0][REG_SWZ], -1, 1, 0, 0);
1401 ASSIGN_4V(m->File[0][REG_NEG], -1, -1, -1, -1);
1402 ASSIGN_4V(m->File[0][REG_LIT], 1, 0, 0, 1);
1403 ASSIGN_4V(m->File[0][REG_LIT2], 1, .5, .2, 1); /* debug value */
1404
1405 if (_mesa_getenv("MESA_EXPERIMENTAL"))
1406 m->try_codegen = 1;
1407
1408 /* Allocate arrays of vertex output values */
1409 for (i = 0; i < VERT_RESULT_MAX; i++) {
1410 _mesa_vector4f_alloc( &m->attribs[i], 0, size, 32 );
1411 m->attribs[i].size = 4;
1412 }
1413
1414 /* a few other misc allocations */
1415 _mesa_vector4f_alloc( &m->ndcCoords, 0, size, 32 );
1416 m->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
1417
1418 if (ctx->_MaintainTnlProgram)
1419 _mesa_allow_light_in_model( ctx, GL_FALSE );
1420
1421 m->fpucntl_rnd_neg = RND_NEG_FPU; /* const value */
1422 m->fpucntl_restore = RESTORE_FPU; /* const value */
1423
1424 return GL_TRUE;
1425 }
1426
1427
1428
1429
1430 /**
1431 * Destructor for this pipeline stage.
1432 */
1433 static void dtr( struct tnl_pipeline_stage *stage )
1434 {
1435 struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
1436
1437 if (m) {
1438 GLuint i;
1439
1440 /* free the vertex program result arrays */
1441 for (i = 0; i < VERT_RESULT_MAX; i++)
1442 _mesa_vector4f_free( &m->attribs[i] );
1443
1444 /* free misc arrays */
1445 _mesa_vector4f_free( &m->ndcCoords );
1446 ALIGN_FREE( m->clipmask );
1447 ALIGN_FREE( m->File[0] );
1448
1449 _mesa_free( m );
1450 stage->privatePtr = NULL;
1451 }
1452 }
1453
1454 /**
1455 * Public description of this pipeline stage.
1456 */
1457 const struct tnl_pipeline_stage _tnl_arb_vertex_program_stage =
1458 {
1459 "vertex-program",
1460 NULL, /* private_data */
1461 init_vertex_program, /* create */
1462 dtr, /* destroy */
1463 validate_vertex_program, /* validate */
1464 run_arb_vertex_program /* run */
1465 };