tgsi_dump.c revision bdbe77f9c6f06cfaa155f27c2ade3c523d7fbea7
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 93const char * 94tgsi_file_names[TGSI_FILE_COUNT] = 95{ 96 "NULL", 97 "CONST", 98 "IN", 99 "OUT", 100 "TEMP", 101 "SAMP", 102 "ADDR", 103 "IMM", 104 "PRED", 105 "SV", 106 "IMMX", 107 "TEMPX", 108 "RES" 109}; 110 111static const char *interpolate_names[] = 112{ 113 "CONSTANT", 114 "LINEAR", 115 "PERSPECTIVE" 116}; 117 118static const char *semantic_names[] = 119{ 120 "POSITION", 121 "COLOR", 122 "BCOLOR", 123 "FOG", 124 "PSIZE", 125 "GENERIC", 126 "NORMAL", 127 "FACE", 128 "EDGEFLAG", 129 "PRIM_ID", 130 "INSTANCEID", 131 "STENCIL" 132}; 133 134static const char *immediate_type_names[] = 135{ 136 "FLT32", 137 "UINT32", 138 "INT32" 139}; 140 141const char * 142tgsi_swizzle_names[4] = 143{ 144 "x", 145 "y", 146 "z", 147 "w" 148}; 149 150const char * 151tgsi_texture_names[TGSI_TEXTURE_COUNT] = 152{ 153 "UNKNOWN", 154 "1D", 155 "2D", 156 "3D", 157 "CUBE", 158 "RECT", 159 "SHADOW1D", 160 "SHADOW2D", 161 "SHADOWRECT" 162}; 163 164const char *tgsi_property_names[TGSI_PROPERTY_COUNT] = 165{ 166 "GS_INPUT_PRIMITIVE", 167 "GS_OUTPUT_PRIMITIVE", 168 "GS_MAX_OUTPUT_VERTICES", 169 "FS_COORD_ORIGIN", 170 "FS_COORD_PIXEL_CENTER", 171 "FS_COLOR0_WRITES_ALL_CBUFS", 172}; 173 174static const char *tgsi_type_names[] = 175{ 176 "UNORM", 177 "SNORM", 178 "SINT", 179 "UINT", 180 "FLOAT" 181}; 182 183const char *tgsi_primitive_names[PIPE_PRIM_MAX] = 184{ 185 "POINTS", 186 "LINES", 187 "LINE_LOOP", 188 "LINE_STRIP", 189 "TRIANGLES", 190 "TRIANGLE_STRIP", 191 "TRIANGLE_FAN", 192 "QUADS", 193 "QUAD_STRIP", 194 "POLYGON", 195 "LINES_ADJACENCY", 196 "LINE_STRIP_ADJACENCY", 197 "TRIANGLES_ADJACENCY", 198 "TRIANGLE_STRIP_ADJACENCY" 199}; 200 201const char *tgsi_fs_coord_origin_names[2] = 202{ 203 "UPPER_LEFT", 204 "LOWER_LEFT" 205}; 206 207const char *tgsi_fs_coord_pixel_center_names[2] = 208{ 209 "HALF_INTEGER", 210 "INTEGER" 211}; 212 213 214static void 215_dump_register_src( 216 struct dump_ctx *ctx, 217 const struct tgsi_full_src_register *src ) 218{ 219 ENM(src->Register.File, tgsi_file_names); 220 if (src->Register.Dimension) { 221 if (src->Dimension.Indirect) { 222 CHR( '[' ); 223 ENM( src->DimIndirect.File, tgsi_file_names ); 224 CHR( '[' ); 225 SID( src->DimIndirect.Index ); 226 TXT( "]." ); 227 ENM( src->DimIndirect.SwizzleX, tgsi_swizzle_names ); 228 if (src->Dimension.Index != 0) { 229 if (src->Dimension.Index > 0) 230 CHR( '+' ); 231 SID( src->Dimension.Index ); 232 } 233 CHR( ']' ); 234 } else { 235 CHR('['); 236 SID(src->Dimension.Index); 237 CHR(']'); 238 } 239 } 240 if (src->Register.Indirect) { 241 CHR( '[' ); 242 ENM( src->Indirect.File, tgsi_file_names ); 243 CHR( '[' ); 244 SID( src->Indirect.Index ); 245 TXT( "]." ); 246 ENM( src->Indirect.SwizzleX, tgsi_swizzle_names ); 247 if (src->Register.Index != 0) { 248 if (src->Register.Index > 0) 249 CHR( '+' ); 250 SID( src->Register.Index ); 251 } 252 CHR( ']' ); 253 } else { 254 CHR( '[' ); 255 SID( src->Register.Index ); 256 CHR( ']' ); 257 } 258} 259 260 261static void 262_dump_register_dst( 263 struct dump_ctx *ctx, 264 const struct tgsi_full_dst_register *dst ) 265{ 266 ENM(dst->Register.File, tgsi_file_names); 267 if (dst->Register.Dimension) { 268 if (dst->Dimension.Indirect) { 269 CHR( '[' ); 270 ENM( dst->DimIndirect.File, tgsi_file_names ); 271 CHR( '[' ); 272 SID( dst->DimIndirect.Index ); 273 TXT( "]." ); 274 ENM( dst->DimIndirect.SwizzleX, tgsi_swizzle_names ); 275 if (dst->Dimension.Index != 0) { 276 if (dst->Dimension.Index > 0) 277 CHR( '+' ); 278 SID( dst->Dimension.Index ); 279 } 280 CHR( ']' ); 281 } else { 282 CHR('['); 283 SID(dst->Dimension.Index); 284 CHR(']'); 285 } 286 } 287 if (dst->Register.Indirect) { 288 CHR( '[' ); 289 ENM( dst->Indirect.File, tgsi_file_names ); 290 CHR( '[' ); 291 SID( dst->Indirect.Index ); 292 TXT( "]." ); 293 ENM( dst->Indirect.SwizzleX, tgsi_swizzle_names ); 294 if (dst->Register.Index != 0) { 295 if (dst->Register.Index > 0) 296 CHR( '+' ); 297 SID( dst->Register.Index ); 298 } 299 CHR( ']' ); 300 } else { 301 CHR( '[' ); 302 SID( dst->Register.Index ); 303 CHR( ']' ); 304 } 305} 306static void 307_dump_writemask( 308 struct dump_ctx *ctx, 309 uint writemask ) 310{ 311 if (writemask != TGSI_WRITEMASK_XYZW) { 312 CHR( '.' ); 313 if (writemask & TGSI_WRITEMASK_X) 314 CHR( 'x' ); 315 if (writemask & TGSI_WRITEMASK_Y) 316 CHR( 'y' ); 317 if (writemask & TGSI_WRITEMASK_Z) 318 CHR( 'z' ); 319 if (writemask & TGSI_WRITEMASK_W) 320 CHR( 'w' ); 321 } 322} 323 324static void 325dump_imm_data(struct tgsi_iterate_context *iter, 326 union tgsi_immediate_data *data, 327 unsigned num_tokens, 328 unsigned data_type) 329{ 330 struct dump_ctx *ctx = (struct dump_ctx *)iter; 331 unsigned i ; 332 333 TXT( " {" ); 334 335 assert( num_tokens <= 4 ); 336 for (i = 0; i < num_tokens; i++) { 337 switch (data_type) { 338 case TGSI_IMM_FLOAT32: 339 FLT( data[i].Float ); 340 break; 341 case TGSI_IMM_UINT32: 342 UID(data[i].Uint); 343 break; 344 case TGSI_IMM_INT32: 345 SID(data[i].Int); 346 break; 347 default: 348 assert( 0 ); 349 } 350 351 if (i < num_tokens - 1) 352 TXT( ", " ); 353 } 354 TXT( "}" ); 355} 356 357static boolean 358iter_declaration( 359 struct tgsi_iterate_context *iter, 360 struct tgsi_full_declaration *decl ) 361{ 362 struct dump_ctx *ctx = (struct dump_ctx *)iter; 363 364 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT); 365 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT); 366 367 TXT( "DCL " ); 368 369 ENM(decl->Declaration.File, tgsi_file_names); 370 371 /* all geometry shader inputs are two dimensional */ 372 if (decl->Declaration.File == TGSI_FILE_INPUT && 373 iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) { 374 TXT("[]"); 375 } 376 377 if (decl->Declaration.Dimension) { 378 CHR('['); 379 SID(decl->Dim.Index2D); 380 CHR(']'); 381 } 382 383 CHR('['); 384 SID(decl->Range.First); 385 if (decl->Range.First != decl->Range.Last) { 386 TXT(".."); 387 SID(decl->Range.Last); 388 } 389 CHR(']'); 390 391 _dump_writemask( 392 ctx, 393 decl->Declaration.UsageMask ); 394 395 if (decl->Declaration.Semantic) { 396 TXT( ", " ); 397 ENM( decl->Semantic.Name, semantic_names ); 398 if (decl->Semantic.Index != 0 || 399 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) { 400 CHR( '[' ); 401 UID( decl->Semantic.Index ); 402 CHR( ']' ); 403 } 404 } 405 406 if (decl->Declaration.File == TGSI_FILE_RESOURCE) { 407 TXT(", "); 408 ENM(decl->Resource.Resource, tgsi_texture_names); 409 TXT(", "); 410 if ((decl->Resource.ReturnTypeX == decl->Resource.ReturnTypeY) && 411 (decl->Resource.ReturnTypeX == decl->Resource.ReturnTypeZ) && 412 (decl->Resource.ReturnTypeX == decl->Resource.ReturnTypeW)) { 413 ENM(decl->Resource.ReturnTypeX, tgsi_type_names); 414 } else { 415 ENM(decl->Resource.ReturnTypeX, tgsi_type_names); 416 TXT(", "); 417 ENM(decl->Resource.ReturnTypeY, tgsi_type_names); 418 TXT(", "); 419 ENM(decl->Resource.ReturnTypeZ, tgsi_type_names); 420 TXT(", "); 421 ENM(decl->Resource.ReturnTypeW, tgsi_type_names); 422 } 423 424 } 425 426 if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT && 427 decl->Declaration.File == TGSI_FILE_INPUT) 428 { 429 TXT( ", " ); 430 ENM( decl->Declaration.Interpolate, interpolate_names ); 431 } 432 433 if (decl->Declaration.Centroid) { 434 TXT( ", CENTROID" ); 435 } 436 437 if (decl->Declaration.Invariant) { 438 TXT( ", INVARIANT" ); 439 } 440 441 if (decl->Declaration.CylindricalWrap) { 442 TXT(", CYLWRAP_"); 443 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) { 444 CHR('X'); 445 } 446 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) { 447 CHR('Y'); 448 } 449 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) { 450 CHR('Z'); 451 } 452 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) { 453 CHR('W'); 454 } 455 } 456 457 if (decl->Declaration.File == TGSI_FILE_IMMEDIATE_ARRAY) { 458 unsigned i; 459 char range_indent[4]; 460 461 TXT(" {"); 462 463 if (decl->Range.Last < 10) 464 range_indent[0] = '\0'; 465 else if (decl->Range.Last < 100) { 466 range_indent[0] = ' '; 467 range_indent[1] = '\0'; 468 } else if (decl->Range.Last < 1000) { 469 range_indent[0] = ' '; 470 range_indent[1] = ' '; 471 range_indent[2] = '\0'; 472 } else { 473 range_indent[0] = ' '; 474 range_indent[1] = ' '; 475 range_indent[2] = ' '; 476 range_indent[3] = '\0'; 477 } 478 479 dump_imm_data(iter, decl->ImmediateData.u, 480 4, TGSI_IMM_FLOAT32); 481 for(i = 1; i <= decl->Range.Last; ++i) { 482 /* indent by strlen of: 483 * "DCL IMMX[0..1] {" */ 484 CHR('\n'); 485 TXT( " " ); 486 TXT( range_indent ); 487 dump_imm_data(iter, decl->ImmediateData.u + i, 488 4, TGSI_IMM_FLOAT32); 489 } 490 491 TXT(" }"); 492 } 493 494 EOL(); 495 496 return TRUE; 497} 498 499void 500tgsi_dump_declaration( 501 const struct tgsi_full_declaration *decl ) 502{ 503 struct dump_ctx ctx; 504 505 ctx.printf = dump_ctx_printf; 506 507 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl ); 508} 509 510static boolean 511iter_property( 512 struct tgsi_iterate_context *iter, 513 struct tgsi_full_property *prop ) 514{ 515 int i; 516 struct dump_ctx *ctx = (struct dump_ctx *)iter; 517 518 assert(Elements(tgsi_property_names) == TGSI_PROPERTY_COUNT); 519 520 TXT( "PROPERTY " ); 521 ENM(prop->Property.PropertyName, tgsi_property_names); 522 523 if (prop->Property.NrTokens > 1) 524 TXT(" "); 525 526 for (i = 0; i < prop->Property.NrTokens - 1; ++i) { 527 switch (prop->Property.PropertyName) { 528 case TGSI_PROPERTY_GS_INPUT_PRIM: 529 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 530 ENM(prop->u[i].Data, tgsi_primitive_names); 531 break; 532 case TGSI_PROPERTY_FS_COORD_ORIGIN: 533 ENM(prop->u[i].Data, tgsi_fs_coord_origin_names); 534 break; 535 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: 536 ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names); 537 break; 538 default: 539 SID( prop->u[i].Data ); 540 break; 541 } 542 if (i < prop->Property.NrTokens - 2) 543 TXT( ", " ); 544 } 545 EOL(); 546 547 return TRUE; 548} 549 550void tgsi_dump_property( 551 const struct tgsi_full_property *prop ) 552{ 553 struct dump_ctx ctx; 554 555 ctx.printf = dump_ctx_printf; 556 557 iter_property( &ctx.iter, (struct tgsi_full_property *)prop ); 558} 559 560static boolean 561iter_immediate( 562 struct tgsi_iterate_context *iter, 563 struct tgsi_full_immediate *imm ) 564{ 565 struct dump_ctx *ctx = (struct dump_ctx *) iter; 566 567 TXT( "IMM " ); 568 ENM( imm->Immediate.DataType, immediate_type_names ); 569 570 dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1, 571 imm->Immediate.DataType); 572 573 EOL(); 574 575 return TRUE; 576} 577 578void 579tgsi_dump_immediate( 580 const struct tgsi_full_immediate *imm ) 581{ 582 struct dump_ctx ctx; 583 584 ctx.printf = dump_ctx_printf; 585 586 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm ); 587} 588 589static boolean 590iter_instruction( 591 struct tgsi_iterate_context *iter, 592 struct tgsi_full_instruction *inst ) 593{ 594 struct dump_ctx *ctx = (struct dump_ctx *) iter; 595 uint instno = ctx->instno++; 596 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode ); 597 uint i; 598 boolean first_reg = TRUE; 599 600 INSTID( instno ); 601 TXT( ": " ); 602 603 ctx->indent -= info->pre_dedent; 604 for(i = 0; (int)i < ctx->indent; ++i) 605 TXT( " " ); 606 ctx->indent += info->post_indent; 607 608 if (inst->Instruction.Predicate) { 609 CHR( '(' ); 610 611 if (inst->Predicate.Negate) 612 CHR( '!' ); 613 614 TXT( "PRED[" ); 615 SID( inst->Predicate.Index ); 616 CHR( ']' ); 617 618 if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X || 619 inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y || 620 inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z || 621 inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) { 622 CHR( '.' ); 623 ENM( inst->Predicate.SwizzleX, tgsi_swizzle_names ); 624 ENM( inst->Predicate.SwizzleY, tgsi_swizzle_names ); 625 ENM( inst->Predicate.SwizzleZ, tgsi_swizzle_names ); 626 ENM( inst->Predicate.SwizzleW, tgsi_swizzle_names ); 627 } 628 629 TXT( ") " ); 630 } 631 632 TXT( info->mnemonic ); 633 634 switch (inst->Instruction.Saturate) { 635 case TGSI_SAT_NONE: 636 break; 637 case TGSI_SAT_ZERO_ONE: 638 TXT( "_SAT" ); 639 break; 640 case TGSI_SAT_MINUS_PLUS_ONE: 641 TXT( "_SATNV" ); 642 break; 643 default: 644 assert( 0 ); 645 } 646 647 for (i = 0; i < inst->Instruction.NumDstRegs; i++) { 648 const struct tgsi_full_dst_register *dst = &inst->Dst[i]; 649 650 if (!first_reg) 651 CHR( ',' ); 652 CHR( ' ' ); 653 654 _dump_register_dst( ctx, dst ); 655 _dump_writemask( ctx, dst->Register.WriteMask ); 656 657 first_reg = FALSE; 658 } 659 660 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { 661 const struct tgsi_full_src_register *src = &inst->Src[i]; 662 663 if (!first_reg) 664 CHR( ',' ); 665 CHR( ' ' ); 666 667 if (src->Register.Negate) 668 CHR( '-' ); 669 if (src->Register.Absolute) 670 CHR( '|' ); 671 672 _dump_register_src(ctx, src); 673 674 if (src->Register.SwizzleX != TGSI_SWIZZLE_X || 675 src->Register.SwizzleY != TGSI_SWIZZLE_Y || 676 src->Register.SwizzleZ != TGSI_SWIZZLE_Z || 677 src->Register.SwizzleW != TGSI_SWIZZLE_W) { 678 CHR( '.' ); 679 ENM( src->Register.SwizzleX, tgsi_swizzle_names ); 680 ENM( src->Register.SwizzleY, tgsi_swizzle_names ); 681 ENM( src->Register.SwizzleZ, tgsi_swizzle_names ); 682 ENM( src->Register.SwizzleW, tgsi_swizzle_names ); 683 } 684 685 if (src->Register.Absolute) 686 CHR( '|' ); 687 688 first_reg = FALSE; 689 } 690 691 if (inst->Instruction.Texture) { 692 TXT( ", " ); 693 ENM( inst->Texture.Texture, tgsi_texture_names ); 694 } 695 696 switch (inst->Instruction.Opcode) { 697 case TGSI_OPCODE_IF: 698 case TGSI_OPCODE_ELSE: 699 case TGSI_OPCODE_BGNLOOP: 700 case TGSI_OPCODE_ENDLOOP: 701 case TGSI_OPCODE_CAL: 702 TXT( " :" ); 703 UID( inst->Label.Label ); 704 break; 705 } 706 707 /* update indentation */ 708 if (inst->Instruction.Opcode == TGSI_OPCODE_IF || 709 inst->Instruction.Opcode == TGSI_OPCODE_ELSE || 710 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) { 711 ctx->indentation += indent_spaces; 712 } 713 714 EOL(); 715 716 return TRUE; 717} 718 719void 720tgsi_dump_instruction( 721 const struct tgsi_full_instruction *inst, 722 uint instno ) 723{ 724 struct dump_ctx ctx; 725 726 ctx.instno = instno; 727 ctx.indent = 0; 728 ctx.printf = dump_ctx_printf; 729 ctx.indentation = 0; 730 731 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst ); 732} 733 734static boolean 735prolog( 736 struct tgsi_iterate_context *iter ) 737{ 738 struct dump_ctx *ctx = (struct dump_ctx *) iter; 739 ENM( iter->processor.Processor, processor_type_names ); 740 EOL(); 741 return TRUE; 742} 743 744void 745tgsi_dump( 746 const struct tgsi_token *tokens, 747 uint flags ) 748{ 749 struct dump_ctx ctx; 750 751 ctx.iter.prolog = prolog; 752 ctx.iter.iterate_instruction = iter_instruction; 753 ctx.iter.iterate_declaration = iter_declaration; 754 ctx.iter.iterate_immediate = iter_immediate; 755 ctx.iter.iterate_property = iter_property; 756 ctx.iter.epilog = NULL; 757 758 ctx.instno = 0; 759 ctx.indent = 0; 760 ctx.printf = dump_ctx_printf; 761 ctx.indentation = 0; 762 763 tgsi_iterate_shader( tokens, &ctx.iter ); 764} 765 766struct str_dump_ctx 767{ 768 struct dump_ctx base; 769 char *str; 770 char *ptr; 771 int left; 772}; 773 774static void 775str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...) 776{ 777 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx; 778 779 if(sctx->left > 1) { 780 int written; 781 va_list ap; 782 va_start(ap, format); 783 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap); 784 va_end(ap); 785 786 /* Some complicated logic needed to handle the return value of 787 * vsnprintf: 788 */ 789 if (written > 0) { 790 written = MIN2(sctx->left, written); 791 sctx->ptr += written; 792 sctx->left -= written; 793 } 794 } 795} 796 797void 798tgsi_dump_str( 799 const struct tgsi_token *tokens, 800 uint flags, 801 char *str, 802 size_t size) 803{ 804 struct str_dump_ctx ctx; 805 806 ctx.base.iter.prolog = prolog; 807 ctx.base.iter.iterate_instruction = iter_instruction; 808 ctx.base.iter.iterate_declaration = iter_declaration; 809 ctx.base.iter.iterate_immediate = iter_immediate; 810 ctx.base.iter.iterate_property = iter_property; 811 ctx.base.iter.epilog = NULL; 812 813 ctx.base.instno = 0; 814 ctx.base.indent = 0; 815 ctx.base.printf = &str_dump_ctx_printf; 816 ctx.base.indentation = 0; 817 818 ctx.str = str; 819 ctx.str[0] = 0; 820 ctx.ptr = str; 821 ctx.left = (int)size; 822 823 tgsi_iterate_shader( tokens, &ctx.base.iter ); 824} 825