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