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