tgsi_dump.c revision 399190d13668ed457cf5d6bbbefe908a95bad289
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#include "util/u_debug.h" 29#include "util/u_string.h" 30#include "util/u_math.h" 31#include "util/u_memory.h" 32#include "tgsi_dump.h" 33#include "tgsi_info.h" 34#include "tgsi_iterate.h" 35 36 37/** Number of spaces to indent for IF/LOOP/etc */ 38static const int indent_spaces = 3; 39 40 41struct dump_ctx 42{ 43 struct tgsi_iterate_context iter; 44 45 uint instno; 46 int indent; 47 48 uint indentation; 49 50 void (*printf)(struct dump_ctx *ctx, const char *format, ...); 51}; 52 53static void 54dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...) 55{ 56 va_list ap; 57 (void)ctx; 58 va_start(ap, format); 59 debug_vprintf(format, ap); 60 va_end(ap); 61} 62 63static void 64dump_enum( 65 struct dump_ctx *ctx, 66 uint e, 67 const char **enums, 68 uint enum_count ) 69{ 70 if (e >= enum_count) 71 ctx->printf( ctx, "%u", e ); 72 else 73 ctx->printf( ctx, "%s", enums[e] ); 74} 75 76#define EOL() ctx->printf( ctx, "\n" ) 77#define TXT(S) ctx->printf( ctx, "%s", S ) 78#define CHR(C) ctx->printf( ctx, "%c", C ) 79#define UIX(I) ctx->printf( ctx, "0x%x", I ) 80#define UID(I) ctx->printf( ctx, "%u", I ) 81#define INSTID(I) ctx->printf( ctx, "% 3u", I ) 82#define SID(I) ctx->printf( ctx, "%d", I ) 83#define FLT(F) ctx->printf( ctx, "%10.4f", F ) 84#define ENM(E,ENUMS) dump_enum( ctx, E, ENUMS, sizeof( ENUMS ) / sizeof( *ENUMS ) ) 85 86static const char *processor_type_names[] = 87{ 88 "FRAG", 89 "VERT", 90 "GEOM" 91}; 92 93static const char *file_names[TGSI_FILE_COUNT] = 94{ 95 "NULL", 96 "CONST", 97 "IN", 98 "OUT", 99 "TEMP", 100 "SAMP", 101 "ADDR", 102 "IMM", 103 "LOOP", 104 "PRED", 105 "SV" 106}; 107 108static const char *interpolate_names[] = 109{ 110 "CONSTANT", 111 "LINEAR", 112 "PERSPECTIVE" 113}; 114 115static const char *semantic_names[] = 116{ 117 "POSITION", 118 "COLOR", 119 "BCOLOR", 120 "FOG", 121 "PSIZE", 122 "GENERIC", 123 "NORMAL", 124 "FACE", 125 "EDGEFLAG", 126 "PRIM_ID" 127}; 128 129static const char *immediate_type_names[] = 130{ 131 "FLT32" 132}; 133 134static const char *swizzle_names[] = 135{ 136 "x", 137 "y", 138 "z", 139 "w" 140}; 141 142static const char *texture_names[] = 143{ 144 "UNKNOWN", 145 "1D", 146 "2D", 147 "3D", 148 "CUBE", 149 "RECT", 150 "SHADOW1D", 151 "SHADOW2D", 152 "SHADOWRECT" 153}; 154 155static const char *property_names[] = 156{ 157 "GS_INPUT_PRIMITIVE", 158 "GS_OUTPUT_PRIMITIVE", 159 "GS_MAX_OUTPUT_VERTICES" 160}; 161 162static const char *primitive_names[] = 163{ 164 "POINTS", 165 "LINES", 166 "LINE_LOOP", 167 "LINE_STRIP", 168 "TRIANGLES", 169 "TRIANGLE_STRIP", 170 "TRIANGLE_FAN", 171 "QUADS", 172 "QUAD_STRIP", 173 "POLYGON" 174}; 175 176 177static void 178_dump_register_decl( 179 struct dump_ctx *ctx, 180 uint file, 181 int first, 182 int last ) 183{ 184 ENM( file, file_names ); 185 186 /* all geometry shader inputs are two dimensional */ 187 if (file == TGSI_FILE_INPUT && 188 ctx->iter.processor.Processor == TGSI_PROCESSOR_GEOMETRY) 189 TXT("[]"); 190 191 CHR( '[' ); 192 SID( first ); 193 if (first != last) { 194 TXT( ".." ); 195 SID( last ); 196 } 197 CHR( ']' ); 198} 199 200static void 201_dump_register_dst( 202 struct dump_ctx *ctx, 203 uint file, 204 int index) 205{ 206 ENM( file, file_names ); 207 208 CHR( '[' ); 209 SID( index ); 210 CHR( ']' ); 211} 212 213 214static void 215_dump_register_src( 216 struct dump_ctx *ctx, 217 const struct tgsi_full_src_register *src ) 218{ 219 if (src->Register.Indirect) { 220 ENM( src->Register.File, file_names ); 221 CHR( '[' ); 222 ENM( src->Indirect.File, file_names ); 223 CHR( '[' ); 224 SID( src->Indirect.Index ); 225 TXT( "]." ); 226 ENM( src->Indirect.SwizzleX, swizzle_names ); 227 if (src->Register.Index != 0) { 228 if (src->Register.Index > 0) 229 CHR( '+' ); 230 SID( src->Register.Index ); 231 } 232 CHR( ']' ); 233 } else { 234 ENM( src->Register.File, file_names ); 235 CHR( '[' ); 236 SID( src->Register.Index ); 237 CHR( ']' ); 238 } 239 if (src->Register.Dimension) { 240 CHR( '[' ); 241 SID( src->Dimension.Index ); 242 CHR( ']' ); 243 } 244} 245 246static void 247_dump_register_ind( 248 struct dump_ctx *ctx, 249 uint file, 250 int index, 251 uint ind_file, 252 int ind_index, 253 uint ind_swizzle ) 254{ 255 ENM( file, file_names ); 256 CHR( '[' ); 257 ENM( ind_file, file_names ); 258 CHR( '[' ); 259 SID( ind_index ); 260 TXT( "]." ); 261 ENM( ind_swizzle, swizzle_names ); 262 if (index != 0) { 263 if (index > 0) 264 CHR( '+' ); 265 SID( index ); 266 } 267 CHR( ']' ); 268} 269 270static void 271_dump_writemask( 272 struct dump_ctx *ctx, 273 uint writemask ) 274{ 275 if (writemask != TGSI_WRITEMASK_XYZW) { 276 CHR( '.' ); 277 if (writemask & TGSI_WRITEMASK_X) 278 CHR( 'x' ); 279 if (writemask & TGSI_WRITEMASK_Y) 280 CHR( 'y' ); 281 if (writemask & TGSI_WRITEMASK_Z) 282 CHR( 'z' ); 283 if (writemask & TGSI_WRITEMASK_W) 284 CHR( 'w' ); 285 } 286} 287 288static boolean 289iter_declaration( 290 struct tgsi_iterate_context *iter, 291 struct tgsi_full_declaration *decl ) 292{ 293 struct dump_ctx *ctx = (struct dump_ctx *)iter; 294 295 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT); 296 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT); 297 298 TXT( "DCL " ); 299 300 _dump_register_decl( 301 ctx, 302 decl->Declaration.File, 303 decl->Range.First, 304 decl->Range.Last ); 305 _dump_writemask( 306 ctx, 307 decl->Declaration.UsageMask ); 308 309 if (decl->Declaration.Semantic) { 310 TXT( ", " ); 311 ENM( decl->Semantic.Name, semantic_names ); 312 if (decl->Semantic.Index != 0 || 313 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) { 314 CHR( '[' ); 315 UID( decl->Semantic.Index ); 316 CHR( ']' ); 317 } 318 } 319 320 if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT && 321 decl->Declaration.File == TGSI_FILE_INPUT) 322 { 323 TXT( ", " ); 324 ENM( decl->Declaration.Interpolate, interpolate_names ); 325 } 326 327 if (decl->Declaration.Centroid) { 328 TXT( ", CENTROID" ); 329 } 330 331 if (decl->Declaration.Invariant) { 332 TXT( ", INVARIANT" ); 333 } 334 335 EOL(); 336 337 return TRUE; 338} 339 340void 341tgsi_dump_declaration( 342 const struct tgsi_full_declaration *decl ) 343{ 344 struct dump_ctx ctx; 345 346 ctx.printf = dump_ctx_printf; 347 348 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl ); 349} 350 351static boolean 352iter_property( 353 struct tgsi_iterate_context *iter, 354 struct tgsi_full_property *prop ) 355{ 356 int i; 357 struct dump_ctx *ctx = (struct dump_ctx *)iter; 358 359 assert(Elements(property_names) == TGSI_PROPERTY_COUNT); 360 361 TXT( "PROPERTY " ); 362 ENM(prop->Property.PropertyName, property_names); 363 364 if (prop->Property.NrTokens > 1) 365 TXT(" "); 366 367 for (i = 0; i < prop->Property.NrTokens - 1; ++i) { 368 switch (prop->Property.PropertyName) { 369 case TGSI_PROPERTY_GS_INPUT_PRIM: 370 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 371 ENM(prop->u[i].Data, primitive_names); 372 break; 373 default: 374 SID( prop->u[i].Data ); 375 break; 376 } 377 if (i < prop->Property.NrTokens - 2) 378 TXT( ", " ); 379 } 380 EOL(); 381 382 return TRUE; 383} 384 385void tgsi_dump_property( 386 const struct tgsi_full_property *prop ) 387{ 388 struct dump_ctx ctx; 389 390 ctx.printf = dump_ctx_printf; 391 392 iter_property( &ctx.iter, (struct tgsi_full_property *)prop ); 393} 394 395static boolean 396iter_immediate( 397 struct tgsi_iterate_context *iter, 398 struct tgsi_full_immediate *imm ) 399{ 400 struct dump_ctx *ctx = (struct dump_ctx *) iter; 401 402 uint i; 403 404 TXT( "IMM " ); 405 ENM( imm->Immediate.DataType, immediate_type_names ); 406 407 TXT( " { " ); 408 409 assert( imm->Immediate.NrTokens <= 4 + 1 ); 410 for (i = 0; i < imm->Immediate.NrTokens - 1; i++) { 411 switch (imm->Immediate.DataType) { 412 case TGSI_IMM_FLOAT32: 413 FLT( imm->u[i].Float ); 414 break; 415 default: 416 assert( 0 ); 417 } 418 419 if (i < imm->Immediate.NrTokens - 2) 420 TXT( ", " ); 421 } 422 TXT( " }" ); 423 424 EOL(); 425 426 return TRUE; 427} 428 429void 430tgsi_dump_immediate( 431 const struct tgsi_full_immediate *imm ) 432{ 433 struct dump_ctx ctx; 434 435 ctx.printf = dump_ctx_printf; 436 437 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm ); 438} 439 440static boolean 441iter_instruction( 442 struct tgsi_iterate_context *iter, 443 struct tgsi_full_instruction *inst ) 444{ 445 struct dump_ctx *ctx = (struct dump_ctx *) iter; 446 uint instno = ctx->instno++; 447 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode ); 448 uint i; 449 boolean first_reg = TRUE; 450 451 INSTID( instno ); 452 TXT( ": " ); 453 454 ctx->indent -= info->pre_dedent; 455 for(i = 0; (int)i < ctx->indent; ++i) 456 TXT( " " ); 457 ctx->indent += info->post_indent; 458 459 TXT( info->mnemonic ); 460 461 switch (inst->Instruction.Saturate) { 462 case TGSI_SAT_NONE: 463 break; 464 case TGSI_SAT_ZERO_ONE: 465 TXT( "_SAT" ); 466 break; 467 case TGSI_SAT_MINUS_PLUS_ONE: 468 TXT( "_SATNV" ); 469 break; 470 default: 471 assert( 0 ); 472 } 473 474 for (i = 0; i < inst->Instruction.NumDstRegs; i++) { 475 const struct tgsi_full_dst_register *dst = &inst->Dst[i]; 476 477 if (!first_reg) 478 CHR( ',' ); 479 CHR( ' ' ); 480 481 if (dst->Register.Indirect) { 482 _dump_register_ind( 483 ctx, 484 dst->Register.File, 485 dst->Register.Index, 486 dst->Indirect.File, 487 dst->Indirect.Index, 488 dst->Indirect.SwizzleX ); 489 } 490 else { 491 _dump_register_dst( 492 ctx, 493 dst->Register.File, 494 dst->Register.Index ); 495 } 496 _dump_writemask( ctx, dst->Register.WriteMask ); 497 498 first_reg = FALSE; 499 } 500 501 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { 502 const struct tgsi_full_src_register *src = &inst->Src[i]; 503 504 if (!first_reg) 505 CHR( ',' ); 506 CHR( ' ' ); 507 508 if (src->Register.Negate) 509 CHR( '-' ); 510 if (src->Register.Absolute) 511 CHR( '|' ); 512 513 _dump_register_src(ctx, src); 514 515 if (src->Register.SwizzleX != TGSI_SWIZZLE_X || 516 src->Register.SwizzleY != TGSI_SWIZZLE_Y || 517 src->Register.SwizzleZ != TGSI_SWIZZLE_Z || 518 src->Register.SwizzleW != TGSI_SWIZZLE_W) { 519 CHR( '.' ); 520 ENM( src->Register.SwizzleX, swizzle_names ); 521 ENM( src->Register.SwizzleY, swizzle_names ); 522 ENM( src->Register.SwizzleZ, swizzle_names ); 523 ENM( src->Register.SwizzleW, swizzle_names ); 524 } 525 526 if (src->Register.Absolute) 527 CHR( '|' ); 528 529 first_reg = FALSE; 530 } 531 532 if (inst->Instruction.Texture) { 533 TXT( ", " ); 534 ENM( inst->Texture.Texture, texture_names ); 535 } 536 537 switch (inst->Instruction.Opcode) { 538 case TGSI_OPCODE_IF: 539 case TGSI_OPCODE_ELSE: 540 case TGSI_OPCODE_BGNLOOP: 541 case TGSI_OPCODE_ENDLOOP: 542 case TGSI_OPCODE_CAL: 543 TXT( " :" ); 544 UID( inst->Label.Label ); 545 break; 546 } 547 548 /* update indentation */ 549 if (inst->Instruction.Opcode == TGSI_OPCODE_IF || 550 inst->Instruction.Opcode == TGSI_OPCODE_ELSE || 551 inst->Instruction.Opcode == TGSI_OPCODE_BGNFOR || 552 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) { 553 ctx->indentation += indent_spaces; 554 } 555 556 EOL(); 557 558 return TRUE; 559} 560 561void 562tgsi_dump_instruction( 563 const struct tgsi_full_instruction *inst, 564 uint instno ) 565{ 566 struct dump_ctx ctx; 567 568 ctx.instno = instno; 569 ctx.indent = 0; 570 ctx.printf = dump_ctx_printf; 571 ctx.indentation = 0; 572 573 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst ); 574} 575 576static boolean 577prolog( 578 struct tgsi_iterate_context *iter ) 579{ 580 struct dump_ctx *ctx = (struct dump_ctx *) iter; 581 ENM( iter->processor.Processor, processor_type_names ); 582 EOL(); 583 return TRUE; 584} 585 586void 587tgsi_dump( 588 const struct tgsi_token *tokens, 589 uint flags ) 590{ 591 struct dump_ctx ctx; 592 593 ctx.iter.prolog = prolog; 594 ctx.iter.iterate_instruction = iter_instruction; 595 ctx.iter.iterate_declaration = iter_declaration; 596 ctx.iter.iterate_immediate = iter_immediate; 597 ctx.iter.iterate_property = iter_property; 598 ctx.iter.epilog = NULL; 599 600 ctx.instno = 0; 601 ctx.indent = 0; 602 ctx.printf = dump_ctx_printf; 603 ctx.indentation = 0; 604 605 tgsi_iterate_shader( tokens, &ctx.iter ); 606} 607 608struct str_dump_ctx 609{ 610 struct dump_ctx base; 611 char *str; 612 char *ptr; 613 int left; 614}; 615 616static void 617str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...) 618{ 619 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx; 620 621 if(sctx->left > 1) { 622 int written; 623 va_list ap; 624 va_start(ap, format); 625 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap); 626 va_end(ap); 627 628 /* Some complicated logic needed to handle the return value of 629 * vsnprintf: 630 */ 631 if (written > 0) { 632 written = MIN2(sctx->left, written); 633 sctx->ptr += written; 634 sctx->left -= written; 635 } 636 } 637} 638 639void 640tgsi_dump_str( 641 const struct tgsi_token *tokens, 642 uint flags, 643 char *str, 644 size_t size) 645{ 646 struct str_dump_ctx ctx; 647 648 ctx.base.iter.prolog = prolog; 649 ctx.base.iter.iterate_instruction = iter_instruction; 650 ctx.base.iter.iterate_declaration = iter_declaration; 651 ctx.base.iter.iterate_immediate = iter_immediate; 652 ctx.base.iter.iterate_property = iter_property; 653 ctx.base.iter.epilog = NULL; 654 655 ctx.base.instno = 0; 656 ctx.base.indent = 0; 657 ctx.base.printf = &str_dump_ctx_printf; 658 ctx.base.indentation = 0; 659 660 ctx.str = str; 661 ctx.str[0] = 0; 662 ctx.ptr = str; 663 ctx.left = (int)size; 664 665 tgsi_iterate_shader( tokens, &ctx.base.iter ); 666} 667