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