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