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