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 */ 42static const int indent_spaces = 3; 43 44 45struct 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 61static void 62dump_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 74static void 75dump_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 101const char * 102tgsi_swizzle_names[4] = 103{ 104 "x", 105 "y", 106 "z", 107 "w" 108}; 109 110static 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 167static 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} 222static 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 240static void 241dump_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 297static boolean 298iter_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 441 if (decl->Declaration.Invariant) { 442 TXT( ", INVARIANT" ); 443 } 444 445 EOL(); 446 447 return TRUE; 448} 449 450void 451tgsi_dump_declaration( 452 const struct tgsi_full_declaration *decl ) 453{ 454 struct dump_ctx ctx; 455 memset(&ctx, 0, sizeof(ctx)); 456 457 ctx.dump_printf = dump_ctx_printf; 458 459 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl ); 460} 461 462static boolean 463iter_property( 464 struct tgsi_iterate_context *iter, 465 struct tgsi_full_property *prop ) 466{ 467 int i; 468 struct dump_ctx *ctx = (struct dump_ctx *)iter; 469 470 TXT( "PROPERTY " ); 471 ENM(prop->Property.PropertyName, tgsi_property_names); 472 473 if (prop->Property.NrTokens > 1) 474 TXT(" "); 475 476 for (i = 0; i < prop->Property.NrTokens - 1; ++i) { 477 switch (prop->Property.PropertyName) { 478 case TGSI_PROPERTY_GS_INPUT_PRIM: 479 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 480 ENM(prop->u[i].Data, tgsi_primitive_names); 481 break; 482 case TGSI_PROPERTY_FS_COORD_ORIGIN: 483 ENM(prop->u[i].Data, tgsi_fs_coord_origin_names); 484 break; 485 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: 486 ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names); 487 break; 488 case TGSI_PROPERTY_NEXT_SHADER: 489 ENM(prop->u[i].Data, tgsi_processor_type_names); 490 break; 491 default: 492 SID( prop->u[i].Data ); 493 break; 494 } 495 if (i < prop->Property.NrTokens - 2) 496 TXT( ", " ); 497 } 498 EOL(); 499 500 return TRUE; 501} 502 503void tgsi_dump_property( 504 const struct tgsi_full_property *prop ) 505{ 506 struct dump_ctx ctx; 507 memset(&ctx, 0, sizeof(ctx)); 508 509 ctx.dump_printf = dump_ctx_printf; 510 511 iter_property( &ctx.iter, (struct tgsi_full_property *)prop ); 512} 513 514static boolean 515iter_immediate( 516 struct tgsi_iterate_context *iter, 517 struct tgsi_full_immediate *imm ) 518{ 519 struct dump_ctx *ctx = (struct dump_ctx *) iter; 520 521 TXT( "IMM[" ); 522 SID( ctx->immno++ ); 523 TXT( "] " ); 524 ENM( imm->Immediate.DataType, tgsi_immediate_type_names ); 525 526 dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1, 527 imm->Immediate.DataType); 528 529 EOL(); 530 531 return TRUE; 532} 533 534void 535tgsi_dump_immediate( 536 const struct tgsi_full_immediate *imm ) 537{ 538 struct dump_ctx ctx; 539 memset(&ctx, 0, sizeof(ctx)); 540 541 ctx.dump_printf = dump_ctx_printf; 542 543 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm ); 544} 545 546static boolean 547iter_instruction( 548 struct tgsi_iterate_context *iter, 549 struct tgsi_full_instruction *inst ) 550{ 551 struct dump_ctx *ctx = (struct dump_ctx *) iter; 552 uint instno = ctx->instno++; 553 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode ); 554 uint i; 555 boolean first_reg = TRUE; 556 557 INSTID( instno ); 558 TXT( ": " ); 559 560 ctx->indent -= info->pre_dedent; 561 for(i = 0; (int)i < ctx->indent; ++i) 562 TXT( " " ); 563 ctx->indent += info->post_indent; 564 565 TXT( tgsi_get_opcode_name(inst->Instruction.Opcode) ); 566 567 if (inst->Instruction.Saturate) { 568 TXT( "_SAT" ); 569 } 570 571 if (inst->Instruction.Precise) { 572 TXT( "_PRECISE" ); 573 } 574 575 for (i = 0; i < inst->Instruction.NumDstRegs; i++) { 576 const struct tgsi_full_dst_register *dst = &inst->Dst[i]; 577 578 if (!first_reg) 579 CHR( ',' ); 580 CHR( ' ' ); 581 582 _dump_register_dst( ctx, dst ); 583 _dump_writemask( ctx, dst->Register.WriteMask ); 584 585 first_reg = FALSE; 586 } 587 588 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { 589 const struct tgsi_full_src_register *src = &inst->Src[i]; 590 591 if (!first_reg) 592 CHR( ',' ); 593 CHR( ' ' ); 594 595 if (src->Register.Negate) 596 CHR( '-' ); 597 if (src->Register.Absolute) 598 CHR( '|' ); 599 600 _dump_register_src(ctx, src); 601 602 if (src->Register.SwizzleX != TGSI_SWIZZLE_X || 603 src->Register.SwizzleY != TGSI_SWIZZLE_Y || 604 src->Register.SwizzleZ != TGSI_SWIZZLE_Z || 605 src->Register.SwizzleW != TGSI_SWIZZLE_W) { 606 CHR( '.' ); 607 ENM( src->Register.SwizzleX, tgsi_swizzle_names ); 608 ENM( src->Register.SwizzleY, tgsi_swizzle_names ); 609 ENM( src->Register.SwizzleZ, tgsi_swizzle_names ); 610 ENM( src->Register.SwizzleW, tgsi_swizzle_names ); 611 } 612 613 if (src->Register.Absolute) 614 CHR( '|' ); 615 616 first_reg = FALSE; 617 } 618 619 if (inst->Instruction.Texture) { 620 if (!(inst->Instruction.Opcode >= TGSI_OPCODE_SAMPLE && 621 inst->Instruction.Opcode <= TGSI_OPCODE_GATHER4)) { 622 TXT( ", " ); 623 ENM( inst->Texture.Texture, tgsi_texture_names ); 624 } 625 for (i = 0; i < inst->Texture.NumOffsets; i++) { 626 TXT( ", " ); 627 TXT(tgsi_file_name(inst->TexOffsets[i].File)); 628 CHR( '[' ); 629 SID( inst->TexOffsets[i].Index ); 630 CHR( ']' ); 631 CHR( '.' ); 632 ENM( inst->TexOffsets[i].SwizzleX, tgsi_swizzle_names); 633 ENM( inst->TexOffsets[i].SwizzleY, tgsi_swizzle_names); 634 ENM( inst->TexOffsets[i].SwizzleZ, tgsi_swizzle_names); 635 } 636 } 637 638 if (inst->Instruction.Memory) { 639 uint32_t qualifier = inst->Memory.Qualifier; 640 while (qualifier) { 641 int bit = ffs(qualifier) - 1; 642 qualifier &= ~(1U << bit); 643 TXT(", "); 644 ENM(bit, tgsi_memory_names); 645 } 646 if (inst->Memory.Texture) { 647 TXT( ", " ); 648 ENM( inst->Memory.Texture, tgsi_texture_names ); 649 } 650 if (inst->Memory.Format) { 651 TXT( ", " ); 652 TXT( util_format_name(inst->Memory.Format) ); 653 } 654 } 655 656 if (inst->Instruction.Label) { 657 switch (inst->Instruction.Opcode) { 658 case TGSI_OPCODE_IF: 659 case TGSI_OPCODE_UIF: 660 case TGSI_OPCODE_ELSE: 661 case TGSI_OPCODE_BGNLOOP: 662 case TGSI_OPCODE_ENDLOOP: 663 case TGSI_OPCODE_CAL: 664 case TGSI_OPCODE_BGNSUB: 665 TXT( " :" ); 666 UID( inst->Label.Label ); 667 break; 668 } 669 } 670 671 /* update indentation */ 672 if (inst->Instruction.Opcode == TGSI_OPCODE_IF || 673 inst->Instruction.Opcode == TGSI_OPCODE_UIF || 674 inst->Instruction.Opcode == TGSI_OPCODE_ELSE || 675 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) { 676 ctx->indentation += indent_spaces; 677 } 678 679 EOL(); 680 681 return TRUE; 682} 683 684void 685tgsi_dump_instruction( 686 const struct tgsi_full_instruction *inst, 687 uint instno ) 688{ 689 struct dump_ctx ctx; 690 memset(&ctx, 0, sizeof(ctx)); 691 692 ctx.instno = instno; 693 ctx.immno = instno; 694 ctx.indent = 0; 695 ctx.dump_printf = dump_ctx_printf; 696 ctx.indentation = 0; 697 ctx.file = NULL; 698 699 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst ); 700} 701 702static boolean 703prolog( 704 struct tgsi_iterate_context *iter ) 705{ 706 struct dump_ctx *ctx = (struct dump_ctx *) iter; 707 ENM( iter->processor.Processor, tgsi_processor_type_names ); 708 EOL(); 709 return TRUE; 710} 711 712static void 713init_dump_ctx(struct dump_ctx *ctx, uint flags) 714{ 715 memset(ctx, 0, sizeof(*ctx)); 716 717 ctx->iter.prolog = prolog; 718 ctx->iter.iterate_instruction = iter_instruction; 719 ctx->iter.iterate_declaration = iter_declaration; 720 ctx->iter.iterate_immediate = iter_immediate; 721 ctx->iter.iterate_property = iter_property; 722 723 if (flags & TGSI_DUMP_FLOAT_AS_HEX) 724 ctx->dump_float_as_hex = TRUE; 725} 726 727void 728tgsi_dump_to_file(const struct tgsi_token *tokens, uint flags, FILE *file) 729{ 730 struct dump_ctx ctx; 731 memset(&ctx, 0, sizeof(ctx)); 732 733 init_dump_ctx(&ctx, flags); 734 735 ctx.dump_printf = dump_ctx_printf; 736 ctx.file = file; 737 738 tgsi_iterate_shader( tokens, &ctx.iter ); 739} 740 741void 742tgsi_dump(const struct tgsi_token *tokens, uint flags) 743{ 744 tgsi_dump_to_file(tokens, flags, NULL); 745} 746 747struct str_dump_ctx 748{ 749 struct dump_ctx base; 750 char *str; 751 char *ptr; 752 int left; 753 bool nospace; 754}; 755 756static void 757str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...) 758{ 759 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx; 760 761 if (!sctx->nospace) { 762 int written; 763 va_list ap; 764 va_start(ap, format); 765 written = vsnprintf(sctx->ptr, sctx->left, format, ap); 766 va_end(ap); 767 768 /* Some complicated logic needed to handle the return value of 769 * vsnprintf: 770 */ 771 if (written > 0) { 772 if (written >= sctx->left) { 773 sctx->nospace = true; 774 written = sctx->left; 775 } 776 sctx->ptr += written; 777 sctx->left -= written; 778 } 779 } 780} 781 782bool 783tgsi_dump_str( 784 const struct tgsi_token *tokens, 785 uint flags, 786 char *str, 787 size_t size) 788{ 789 struct str_dump_ctx ctx; 790 memset(&ctx, 0, sizeof(ctx)); 791 792 init_dump_ctx(&ctx.base, flags); 793 794 ctx.base.dump_printf = &str_dump_ctx_printf; 795 796 ctx.str = str; 797 ctx.str[0] = 0; 798 ctx.ptr = str; 799 ctx.left = (int)size; 800 ctx.nospace = false; 801 802 tgsi_iterate_shader( tokens, &ctx.base.iter ); 803 804 return !ctx.nospace; 805} 806 807void 808tgsi_dump_instruction_str( 809 const struct tgsi_full_instruction *inst, 810 uint instno, 811 char *str, 812 size_t size) 813{ 814 struct str_dump_ctx ctx; 815 memset(&ctx, 0, sizeof(ctx)); 816 817 ctx.base.instno = instno; 818 ctx.base.immno = instno; 819 ctx.base.indent = 0; 820 ctx.base.dump_printf = &str_dump_ctx_printf; 821 ctx.base.indentation = 0; 822 ctx.base.file = NULL; 823 824 ctx.str = str; 825 ctx.str[0] = 0; 826 ctx.ptr = str; 827 ctx.left = (int)size; 828 ctx.nospace = false; 829 830 iter_instruction( &ctx.base.iter, (struct tgsi_full_instruction *)inst ); 831} 832