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