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