st_mesa_to_tgsi.c revision 4295b34d25f40f38b8cfd3ebdc64aef29d0666db
1/**************************************************************************
2 *
3 * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28/*
29 * \author
30 * Michal Krol,
31 * Keith Whitwell
32 */
33
34#include "pipe/p_compiler.h"
35#include "pipe/p_shader_tokens.h"
36#include "pipe/p_state.h"
37#include "tgsi/tgsi_ureg.h"
38#include "st_mesa_to_tgsi.h"
39#include "shader/prog_instruction.h"
40#include "shader/prog_parameter.h"
41#include "shader/prog_print.h"
42#include "util/u_debug.h"
43#include "util/u_math.h"
44#include "util/u_memory.h"
45
46struct label {
47   unsigned branch_target;
48   unsigned token;
49};
50
51struct st_translate {
52   struct ureg_program *ureg;
53
54   struct ureg_dst temps[MAX_PROGRAM_TEMPS];
55   struct ureg_src *constants;
56   struct ureg_dst outputs[PIPE_MAX_SHADER_OUTPUTS];
57   struct ureg_src inputs[PIPE_MAX_SHADER_INPUTS];
58   struct ureg_dst address[1];
59   struct ureg_src samplers[PIPE_MAX_SAMPLERS];
60
61   const GLuint *inputMapping;
62   const GLuint *outputMapping;
63
64   /* For every instruction that contains a label (eg CALL), keep
65    * details so that we can go back afterwards and emit the correct
66    * tgsi instruction number for each label.
67    */
68   struct label *labels;
69   unsigned labels_size;
70   unsigned labels_count;
71
72   /* Keep a record of the tgsi instruction number that each mesa
73    * instruction starts at, will be used to fix up labels after
74    * translation.
75    */
76   unsigned *insn;
77   unsigned insn_size;
78   unsigned insn_count;
79
80   GLenum procType;
81
82   boolean error;
83};
84
85
86static unsigned *get_label( struct st_translate *t,
87                            unsigned branch_target )
88{
89   unsigned i;
90
91   if (t->labels_count + 1 >= t->labels_size) {
92      unsigned old_size = t->labels_size;
93      t->labels_size = 1 << (util_logbase2(t->labels_size) + 1);
94      t->labels = REALLOC( t->labels,
95                           old_size * sizeof t->labels[0],
96                           t->labels_size * sizeof t->labels[0] );
97      if (t->labels == NULL) {
98         static unsigned dummy;
99         t->error = TRUE;
100         return &dummy;
101      }
102   }
103
104   i = t->labels_count++;
105   t->labels[i].branch_target = branch_target;
106   return &t->labels[i].token;
107}
108
109
110static void set_insn_start( struct st_translate *t,
111                            unsigned start )
112{
113   if (t->insn_count + 1 >= t->insn_size) {
114      unsigned old_size = t->insn_size;
115      t->insn_size = 1 << (util_logbase2(t->insn_size) + 1);
116      t->insn = REALLOC( t->insn,
117                         old_size * sizeof t->insn[0],
118                         t->insn_size * sizeof t->insn[0] );
119      if (t->insn == NULL) {
120         t->error = TRUE;
121         return;
122      }
123   }
124
125   t->insn[t->insn_count++] = start;
126}
127
128
129
130/*
131 * Map mesa register file to TGSI register file.
132 */
133static struct ureg_dst
134dst_register( struct st_translate *t,
135              gl_register_file file,
136              GLuint index )
137{
138   switch( file ) {
139   case PROGRAM_UNDEFINED:
140      return ureg_dst_undef();
141
142   case PROGRAM_TEMPORARY:
143      if (ureg_dst_is_undef(t->temps[index]))
144         t->temps[index] = ureg_DECL_temporary( t->ureg );
145
146      return t->temps[index];
147
148   case PROGRAM_OUTPUT:
149      return t->outputs[t->outputMapping[index]];
150
151   case PROGRAM_ADDRESS:
152      return t->address[index];
153
154   default:
155      assert( 0 );
156      return ureg_dst_undef();
157   }
158}
159
160
161
162static struct ureg_src
163src_register( struct st_translate *t,
164              gl_register_file file,
165              GLuint index )
166{
167   switch( file ) {
168   case PROGRAM_UNDEFINED:
169      return ureg_src_undef();
170
171   case PROGRAM_TEMPORARY:
172      if (ureg_dst_is_undef(t->temps[index]))
173         t->temps[index] = ureg_DECL_temporary( t->ureg );
174      return ureg_src(t->temps[index]);
175
176   case PROGRAM_STATE_VAR:
177   case PROGRAM_NAMED_PARAM:
178   case PROGRAM_UNIFORM:
179   case PROGRAM_CONSTANT:
180      return t->constants[index];
181
182   case PROGRAM_INPUT:
183      return t->inputs[t->inputMapping[index]];
184
185   case PROGRAM_OUTPUT:
186      return ureg_src(t->outputs[t->outputMapping[index]]); /* not needed? */
187
188   case PROGRAM_ADDRESS:
189      return ureg_src(t->address[index]);
190
191   default:
192      assert( 0 );
193      return ureg_src_undef();
194   }
195}
196
197
198/*
199 * Map mesa texture target to TGSI texture target.
200 */
201static unsigned
202translate_texture_target( GLuint textarget,
203                          GLboolean shadow )
204{
205   if (shadow) {
206      switch( textarget ) {
207      case TEXTURE_1D_INDEX:   return TGSI_TEXTURE_SHADOW1D;
208      case TEXTURE_2D_INDEX:   return TGSI_TEXTURE_SHADOW2D;
209      case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_SHADOWRECT;
210      default: break;
211      }
212   }
213
214   switch( textarget ) {
215   case TEXTURE_1D_INDEX:   return TGSI_TEXTURE_1D;
216   case TEXTURE_2D_INDEX:   return TGSI_TEXTURE_2D;
217   case TEXTURE_3D_INDEX:   return TGSI_TEXTURE_3D;
218   case TEXTURE_CUBE_INDEX: return TGSI_TEXTURE_CUBE;
219   case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_RECT;
220   default:
221      assert( 0 );
222      return TGSI_TEXTURE_1D;
223   }
224}
225
226
227
228static struct ureg_dst
229translate_dst( struct st_translate *t,
230               const struct prog_dst_register *DstReg,
231               boolean saturate )
232{
233   struct ureg_dst dst = dst_register( t,
234                                       DstReg->File,
235                                       DstReg->Index );
236
237   dst = ureg_writemask( dst,
238                         DstReg->WriteMask );
239
240   if (saturate)
241      dst = ureg_saturate( dst );
242
243   if (DstReg->RelAddr)
244      dst = ureg_dst_indirect( dst, ureg_src(t->address[0]) );
245
246   return dst;
247}
248
249
250
251
252
253static struct ureg_src
254translate_src( struct st_translate *t,
255               const struct prog_src_register *SrcReg )
256{
257   struct ureg_src src = src_register( t, SrcReg->File, SrcReg->Index );
258
259   src = ureg_swizzle( src,
260                       GET_SWZ( SrcReg->Swizzle, 0 ) & 0x3,
261                       GET_SWZ( SrcReg->Swizzle, 1 ) & 0x3,
262                       GET_SWZ( SrcReg->Swizzle, 2 ) & 0x3,
263                       GET_SWZ( SrcReg->Swizzle, 3 ) & 0x3);
264
265   if (SrcReg->Negate == NEGATE_XYZW)
266      src = ureg_negate(src);
267
268   if (SrcReg->Abs)
269      src = ureg_abs(src);
270
271   if (SrcReg->RelAddr)
272      src = ureg_src_indirect( src, ureg_src(t->address[0]));
273
274   return src;
275}
276
277static struct ureg_src swizzle_4v( struct ureg_src src,
278                                   const unsigned *swz )
279{
280   return ureg_swizzle( src, swz[0], swz[1], swz[2], swz[3] );
281}
282
283
284/* Translate SWZ instructions into a single MAD.  EG:
285 *
286 *   SWZ dst, src.x-y10
287 *
288 * becomes:
289 *
290 *   MAD dst {1,-1,0,0}, src.xyxx, {0,0,1,0}
291 */
292static void emit_swz( struct st_translate *t,
293                      struct ureg_dst dst,
294                      const struct prog_src_register *SrcReg )
295{
296   struct ureg_program *ureg = t->ureg;
297   struct ureg_src src = src_register( t, SrcReg->File, SrcReg->Index );
298
299   unsigned negate_mask =  SrcReg->Negate;
300
301   unsigned one_mask = ((GET_SWZ(SrcReg->Swizzle, 0) == SWIZZLE_ONE) << 0 |
302                        (GET_SWZ(SrcReg->Swizzle, 1) == SWIZZLE_ONE) << 1 |
303                        (GET_SWZ(SrcReg->Swizzle, 2) == SWIZZLE_ONE) << 2 |
304                        (GET_SWZ(SrcReg->Swizzle, 3) == SWIZZLE_ONE) << 3);
305
306   unsigned zero_mask = ((GET_SWZ(SrcReg->Swizzle, 0) == SWIZZLE_ZERO) << 0 |
307                         (GET_SWZ(SrcReg->Swizzle, 1) == SWIZZLE_ZERO) << 1 |
308                         (GET_SWZ(SrcReg->Swizzle, 2) == SWIZZLE_ZERO) << 2 |
309                         (GET_SWZ(SrcReg->Swizzle, 3) == SWIZZLE_ZERO) << 3);
310
311   unsigned negative_one_mask = one_mask & negate_mask;
312   unsigned positive_one_mask = one_mask & ~negate_mask;
313
314   struct ureg_src imm;
315   unsigned i;
316   unsigned mul_swizzle[4] = {0,0,0,0};
317   unsigned add_swizzle[4] = {0,0,0,0};
318   unsigned src_swizzle[4] = {0,0,0,0};
319   boolean need_add = FALSE;
320   boolean need_mul = FALSE;
321
322   if (dst.WriteMask == 0)
323      return;
324
325   /* Is this just a MOV?
326    */
327   if (zero_mask == 0 &&
328       one_mask == 0 &&
329       (negate_mask == 0 || negate_mask == TGSI_WRITEMASK_XYZW))
330   {
331      ureg_MOV( ureg, dst, translate_src( t, SrcReg ));
332      return;
333   }
334
335#define IMM_ZERO    0
336#define IMM_ONE     1
337#define IMM_NEG_ONE 2
338
339   imm = ureg_imm3f( ureg, 0, 1, -1 );
340
341   for (i = 0; i < 4; i++) {
342      unsigned bit = 1 << i;
343
344      if (dst.WriteMask & bit) {
345         if (positive_one_mask & bit) {
346            mul_swizzle[i] = IMM_ZERO;
347            add_swizzle[i] = IMM_ONE;
348            need_add = TRUE;
349         }
350         else if (negative_one_mask & bit) {
351            mul_swizzle[i] = IMM_ZERO;
352            add_swizzle[i] = IMM_NEG_ONE;
353            need_add = TRUE;
354         }
355         else if (zero_mask & bit) {
356            mul_swizzle[i] = IMM_ZERO;
357            add_swizzle[i] = IMM_ZERO;
358            need_add = TRUE;
359         }
360         else {
361            add_swizzle[i] = IMM_ZERO;
362            src_swizzle[i] = GET_SWZ(SrcReg->Swizzle, i);
363            need_mul = TRUE;
364            if (negate_mask & bit) {
365               mul_swizzle[i] = IMM_NEG_ONE;
366            }
367            else {
368               mul_swizzle[i] = IMM_ONE;
369            }
370         }
371      }
372   }
373
374   if (need_mul && need_add) {
375      ureg_MAD( ureg,
376                dst,
377                swizzle_4v( src, src_swizzle ),
378                swizzle_4v( imm, mul_swizzle ),
379                swizzle_4v( imm, add_swizzle ) );
380   }
381   else if (need_mul) {
382      ureg_MUL( ureg,
383                dst,
384                swizzle_4v( src, src_swizzle ),
385                swizzle_4v( imm, mul_swizzle ) );
386   }
387   else if (need_add) {
388      ureg_MOV( ureg,
389                dst,
390                swizzle_4v( imm, add_swizzle ) );
391   }
392   else {
393      assert(0);
394   }
395
396#undef IMM_ZERO
397#undef IMM_ONE
398#undef IMM_NEG_ONE
399}
400
401
402
403static unsigned
404translate_opcode( unsigned op )
405{
406   switch( op ) {
407   case OPCODE_ARL:
408      return TGSI_OPCODE_ARL;
409   case OPCODE_ABS:
410      return TGSI_OPCODE_ABS;
411   case OPCODE_ADD:
412      return TGSI_OPCODE_ADD;
413   case OPCODE_BGNLOOP:
414      return TGSI_OPCODE_BGNLOOP;
415   case OPCODE_BGNSUB:
416      return TGSI_OPCODE_BGNSUB;
417   case OPCODE_BRA:
418      return TGSI_OPCODE_BRA;
419   case OPCODE_BRK:
420      return TGSI_OPCODE_BRK;
421   case OPCODE_CAL:
422      return TGSI_OPCODE_CAL;
423   case OPCODE_CMP:
424      return TGSI_OPCODE_CMP;
425   case OPCODE_CONT:
426      return TGSI_OPCODE_CONT;
427   case OPCODE_COS:
428      return TGSI_OPCODE_COS;
429   case OPCODE_DDX:
430      return TGSI_OPCODE_DDX;
431   case OPCODE_DDY:
432      return TGSI_OPCODE_DDY;
433   case OPCODE_DP2:
434      return TGSI_OPCODE_DP2;
435   case OPCODE_DP2A:
436      return TGSI_OPCODE_DP2A;
437   case OPCODE_DP3:
438      return TGSI_OPCODE_DP3;
439   case OPCODE_DP4:
440      return TGSI_OPCODE_DP4;
441   case OPCODE_DPH:
442      return TGSI_OPCODE_DPH;
443   case OPCODE_DST:
444      return TGSI_OPCODE_DST;
445   case OPCODE_ELSE:
446      return TGSI_OPCODE_ELSE;
447   case OPCODE_ENDIF:
448      return TGSI_OPCODE_ENDIF;
449   case OPCODE_ENDLOOP:
450      return TGSI_OPCODE_ENDLOOP;
451   case OPCODE_ENDSUB:
452      return TGSI_OPCODE_ENDSUB;
453   case OPCODE_EX2:
454      return TGSI_OPCODE_EX2;
455   case OPCODE_EXP:
456      return TGSI_OPCODE_EXP;
457   case OPCODE_FLR:
458      return TGSI_OPCODE_FLR;
459   case OPCODE_FRC:
460      return TGSI_OPCODE_FRC;
461   case OPCODE_IF:
462      return TGSI_OPCODE_IF;
463   case OPCODE_TRUNC:
464      return TGSI_OPCODE_TRUNC;
465   case OPCODE_KIL:
466      return TGSI_OPCODE_KIL;
467   case OPCODE_KIL_NV:
468      return TGSI_OPCODE_KILP;
469   case OPCODE_LG2:
470      return TGSI_OPCODE_LG2;
471   case OPCODE_LOG:
472      return TGSI_OPCODE_LOG;
473   case OPCODE_LIT:
474      return TGSI_OPCODE_LIT;
475   case OPCODE_LRP:
476      return TGSI_OPCODE_LRP;
477   case OPCODE_MAD:
478      return TGSI_OPCODE_MAD;
479   case OPCODE_MAX:
480      return TGSI_OPCODE_MAX;
481   case OPCODE_MIN:
482      return TGSI_OPCODE_MIN;
483   case OPCODE_MOV:
484      return TGSI_OPCODE_MOV;
485   case OPCODE_MUL:
486      return TGSI_OPCODE_MUL;
487   case OPCODE_NOISE1:
488      return TGSI_OPCODE_NOISE1;
489   case OPCODE_NOISE2:
490      return TGSI_OPCODE_NOISE2;
491   case OPCODE_NOISE3:
492      return TGSI_OPCODE_NOISE3;
493   case OPCODE_NOISE4:
494      return TGSI_OPCODE_NOISE4;
495   case OPCODE_NOP:
496      return TGSI_OPCODE_NOP;
497   case OPCODE_NRM3:
498      return TGSI_OPCODE_NRM;
499   case OPCODE_NRM4:
500      return TGSI_OPCODE_NRM4;
501   case OPCODE_POW:
502      return TGSI_OPCODE_POW;
503   case OPCODE_RCP:
504      return TGSI_OPCODE_RCP;
505   case OPCODE_RET:
506      return TGSI_OPCODE_RET;
507   case OPCODE_RSQ:
508      return TGSI_OPCODE_RSQ;
509   case OPCODE_SCS:
510      return TGSI_OPCODE_SCS;
511   case OPCODE_SEQ:
512      return TGSI_OPCODE_SEQ;
513   case OPCODE_SGE:
514      return TGSI_OPCODE_SGE;
515   case OPCODE_SGT:
516      return TGSI_OPCODE_SGT;
517   case OPCODE_SIN:
518      return TGSI_OPCODE_SIN;
519   case OPCODE_SLE:
520      return TGSI_OPCODE_SLE;
521   case OPCODE_SLT:
522      return TGSI_OPCODE_SLT;
523   case OPCODE_SNE:
524      return TGSI_OPCODE_SNE;
525   case OPCODE_SSG:
526      return TGSI_OPCODE_SSG;
527   case OPCODE_SUB:
528      return TGSI_OPCODE_SUB;
529   case OPCODE_SWZ:
530      return TGSI_OPCODE_SWZ;
531   case OPCODE_TEX:
532      return TGSI_OPCODE_TEX;
533   case OPCODE_TXB:
534      return TGSI_OPCODE_TXB;
535   case OPCODE_TXD:
536      return TGSI_OPCODE_TXD;
537   case OPCODE_TXL:
538      return TGSI_OPCODE_TXL;
539   case OPCODE_TXP:
540      return TGSI_OPCODE_TXP;
541   case OPCODE_XPD:
542      return TGSI_OPCODE_XPD;
543   case OPCODE_END:
544      return TGSI_OPCODE_END;
545   default:
546      assert( 0 );
547      return TGSI_OPCODE_NOP;
548   }
549}
550
551
552static void
553compile_instruction(
554   struct st_translate *t,
555   const struct prog_instruction *inst )
556{
557   struct ureg_program *ureg = t->ureg;
558   GLuint i;
559   struct ureg_dst dst[1];
560   struct ureg_src src[4];
561   unsigned num_dst;
562   unsigned num_src;
563
564   num_dst = _mesa_num_inst_dst_regs( inst->Opcode );
565   num_src = _mesa_num_inst_src_regs( inst->Opcode );
566
567   if (num_dst)
568      dst[0] = translate_dst( t,
569                              &inst->DstReg,
570                              inst->SaturateMode );
571
572   for (i = 0; i < num_src; i++)
573      src[i] = translate_src( t, &inst->SrcReg[i] );
574
575   switch( inst->Opcode ) {
576   case OPCODE_SWZ:
577      emit_swz( t, dst[0], &inst->SrcReg[0] );
578      return;
579
580   case OPCODE_BGNLOOP:
581   case OPCODE_CAL:
582   case OPCODE_ELSE:
583   case OPCODE_ENDLOOP:
584   case OPCODE_IF:
585      assert(num_dst == 0);
586
587      /* Currently assuming a 1:1 relationship between mesa
588       * instructions and TGSI instructions.  That won't always be the
589       * case, and to be generic we'll have to make a table of labels
590       * that get fixed up afterwards.  Or make labels symbolic in
591       * TGSI.
592       */
593      ureg_label_insn( ureg,
594                       translate_opcode( inst->Opcode ),
595                       src, num_src,
596                       get_label( t, inst->BranchTarget ));
597      return;
598
599   case OPCODE_TEX:
600   case OPCODE_TXB:
601   case OPCODE_TXD:
602   case OPCODE_TXL:
603   case OPCODE_TXP:
604      src[num_src++] = t->samplers[inst->TexSrcUnit];
605      ureg_tex_insn( ureg,
606                     translate_opcode( inst->Opcode ),
607                     dst, num_dst,
608                     translate_texture_target( inst->TexSrcTarget,
609                                               inst->TexShadow ),
610                     src, num_src );
611      return;
612
613
614   case OPCODE_SCS:
615      dst[0] = ureg_writemask(dst[0], TGSI_WRITEMASK_XY );
616      ureg_insn( ureg,
617                 translate_opcode( inst->Opcode ),
618                 dst, num_dst,
619                 src, num_src );
620      break;
621
622   case OPCODE_XPD:
623      dst[0] = ureg_writemask(dst[0], TGSI_WRITEMASK_XYZ );
624      ureg_insn( ureg,
625                 translate_opcode( inst->Opcode ),
626                 dst, num_dst,
627                 src, num_src );
628      break;
629
630   default:
631      ureg_insn( ureg,
632                 translate_opcode( inst->Opcode ),
633                 dst, num_dst,
634                 src, num_src );
635      break;
636   }
637
638}
639
640
641
642
643
644
645
646/**
647 * Emit the TGSI instructions for inverting the WPOS y coordinate.
648 */
649static void
650emit_inverted_wpos( struct st_translate *t,
651                    const struct gl_program *program )
652{
653   struct ureg_program *ureg = t->ureg;
654
655   /* Fragment program uses fragment position input.
656    * Need to replace instances of INPUT[WPOS] with temp T
657    * where T = INPUT[WPOS] by y is inverted.
658    */
659   static const gl_state_index winSizeState[STATE_LENGTH]
660      = { STATE_INTERNAL, STATE_FB_SIZE, 0, 0, 0 };
661
662   /* XXX: note we are modifying the incoming shader here!  Need to
663    * do this before emitting the constant decls below, or this
664    * will be missed:
665    */
666   unsigned winHeightConst = _mesa_add_state_reference(program->Parameters,
667                                                       winSizeState);
668
669   struct ureg_src winsize = ureg_DECL_constant( ureg, winHeightConst );
670   struct ureg_dst wpos_temp = ureg_DECL_temporary( ureg );
671   struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]];
672
673   /* MOV wpos_temp, input[wpos]
674    */
675   ureg_MOV( ureg, wpos_temp, wpos_input );
676
677   /* SUB wpos_temp.y, winsize_const, wpos_input
678    */
679   ureg_SUB( ureg,
680             ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ),
681             winsize,
682             wpos_input);
683
684   /* Use wpos_temp as position input from here on:
685    */
686   t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]] = ureg_src(wpos_temp);
687}
688
689
690
691
692/**
693 * Translate Mesa program to TGSI format.
694 * \param program  the program to translate
695 * \param numInputs  number of input registers used
696 * \param inputMapping  maps Mesa fragment program inputs to TGSI generic
697 *                      input indexes
698 * \param inputSemanticName  the TGSI_SEMANTIC flag for each input
699 * \param inputSemanticIndex  the semantic index (ex: which texcoord) for each input
700 * \param interpMode  the TGSI_INTERPOLATE_LINEAR/PERSP mode for each input
701
702 * \param numOutputs  number of output registers used
703 * \param outputMapping  maps Mesa fragment program outputs to TGSI
704 *                       generic outputs
705 * \param outputSemanticName  the TGSI_SEMANTIC flag for each output
706 * \param outputSemanticIndex  the semantic index (ex: which texcoord) for each output
707 *
708 * \return  array of translated tokens, caller's responsibility to free
709 */
710const struct tgsi_token *
711st_translate_mesa_program(
712   GLcontext *ctx,
713   uint procType,
714   const struct gl_program *program,
715   GLuint numInputs,
716   const GLuint inputMapping[],
717   const ubyte inputSemanticName[],
718   const ubyte inputSemanticIndex[],
719   const GLuint interpMode[],
720   const GLbitfield inputFlags[],
721   GLuint numOutputs,
722   const GLuint outputMapping[],
723   const ubyte outputSemanticName[],
724   const ubyte outputSemanticIndex[],
725   const GLbitfield outputFlags[] )
726{
727   struct st_translate translate, *t;
728   struct ureg_program *ureg;
729   const struct tgsi_token *tokens = NULL;
730   unsigned i;
731
732   t = &translate;
733   memset(t, 0, sizeof *t);
734
735   t->procType = procType;
736   t->inputMapping = inputMapping;
737   t->outputMapping = outputMapping;
738   t->ureg = ureg_create( procType );
739   if (t->ureg == NULL)
740      return NULL;
741
742   ureg = t->ureg;
743
744   _mesa_print_program(program);
745
746   /*
747    * Declare input attributes.
748    */
749   if (procType == TGSI_PROCESSOR_FRAGMENT) {
750      for (i = 0; i < numInputs; i++) {
751         t->inputs[i] = ureg_DECL_fs_input(ureg,
752                                           inputSemanticName[i],
753                                           inputSemanticIndex[i],
754                                           interpMode[i]);
755      }
756
757      if (program->InputsRead & FRAG_BIT_WPOS) {
758         /* Must do this after setting up t->inputs, and before
759          * emitting constant references, below:
760          */
761         emit_inverted_wpos( t, program );
762      }
763
764      /*
765       * Declare output attributes.
766       */
767      for (i = 0; i < numOutputs; i++) {
768         switch (outputSemanticName[i]) {
769         case TGSI_SEMANTIC_POSITION:
770            t->outputs[i] = ureg_DECL_output( ureg,
771                                              TGSI_SEMANTIC_POSITION, /* Z / Depth */
772                                              outputSemanticIndex[i] );
773
774            t->outputs[i] = ureg_writemask( t->outputs[i],
775                                            TGSI_WRITEMASK_Z );
776            break;
777         case TGSI_SEMANTIC_COLOR:
778            t->outputs[i] = ureg_DECL_output( ureg,
779                                              TGSI_SEMANTIC_COLOR,
780                                              outputSemanticIndex[i] );
781            break;
782         default:
783            assert(0);
784            return 0;
785         }
786      }
787   }
788   else {
789      for (i = 0; i < numInputs; i++) {
790         t->inputs[i] = ureg_DECL_vs_input(ureg, i);
791      }
792
793      for (i = 0; i < numOutputs; i++) {
794         t->outputs[i] = ureg_DECL_output( ureg,
795                                           outputSemanticName[i],
796                                           outputSemanticIndex[i] );
797      }
798   }
799
800   /* Declare address register.
801    */
802   if (program->NumAddressRegs > 0) {
803      assert( program->NumAddressRegs == 1 );
804      t->address[0] = ureg_DECL_address( ureg );
805   }
806
807
808   /* Emit constants and immediates.  Mesa uses a single index space
809    * for these, so we put all the translated regs in t->constants.
810    */
811   if (program->Parameters) {
812
813      t->constants = CALLOC( program->Parameters->NumParameters,
814                             sizeof t->constants[0] );
815      if (t->constants == NULL)
816         goto out;
817
818      for (i = 0; i < program->Parameters->NumParameters; i++) {
819         switch (program->Parameters->Parameters[i].Type) {
820         case PROGRAM_ENV_PARAM:
821         case PROGRAM_STATE_VAR:
822         case PROGRAM_NAMED_PARAM:
823         case PROGRAM_UNIFORM:
824            t->constants[i] = ureg_DECL_constant( ureg, i );
825            break;
826
827            /* Emit immediates only when there is no address register
828             * in use.  FIXME: Be smarter and recognize param arrays:
829             * indirect addressing is only valid within the referenced
830             * array.
831             */
832         case PROGRAM_CONSTANT:
833            if (program->NumAddressRegs > 0)
834               t->constants[i] = ureg_DECL_constant( ureg, i );
835            else
836               t->constants[i] =
837                  ureg_DECL_immediate( ureg,
838                                       program->Parameters->ParameterValues[i],
839                                       4 );
840            break;
841         default:
842            break;
843         }
844      }
845   }
846
847   /* texture samplers */
848   for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
849      if (program->SamplersUsed & (1 << i)) {
850         t->samplers[i] = ureg_DECL_sampler( ureg, i );
851      }
852   }
853
854   /* Emit each instruction in turn:
855    */
856   for (i = 0; i < program->NumInstructions; i++) {
857      set_insn_start( t, ureg_get_instruction_number( ureg ));
858      compile_instruction( t, &program->Instructions[i] );
859   }
860
861   /* Fix up all emitted labels:
862    */
863   for (i = 0; i < t->labels_count; i++) {
864      ureg_fixup_label( ureg,
865                        t->labels[i].token,
866                        t->insn[t->labels[i].branch_target] );
867   }
868
869   tokens = ureg_get_tokens( ureg, NULL );
870   ureg_destroy( ureg );
871
872out:
873   FREE(t->insn);
874   FREE(t->labels);
875   FREE(t->constants);
876
877   if (t->error) {
878      debug_printf("%s: translate error flag set\n", __FUNCTION__);
879      FREE((void *)tokens);
880      tokens = NULL;
881   }
882
883   if (!tokens) {
884      debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__);
885      _mesa_print_program(program);
886      assert(0);
887   }
888
889   return tokens;
890}
891