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