f4bae2a82d000d4c0fccb5517ab163d1694829f6
[mesa.git] / src / mesa / swrast / s_fragprog_to_c.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.1
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 /* An amusing little utility to print ARB fragment programs out as a C
26 * function. Resulting code not tested except visually.
27 */
28
29
30 #include "glheader.h"
31 #include "colormac.h"
32 #include "context.h"
33 #include "nvfragprog.h"
34 #include "macros.h"
35 #include "program.h"
36
37 #include "s_nvfragprog.h"
38 #include "s_span.h"
39 #include "s_texture.h"
40
41
42 /* UREG - a way of representing an FP source register including
43 * swizzling and negation in a single GLuint. Major flaw is the
44 * limitiation to source->Index < 32. Secondary flaw is the fact that
45 * it's overkill & we could probably just pass around the original
46 * datatypes instead.
47 */
48
49 #define UREG_TYPE_TEMP 0
50 #define UREG_TYPE_INTERP 1
51 #define UREG_TYPE_LOCAL_CONST 2
52 #define UREG_TYPE_ENV_CONST 3
53 #define UREG_TYPE_STATE_CONST 4
54 #define UREG_TYPE_PARAM 5
55 #define UREG_TYPE_OUTPUT 6
56 #define UREG_TYPE_MASK 0x7
57
58 #define UREG_TYPE_SHIFT 29
59 #define UREG_NR_SHIFT 24
60 #define UREG_NR_MASK 0x1f /* 31 */
61 #define UREG_CHANNEL_X_NEGATE_SHIFT 23
62 #define UREG_CHANNEL_X_SHIFT 20
63 #define UREG_CHANNEL_Y_NEGATE_SHIFT 19
64 #define UREG_CHANNEL_Y_SHIFT 16
65 #define UREG_CHANNEL_Z_NEGATE_SHIFT 15
66 #define UREG_CHANNEL_Z_SHIFT 12
67 #define UREG_CHANNEL_W_NEGATE_SHIFT 11
68 #define UREG_CHANNEL_W_SHIFT 8
69 #define UREG_CHANNEL_ZERO_NEGATE_MBZ 5
70 #define UREG_CHANNEL_ZERO_SHIFT 4
71 #define UREG_CHANNEL_ONE_NEGATE_MBZ 1
72 #define UREG_CHANNEL_ONE_SHIFT 0
73
74 #define UREG_BAD 0xffffffff /* not a valid ureg */
75
76 #define _X 0
77 #define _Y 1
78 #define _Z 2
79 #define _W 3
80 #define _ZERO 4 /* NOTE! */
81 #define _ONE 5 /* NOTE! */
82
83
84 /* Construct a ureg:
85 */
86 #define UREG( type, nr ) (((type)<< UREG_TYPE_SHIFT) | \
87 ((nr) << UREG_NR_SHIFT) | \
88 (_X << UREG_CHANNEL_X_SHIFT) | \
89 (_Y << UREG_CHANNEL_Y_SHIFT) | \
90 (_Z << UREG_CHANNEL_Z_SHIFT) | \
91 (_W << UREG_CHANNEL_W_SHIFT) | \
92 (_ZERO << UREG_CHANNEL_ZERO_SHIFT) | \
93 (_ONE << UREG_CHANNEL_ONE_SHIFT))
94
95 #define GET_CHANNEL_SRC( reg, channel ) ((reg<<(channel*4)) & \
96 (0xf<<UREG_CHANNEL_X_SHIFT))
97 #define CHANNEL_SRC( src, channel ) (src>>(channel*4))
98
99 #define GET_UREG_TYPE(reg) (((reg)>>UREG_TYPE_SHIFT)&UREG_TYPE_MASK)
100 #define GET_UREG_NR(reg) (((reg)>>UREG_NR_SHIFT)&UREG_NR_MASK)
101
102
103
104 #define UREG_XYZW_CHANNEL_MASK 0x00ffff00
105
106 #define deref(reg,pos) swizzle(reg, pos, pos, pos, pos)
107
108
109 static INLINE int is_swizzled( int reg )
110 {
111 return ((reg & UREG_XYZW_CHANNEL_MASK) !=
112 (UREG(0,0) & UREG_XYZW_CHANNEL_MASK));
113 }
114
115
116 /* One neat thing about the UREG representation:
117 */
118 static INLINE int swizzle( int reg, int x, int y, int z, int w )
119 {
120 return ((reg & ~UREG_XYZW_CHANNEL_MASK) |
121 CHANNEL_SRC( GET_CHANNEL_SRC( reg, x ), 0 ) |
122 CHANNEL_SRC( GET_CHANNEL_SRC( reg, y ), 1 ) |
123 CHANNEL_SRC( GET_CHANNEL_SRC( reg, z ), 2 ) |
124 CHANNEL_SRC( GET_CHANNEL_SRC( reg, w ), 3 ));
125 }
126
127 /* Another neat thing about the UREG representation:
128 */
129 static INLINE int negate( int reg, int x, int y, int z, int w )
130 {
131 return reg ^ (((x&1)<<UREG_CHANNEL_X_NEGATE_SHIFT)|
132 ((y&1)<<UREG_CHANNEL_Y_NEGATE_SHIFT)|
133 ((z&1)<<UREG_CHANNEL_Z_NEGATE_SHIFT)|
134 ((w&1)<<UREG_CHANNEL_W_NEGATE_SHIFT));
135 }
136
137
138
139 static GLuint src_reg_file( GLuint file )
140 {
141 switch (file) {
142 case PROGRAM_TEMPORARY: return UREG_TYPE_TEMP;
143 case PROGRAM_INPUT: return UREG_TYPE_INTERP;
144 case PROGRAM_LOCAL_PARAM: return UREG_TYPE_LOCAL_CONST;
145 case PROGRAM_ENV_PARAM: return UREG_TYPE_ENV_CONST;
146
147 case PROGRAM_STATE_VAR: return UREG_TYPE_STATE_CONST;
148 case PROGRAM_NAMED_PARAM: return UREG_TYPE_PARAM;
149 default: return UREG_BAD;
150 }
151 }
152
153 static void emit( struct fragment_program *p,
154 const char *fmt,
155 ... )
156 {
157 va_list ap;
158 va_start( ap, fmt );
159
160 p->c_strlen += vsnprintf( p->c_str + p->c_strlen,
161 sizeof(p->c_str) - p->c_strlen,
162 fmt, ap );
163
164 va_end( ap );
165 }
166
167 static INLINE void emit_char( struct fragment_program *p, char c )
168 {
169 if (p->c_strlen < sizeof(p->c_str))
170 p->c_str[p->c_strlen] = c;
171
172 p->c_strlen++;
173 }
174
175
176 /**
177 * Retrieve a ureg for the given source register. Will emit
178 * constants, apply swizzling and negation as needed.
179 */
180 static GLuint src_vector( const struct fp_src_register *source )
181 {
182 GLuint src;
183
184 assert(source->Index < 32); /* limitiation of UREG representation */
185
186 src = UREG( src_reg_file( source->File ), source->Index );
187
188 src = swizzle(src,
189 _X + source->Swizzle[0],
190 _X + source->Swizzle[1],
191 _X + source->Swizzle[2],
192 _X + source->Swizzle[3]);
193
194 if (source->NegateBase)
195 src = negate( src, 1,1,1,1 );
196
197 return src;
198 }
199
200
201 static void print_header( struct fragment_program *p )
202 {
203 emit(p, "\n\n\n");
204
205 /* Texture samplers, not written yet:
206 */
207 emit(p, "extern void TEX( void *ctx, const float *txc, int unit, float *rslt );\n"
208 "extern void TXB( void *ctx, const float *txc, int unit, float *rslt );\n"
209 "extern void TXP( void *ctx, const float *txc, int unit, float *rslt );\n");
210
211 /* Resort to the standard math library (float versions):
212 */
213 emit(p, "extern float fabsf( float );\n"
214 "extern float cosf( float );\n"
215 "extern float sinf( float );\n"
216 "extern float expf( float );\n"
217 "extern float powf( float, float );\n"
218 "extern float floorf( float );\n");
219
220 /* These ones we have fast code in Mesa for:
221 */
222 emit(p, "extern float LOG2( float );\n"
223 "extern float _mesa_inv_sqrtf( float );\n");
224
225 /* The usual macros, not really needed, but handy:
226 */
227 emit(p, "#define MIN2(x,y) ((x)<(y)?(x):(y))\n"
228 "#define MAX2(x,y) ((x)<(y)?(x):(y))\n");
229
230 /* Our function!
231 */
232 emit(p, "void run_program( void *ctx, \n"
233 " const float (*local_param)[4], \n"
234 " const float (*env_param)[4], \n"
235 " const float (*state_param)[4], \n"
236 " const float (*interp)[4], \n"
237 " float (*outputs)[4])\n"
238 "{\n"
239 " float temp[32][4];\n"
240 );
241 }
242
243 static void print_footer( struct fragment_program *p )
244 {
245 emit(p, "}\n");
246 }
247
248 static void print_dest_reg( struct fragment_program *p,
249 const struct fp_instruction *inst )
250 {
251 switch (inst->DstReg.File) {
252 case PROGRAM_OUTPUT:
253 emit(p, "outputs[%d]", inst->DstReg.Index);
254 break;
255 case PROGRAM_TEMPORARY:
256 emit(p, "temp[%d]", inst->DstReg.Index);
257 break;
258 default:
259 break;
260 }
261 }
262
263 static void print_dest( struct fragment_program *p,
264 const struct fp_instruction *inst,
265 GLuint idx )
266 {
267 print_dest_reg(p, inst);
268 emit(p, "[%d]", idx);
269 }
270
271
272 #define UREG_SRC0(reg) (((reg)>>UREG_CHANNEL_X_SHIFT) & 0x7)
273
274 static void print_reg( struct fragment_program *p,
275 GLuint arg )
276 {
277 switch (GET_UREG_TYPE(arg)) {
278 case UREG_TYPE_TEMP: emit(p, "temp"); break;
279 case UREG_TYPE_INTERP: emit(p, "interp"); break;
280 case UREG_TYPE_LOCAL_CONST: emit(p, "local_const"); break;
281 case UREG_TYPE_ENV_CONST: emit(p, "env_const"); break;
282 case UREG_TYPE_STATE_CONST: emit(p, "state_const"); break;
283 case UREG_TYPE_PARAM: emit(p, "param"); break;
284 };
285
286 emit(p, "[%d]", GET_UREG_NR(arg));
287 }
288
289
290 static void print_arg( struct fragment_program *p,
291 GLuint arg )
292 {
293 GLuint src = UREG_SRC0(arg);
294
295 if (src == _ZERO) {
296 emit(p, "0");
297 return;
298 }
299
300 if (arg & (1<<UREG_CHANNEL_X_NEGATE_SHIFT))
301 emit(p, "-");
302
303 if (src == _ONE) {
304 emit(p, "1");
305 return;
306 }
307
308 if (GET_UREG_TYPE(arg) == UREG_TYPE_STATE_CONST) {
309 emit(p, "%g", p->Parameters->Parameters[GET_UREG_NR(arg)].Values[src]);
310 return;
311 }
312
313 print_reg( p, arg );
314
315 switch (src){
316 case _X: emit(p, "[0]"); break;
317 case _Y: emit(p, "[1]"); break;
318 case _Z: emit(p, "[2]"); break;
319 case _W: emit(p, "[3]"); break;
320 }
321 }
322
323
324 /* This is where the handling of expressions breaks down into string
325 * processing:
326 */
327 static void print_expression( struct fragment_program *p,
328 GLuint i,
329 const char *fmt,
330 va_list ap )
331 {
332 while (*fmt) {
333 if (*fmt == '%' && *(fmt+1) == 's') {
334 int reg = va_arg(ap, int);
335
336 /* Use of deref() is a bit of a hack:
337 */
338 print_arg( p, deref(reg, i) );
339 fmt += 2;
340 }
341 else {
342 emit_char(p, *fmt);
343 fmt++;
344 }
345 }
346
347 emit(p, ";\n");
348 }
349
350 static void do_tex_simple( struct fragment_program *p,
351 const struct fp_instruction *inst,
352 const char *fn, GLuint texunit, GLuint arg )
353 {
354 emit(p, " %s( ctx, ", fn);
355 print_reg( p, arg );
356 emit(p, ", %d, ", texunit );
357 print_dest_reg(p, inst);
358 emit(p, ");\n");
359 }
360
361
362 static void do_tex( struct fragment_program *p,
363 const struct fp_instruction *inst,
364 const char *fn, GLuint texunit, GLuint arg )
365 {
366 GLuint i;
367 GLboolean need_tex = GL_FALSE, need_result = GL_FALSE;
368
369 for (i = 0; i < 4; i++)
370 if (!inst->DstReg.WriteMask[i])
371 need_result = GL_TRUE;
372
373 if (is_swizzled(arg))
374 need_tex = GL_TRUE;
375
376 if (!need_tex && !need_result) {
377 do_tex_simple( p, inst, fn, texunit, arg );
378 return;
379 }
380
381 emit(p, " {\n");
382 emit(p, " float texcoord[4];\n");
383 emit(p, " float result[4];\n");
384
385 for (i = 0; i < 4; i++) {
386 emit(p, " texcoord[%d] = ", i);
387 print_arg( p, deref(arg, i) );
388 emit(p, ";\n");
389 }
390
391 emit(p, " %s( ctx, texcoord, %d, result);\n", fn, texunit );
392
393 for (i = 0; i < 4; i++) {
394 if (inst->DstReg.WriteMask[i]) {
395 emit(p, " ");
396 print_dest(p, inst, i);
397 emit(p, " = result[%d];\n", i);
398 }
399 }
400
401 emit(p, " }\n");
402 }
403
404
405 static void saturate( struct fragment_program *p,
406 const struct fp_instruction *inst,
407 GLuint i )
408 {
409 emit(p, " ");
410 print_dest(p, inst, i);
411 emit(p, " = CLAMPF( ");
412 print_dest(p, inst, i);
413 emit(p, ", 0.0, 1.0);\n");
414 }
415
416 static void assign_single( GLuint i,
417 struct fragment_program *p,
418 const struct fp_instruction *inst,
419 const char *fmt,
420 ... )
421 {
422 va_list ap;
423 va_start( ap, fmt );
424
425 if (inst->DstReg.WriteMask[i]) {
426 emit(p, " ");
427 print_dest(p, inst, i);
428 emit(p, " = ");
429 print_expression( p, i, fmt, ap);
430 if (inst->Saturate)
431 saturate(p, inst, i);
432 }
433
434 va_end( ap );
435 }
436
437 static void assign4( struct fragment_program *p,
438 const struct fp_instruction *inst,
439 const char *fmt,
440 ... )
441 {
442 GLuint i;
443 va_list ap;
444 va_start( ap, fmt );
445
446 for (i = 0; i < 4; i++)
447 if (inst->DstReg.WriteMask[i]) {
448 emit(p, " ");
449 print_dest(p, inst, i);
450 emit(p, " = ");
451 print_expression( p, i, fmt, ap);
452 if (inst->Saturate)
453 saturate(p, inst, i);
454 }
455
456 va_end( ap );
457 }
458
459 static void assign4_replicate( struct fragment_program *p,
460 const struct fp_instruction *inst,
461 const char *fmt,
462 ... )
463 {
464 GLuint i, first = 0;
465 GLboolean ok = 0;
466 va_list ap;
467
468 for (i = 0; i < 4; i++)
469 if (inst->DstReg.WriteMask[i]) {
470 ok = 1;
471 first = i;
472 break;
473 }
474
475 if (!ok) return;
476
477 va_start( ap, fmt );
478
479 emit(p, " ");
480
481 print_dest(p, inst, first);
482 emit(p, " = ");
483 print_expression( p, 0, fmt, ap);
484 if (inst->Saturate)
485 saturate(p, inst, first);
486 va_end( ap );
487
488 for (i = first+1; i < 4; i++)
489 if (inst->DstReg.WriteMask[i]) {
490 emit(p, " ");
491 print_dest(p, inst, i);
492 emit(p, " = ");
493 print_dest(p, inst, first);
494 emit(p, ";\n");
495 }
496 }
497
498
499
500
501 static GLuint nr_args( GLuint opcode )
502 {
503 switch (opcode) {
504 case FP_OPCODE_ABS: return 1;
505 case FP_OPCODE_ADD: return 2;
506 case FP_OPCODE_CMP: return 3;
507 case FP_OPCODE_COS: return 1;
508 case FP_OPCODE_DP3: return 2;
509 case FP_OPCODE_DP4: return 2;
510 case FP_OPCODE_DPH: return 2;
511 case FP_OPCODE_DST: return 2;
512 case FP_OPCODE_EX2: return 1;
513 case FP_OPCODE_FLR: return 1;
514 case FP_OPCODE_FRC: return 1;
515 case FP_OPCODE_KIL: return 1;
516 case FP_OPCODE_LG2: return 1;
517 case FP_OPCODE_LIT: return 1;
518 case FP_OPCODE_LRP: return 3;
519 case FP_OPCODE_MAD: return 3;
520 case FP_OPCODE_MAX: return 2;
521 case FP_OPCODE_MIN: return 2;
522 case FP_OPCODE_MOV: return 1;
523 case FP_OPCODE_MUL: return 2;
524 case FP_OPCODE_POW: return 2;
525 case FP_OPCODE_RCP: return 1;
526 case FP_OPCODE_RSQ: return 1;
527 case FP_OPCODE_SCS: return 1;
528 case FP_OPCODE_SGE: return 2;
529 case FP_OPCODE_SIN: return 1;
530 case FP_OPCODE_SLT: return 2;
531 case FP_OPCODE_SUB: return 2;
532 case FP_OPCODE_SWZ: return 1;
533 case FP_OPCODE_TEX: return 1;
534 case FP_OPCODE_TXB: return 1;
535 case FP_OPCODE_TXP: return 1;
536 case FP_OPCODE_XPD: return 2;
537 default: return 0;
538 }
539 }
540
541
542
543 static void translate_program( struct fragment_program *p )
544 {
545 const struct fp_instruction *inst = p->Instructions;
546
547 for (; inst->Opcode != FP_OPCODE_END; inst++) {
548
549 GLuint src[3], i;
550 GLuint nr = nr_args( inst->Opcode );
551
552 for (i = 0; i < nr; i++)
553 src[i] = src_vector( &inst->SrcReg[i] );
554
555 /* Print the original program instruction string */
556 if (p->Base.String)
557 {
558 const char *s = (const char *) p->Base.String + inst->StringPos;
559 emit(p, " /* ");
560 while (*s != ';') {
561 emit_char(p, *s);
562 s++;
563 }
564 emit(p, "; */\n");
565 }
566
567 switch (inst->Opcode) {
568 case FP_OPCODE_ABS:
569 assign4(p, inst, "fabsf(%s)", src[0]);
570 break;
571
572 case FP_OPCODE_ADD:
573 assign4(p, inst, "%s + %s", src[0], src[1]);
574 break;
575
576 case FP_OPCODE_CMP:
577 assign4(p, inst, "%s < 0.0F ? %s : %s", src[0], src[1], src[2]);
578 break;
579
580 case FP_OPCODE_COS:
581 assign4_replicate(p, inst, "COS(%s)", src[0]);
582 break;
583
584 case FP_OPCODE_DP3:
585 assign4_replicate(p, inst,
586 "%s*%s + %s*%s + %s*%s",
587 deref(src[0],_X),
588 deref(src[1],_X),
589 deref(src[0],_Y),
590 deref(src[1],_Y),
591 deref(src[0],_Z),
592 deref(src[1],_Z));
593 break;
594
595 case FP_OPCODE_DP4:
596 assign4_replicate(p, inst,
597 "%s*%s + %s*%s + %s*%s + %s*%s",
598 deref(src[0],_X),
599 deref(src[1],_X),
600 deref(src[0],_Y),
601 deref(src[1],_Y),
602 deref(src[0],_Z),
603 deref(src[1],_Z));
604 break;
605
606 case FP_OPCODE_DPH:
607 assign4_replicate(p, inst,
608 "%s*%s + %s*%s + %s*%s + %s",
609 deref(src[0],_X),
610 deref(src[1],_X),
611 deref(src[0],_Y),
612 deref(src[1],_Y),
613 deref(src[1],_Z));
614 break;
615
616 case FP_OPCODE_DST:
617 /* result[0] = 1 * 1;
618 * result[1] = a[1] * b[1];
619 * result[2] = a[2] * 1;
620 * result[3] = 1 * b[3];
621 */
622 assign_single(0, p, inst, "1.0");
623
624 assign_single(1, p, inst, "%s * %s",
625 deref(src[0], _Y), deref(src[1], _Y));
626
627 assign_single(2, p, inst, "%s", deref(src[0], _Z));
628 assign_single(3, p, inst, "%s", deref(src[1], _W));
629 break;
630
631 case FP_OPCODE_EX2:
632 assign4_replicate(p, inst, "powf(2.0, %s)", src[0]);
633 break;
634
635 case FP_OPCODE_FLR:
636 assign4_replicate(p, inst, "floorf(%s)", src[0]);
637 break;
638
639 case FP_OPCODE_FRC:
640 assign4_replicate(p, inst, "%s - floorf(%s)", src[0], src[0]);
641 break;
642
643 case FP_OPCODE_KIL:
644 /* TODO */
645 break;
646
647 case FP_OPCODE_LG2:
648 assign4_replicate(p, inst, "LOG2(%s)", src[0]);
649 break;
650
651 case FP_OPCODE_LIT:
652 assign_single(0, p, inst, "1.0");
653 assign_single(1, p, inst, "MIN2(%s, 0)", deref(src[0], _X));
654 assign_single(2, p, inst, "(%s > 0.0) ? expf(%s * MIN2(%s, 0)) : 0.0",
655 deref(src[0], _X),
656 deref(src[0], _Z),
657 deref(src[0], _Y));
658 assign_single(3, p, inst, "1.0");
659 break;
660
661 case FP_OPCODE_LRP:
662 assign4(p, inst,
663 "%s * %s + (1.0 - %s) * %s",
664 src[0], src[1], src[0], src[2]);
665 break;
666
667 case FP_OPCODE_MAD:
668 assign4(p, inst, "%s * %s + %s", src[0], src[1], src[2]);
669 break;
670
671 case FP_OPCODE_MAX:
672 assign4(p, inst, "MAX2(%s, %s)", src[0], src[1]);
673 break;
674
675 case FP_OPCODE_MIN:
676 assign4(p, inst, "MIN2(%s, %s)", src[0], src[1]);
677 break;
678
679 case FP_OPCODE_MOV:
680 assign4(p, inst, "%s", src[0]);
681 break;
682
683 case FP_OPCODE_MUL:
684 assign4(p, inst, "%s * %s", src[0], src[1]);
685 break;
686
687 case FP_OPCODE_POW:
688 assign4_replicate(p, inst, "powf(%s, %s)", src[0], src[1]);
689 break;
690
691 case FP_OPCODE_RCP:
692 assign4_replicate(p, inst, "1.0/%s", src[0]);
693 break;
694
695 case FP_OPCODE_RSQ:
696 assign4_replicate(p, inst, "_mesa_inv_sqrtf(%s)", src[0]);
697 break;
698
699 case FP_OPCODE_SCS:
700 if (inst->DstReg.WriteMask[0]) {
701 assign_single(0, p, inst, "cosf(%s)", deref(src[0], _X));
702 }
703
704 if (inst->DstReg.WriteMask[1]) {
705 assign_single(1, p, inst, "sinf(%s)", deref(src[0], _X));
706 }
707 break;
708
709 case FP_OPCODE_SGE:
710 assign4(p, inst, "%s >= %s ? 1.0 : 0.0", src[0], src[1]);
711 break;
712
713 case FP_OPCODE_SIN:
714 assign4_replicate(p, inst, "sinf(%s)", src[0]);
715 break;
716
717 case FP_OPCODE_SLT:
718 assign4(p, inst, "%s < %s ? 1.0 : 0.0", src[0], src[1]);
719 break;
720
721 case FP_OPCODE_SUB:
722 assign4(p, inst, "%s - %s", src[0], src[1]);
723 break;
724
725 case FP_OPCODE_SWZ: /* same implementation as MOV: */
726 assign4(p, inst, "%s", src[0]);
727 break;
728
729 case FP_OPCODE_TEX:
730 do_tex(p, inst, "TEX", inst->TexSrcUnit, src[0]);
731 break;
732
733 case FP_OPCODE_TXB:
734 do_tex(p, inst, "TXB", inst->TexSrcUnit, src[0]);
735 break;
736
737 case FP_OPCODE_TXP:
738 do_tex(p, inst, "TXP", inst->TexSrcUnit, src[0]);
739 break;
740
741 case FP_OPCODE_XPD:
742 /* Cross product:
743 * result.x = src[0].y * src[1].z - src[0].z * src[1].y;
744 * result.y = src[0].z * src[1].x - src[0].x * src[1].z;
745 * result.z = src[0].x * src[1].y - src[0].y * src[1].x;
746 * result.w = undef;
747 */
748 assign4(p, inst,
749 "%s * %s - %s * %s",
750 swizzle(src[0], _Y, _Z, _X, _ONE),
751 swizzle(src[1], _Z, _X, _Y, _ONE),
752 swizzle(src[0], _Z, _X, _Y, _ONE),
753 swizzle(src[1], _Y, _Z, _X, _ONE));
754 break;
755
756 default:
757 emit(p, "BOGUS OPCODE\n");
758 return;
759 }
760 }
761 }
762
763
764
765
766
767 void _swrast_translate_program( GLcontext *ctx )
768 {
769 struct fragment_program *p = ctx->FragmentProgram.Current;
770
771 if (p) {
772 p->c_strlen = 0;
773
774 print_header( p );
775 translate_program( p );
776 print_footer( p );
777 emit_char(p, 0);
778
779 printf("C program length: %d/%d chars\n", p->c_strlen, strlen(p->c_str));
780 printf(p->c_str);
781 }
782 }
783