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