tgsi_dump.c revision cb90c43676c258419e4b617c908570891d3674cb
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 36struct dump_ctx 37{ 38 struct tgsi_iterate_context iter; 39 40 uint instno; 41 42 void (*printf)(struct dump_ctx *ctx, const char *format, ...); 43}; 44 45static void 46dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...) 47{ 48 va_list ap; 49 (void)ctx; 50 va_start(ap, format); 51 debug_vprintf(format, ap); 52 va_end(ap); 53} 54 55static void 56dump_enum( 57 struct dump_ctx *ctx, 58 uint e, 59 const char **enums, 60 uint enum_count ) 61{ 62 if (e >= enum_count) 63 ctx->printf( ctx, "%u", e ); 64 else 65 ctx->printf( ctx, "%s", enums[e] ); 66} 67 68#define EOL() ctx->printf( ctx, "\n" ) 69#define TXT(S) ctx->printf( ctx, "%s", S ) 70#define CHR(C) ctx->printf( ctx, "%c", C ) 71#define UIX(I) ctx->printf( ctx, "0x%x", I ) 72#define UID(I) ctx->printf( ctx, "%u", I ) 73#define INSTID(I) ctx->printf( ctx, "% 3u", I ) 74#define SID(I) ctx->printf( ctx, "%d", I ) 75#define FLT(F) ctx->printf( ctx, "%10.4f", F ) 76#define ENM(E,ENUMS) dump_enum( ctx, E, ENUMS, sizeof( ENUMS ) / sizeof( *ENUMS ) ) 77 78static const char *processor_type_names[] = 79{ 80 "FRAG", 81 "VERT", 82 "GEOM" 83}; 84 85static const char *file_names[TGSI_FILE_COUNT] = 86{ 87 "NULL", 88 "CONST", 89 "IN", 90 "OUT", 91 "TEMP", 92 "SAMP", 93 "ADDR", 94 "IMM", 95 "LOOP" 96}; 97 98static const char *interpolate_names[] = 99{ 100 "CONSTANT", 101 "LINEAR", 102 "PERSPECTIVE" 103}; 104 105static const char *semantic_names[] = 106{ 107 "POSITION", 108 "COLOR", 109 "BCOLOR", 110 "FOG", 111 "PSIZE", 112 "GENERIC", 113 "NORMAL", 114 "FACE" 115}; 116 117static const char *immediate_type_names[] = 118{ 119 "FLT32" 120}; 121 122static const char *swizzle_names[] = 123{ 124 "x", 125 "y", 126 "z", 127 "w" 128}; 129 130static const char *texture_names[] = 131{ 132 "UNKNOWN", 133 "1D", 134 "2D", 135 "3D", 136 "CUBE", 137 "RECT", 138 "SHADOW1D", 139 "SHADOW2D", 140 "SHADOWRECT" 141}; 142 143static const char *extswizzle_names[] = 144{ 145 "x", 146 "y", 147 "z", 148 "w", 149 "0", 150 "1" 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 339 uint i; 340 boolean first_reg = TRUE; 341 342 INSTID( instno ); 343 TXT( ": " ); 344 TXT( tgsi_get_opcode_info( inst->Instruction.Opcode )->mnemonic ); 345 346 switch (inst->Instruction.Saturate) { 347 case TGSI_SAT_NONE: 348 break; 349 case TGSI_SAT_ZERO_ONE: 350 TXT( "_SAT" ); 351 break; 352 case TGSI_SAT_MINUS_PLUS_ONE: 353 TXT( "_SATNV" ); 354 break; 355 default: 356 assert( 0 ); 357 } 358 359 for (i = 0; i < inst->Instruction.NumDstRegs; i++) { 360 const struct tgsi_full_dst_register *dst = &inst->FullDstRegisters[i]; 361 362 if (!first_reg) 363 CHR( ',' ); 364 CHR( ' ' ); 365 366 if (dst->DstRegister.Indirect) { 367 _dump_register_ind( 368 ctx, 369 dst->DstRegister.File, 370 dst->DstRegister.Index, 371 dst->DstRegisterInd.File, 372 dst->DstRegisterInd.Index, 373 dst->DstRegisterInd.SwizzleX ); 374 } 375 else { 376 _dump_register( 377 ctx, 378 dst->DstRegister.File, 379 dst->DstRegister.Index, 380 dst->DstRegister.Index ); 381 } 382 ENM( dst->DstRegisterExtModulate.Modulate, modulate_names ); 383 _dump_writemask( ctx, dst->DstRegister.WriteMask ); 384 385 first_reg = FALSE; 386 } 387 388 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) { 389 const struct tgsi_full_src_register *src = &inst->FullSrcRegisters[i]; 390 391 if (!first_reg) 392 CHR( ',' ); 393 CHR( ' ' ); 394 395 if (src->SrcRegisterExtMod.Negate) 396 TXT( "-(" ); 397 if (src->SrcRegisterExtMod.Absolute) 398 CHR( '|' ); 399 if (src->SrcRegisterExtMod.Scale2X) 400 TXT( "2*(" ); 401 if (src->SrcRegisterExtMod.Bias) 402 CHR( '(' ); 403 if (src->SrcRegisterExtMod.Complement) 404 TXT( "1-(" ); 405 if (src->SrcRegister.Negate) 406 CHR( '-' ); 407 408 if (src->SrcRegister.Indirect) { 409 _dump_register_ind( 410 ctx, 411 src->SrcRegister.File, 412 src->SrcRegister.Index, 413 src->SrcRegisterInd.File, 414 src->SrcRegisterInd.Index, 415 src->SrcRegisterInd.SwizzleX ); 416 } 417 else { 418 _dump_register( 419 ctx, 420 src->SrcRegister.File, 421 src->SrcRegister.Index, 422 src->SrcRegister.Index ); 423 } 424 425 if (src->SrcRegister.SwizzleX != TGSI_SWIZZLE_X || 426 src->SrcRegister.SwizzleY != TGSI_SWIZZLE_Y || 427 src->SrcRegister.SwizzleZ != TGSI_SWIZZLE_Z || 428 src->SrcRegister.SwizzleW != TGSI_SWIZZLE_W) { 429 CHR( '.' ); 430 ENM( src->SrcRegister.SwizzleX, swizzle_names ); 431 ENM( src->SrcRegister.SwizzleY, swizzle_names ); 432 ENM( src->SrcRegister.SwizzleZ, swizzle_names ); 433 ENM( src->SrcRegister.SwizzleW, swizzle_names ); 434 } 435 if (src->SrcRegisterExtSwz.ExtSwizzleX != TGSI_EXTSWIZZLE_X || 436 src->SrcRegisterExtSwz.ExtSwizzleY != TGSI_EXTSWIZZLE_Y || 437 src->SrcRegisterExtSwz.ExtSwizzleZ != TGSI_EXTSWIZZLE_Z || 438 src->SrcRegisterExtSwz.ExtSwizzleW != TGSI_EXTSWIZZLE_W) { 439 CHR( '.' ); 440 if (src->SrcRegisterExtSwz.NegateX) 441 TXT("-"); 442 ENM( src->SrcRegisterExtSwz.ExtSwizzleX, extswizzle_names ); 443 if (src->SrcRegisterExtSwz.NegateY) 444 TXT("-"); 445 ENM( src->SrcRegisterExtSwz.ExtSwizzleY, extswizzle_names ); 446 if (src->SrcRegisterExtSwz.NegateZ) 447 TXT("-"); 448 ENM( src->SrcRegisterExtSwz.ExtSwizzleZ, extswizzle_names ); 449 if (src->SrcRegisterExtSwz.NegateW) 450 TXT("-"); 451 ENM( src->SrcRegisterExtSwz.ExtSwizzleW, extswizzle_names ); 452 } 453 454 if (src->SrcRegisterExtMod.Complement) 455 CHR( ')' ); 456 if (src->SrcRegisterExtMod.Bias) 457 TXT( ")-.5" ); 458 if (src->SrcRegisterExtMod.Scale2X) 459 CHR( ')' ); 460 if (src->SrcRegisterExtMod.Absolute) 461 CHR( '|' ); 462 if (src->SrcRegisterExtMod.Negate) 463 CHR( ')' ); 464 465 first_reg = FALSE; 466 } 467 468 if (inst->InstructionExtTexture.Texture != TGSI_TEXTURE_UNKNOWN) { 469 TXT( ", " ); 470 ENM( inst->InstructionExtTexture.Texture, texture_names ); 471 } 472 473 switch (inst->Instruction.Opcode) { 474 case TGSI_OPCODE_IF: 475 case TGSI_OPCODE_ELSE: 476 case TGSI_OPCODE_BGNLOOP: 477 case TGSI_OPCODE_ENDLOOP: 478 case TGSI_OPCODE_CAL: 479 TXT( " :" ); 480 UID( inst->InstructionExtLabel.Label ); 481 break; 482 } 483 484 EOL(); 485 486 return TRUE; 487} 488 489void 490tgsi_dump_instruction( 491 const struct tgsi_full_instruction *inst, 492 uint instno ) 493{ 494 struct dump_ctx ctx; 495 496 ctx.instno = instno; 497 ctx.printf = dump_ctx_printf; 498 499 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst ); 500} 501 502static boolean 503prolog( 504 struct tgsi_iterate_context *iter ) 505{ 506 struct dump_ctx *ctx = (struct dump_ctx *) iter; 507 ENM( iter->processor.Processor, processor_type_names ); 508 UID( iter->version.MajorVersion ); 509 CHR( '.' ); 510 UID( iter->version.MinorVersion ); 511 EOL(); 512 return TRUE; 513} 514 515void 516tgsi_dump( 517 const struct tgsi_token *tokens, 518 uint flags ) 519{ 520 struct dump_ctx ctx; 521 522 ctx.iter.prolog = prolog; 523 ctx.iter.iterate_instruction = iter_instruction; 524 ctx.iter.iterate_declaration = iter_declaration; 525 ctx.iter.iterate_immediate = iter_immediate; 526 ctx.iter.epilog = NULL; 527 528 ctx.instno = 0; 529 ctx.printf = dump_ctx_printf; 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.printf = &str_dump_ctx_printf; 582 583 ctx.str = str; 584 ctx.str[0] = 0; 585 ctx.ptr = str; 586 ctx.left = (int)size; 587 588 tgsi_iterate_shader( tokens, &ctx.base.iter ); 589} 590