1/**********************************************************
2 * Copyright 2008-2009 VMware, Inc.  All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 **********************************************************/
25
26/**
27 * @file
28 * SVGA Shader Dump Facilities
29 *
30 * @author Michal Krol <michal@vmware.com>
31 */
32
33#include "svga_shader.h"
34#include "svga_shader_dump.h"
35#include "svga_shader_op.h"
36#include "util/u_debug.h"
37
38#include "../svga_hw_reg.h"
39#include "svga3d_shaderdefs.h"
40
41struct dump_info
42{
43   uint32 version;
44   boolean is_ps;
45   int indent;
46};
47
48#define DUMP_MAX_OP_SRC 4
49
50struct dump_op
51{
52   struct sh_op op;
53   struct sh_dstreg dst;
54   struct sh_srcreg dstind;
55   struct sh_srcreg src[DUMP_MAX_OP_SRC];
56   struct sh_srcreg srcind[DUMP_MAX_OP_SRC];
57   struct sh_srcreg p0;
58};
59
60static void
61dump_indent(int indent)
62{
63   int i;
64
65   for (i = 0; i < indent; ++i) {
66      _debug_printf("  ");
67   }
68}
69
70static void dump_op( struct sh_op op, const char *mnemonic )
71{
72   assert( op.is_reg == 0 );
73
74   if (op.predicated) {
75      _debug_printf("(p0) ");
76   }
77   if (op.coissue)
78      _debug_printf( "+" );
79   _debug_printf( "%s", mnemonic );
80
81   switch (op.opcode) {
82   case SVGA3DOP_TEX:
83      switch (op.control) {
84      case 0:
85         break;
86      case 1 /* PROJECT */:
87         _debug_printf("p");
88         break;
89      case 2 /* BIAS */:
90         _debug_printf("b");
91         break;
92      default:
93         assert(0);
94      }
95      break;
96
97   case SVGA3DOP_IFC:
98   case SVGA3DOP_BREAKC:
99   case SVGA3DOP_SETP:
100      switch (op.control) {
101      case SVGA3DOPCOMP_GT:
102         _debug_printf("_gt");
103         break;
104      case SVGA3DOPCOMP_EQ:
105         _debug_printf("_eq");
106         break;
107      case SVGA3DOPCOMP_GE:
108         _debug_printf("_ge");
109         break;
110      case SVGA3DOPCOMP_LT:
111         _debug_printf("_lt");
112         break;
113      case SVGA3DOPCOMPC_NE:
114         _debug_printf("_ne");
115         break;
116      case SVGA3DOPCOMP_LE:
117         _debug_printf("_le");
118         break;
119      default:
120         assert(0);
121      }
122      break;
123
124   default:
125      assert(op.control == 0);
126   }
127}
128
129static void
130format_reg(const char *name,
131           const struct sh_reg reg,
132           const struct sh_srcreg *indreg)
133{
134   if (reg.relative) {
135      assert(indreg);
136
137      if (sh_srcreg_type(*indreg) == SVGA3DREG_LOOP) {
138         _debug_printf("%s[aL+%u]", name, reg.number);
139      } else {
140         _debug_printf("%s[a%u.x+%u]", name, indreg->number, reg.number);
141      }
142   } else {
143      _debug_printf("%s%u", name, reg.number);
144   }
145}
146
147static void dump_reg( struct sh_reg reg, struct sh_srcreg *indreg, const struct dump_info *di )
148{
149   assert( reg.is_reg == 1 );
150
151   switch (sh_reg_type( reg )) {
152   case SVGA3DREG_TEMP:
153      format_reg("r", reg, NULL);
154      break;
155
156   case SVGA3DREG_INPUT:
157      format_reg("v", reg, indreg);
158      break;
159
160   case SVGA3DREG_CONST:
161      format_reg("c", reg, indreg);
162      break;
163
164   case SVGA3DREG_ADDR:    /* VS */
165   /* SVGA3DREG_TEXTURE */ /* PS */
166      assert(!reg.relative);
167      if (di->is_ps) {
168         format_reg("t", reg, NULL);
169      } else {
170         format_reg("a", reg, NULL);
171      }
172      break;
173
174   case SVGA3DREG_RASTOUT:
175      assert(!reg.relative);
176      switch (reg.number) {
177      case 0 /*POSITION*/:
178         _debug_printf( "oPos" );
179         break;
180      case 1 /*FOG*/:
181         _debug_printf( "oFog" );
182         break;
183      case 2 /*POINT_SIZE*/:
184         _debug_printf( "oPts" );
185         break;
186      default:
187         assert( 0 );
188         _debug_printf( "???" );
189      }
190      break;
191
192   case SVGA3DREG_ATTROUT:
193      assert( reg.number < 2 );
194      format_reg("oD", reg, NULL);
195      break;
196
197   case SVGA3DREG_TEXCRDOUT:  /* VS */
198   /* SVGA3DREG_OUTPUT */     /* VS3.0+ */
199      if (!di->is_ps && di->version >= SVGA3D_VS_30) {
200         format_reg("o", reg, indreg);
201      } else {
202         format_reg("oT", reg, NULL);
203      }
204      break;
205
206   case SVGA3DREG_COLOROUT:
207      format_reg("oC", reg, NULL);
208      break;
209
210   case SVGA3DREG_DEPTHOUT:
211      assert(!reg.relative);
212      assert(reg.number == 0);
213      _debug_printf("oDepth");
214      break;
215
216   case SVGA3DREG_SAMPLER:
217      format_reg("s", reg, NULL);
218      break;
219
220   case SVGA3DREG_CONSTBOOL:
221      format_reg("b", reg, NULL);
222      break;
223
224   case SVGA3DREG_CONSTINT:
225      format_reg("i", reg, NULL);
226      break;
227
228   case SVGA3DREG_LOOP:
229      assert(!reg.relative);
230      assert( reg.number == 0 );
231      _debug_printf( "aL" );
232      break;
233
234   case SVGA3DREG_MISCTYPE:
235      assert(!reg.relative);
236      switch (reg.number) {
237      case SVGA3DMISCREG_POSITION:
238         _debug_printf("vPos");
239         break;
240      case SVGA3DMISCREG_FACE:
241         _debug_printf("vFace");
242         break;
243      default:
244         assert(0);
245         _debug_printf("???");
246      }
247      break;
248
249   case SVGA3DREG_LABEL:
250      format_reg("l", reg, NULL);
251      break;
252
253   case SVGA3DREG_PREDICATE:
254      format_reg("p", reg, NULL);
255      break;
256
257   default:
258      assert( 0 );
259      _debug_printf( "???" );
260   }
261}
262
263static void dump_cdata( struct sh_cdata cdata )
264{
265   _debug_printf( "%f, %f, %f, %f", cdata.xyzw[0], cdata.xyzw[1], cdata.xyzw[2], cdata.xyzw[3] );
266}
267
268static void dump_idata( struct sh_idata idata )
269{
270   _debug_printf( "%d, %d, %d, %d", idata.xyzw[0], idata.xyzw[1], idata.xyzw[2], idata.xyzw[3] );
271}
272
273static void dump_bdata( boolean bdata )
274{
275   _debug_printf( bdata ? "TRUE" : "FALSE" );
276}
277
278static void
279dump_sampleinfo(struct sh_sampleinfo sampleinfo)
280{
281   assert( sampleinfo.is_reg == 1 );
282
283   switch (sampleinfo.texture_type) {
284   case SVGA3DSAMP_2D:
285      _debug_printf( "_2d" );
286      break;
287   case SVGA3DSAMP_CUBE:
288      _debug_printf( "_cube" );
289      break;
290   case SVGA3DSAMP_VOLUME:
291      _debug_printf( "_volume" );
292      break;
293   default:
294      assert( 0 );
295   }
296}
297
298static void
299dump_semantic(uint usage,
300              uint usage_index)
301{
302   switch (usage) {
303   case SVGA3D_DECLUSAGE_POSITION:
304      _debug_printf("_position");
305      break;
306   case SVGA3D_DECLUSAGE_BLENDWEIGHT:
307      _debug_printf("_blendweight");
308      break;
309   case SVGA3D_DECLUSAGE_BLENDINDICES:
310      _debug_printf("_blendindices");
311      break;
312   case SVGA3D_DECLUSAGE_NORMAL:
313      _debug_printf("_normal");
314      break;
315   case SVGA3D_DECLUSAGE_PSIZE:
316      _debug_printf("_psize");
317      break;
318   case SVGA3D_DECLUSAGE_TEXCOORD:
319      _debug_printf("_texcoord");
320      break;
321   case SVGA3D_DECLUSAGE_TANGENT:
322      _debug_printf("_tangent");
323      break;
324   case SVGA3D_DECLUSAGE_BINORMAL:
325      _debug_printf("_binormal");
326      break;
327   case SVGA3D_DECLUSAGE_TESSFACTOR:
328      _debug_printf("_tessfactor");
329      break;
330   case SVGA3D_DECLUSAGE_POSITIONT:
331      _debug_printf("_positiont");
332      break;
333   case SVGA3D_DECLUSAGE_COLOR:
334      _debug_printf("_color");
335      break;
336   case SVGA3D_DECLUSAGE_FOG:
337      _debug_printf("_fog");
338      break;
339   case SVGA3D_DECLUSAGE_DEPTH:
340      _debug_printf("_depth");
341      break;
342   case SVGA3D_DECLUSAGE_SAMPLE:
343      _debug_printf("_sample");
344      break;
345   default:
346      assert(!"Unknown usage");
347      _debug_printf("_???");
348   }
349
350   if (usage_index) {
351      _debug_printf("%u", usage_index);
352   }
353}
354
355static void
356dump_dstreg(struct sh_dstreg dstreg,
357            struct sh_srcreg *indreg,
358            const struct dump_info *di)
359{
360   union {
361      struct sh_reg reg;
362      struct sh_dstreg dstreg;
363   } u;
364
365   memset(&u, 0, sizeof(u));
366
367   assert( (dstreg.modifier & (SVGA3DDSTMOD_SATURATE | SVGA3DDSTMOD_PARTIALPRECISION)) == dstreg.modifier );
368
369   if (dstreg.modifier & SVGA3DDSTMOD_SATURATE)
370      _debug_printf( "_sat" );
371   if (dstreg.modifier & SVGA3DDSTMOD_PARTIALPRECISION)
372      _debug_printf( "_pp" );
373   switch (dstreg.shift_scale) {
374   case 0:
375      break;
376   case 1:
377      _debug_printf( "_x2" );
378      break;
379   case 2:
380      _debug_printf( "_x4" );
381      break;
382   case 3:
383      _debug_printf( "_x8" );
384      break;
385   case 13:
386      _debug_printf( "_d8" );
387      break;
388   case 14:
389      _debug_printf( "_d4" );
390      break;
391   case 15:
392      _debug_printf( "_d2" );
393      break;
394   default:
395      assert( 0 );
396   }
397   _debug_printf( " " );
398
399   u.dstreg = dstreg;
400   dump_reg( u.reg, indreg, di);
401   if (dstreg.write_mask != SVGA3DWRITEMASK_ALL) {
402      _debug_printf( "." );
403      if (dstreg.write_mask & SVGA3DWRITEMASK_0)
404         _debug_printf( "x" );
405      if (dstreg.write_mask & SVGA3DWRITEMASK_1)
406         _debug_printf( "y" );
407      if (dstreg.write_mask & SVGA3DWRITEMASK_2)
408         _debug_printf( "z" );
409      if (dstreg.write_mask & SVGA3DWRITEMASK_3)
410         _debug_printf( "w" );
411   }
412}
413
414static void dump_srcreg( struct sh_srcreg srcreg, struct sh_srcreg *indreg, const struct dump_info *di )
415{
416   switch (srcreg.modifier) {
417   case SVGA3DSRCMOD_NEG:
418   case SVGA3DSRCMOD_BIASNEG:
419   case SVGA3DSRCMOD_SIGNNEG:
420   case SVGA3DSRCMOD_X2NEG:
421   case SVGA3DSRCMOD_ABSNEG:
422      _debug_printf( "-" );
423      break;
424   case SVGA3DSRCMOD_COMP:
425      _debug_printf( "1-" );
426      break;
427   case SVGA3DSRCMOD_NOT:
428      _debug_printf( "!" );
429   }
430   dump_reg( *(struct sh_reg *) &srcreg, indreg, di );
431   switch (srcreg.modifier) {
432   case SVGA3DSRCMOD_NONE:
433   case SVGA3DSRCMOD_NEG:
434   case SVGA3DSRCMOD_COMP:
435   case SVGA3DSRCMOD_NOT:
436      break;
437   case SVGA3DSRCMOD_BIAS:
438   case SVGA3DSRCMOD_BIASNEG:
439      _debug_printf( "_bias" );
440      break;
441   case SVGA3DSRCMOD_SIGN:
442   case SVGA3DSRCMOD_SIGNNEG:
443      _debug_printf( "_bx2" );
444      break;
445   case SVGA3DSRCMOD_X2:
446   case SVGA3DSRCMOD_X2NEG:
447      _debug_printf( "_x2" );
448      break;
449   case SVGA3DSRCMOD_DZ:
450      _debug_printf( "_dz" );
451      break;
452   case SVGA3DSRCMOD_DW:
453      _debug_printf( "_dw" );
454      break;
455   case SVGA3DSRCMOD_ABS:
456   case SVGA3DSRCMOD_ABSNEG:
457      _debug_printf("_abs");
458      break;
459   default:
460      assert( 0 );
461   }
462   if (srcreg.swizzle_x != 0 || srcreg.swizzle_y != 1 || srcreg.swizzle_z != 2 || srcreg.swizzle_w != 3) {
463      _debug_printf( "." );
464      if (srcreg.swizzle_x == srcreg.swizzle_y && srcreg.swizzle_y == srcreg.swizzle_z && srcreg.swizzle_z == srcreg.swizzle_w) {
465         _debug_printf( "%c", "xyzw"[srcreg.swizzle_x] );
466      }
467      else {
468         _debug_printf( "%c", "xyzw"[srcreg.swizzle_x] );
469         _debug_printf( "%c", "xyzw"[srcreg.swizzle_y] );
470         _debug_printf( "%c", "xyzw"[srcreg.swizzle_z] );
471         _debug_printf( "%c", "xyzw"[srcreg.swizzle_w] );
472      }
473   }
474}
475
476static void
477parse_op(struct dump_info *di,
478         const uint **token,
479         struct dump_op *op,
480         uint num_dst,
481         uint num_src)
482{
483   uint i;
484
485   assert(num_dst <= 1);
486   assert(num_src <= DUMP_MAX_OP_SRC);
487
488   op->op = *(struct sh_op *)*token;
489   *token += sizeof(struct sh_op) / sizeof(uint);
490
491   if (num_dst >= 1) {
492      op->dst = *(struct sh_dstreg *)*token;
493      *token += sizeof(struct sh_dstreg) / sizeof(uint);
494      if (op->dst.relative &&
495          (!di->is_ps && di->version >= SVGA3D_VS_30)) {
496         op->dstind = *(struct sh_srcreg *)*token;
497         *token += sizeof(struct sh_srcreg) / sizeof(uint);
498      }
499   }
500
501   if (op->op.predicated) {
502      op->p0 = *(struct sh_srcreg *)*token;
503      *token += sizeof(struct sh_srcreg) / sizeof(uint);
504   }
505
506   for (i = 0; i < num_src; ++i) {
507      op->src[i] = *(struct sh_srcreg *)*token;
508      *token += sizeof(struct sh_srcreg) / sizeof(uint);
509      if (op->src[i].relative &&
510          ((!di->is_ps && di->version >= SVGA3D_VS_20) ||
511          (di->is_ps && di->version >= SVGA3D_PS_30))) {
512         op->srcind[i] = *(struct sh_srcreg *)*token;
513         *token += sizeof(struct sh_srcreg) / sizeof(uint);
514      }
515   }
516}
517
518static void
519dump_inst(struct dump_info *di,
520          const unsigned **assem,
521          struct sh_op op,
522          const struct sh_opcode_info *info)
523{
524   struct dump_op dop;
525   boolean not_first_arg = FALSE;
526   uint i;
527
528   assert(info->num_dst <= 1);
529
530   di->indent -= info->pre_dedent;
531   dump_indent(di->indent);
532   di->indent += info->post_indent;
533
534   dump_op(op, info->mnemonic);
535
536   parse_op(di, assem, &dop, info->num_dst, info->num_src);
537   if (info->num_dst > 0) {
538      dump_dstreg(dop.dst, &dop.dstind, di);
539      not_first_arg = TRUE;
540   }
541
542   for (i = 0; i < info->num_src; i++) {
543      if (not_first_arg) {
544         _debug_printf(", ");
545      } else {
546         _debug_printf(" ");
547      }
548      dump_srcreg(dop.src[i], &dop.srcind[i], di);
549      not_first_arg = TRUE;
550   }
551
552   _debug_printf("\n");
553}
554
555void
556svga_shader_dump(
557   const unsigned *assem,
558   unsigned dwords,
559   unsigned do_binary )
560{
561   boolean finished = FALSE;
562   struct dump_info di;
563
564   di.version = *assem++;
565   di.is_ps = (di.version & 0xFFFF0000) == 0xFFFF0000;
566   di.indent = 0;
567
568   _debug_printf(
569      "%s_%u_%u\n",
570      di.is_ps ? "ps" : "vs",
571      (di.version >> 8) & 0xff,
572      di.version & 0xff );
573
574   while (!finished) {
575      struct sh_op op = *(struct sh_op *) assem;
576
577      switch (op.opcode) {
578      case SVGA3DOP_DCL:
579         {
580            struct sh_dcl dcl = *(struct sh_dcl *) assem;
581
582            _debug_printf( "dcl" );
583            switch (sh_dstreg_type(dcl.reg)) {
584            case SVGA3DREG_INPUT:
585               if ((di.is_ps && di.version >= SVGA3D_PS_30) ||
586                   (!di.is_ps && di.version >= SVGA3D_VS_30)) {
587                  dump_semantic(dcl.u.semantic.usage,
588                                dcl.u.semantic.usage_index);
589               }
590               break;
591            case SVGA3DREG_TEXCRDOUT:
592               if (!di.is_ps && di.version >= SVGA3D_VS_30) {
593                  dump_semantic(dcl.u.semantic.usage,
594                                dcl.u.semantic.usage_index);
595               }
596               break;
597            case SVGA3DREG_SAMPLER:
598               dump_sampleinfo( dcl.u.sampleinfo );
599               break;
600            }
601            dump_dstreg(dcl.reg, NULL, &di);
602            _debug_printf( "\n" );
603            assem += sizeof( struct sh_dcl ) / sizeof( unsigned );
604         }
605         break;
606
607      case SVGA3DOP_DEFB:
608         {
609            struct sh_defb defb = *(struct sh_defb *) assem;
610
611            _debug_printf( "defb " );
612            dump_reg( defb.reg, NULL, &di );
613            _debug_printf( ", " );
614            dump_bdata( defb.data );
615            _debug_printf( "\n" );
616            assem += sizeof( struct sh_defb ) / sizeof( unsigned );
617         }
618         break;
619
620      case SVGA3DOP_DEFI:
621         {
622            struct sh_defi defi = *(struct sh_defi *) assem;
623
624            _debug_printf( "defi " );
625            dump_reg( defi.reg, NULL, &di );
626            _debug_printf( ", " );
627            dump_idata( defi.idata );
628            _debug_printf( "\n" );
629            assem += sizeof( struct sh_defi ) / sizeof( unsigned );
630         }
631         break;
632
633      case SVGA3DOP_TEXCOORD:
634         {
635            struct sh_opcode_info info = *svga_opcode_info(op.opcode);
636
637            assert(di.is_ps);
638            if (di.version > SVGA3D_PS_13) {
639               assert(info.num_src == 0);
640
641               info.num_src = 1;
642            }
643
644            dump_inst(&di, &assem, op, &info);
645         }
646         break;
647
648      case SVGA3DOP_TEX:
649         {
650            struct sh_opcode_info info = *svga_opcode_info(op.opcode);
651
652            assert(di.is_ps);
653            if (di.version > SVGA3D_PS_13) {
654               assert(info.num_src == 0);
655
656               if (di.version > SVGA3D_PS_14) {
657                  info.num_src = 2;
658                  info.mnemonic = "texld";
659               } else {
660                  info.num_src = 1;
661               }
662            }
663
664            dump_inst(&di, &assem, op, &info);
665         }
666         break;
667
668      case SVGA3DOP_DEF:
669         {
670            struct sh_def def = *(struct sh_def *) assem;
671
672            _debug_printf( "def " );
673            dump_reg( def.reg, NULL, &di );
674            _debug_printf( ", " );
675            dump_cdata( def.cdata );
676            _debug_printf( "\n" );
677            assem += sizeof( struct sh_def ) / sizeof( unsigned );
678         }
679         break;
680
681      case SVGA3DOP_SINCOS:
682         {
683            struct sh_opcode_info info = *svga_opcode_info(op.opcode);
684
685            if ((di.is_ps && di.version >= SVGA3D_PS_30) ||
686                (!di.is_ps && di.version >= SVGA3D_VS_30)) {
687               assert(info.num_src == 3);
688
689               info.num_src = 1;
690            }
691
692            dump_inst(&di, &assem, op, &info);
693         }
694         break;
695
696      case SVGA3DOP_PHASE:
697         _debug_printf( "phase\n" );
698         assem += sizeof( struct sh_op ) / sizeof( unsigned );
699         break;
700
701      case SVGA3DOP_COMMENT:
702         {
703            struct sh_comment comment = *(struct sh_comment *)assem;
704
705            /* Ignore comment contents. */
706            assem += sizeof(struct sh_comment) / sizeof(unsigned) + comment.size;
707         }
708         break;
709
710      case SVGA3DOP_END:
711         finished = TRUE;
712         break;
713
714      default:
715         {
716            const struct sh_opcode_info *info = svga_opcode_info(op.opcode);
717
718            dump_inst(&di, &assem, op, info);
719         }
720      }
721   }
722}
723