tgsi_dump.c revision 89d8577fb3036547ef0b47498cc8dc5c77f886e0
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 "VERTICES_IN", 127 "PRIM_ID" 128}; 129 130static const char *immediate_type_names[] = 131{ 132 "FLT32" 133}; 134 135static const char *swizzle_names[] = 136{ 137 "x", 138 "y", 139 "z", 140 "w" 141}; 142 143static const char *texture_names[] = 144{ 145 "UNKNOWN", 146 "1D", 147 "2D", 148 "3D", 149 "CUBE", 150 "RECT", 151 "SHADOW1D", 152 "SHADOW2D", 153 "SHADOWRECT" 154}; 155 156static const char *property_names[] = 157{ 158 "GS_INPUT_PRIMITIVE", 159 "GS_OUTPUT_PRIMITIVE", 160 "GS_MAX_OUTPUT_VERTICES" 161}; 162 163static const char *primitive_names[] = 164{ 165 "POINTS", 166 "LINES", 167 "LINE_LOOP", 168 "LINE_STRIP", 169 "TRIANGLES", 170 "TRIANGLE_STRIP", 171 "TRIANGLE_FAN", 172 "QUADS", 173 "QUAD_STRIP", 174 "POLYGON" 175}; 176 177 178static void 179_dump_register( 180 struct dump_ctx *ctx, 181 uint file, 182 int first, 183 int last ) 184{ 185 ENM( file, file_names ); 186 CHR( '[' ); 187 SID( first ); 188 if (first != last) { 189 TXT( ".." ); 190 SID( last ); 191 } 192 CHR( ']' ); 193} 194 195static void 196_dump_register_ind( 197 struct dump_ctx *ctx, 198 uint file, 199 int index, 200 uint ind_file, 201 int ind_index, 202 uint ind_swizzle ) 203{ 204 ENM( file, file_names ); 205 CHR( '[' ); 206 ENM( ind_file, file_names ); 207 CHR( '[' ); 208 SID( ind_index ); 209 TXT( "]." ); 210 ENM( ind_swizzle, swizzle_names ); 211 if (index != 0) { 212 if (index > 0) 213 CHR( '+' ); 214 SID( index ); 215 } 216 CHR( ']' ); 217} 218 219static void 220_dump_writemask( 221 struct dump_ctx *ctx, 222 uint writemask ) 223{ 224 if (writemask != TGSI_WRITEMASK_XYZW) { 225 CHR( '.' ); 226 if (writemask & TGSI_WRITEMASK_X) 227 CHR( 'x' ); 228 if (writemask & TGSI_WRITEMASK_Y) 229 CHR( 'y' ); 230 if (writemask & TGSI_WRITEMASK_Z) 231 CHR( 'z' ); 232 if (writemask & TGSI_WRITEMASK_W) 233 CHR( 'w' ); 234 } 235} 236 237static boolean 238iter_declaration( 239 struct tgsi_iterate_context *iter, 240 struct tgsi_full_declaration *decl ) 241{ 242 struct dump_ctx *ctx = (struct dump_ctx *)iter; 243 244 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT); 245 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT); 246 247 TXT( "DCL " ); 248 249 _dump_register( 250 ctx, 251 decl->Declaration.File, 252 decl->Range.First, 253 decl->Range.Last ); 254 _dump_writemask( 255 ctx, 256 decl->Declaration.UsageMask ); 257 258 if (decl->Declaration.Semantic) { 259 TXT( ", " ); 260 ENM( decl->Semantic.Name, semantic_names ); 261 if (decl->Semantic.Index != 0 || 262 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) { 263 CHR( '[' ); 264 UID( decl->Semantic.Index ); 265 CHR( ']' ); 266 } 267 } 268 269 if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT && 270 decl->Declaration.File == TGSI_FILE_INPUT) 271 { 272 TXT( ", " ); 273 ENM( decl->Declaration.Interpolate, interpolate_names ); 274 } 275 276 if (decl->Declaration.Centroid) { 277 TXT( ", CENTROID" ); 278 } 279 280 if (decl->Declaration.Invariant) { 281 TXT( ", INVARIANT" ); 282 } 283 284 EOL(); 285 286 return TRUE; 287} 288 289void 290tgsi_dump_declaration( 291 const struct tgsi_full_declaration *decl ) 292{ 293 struct dump_ctx ctx; 294 295 ctx.printf = dump_ctx_printf; 296 297 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl ); 298} 299 300static boolean 301iter_property( 302 struct tgsi_iterate_context *iter, 303 struct tgsi_full_property *prop ) 304{ 305 int i; 306 struct dump_ctx *ctx = (struct dump_ctx *)iter; 307 308 assert(Elements(property_names) == TGSI_PROPERTY_COUNT); 309 310 TXT( "PROPERTY " ); 311 ENM(prop->Property.PropertyName, property_names); 312 313 if (prop->Property.NrTokens > 1) 314 TXT(" "); 315 316 for (i = 0; i < prop->Property.NrTokens - 1; ++i) { 317 switch (prop->Property.PropertyName) { 318 case TGSI_PROPERTY_GS_INPUT_PRIM: 319 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 320 ENM(prop->u[i].Data, primitive_names); 321 break; 322 default: 323 SID( prop->u[i].Data ); 324 break; 325 } 326 if (i < prop->Property.NrTokens - 2) 327 TXT( ", " ); 328 } 329 EOL(); 330 331 return TRUE; 332} 333 334void tgsi_dump_property( 335 const struct tgsi_full_property *prop ) 336{ 337 struct dump_ctx ctx; 338 339 ctx.printf = dump_ctx_printf; 340 341 iter_property( &ctx.iter, (struct tgsi_full_property *)prop ); 342} 343 344static boolean 345iter_immediate( 346 struct tgsi_iterate_context *iter, 347 struct tgsi_full_immediate *imm ) 348{ 349 struct dump_ctx *ctx = (struct dump_ctx *) iter; 350 351 uint i; 352 353 TXT( "IMM " ); 354 ENM( imm->Immediate.DataType, immediate_type_names ); 355 356 TXT( " { " ); 357 358 assert( imm->Immediate.NrTokens <= 4 + 1 ); 359 for (i = 0; i < imm->Immediate.NrTokens - 1; i++) { 360 switch (imm->Immediate.DataType) { 361 case TGSI_IMM_FLOAT32: 362 FLT( imm->u[i].Float ); 363 break; 364 default: 365 assert( 0 ); 366 } 367 368 if (i < imm->Immediate.NrTokens - 2) 369 TXT( ", " ); 370 } 371 TXT( " }" ); 372 373 EOL(); 374 375 return TRUE; 376} 377 378void 379tgsi_dump_immediate( 380 const struct tgsi_full_immediate *imm ) 381{ 382 struct dump_ctx ctx; 383 384 ctx.printf = dump_ctx_printf; 385 386 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm ); 387} 388 389static boolean 390iter_instruction( 391 struct tgsi_iterate_context *iter, 392 struct tgsi_full_instruction *inst ) 393{ 394 struct dump_ctx *ctx = (struct dump_ctx *) iter; 395 uint instno = ctx->instno++; 396 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode ); 397 uint i; 398 boolean first_reg = TRUE; 399 400 INSTID( instno ); 401 TXT( ": " ); 402 403 ctx->indent -= info->pre_dedent; 404 for(i = 0; (int)i < ctx->indent; ++i) 405 TXT( " " ); 406 ctx->indent += info->post_indent; 407 408 TXT( info->mnemonic ); 409 410 switch (inst->Instruction.Saturate) { 411 case TGSI_SAT_NONE: 412 break; 413 case TGSI_SAT_ZERO_ONE: 414 TXT( "_SAT" ); 415 break; 416 case TGSI_SAT_MINUS_PLUS_ONE: 417 TXT( "_SATNV" ); 418 break; 419 default: 420 assert( 0 ); 421 } 422 423 for (i = 0; i < inst->Instruction.NumDstRegs; i++) { 424 const struct tgsi_full_dst_register *dst = &inst->Dst[i]; 425 426 if (!first_reg) 427 CHR( ',' ); 428 CHR( ' ' ); 429 430 if (dst->Register.Indirect) { 431 _dump_register_ind( 432 ctx, 433 dst->Register.File, 434 dst->Register.Index, 435 dst->Indirect.File, 436 dst->Indirect.Index, 437 dst->Indirect.SwizzleX ); 438 } 439 else { 440 _dump_register( 441 ctx, 442 dst->Register.File, 443 dst->Register.Index, 444 dst->Register.Index ); 445 } 446 _dump_writemask( ctx, dst->Register.WriteMask ); 447 448 first_reg = FALSE; 449 } 450 451 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { 452 const struct tgsi_full_src_register *src = &inst->Src[i]; 453 454 if (!first_reg) 455 CHR( ',' ); 456 CHR( ' ' ); 457 458 if (src->Register.Negate) 459 TXT( "-(" ); 460 if (src->Register.Absolute) 461 CHR( '|' ); 462 463 if (src->Register.Indirect) { 464 _dump_register_ind( 465 ctx, 466 src->Register.File, 467 src->Register.Index, 468 src->Indirect.File, 469 src->Indirect.Index, 470 src->Indirect.SwizzleX ); 471 } 472 else { 473 _dump_register( 474 ctx, 475 src->Register.File, 476 src->Register.Index, 477 src->Register.Index ); 478 } 479 480 if (src->Register.SwizzleX != TGSI_SWIZZLE_X || 481 src->Register.SwizzleY != TGSI_SWIZZLE_Y || 482 src->Register.SwizzleZ != TGSI_SWIZZLE_Z || 483 src->Register.SwizzleW != TGSI_SWIZZLE_W) { 484 CHR( '.' ); 485 ENM( src->Register.SwizzleX, swizzle_names ); 486 ENM( src->Register.SwizzleY, swizzle_names ); 487 ENM( src->Register.SwizzleZ, swizzle_names ); 488 ENM( src->Register.SwizzleW, swizzle_names ); 489 } 490 491 if (src->Register.Absolute) 492 CHR( '|' ); 493 if (src->Register.Negate) 494 CHR( ')' ); 495 496 first_reg = FALSE; 497 } 498 499 if (inst->Instruction.Texture) { 500 TXT( ", " ); 501 ENM( inst->Texture.Texture, texture_names ); 502 } 503 504 switch (inst->Instruction.Opcode) { 505 case TGSI_OPCODE_IF: 506 case TGSI_OPCODE_ELSE: 507 case TGSI_OPCODE_BGNLOOP: 508 case TGSI_OPCODE_ENDLOOP: 509 case TGSI_OPCODE_CAL: 510 TXT( " :" ); 511 UID( inst->Label.Label ); 512 break; 513 } 514 515 /* update indentation */ 516 if (inst->Instruction.Opcode == TGSI_OPCODE_IF || 517 inst->Instruction.Opcode == TGSI_OPCODE_ELSE || 518 inst->Instruction.Opcode == TGSI_OPCODE_BGNFOR || 519 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) { 520 ctx->indentation += indent_spaces; 521 } 522 523 EOL(); 524 525 return TRUE; 526} 527 528void 529tgsi_dump_instruction( 530 const struct tgsi_full_instruction *inst, 531 uint instno ) 532{ 533 struct dump_ctx ctx; 534 535 ctx.instno = instno; 536 ctx.indent = 0; 537 ctx.printf = dump_ctx_printf; 538 ctx.indentation = 0; 539 540 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst ); 541} 542 543static boolean 544prolog( 545 struct tgsi_iterate_context *iter ) 546{ 547 struct dump_ctx *ctx = (struct dump_ctx *) iter; 548 ENM( iter->processor.Processor, processor_type_names ); 549 EOL(); 550 return TRUE; 551} 552 553void 554tgsi_dump( 555 const struct tgsi_token *tokens, 556 uint flags ) 557{ 558 struct dump_ctx ctx; 559 560 ctx.iter.prolog = prolog; 561 ctx.iter.iterate_instruction = iter_instruction; 562 ctx.iter.iterate_declaration = iter_declaration; 563 ctx.iter.iterate_immediate = iter_immediate; 564 ctx.iter.iterate_property = iter_property; 565 ctx.iter.epilog = NULL; 566 567 ctx.instno = 0; 568 ctx.indent = 0; 569 ctx.printf = dump_ctx_printf; 570 ctx.indentation = 0; 571 572 tgsi_iterate_shader( tokens, &ctx.iter ); 573} 574 575struct str_dump_ctx 576{ 577 struct dump_ctx base; 578 char *str; 579 char *ptr; 580 int left; 581}; 582 583static void 584str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...) 585{ 586 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx; 587 588 if(sctx->left > 1) { 589 int written; 590 va_list ap; 591 va_start(ap, format); 592 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap); 593 va_end(ap); 594 595 /* Some complicated logic needed to handle the return value of 596 * vsnprintf: 597 */ 598 if (written > 0) { 599 written = MIN2(sctx->left, written); 600 sctx->ptr += written; 601 sctx->left -= written; 602 } 603 } 604} 605 606void 607tgsi_dump_str( 608 const struct tgsi_token *tokens, 609 uint flags, 610 char *str, 611 size_t size) 612{ 613 struct str_dump_ctx ctx; 614 615 ctx.base.iter.prolog = prolog; 616 ctx.base.iter.iterate_instruction = iter_instruction; 617 ctx.base.iter.iterate_declaration = iter_declaration; 618 ctx.base.iter.iterate_immediate = iter_immediate; 619 ctx.base.iter.iterate_property = iter_property; 620 ctx.base.iter.epilog = NULL; 621 622 ctx.base.instno = 0; 623 ctx.base.indent = 0; 624 ctx.base.printf = &str_dump_ctx_printf; 625 ctx.base.indentation = 0; 626 627 ctx.str = str; 628 ctx.str[0] = 0; 629 ctx.ptr = str; 630 ctx.left = (int)size; 631 632 tgsi_iterate_shader( tokens, &ctx.base.iter ); 633} 634