gallium: edgeflags change fixes
[mesa.git] / src / gallium / auxiliary / tgsi / tgsi_dump.c
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 */
38 static const int indent_spaces = 3;
39
40
41 struct 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
53 static void
54 dump_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
63 static void
64 dump_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
86 static const char *processor_type_names[] =
87 {
88 "FRAG",
89 "VERT",
90 "GEOM"
91 };
92
93 static 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
107 static const char *interpolate_names[] =
108 {
109 "CONSTANT",
110 "LINEAR",
111 "PERSPECTIVE"
112 };
113
114 static 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
127 static const char *immediate_type_names[] =
128 {
129 "FLT32"
130 };
131
132 static const char *swizzle_names[] =
133 {
134 "x",
135 "y",
136 "z",
137 "w"
138 };
139
140 static 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
154 static 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
171 static 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
195 static 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
213 static boolean
214 iter_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
265 void
266 tgsi_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
276 static boolean
277 iter_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
310 void
311 tgsi_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
321 static boolean
322 iter_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
460 void
461 tgsi_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
475 static boolean
476 prolog(
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
485 void
486 tgsi_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
506 struct str_dump_ctx
507 {
508 struct dump_ctx base;
509 char *str;
510 char *ptr;
511 int left;
512 };
513
514 static void
515 str_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
537 void
538 tgsi_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 }