1 /************************************************************************** 2 * 3 * Copyright 2007-2008 VMware, Inc. 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 VMWARE 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 <inttypes.h> 29 30 #include "util/u_debug.h" 31 #include "util/u_string.h" 32 #include "util/u_math.h" 33 #include "util/u_memory.h" 34 #include "util/u_math.h" 35 #include "tgsi_dump.h" 36 #include "tgsi_info.h" 37 #include "tgsi_iterate.h" 38 #include "tgsi_strings.h" 39 40 41 /** Number of spaces to indent for IF/LOOP/etc */ 42 static const int indent_spaces = 3; 43 44 45 struct dump_ctx 46 { 47 struct tgsi_iterate_context iter; 48 49 boolean dump_float_as_hex; 50 51 uint instno; 52 uint immno; 53 int indent; 54 55 uint indentation; 56 FILE *file; 57 58 void (*dump_printf)(struct dump_ctx *ctx, const char *format, ...); 59 }; 60 61 static void 62 dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...) 63 { 64 va_list ap; 65 (void)ctx; 66 va_start(ap, format); 67 if (ctx->file) 68 vfprintf(ctx->file, format, ap); 69 else 70 _debug_vprintf(format, ap); 71 va_end(ap); 72 } 73 74 static void 75 dump_enum( 76 struct dump_ctx *ctx, 77 uint e, 78 const char **enums, 79 uint enum_count ) 80 { 81 if (e >= enum_count) 82 ctx->dump_printf( ctx, "%u", e ); 83 else 84 ctx->dump_printf( ctx, "%s", enums[e] ); 85 } 86 87 #define EOL() ctx->dump_printf( ctx, "\n" ) 88 #define TXT(S) ctx->dump_printf( ctx, "%s", S ) 89 #define CHR(C) ctx->dump_printf( ctx, "%c", C ) 90 #define UIX(I) ctx->dump_printf( ctx, "0x%x", I ) 91 #define UID(I) ctx->dump_printf( ctx, "%u", I ) 92 #define SI64D(I) ctx->dump_printf( ctx, "%"PRId64, I ) 93 #define UI64D(I) ctx->dump_printf( ctx, "%"PRIu64, I ) 94 #define INSTID(I) ctx->dump_printf( ctx, "% 3u", I ) 95 #define SID(I) ctx->dump_printf( ctx, "%d", I ) 96 #define FLT(F) ctx->dump_printf( ctx, "%10.4f", F ) 97 #define DBL(D) ctx->dump_printf( ctx, "%10.8f", D ) 98 #define HFLT(F) ctx->dump_printf( ctx, "0x%08x", fui((F)) ) 99 #define ENM(E,ENUMS) dump_enum( ctx, E, ENUMS, sizeof( ENUMS ) / sizeof( *ENUMS ) ) 100 101 const char * 102 tgsi_swizzle_names[4] = 103 { 104 "x", 105 "y", 106 "z", 107 "w" 108 }; 109 110 static void 111 _dump_register_src( 112 struct dump_ctx *ctx, 113 const struct tgsi_full_src_register *src ) 114 { 115 TXT(tgsi_file_name(src->Register.File)); 116 if (src->Register.Dimension) { 117 if (src->Dimension.Indirect) { 118 CHR( '[' ); 119 TXT(tgsi_file_name(src->DimIndirect.File)); 120 CHR( '[' ); 121 SID( src->DimIndirect.Index ); 122 TXT( "]." ); 123 ENM( src->DimIndirect.Swizzle, tgsi_swizzle_names ); 124 if (src->Dimension.Index != 0) { 125 if (src->Dimension.Index > 0) 126 CHR( '+' ); 127 SID( src->Dimension.Index ); 128 } 129 CHR( ']' ); 130 if (src->DimIndirect.ArrayID) { 131 CHR( '(' ); 132 SID( src->DimIndirect.ArrayID ); 133 CHR( ')' ); 134 } 135 } else { 136 CHR('['); 137 SID(src->Dimension.Index); 138 CHR(']'); 139 } 140 } 141 if (src->Register.Indirect) { 142 CHR( '[' ); 143 TXT(tgsi_file_name(src->Indirect.File)); 144 CHR( '[' ); 145 SID( src->Indirect.Index ); 146 TXT( "]." ); 147 ENM( src->Indirect.Swizzle, tgsi_swizzle_names ); 148 if (src->Register.Index != 0) { 149 if (src->Register.Index > 0) 150 CHR( '+' ); 151 SID( src->Register.Index ); 152 } 153 CHR( ']' ); 154 if (src->Indirect.ArrayID) { 155 CHR( '(' ); 156 SID( src->Indirect.ArrayID ); 157 CHR( ')' ); 158 } 159 } else { 160 CHR( '[' ); 161 SID( src->Register.Index ); 162 CHR( ']' ); 163 } 164 } 165 166 167 static void 168 _dump_register_dst( 169 struct dump_ctx *ctx, 170 const struct tgsi_full_dst_register *dst ) 171 { 172 TXT(tgsi_file_name(dst->Register.File)); 173 if (dst->Register.Dimension) { 174 if (dst->Dimension.Indirect) { 175 CHR( '[' ); 176 TXT(tgsi_file_name(dst->DimIndirect.File)); 177 CHR( '[' ); 178 SID( dst->DimIndirect.Index ); 179 TXT( "]." ); 180 ENM( dst->DimIndirect.Swizzle, tgsi_swizzle_names ); 181 if (dst->Dimension.Index != 0) { 182 if (dst->Dimension.Index > 0) 183 CHR( '+' ); 184 SID( dst->Dimension.Index ); 185 } 186 CHR( ']' ); 187 if (dst->DimIndirect.ArrayID) { 188 CHR( '(' ); 189 SID( dst->DimIndirect.ArrayID ); 190 CHR( ')' ); 191 } 192 } else { 193 CHR('['); 194 SID(dst->Dimension.Index); 195 CHR(']'); 196 } 197 } 198 if (dst->Register.Indirect) { 199 CHR( '[' ); 200 TXT(tgsi_file_name(dst->Indirect.File)); 201 CHR( '[' ); 202 SID( dst->Indirect.Index ); 203 TXT( "]." ); 204 ENM( dst->Indirect.Swizzle, tgsi_swizzle_names ); 205 if (dst->Register.Index != 0) { 206 if (dst->Register.Index > 0) 207 CHR( '+' ); 208 SID( dst->Register.Index ); 209 } 210 CHR( ']' ); 211 if (dst->Indirect.ArrayID) { 212 CHR( '(' ); 213 SID( dst->Indirect.ArrayID ); 214 CHR( ')' ); 215 } 216 } else { 217 CHR( '[' ); 218 SID( dst->Register.Index ); 219 CHR( ']' ); 220 } 221 } 222 static void 223 _dump_writemask( 224 struct dump_ctx *ctx, 225 uint writemask ) 226 { 227 if (writemask != TGSI_WRITEMASK_XYZW) { 228 CHR( '.' ); 229 if (writemask & TGSI_WRITEMASK_X) 230 CHR( 'x' ); 231 if (writemask & TGSI_WRITEMASK_Y) 232 CHR( 'y' ); 233 if (writemask & TGSI_WRITEMASK_Z) 234 CHR( 'z' ); 235 if (writemask & TGSI_WRITEMASK_W) 236 CHR( 'w' ); 237 } 238 } 239 240 static void 241 dump_imm_data(struct tgsi_iterate_context *iter, 242 union tgsi_immediate_data *data, 243 unsigned num_tokens, 244 unsigned data_type) 245 { 246 struct dump_ctx *ctx = (struct dump_ctx *)iter; 247 unsigned i ; 248 249 TXT( " {" ); 250 251 assert( num_tokens <= 4 ); 252 for (i = 0; i < num_tokens; i++) { 253 switch (data_type) { 254 case TGSI_IMM_FLOAT64: { 255 union di d; 256 d.ui = data[i].Uint | (uint64_t)data[i+1].Uint << 32; 257 DBL( d.d ); 258 i++; 259 break; 260 } 261 case TGSI_IMM_INT64: { 262 union di d; 263 d.i = data[i].Uint | (uint64_t)data[i+1].Uint << 32; 264 SI64D( d.i ); 265 i++; 266 break; 267 } 268 case TGSI_IMM_UINT64: { 269 union di d; 270 d.ui = data[i].Uint | (uint64_t)data[i+1].Uint << 32; 271 UI64D( d.ui ); 272 i++; 273 break; 274 } 275 case TGSI_IMM_FLOAT32: 276 if (ctx->dump_float_as_hex) 277 HFLT( data[i].Float ); 278 else 279 FLT( data[i].Float ); 280 break; 281 case TGSI_IMM_UINT32: 282 UID(data[i].Uint); 283 break; 284 case TGSI_IMM_INT32: 285 SID(data[i].Int); 286 break; 287 default: 288 assert( 0 ); 289 } 290 291 if (i < num_tokens - 1) 292 TXT( ", " ); 293 } 294 TXT( "}" ); 295 } 296 297 static boolean 298 iter_declaration( 299 struct tgsi_iterate_context *iter, 300 struct tgsi_full_declaration *decl ) 301 { 302 struct dump_ctx *ctx = (struct dump_ctx *)iter; 303 boolean patch = decl->Semantic.Name == TGSI_SEMANTIC_PATCH || 304 decl->Semantic.Name == TGSI_SEMANTIC_TESSINNER || 305 decl->Semantic.Name == TGSI_SEMANTIC_TESSOUTER || 306 decl->Semantic.Name == TGSI_SEMANTIC_PRIMID; 307 308 TXT( "DCL " ); 309 310 TXT(tgsi_file_name(decl->Declaration.File)); 311 312 /* all geometry shader inputs and non-patch tessellation shader inputs are 313 * two dimensional 314 */ 315 if (decl->Declaration.File == TGSI_FILE_INPUT && 316 (iter->processor.Processor == PIPE_SHADER_GEOMETRY || 317 (!patch && 318 (iter->processor.Processor == PIPE_SHADER_TESS_CTRL || 319 iter->processor.Processor == PIPE_SHADER_TESS_EVAL)))) { 320 TXT("[]"); 321 } 322 323 /* all non-patch tess ctrl shader outputs are two dimensional */ 324 if (decl->Declaration.File == TGSI_FILE_OUTPUT && 325 !patch && 326 iter->processor.Processor == PIPE_SHADER_TESS_CTRL) { 327 TXT("[]"); 328 } 329 330 if (decl->Declaration.Dimension) { 331 CHR('['); 332 SID(decl->Dim.Index2D); 333 CHR(']'); 334 } 335 336 CHR('['); 337 SID(decl->Range.First); 338 if (decl->Range.First != decl->Range.Last) { 339 TXT(".."); 340 SID(decl->Range.Last); 341 } 342 CHR(']'); 343 344 _dump_writemask( 345 ctx, 346 decl->Declaration.UsageMask ); 347 348 if (decl->Declaration.Array) { 349 TXT( ", ARRAY(" ); 350 SID(decl->Array.ArrayID); 351 CHR(')'); 352 } 353 354 if (decl->Declaration.Local) 355 TXT( ", LOCAL" ); 356 357 if (decl->Declaration.Semantic) { 358 TXT( ", " ); 359 ENM( decl->Semantic.Name, tgsi_semantic_names ); 360 if (decl->Semantic.Index != 0 || 361 decl->Semantic.Name == TGSI_SEMANTIC_TEXCOORD || 362 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) { 363 CHR( '[' ); 364 UID( decl->Semantic.Index ); 365 CHR( ']' ); 366 } 367 368 if (decl->Semantic.StreamX != 0 || decl->Semantic.StreamY != 0 || 369 decl->Semantic.StreamZ != 0 || decl->Semantic.StreamW != 0) { 370 TXT(", STREAM("); 371 UID(decl->Semantic.StreamX); 372 TXT(", "); 373 UID(decl->Semantic.StreamY); 374 TXT(", "); 375 UID(decl->Semantic.StreamZ); 376 TXT(", "); 377 UID(decl->Semantic.StreamW); 378 CHR(')'); 379 } 380 } 381 382 if (decl->Declaration.File == TGSI_FILE_IMAGE) { 383 TXT(", "); 384 ENM(decl->Image.Resource, tgsi_texture_names); 385 TXT(", "); 386 TXT(util_format_name(decl->Image.Format)); 387 if (decl->Image.Writable) 388 TXT(", WR"); 389 if (decl->Image.Raw) 390 TXT(", RAW"); 391 } 392 393 if (decl->Declaration.File == TGSI_FILE_BUFFER) { 394 if (decl->Declaration.Atomic) 395 TXT(", ATOMIC"); 396 } 397 398 if (decl->Declaration.File == TGSI_FILE_MEMORY) { 399 switch (decl->Declaration.MemType) { 400 /* Note: ,GLOBAL is optional / the default */ 401 case TGSI_MEMORY_TYPE_GLOBAL: TXT(", GLOBAL"); break; 402 case TGSI_MEMORY_TYPE_SHARED: TXT(", SHARED"); break; 403 case TGSI_MEMORY_TYPE_PRIVATE: TXT(", PRIVATE"); break; 404 case TGSI_MEMORY_TYPE_INPUT: TXT(", INPUT"); break; 405 } 406 } 407 408 if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) { 409 TXT(", "); 410 ENM(decl->SamplerView.Resource, tgsi_texture_names); 411 TXT(", "); 412 if ((decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeY) && 413 (decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeZ) && 414 (decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeW)) { 415 ENM(decl->SamplerView.ReturnTypeX, tgsi_return_type_names); 416 } else { 417 ENM(decl->SamplerView.ReturnTypeX, tgsi_return_type_names); 418 TXT(", "); 419 ENM(decl->SamplerView.ReturnTypeY, tgsi_return_type_names); 420 TXT(", "); 421 ENM(decl->SamplerView.ReturnTypeZ, tgsi_return_type_names); 422 TXT(", "); 423 ENM(decl->SamplerView.ReturnTypeW, tgsi_return_type_names); 424 } 425 } 426 427 if (decl->Declaration.Interpolate) { 428 if (iter->processor.Processor == PIPE_SHADER_FRAGMENT && 429 decl->Declaration.File == TGSI_FILE_INPUT) 430 { 431 TXT( ", " ); 432 ENM( decl->Interp.Interpolate, tgsi_interpolate_names ); 433 } 434 435 if (decl->Interp.Location != TGSI_INTERPOLATE_LOC_CENTER) { 436 TXT( ", " ); 437 ENM( decl->Interp.Location, tgsi_interpolate_locations ); 438 } 439 440 if (decl->Interp.CylindricalWrap) { 441 TXT(", CYLWRAP_"); 442 if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) { 443 CHR('X'); 444 } 445 if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) { 446 CHR('Y'); 447 } 448 if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) { 449 CHR('Z'); 450 } 451 if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) { 452 CHR('W'); 453 } 454 } 455 } 456 457 if (decl->Declaration.Invariant) { 458 TXT( ", INVARIANT" ); 459 } 460 461 EOL(); 462 463 return TRUE; 464 } 465 466 void 467 tgsi_dump_declaration( 468 const struct tgsi_full_declaration *decl ) 469 { 470 struct dump_ctx ctx; 471 memset(&ctx, 0, sizeof(ctx)); 472 473 ctx.dump_printf = dump_ctx_printf; 474 475 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl ); 476 } 477 478 static boolean 479 iter_property( 480 struct tgsi_iterate_context *iter, 481 struct tgsi_full_property *prop ) 482 { 483 unsigned i; 484 struct dump_ctx *ctx = (struct dump_ctx *)iter; 485 486 TXT( "PROPERTY " ); 487 ENM(prop->Property.PropertyName, tgsi_property_names); 488 489 if (prop->Property.NrTokens > 1) 490 TXT(" "); 491 492 for (i = 0; i < prop->Property.NrTokens - 1; ++i) { 493 switch (prop->Property.PropertyName) { 494 case TGSI_PROPERTY_GS_INPUT_PRIM: 495 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 496 ENM(prop->u[i].Data, tgsi_primitive_names); 497 break; 498 case TGSI_PROPERTY_FS_COORD_ORIGIN: 499 ENM(prop->u[i].Data, tgsi_fs_coord_origin_names); 500 break; 501 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: 502 ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names); 503 break; 504 case TGSI_PROPERTY_NEXT_SHADER: 505 ENM(prop->u[i].Data, tgsi_processor_type_names); 506 break; 507 default: 508 SID( prop->u[i].Data ); 509 break; 510 } 511 if (i < prop->Property.NrTokens - 2) 512 TXT( ", " ); 513 } 514 EOL(); 515 516 return TRUE; 517 } 518 519 void tgsi_dump_property( 520 const struct tgsi_full_property *prop ) 521 { 522 struct dump_ctx ctx; 523 memset(&ctx, 0, sizeof(ctx)); 524 525 ctx.dump_printf = dump_ctx_printf; 526 527 iter_property( &ctx.iter, (struct tgsi_full_property *)prop ); 528 } 529 530 static boolean 531 iter_immediate( 532 struct tgsi_iterate_context *iter, 533 struct tgsi_full_immediate *imm ) 534 { 535 struct dump_ctx *ctx = (struct dump_ctx *) iter; 536 537 TXT( "IMM[" ); 538 SID( ctx->immno++ ); 539 TXT( "] " ); 540 ENM( imm->Immediate.DataType, tgsi_immediate_type_names ); 541 542 dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1, 543 imm->Immediate.DataType); 544 545 EOL(); 546 547 return TRUE; 548 } 549 550 void 551 tgsi_dump_immediate( 552 const struct tgsi_full_immediate *imm ) 553 { 554 struct dump_ctx ctx; 555 memset(&ctx, 0, sizeof(ctx)); 556 557 ctx.dump_printf = dump_ctx_printf; 558 559 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm ); 560 } 561 562 static boolean 563 iter_instruction( 564 struct tgsi_iterate_context *iter, 565 struct tgsi_full_instruction *inst ) 566 { 567 struct dump_ctx *ctx = (struct dump_ctx *) iter; 568 uint instno = ctx->instno++; 569 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode ); 570 uint i; 571 boolean first_reg = TRUE; 572 573 INSTID( instno ); 574 TXT( ": " ); 575 576 ctx->indent -= info->pre_dedent; 577 for(i = 0; (int)i < ctx->indent; ++i) 578 TXT( " " ); 579 ctx->indent += info->post_indent; 580 581 TXT( tgsi_get_opcode_name(inst->Instruction.Opcode) ); 582 583 if (inst->Instruction.Saturate) { 584 TXT( "_SAT" ); 585 } 586 587 if (inst->Instruction.Precise) { 588 TXT( "_PRECISE" ); 589 } 590 591 for (i = 0; i < inst->Instruction.NumDstRegs; i++) { 592 const struct tgsi_full_dst_register *dst = &inst->Dst[i]; 593 594 if (!first_reg) 595 CHR( ',' ); 596 CHR( ' ' ); 597 598 _dump_register_dst( ctx, dst ); 599 _dump_writemask( ctx, dst->Register.WriteMask ); 600 601 first_reg = FALSE; 602 } 603 604 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { 605 const struct tgsi_full_src_register *src = &inst->Src[i]; 606 607 if (!first_reg) 608 CHR( ',' ); 609 CHR( ' ' ); 610 611 if (src->Register.Negate) 612 CHR( '-' ); 613 if (src->Register.Absolute) 614 CHR( '|' ); 615 616 _dump_register_src(ctx, src); 617 618 if (src->Register.SwizzleX != TGSI_SWIZZLE_X || 619 src->Register.SwizzleY != TGSI_SWIZZLE_Y || 620 src->Register.SwizzleZ != TGSI_SWIZZLE_Z || 621 src->Register.SwizzleW != TGSI_SWIZZLE_W) { 622 CHR( '.' ); 623 ENM( src->Register.SwizzleX, tgsi_swizzle_names ); 624 ENM( src->Register.SwizzleY, tgsi_swizzle_names ); 625 ENM( src->Register.SwizzleZ, tgsi_swizzle_names ); 626 ENM( src->Register.SwizzleW, tgsi_swizzle_names ); 627 } 628 629 if (src->Register.Absolute) 630 CHR( '|' ); 631 632 first_reg = FALSE; 633 } 634 635 if (inst->Instruction.Texture) { 636 if (!(inst->Instruction.Opcode >= TGSI_OPCODE_SAMPLE && 637 inst->Instruction.Opcode <= TGSI_OPCODE_GATHER4)) { 638 TXT( ", " ); 639 ENM( inst->Texture.Texture, tgsi_texture_names ); 640 } 641 for (i = 0; i < inst->Texture.NumOffsets; i++) { 642 TXT( ", " ); 643 TXT(tgsi_file_name(inst->TexOffsets[i].File)); 644 CHR( '[' ); 645 SID( inst->TexOffsets[i].Index ); 646 CHR( ']' ); 647 CHR( '.' ); 648 ENM( inst->TexOffsets[i].SwizzleX, tgsi_swizzle_names); 649 ENM( inst->TexOffsets[i].SwizzleY, tgsi_swizzle_names); 650 ENM( inst->TexOffsets[i].SwizzleZ, tgsi_swizzle_names); 651 } 652 } 653 654 if (inst->Instruction.Memory) { 655 uint32_t qualifier = inst->Memory.Qualifier; 656 while (qualifier) { 657 int bit = ffs(qualifier) - 1; 658 qualifier &= ~(1U << bit); 659 TXT(", "); 660 ENM(bit, tgsi_memory_names); 661 } 662 if (inst->Memory.Texture) { 663 TXT( ", " ); 664 ENM( inst->Memory.Texture, tgsi_texture_names ); 665 } 666 if (inst->Memory.Format) { 667 TXT( ", " ); 668 TXT( util_format_name(inst->Memory.Format) ); 669 } 670 } 671 672 if (inst->Instruction.Label) { 673 switch (inst->Instruction.Opcode) { 674 case TGSI_OPCODE_IF: 675 case TGSI_OPCODE_UIF: 676 case TGSI_OPCODE_ELSE: 677 case TGSI_OPCODE_BGNLOOP: 678 case TGSI_OPCODE_ENDLOOP: 679 case TGSI_OPCODE_CAL: 680 case TGSI_OPCODE_BGNSUB: 681 TXT( " :" ); 682 UID( inst->Label.Label ); 683 break; 684 } 685 } 686 687 /* update indentation */ 688 if (inst->Instruction.Opcode == TGSI_OPCODE_IF || 689 inst->Instruction.Opcode == TGSI_OPCODE_UIF || 690 inst->Instruction.Opcode == TGSI_OPCODE_ELSE || 691 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) { 692 ctx->indentation += indent_spaces; 693 } 694 695 EOL(); 696 697 return TRUE; 698 } 699 700 void 701 tgsi_dump_instruction( 702 const struct tgsi_full_instruction *inst, 703 uint instno ) 704 { 705 struct dump_ctx ctx; 706 memset(&ctx, 0, sizeof(ctx)); 707 708 ctx.instno = instno; 709 ctx.immno = instno; 710 ctx.indent = 0; 711 ctx.dump_printf = dump_ctx_printf; 712 ctx.indentation = 0; 713 ctx.file = NULL; 714 715 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst ); 716 } 717 718 static boolean 719 prolog( 720 struct tgsi_iterate_context *iter ) 721 { 722 struct dump_ctx *ctx = (struct dump_ctx *) iter; 723 ENM( iter->processor.Processor, tgsi_processor_type_names ); 724 EOL(); 725 return TRUE; 726 } 727 728 static void 729 init_dump_ctx(struct dump_ctx *ctx, uint flags) 730 { 731 memset(ctx, 0, sizeof(*ctx)); 732 733 ctx->iter.prolog = prolog; 734 ctx->iter.iterate_instruction = iter_instruction; 735 ctx->iter.iterate_declaration = iter_declaration; 736 ctx->iter.iterate_immediate = iter_immediate; 737 ctx->iter.iterate_property = iter_property; 738 739 if (flags & TGSI_DUMP_FLOAT_AS_HEX) 740 ctx->dump_float_as_hex = TRUE; 741 } 742 743 void 744 tgsi_dump_to_file(const struct tgsi_token *tokens, uint flags, FILE *file) 745 { 746 struct dump_ctx ctx; 747 memset(&ctx, 0, sizeof(ctx)); 748 749 init_dump_ctx(&ctx, flags); 750 751 ctx.dump_printf = dump_ctx_printf; 752 ctx.file = file; 753 754 tgsi_iterate_shader( tokens, &ctx.iter ); 755 } 756 757 void 758 tgsi_dump(const struct tgsi_token *tokens, uint flags) 759 { 760 tgsi_dump_to_file(tokens, flags, NULL); 761 } 762 763 struct str_dump_ctx 764 { 765 struct dump_ctx base; 766 char *str; 767 char *ptr; 768 int left; 769 bool nospace; 770 }; 771 772 static void 773 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...) 774 { 775 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx; 776 777 if (!sctx->nospace) { 778 int written; 779 va_list ap; 780 va_start(ap, format); 781 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap); 782 va_end(ap); 783 784 /* Some complicated logic needed to handle the return value of 785 * vsnprintf: 786 */ 787 if (written > 0) { 788 if (written >= sctx->left) { 789 sctx->nospace = true; 790 written = sctx->left; 791 } 792 sctx->ptr += written; 793 sctx->left -= written; 794 } 795 } 796 } 797 798 bool 799 tgsi_dump_str( 800 const struct tgsi_token *tokens, 801 uint flags, 802 char *str, 803 size_t size) 804 { 805 struct str_dump_ctx ctx; 806 memset(&ctx, 0, sizeof(ctx)); 807 808 init_dump_ctx(&ctx.base, flags); 809 810 ctx.base.dump_printf = &str_dump_ctx_printf; 811 812 ctx.str = str; 813 ctx.str[0] = 0; 814 ctx.ptr = str; 815 ctx.left = (int)size; 816 ctx.nospace = false; 817 818 tgsi_iterate_shader( tokens, &ctx.base.iter ); 819 820 return !ctx.nospace; 821 } 822 823 void 824 tgsi_dump_instruction_str( 825 const struct tgsi_full_instruction *inst, 826 uint instno, 827 char *str, 828 size_t size) 829 { 830 struct str_dump_ctx ctx; 831 memset(&ctx, 0, sizeof(ctx)); 832 833 ctx.base.instno = instno; 834 ctx.base.immno = instno; 835 ctx.base.indent = 0; 836 ctx.base.dump_printf = &str_dump_ctx_printf; 837 ctx.base.indentation = 0; 838 ctx.base.file = NULL; 839 840 ctx.str = str; 841 ctx.str[0] = 0; 842 ctx.ptr = str; 843 ctx.left = (int)size; 844 ctx.nospace = false; 845 846 iter_instruction( &ctx.base.iter, (struct tgsi_full_instruction *)inst ); 847 } 848