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