Merge remote branch 'origin/master' into pipe-video
[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 const char *
94 tgsi_file_names[TGSI_FILE_COUNT] =
95 {
96 "NULL",
97 "CONST",
98 "IN",
99 "OUT",
100 "TEMP",
101 "SAMP",
102 "ADDR",
103 "IMM",
104 "PRED",
105 "SV",
106 "IMMX",
107 "TEMPX",
108 "RES"
109 };
110
111 static const char *interpolate_names[] =
112 {
113 "CONSTANT",
114 "LINEAR",
115 "PERSPECTIVE"
116 };
117
118 static const char *semantic_names[] =
119 {
120 "POSITION",
121 "COLOR",
122 "BCOLOR",
123 "FOG",
124 "PSIZE",
125 "GENERIC",
126 "NORMAL",
127 "FACE",
128 "EDGEFLAG",
129 "PRIM_ID",
130 "INSTANCEID",
131 "STENCIL"
132 };
133
134 static const char *immediate_type_names[] =
135 {
136 "FLT32",
137 "UINT32",
138 "INT32"
139 };
140
141 const char *
142 tgsi_swizzle_names[4] =
143 {
144 "x",
145 "y",
146 "z",
147 "w"
148 };
149
150 const char *
151 tgsi_texture_names[TGSI_TEXTURE_COUNT] =
152 {
153 "UNKNOWN",
154 "1D",
155 "2D",
156 "3D",
157 "CUBE",
158 "RECT",
159 "SHADOW1D",
160 "SHADOW2D",
161 "SHADOWRECT",
162 "1DARRAY",
163 "2DARRAY"
164 };
165
166 const char *tgsi_property_names[TGSI_PROPERTY_COUNT] =
167 {
168 "GS_INPUT_PRIMITIVE",
169 "GS_OUTPUT_PRIMITIVE",
170 "GS_MAX_OUTPUT_VERTICES",
171 "FS_COORD_ORIGIN",
172 "FS_COORD_PIXEL_CENTER",
173 "FS_COLOR0_WRITES_ALL_CBUFS",
174 };
175
176 static const char *tgsi_type_names[] =
177 {
178 "UNORM",
179 "SNORM",
180 "SINT",
181 "UINT",
182 "FLOAT"
183 };
184
185 const char *tgsi_primitive_names[PIPE_PRIM_MAX] =
186 {
187 "POINTS",
188 "LINES",
189 "LINE_LOOP",
190 "LINE_STRIP",
191 "TRIANGLES",
192 "TRIANGLE_STRIP",
193 "TRIANGLE_FAN",
194 "QUADS",
195 "QUAD_STRIP",
196 "POLYGON",
197 "LINES_ADJACENCY",
198 "LINE_STRIP_ADJACENCY",
199 "TRIANGLES_ADJACENCY",
200 "TRIANGLE_STRIP_ADJACENCY"
201 };
202
203 const char *tgsi_fs_coord_origin_names[2] =
204 {
205 "UPPER_LEFT",
206 "LOWER_LEFT"
207 };
208
209 const char *tgsi_fs_coord_pixel_center_names[2] =
210 {
211 "HALF_INTEGER",
212 "INTEGER"
213 };
214
215
216 static void
217 _dump_register_src(
218 struct dump_ctx *ctx,
219 const struct tgsi_full_src_register *src )
220 {
221 ENM(src->Register.File, tgsi_file_names);
222 if (src->Register.Dimension) {
223 if (src->Dimension.Indirect) {
224 CHR( '[' );
225 ENM( src->DimIndirect.File, tgsi_file_names );
226 CHR( '[' );
227 SID( src->DimIndirect.Index );
228 TXT( "]." );
229 ENM( src->DimIndirect.SwizzleX, tgsi_swizzle_names );
230 if (src->Dimension.Index != 0) {
231 if (src->Dimension.Index > 0)
232 CHR( '+' );
233 SID( src->Dimension.Index );
234 }
235 CHR( ']' );
236 } else {
237 CHR('[');
238 SID(src->Dimension.Index);
239 CHR(']');
240 }
241 }
242 if (src->Register.Indirect) {
243 CHR( '[' );
244 ENM( src->Indirect.File, tgsi_file_names );
245 CHR( '[' );
246 SID( src->Indirect.Index );
247 TXT( "]." );
248 ENM( src->Indirect.SwizzleX, tgsi_swizzle_names );
249 if (src->Register.Index != 0) {
250 if (src->Register.Index > 0)
251 CHR( '+' );
252 SID( src->Register.Index );
253 }
254 CHR( ']' );
255 } else {
256 CHR( '[' );
257 SID( src->Register.Index );
258 CHR( ']' );
259 }
260 }
261
262
263 static void
264 _dump_register_dst(
265 struct dump_ctx *ctx,
266 const struct tgsi_full_dst_register *dst )
267 {
268 ENM(dst->Register.File, tgsi_file_names);
269 if (dst->Register.Dimension) {
270 if (dst->Dimension.Indirect) {
271 CHR( '[' );
272 ENM( dst->DimIndirect.File, tgsi_file_names );
273 CHR( '[' );
274 SID( dst->DimIndirect.Index );
275 TXT( "]." );
276 ENM( dst->DimIndirect.SwizzleX, tgsi_swizzle_names );
277 if (dst->Dimension.Index != 0) {
278 if (dst->Dimension.Index > 0)
279 CHR( '+' );
280 SID( dst->Dimension.Index );
281 }
282 CHR( ']' );
283 } else {
284 CHR('[');
285 SID(dst->Dimension.Index);
286 CHR(']');
287 }
288 }
289 if (dst->Register.Indirect) {
290 CHR( '[' );
291 ENM( dst->Indirect.File, tgsi_file_names );
292 CHR( '[' );
293 SID( dst->Indirect.Index );
294 TXT( "]." );
295 ENM( dst->Indirect.SwizzleX, tgsi_swizzle_names );
296 if (dst->Register.Index != 0) {
297 if (dst->Register.Index > 0)
298 CHR( '+' );
299 SID( dst->Register.Index );
300 }
301 CHR( ']' );
302 } else {
303 CHR( '[' );
304 SID( dst->Register.Index );
305 CHR( ']' );
306 }
307 }
308 static void
309 _dump_writemask(
310 struct dump_ctx *ctx,
311 uint writemask )
312 {
313 if (writemask != TGSI_WRITEMASK_XYZW) {
314 CHR( '.' );
315 if (writemask & TGSI_WRITEMASK_X)
316 CHR( 'x' );
317 if (writemask & TGSI_WRITEMASK_Y)
318 CHR( 'y' );
319 if (writemask & TGSI_WRITEMASK_Z)
320 CHR( 'z' );
321 if (writemask & TGSI_WRITEMASK_W)
322 CHR( 'w' );
323 }
324 }
325
326 static void
327 dump_imm_data(struct tgsi_iterate_context *iter,
328 union tgsi_immediate_data *data,
329 unsigned num_tokens,
330 unsigned data_type)
331 {
332 struct dump_ctx *ctx = (struct dump_ctx *)iter;
333 unsigned i ;
334
335 TXT( " {" );
336
337 assert( num_tokens <= 4 );
338 for (i = 0; i < num_tokens; i++) {
339 switch (data_type) {
340 case TGSI_IMM_FLOAT32:
341 FLT( data[i].Float );
342 break;
343 case TGSI_IMM_UINT32:
344 UID(data[i].Uint);
345 break;
346 case TGSI_IMM_INT32:
347 SID(data[i].Int);
348 break;
349 default:
350 assert( 0 );
351 }
352
353 if (i < num_tokens - 1)
354 TXT( ", " );
355 }
356 TXT( "}" );
357 }
358
359 static boolean
360 iter_declaration(
361 struct tgsi_iterate_context *iter,
362 struct tgsi_full_declaration *decl )
363 {
364 struct dump_ctx *ctx = (struct dump_ctx *)iter;
365
366 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
367 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
368
369 TXT( "DCL " );
370
371 ENM(decl->Declaration.File, tgsi_file_names);
372
373 /* all geometry shader inputs are two dimensional */
374 if (decl->Declaration.File == TGSI_FILE_INPUT &&
375 iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) {
376 TXT("[]");
377 }
378
379 if (decl->Declaration.Dimension) {
380 CHR('[');
381 SID(decl->Dim.Index2D);
382 CHR(']');
383 }
384
385 CHR('[');
386 SID(decl->Range.First);
387 if (decl->Range.First != decl->Range.Last) {
388 TXT("..");
389 SID(decl->Range.Last);
390 }
391 CHR(']');
392
393 _dump_writemask(
394 ctx,
395 decl->Declaration.UsageMask );
396
397 if (decl->Declaration.Semantic) {
398 TXT( ", " );
399 ENM( decl->Semantic.Name, semantic_names );
400 if (decl->Semantic.Index != 0 ||
401 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) {
402 CHR( '[' );
403 UID( decl->Semantic.Index );
404 CHR( ']' );
405 }
406 }
407
408 if (decl->Declaration.File == TGSI_FILE_RESOURCE) {
409 TXT(", ");
410 ENM(decl->Resource.Resource, tgsi_texture_names);
411 TXT(", ");
412 if ((decl->Resource.ReturnTypeX == decl->Resource.ReturnTypeY) &&
413 (decl->Resource.ReturnTypeX == decl->Resource.ReturnTypeZ) &&
414 (decl->Resource.ReturnTypeX == decl->Resource.ReturnTypeW)) {
415 ENM(decl->Resource.ReturnTypeX, tgsi_type_names);
416 } else {
417 ENM(decl->Resource.ReturnTypeX, tgsi_type_names);
418 TXT(", ");
419 ENM(decl->Resource.ReturnTypeY, tgsi_type_names);
420 TXT(", ");
421 ENM(decl->Resource.ReturnTypeZ, tgsi_type_names);
422 TXT(", ");
423 ENM(decl->Resource.ReturnTypeW, tgsi_type_names);
424 }
425
426 }
427
428 if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
429 decl->Declaration.File == TGSI_FILE_INPUT)
430 {
431 TXT( ", " );
432 ENM( decl->Declaration.Interpolate, interpolate_names );
433 }
434
435 if (decl->Declaration.Centroid) {
436 TXT( ", CENTROID" );
437 }
438
439 if (decl->Declaration.Invariant) {
440 TXT( ", INVARIANT" );
441 }
442
443 if (decl->Declaration.CylindricalWrap) {
444 TXT(", CYLWRAP_");
445 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) {
446 CHR('X');
447 }
448 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) {
449 CHR('Y');
450 }
451 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) {
452 CHR('Z');
453 }
454 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) {
455 CHR('W');
456 }
457 }
458
459 if (decl->Declaration.File == TGSI_FILE_IMMEDIATE_ARRAY) {
460 unsigned i;
461 char range_indent[4];
462
463 TXT(" {");
464
465 if (decl->Range.Last < 10)
466 range_indent[0] = '\0';
467 else if (decl->Range.Last < 100) {
468 range_indent[0] = ' ';
469 range_indent[1] = '\0';
470 } else if (decl->Range.Last < 1000) {
471 range_indent[0] = ' ';
472 range_indent[1] = ' ';
473 range_indent[2] = '\0';
474 } else {
475 range_indent[0] = ' ';
476 range_indent[1] = ' ';
477 range_indent[2] = ' ';
478 range_indent[3] = '\0';
479 }
480
481 dump_imm_data(iter, decl->ImmediateData.u,
482 4, TGSI_IMM_FLOAT32);
483 for(i = 1; i <= decl->Range.Last; ++i) {
484 /* indent by strlen of:
485 * "DCL IMMX[0..1] {" */
486 CHR('\n');
487 TXT( " " );
488 TXT( range_indent );
489 dump_imm_data(iter, decl->ImmediateData.u + i,
490 4, TGSI_IMM_FLOAT32);
491 }
492
493 TXT(" }");
494 }
495
496 EOL();
497
498 return TRUE;
499 }
500
501 void
502 tgsi_dump_declaration(
503 const struct tgsi_full_declaration *decl )
504 {
505 struct dump_ctx ctx;
506
507 ctx.printf = dump_ctx_printf;
508
509 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
510 }
511
512 static boolean
513 iter_property(
514 struct tgsi_iterate_context *iter,
515 struct tgsi_full_property *prop )
516 {
517 int i;
518 struct dump_ctx *ctx = (struct dump_ctx *)iter;
519
520 assert(Elements(tgsi_property_names) == TGSI_PROPERTY_COUNT);
521
522 TXT( "PROPERTY " );
523 ENM(prop->Property.PropertyName, tgsi_property_names);
524
525 if (prop->Property.NrTokens > 1)
526 TXT(" ");
527
528 for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
529 switch (prop->Property.PropertyName) {
530 case TGSI_PROPERTY_GS_INPUT_PRIM:
531 case TGSI_PROPERTY_GS_OUTPUT_PRIM:
532 ENM(prop->u[i].Data, tgsi_primitive_names);
533 break;
534 case TGSI_PROPERTY_FS_COORD_ORIGIN:
535 ENM(prop->u[i].Data, tgsi_fs_coord_origin_names);
536 break;
537 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
538 ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names);
539 break;
540 default:
541 SID( prop->u[i].Data );
542 break;
543 }
544 if (i < prop->Property.NrTokens - 2)
545 TXT( ", " );
546 }
547 EOL();
548
549 return TRUE;
550 }
551
552 void tgsi_dump_property(
553 const struct tgsi_full_property *prop )
554 {
555 struct dump_ctx ctx;
556
557 ctx.printf = dump_ctx_printf;
558
559 iter_property( &ctx.iter, (struct tgsi_full_property *)prop );
560 }
561
562 static boolean
563 iter_immediate(
564 struct tgsi_iterate_context *iter,
565 struct tgsi_full_immediate *imm )
566 {
567 struct dump_ctx *ctx = (struct dump_ctx *) iter;
568
569 TXT( "IMM " );
570 ENM( imm->Immediate.DataType, immediate_type_names );
571
572 dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1,
573 imm->Immediate.DataType);
574
575 EOL();
576
577 return TRUE;
578 }
579
580 void
581 tgsi_dump_immediate(
582 const struct tgsi_full_immediate *imm )
583 {
584 struct dump_ctx ctx;
585
586 ctx.printf = dump_ctx_printf;
587
588 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
589 }
590
591 static boolean
592 iter_instruction(
593 struct tgsi_iterate_context *iter,
594 struct tgsi_full_instruction *inst )
595 {
596 struct dump_ctx *ctx = (struct dump_ctx *) iter;
597 uint instno = ctx->instno++;
598 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
599 uint i;
600 boolean first_reg = TRUE;
601
602 INSTID( instno );
603 TXT( ": " );
604
605 ctx->indent -= info->pre_dedent;
606 for(i = 0; (int)i < ctx->indent; ++i)
607 TXT( " " );
608 ctx->indent += info->post_indent;
609
610 if (inst->Instruction.Predicate) {
611 CHR( '(' );
612
613 if (inst->Predicate.Negate)
614 CHR( '!' );
615
616 TXT( "PRED[" );
617 SID( inst->Predicate.Index );
618 CHR( ']' );
619
620 if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X ||
621 inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y ||
622 inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
623 inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
624 CHR( '.' );
625 ENM( inst->Predicate.SwizzleX, tgsi_swizzle_names );
626 ENM( inst->Predicate.SwizzleY, tgsi_swizzle_names );
627 ENM( inst->Predicate.SwizzleZ, tgsi_swizzle_names );
628 ENM( inst->Predicate.SwizzleW, tgsi_swizzle_names );
629 }
630
631 TXT( ") " );
632 }
633
634 TXT( info->mnemonic );
635
636 switch (inst->Instruction.Saturate) {
637 case TGSI_SAT_NONE:
638 break;
639 case TGSI_SAT_ZERO_ONE:
640 TXT( "_SAT" );
641 break;
642 case TGSI_SAT_MINUS_PLUS_ONE:
643 TXT( "_SATNV" );
644 break;
645 default:
646 assert( 0 );
647 }
648
649 for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
650 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
651
652 if (!first_reg)
653 CHR( ',' );
654 CHR( ' ' );
655
656 _dump_register_dst( ctx, dst );
657 _dump_writemask( ctx, dst->Register.WriteMask );
658
659 first_reg = FALSE;
660 }
661
662 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
663 const struct tgsi_full_src_register *src = &inst->Src[i];
664
665 if (!first_reg)
666 CHR( ',' );
667 CHR( ' ' );
668
669 if (src->Register.Negate)
670 CHR( '-' );
671 if (src->Register.Absolute)
672 CHR( '|' );
673
674 _dump_register_src(ctx, src);
675
676 if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
677 src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
678 src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
679 src->Register.SwizzleW != TGSI_SWIZZLE_W) {
680 CHR( '.' );
681 ENM( src->Register.SwizzleX, tgsi_swizzle_names );
682 ENM( src->Register.SwizzleY, tgsi_swizzle_names );
683 ENM( src->Register.SwizzleZ, tgsi_swizzle_names );
684 ENM( src->Register.SwizzleW, tgsi_swizzle_names );
685 }
686
687 if (src->Register.Absolute)
688 CHR( '|' );
689
690 first_reg = FALSE;
691 }
692
693 if (inst->Instruction.Texture) {
694 TXT( ", " );
695 ENM( inst->Texture.Texture, tgsi_texture_names );
696 }
697
698 switch (inst->Instruction.Opcode) {
699 case TGSI_OPCODE_IF:
700 case TGSI_OPCODE_ELSE:
701 case TGSI_OPCODE_BGNLOOP:
702 case TGSI_OPCODE_ENDLOOP:
703 case TGSI_OPCODE_CAL:
704 TXT( " :" );
705 UID( inst->Label.Label );
706 break;
707 }
708
709 /* update indentation */
710 if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
711 inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
712 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
713 ctx->indentation += indent_spaces;
714 }
715
716 EOL();
717
718 return TRUE;
719 }
720
721 void
722 tgsi_dump_instruction(
723 const struct tgsi_full_instruction *inst,
724 uint instno )
725 {
726 struct dump_ctx ctx;
727
728 ctx.instno = instno;
729 ctx.indent = 0;
730 ctx.printf = dump_ctx_printf;
731 ctx.indentation = 0;
732
733 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
734 }
735
736 static boolean
737 prolog(
738 struct tgsi_iterate_context *iter )
739 {
740 struct dump_ctx *ctx = (struct dump_ctx *) iter;
741 ENM( iter->processor.Processor, processor_type_names );
742 EOL();
743 return TRUE;
744 }
745
746 void
747 tgsi_dump(
748 const struct tgsi_token *tokens,
749 uint flags )
750 {
751 struct dump_ctx ctx;
752
753 ctx.iter.prolog = prolog;
754 ctx.iter.iterate_instruction = iter_instruction;
755 ctx.iter.iterate_declaration = iter_declaration;
756 ctx.iter.iterate_immediate = iter_immediate;
757 ctx.iter.iterate_property = iter_property;
758 ctx.iter.epilog = NULL;
759
760 ctx.instno = 0;
761 ctx.indent = 0;
762 ctx.printf = dump_ctx_printf;
763 ctx.indentation = 0;
764
765 tgsi_iterate_shader( tokens, &ctx.iter );
766 }
767
768 struct str_dump_ctx
769 {
770 struct dump_ctx base;
771 char *str;
772 char *ptr;
773 int left;
774 };
775
776 static void
777 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
778 {
779 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
780
781 if(sctx->left > 1) {
782 int written;
783 va_list ap;
784 va_start(ap, format);
785 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
786 va_end(ap);
787
788 /* Some complicated logic needed to handle the return value of
789 * vsnprintf:
790 */
791 if (written > 0) {
792 written = MIN2(sctx->left, written);
793 sctx->ptr += written;
794 sctx->left -= written;
795 }
796 }
797 }
798
799 void
800 tgsi_dump_str(
801 const struct tgsi_token *tokens,
802 uint flags,
803 char *str,
804 size_t size)
805 {
806 struct str_dump_ctx ctx;
807
808 ctx.base.iter.prolog = prolog;
809 ctx.base.iter.iterate_instruction = iter_instruction;
810 ctx.base.iter.iterate_declaration = iter_declaration;
811 ctx.base.iter.iterate_immediate = iter_immediate;
812 ctx.base.iter.iterate_property = iter_property;
813 ctx.base.iter.epilog = NULL;
814
815 ctx.base.instno = 0;
816 ctx.base.indent = 0;
817 ctx.base.printf = &str_dump_ctx_printf;
818 ctx.base.indentation = 0;
819
820 ctx.str = str;
821 ctx.str[0] = 0;
822 ctx.ptr = str;
823 ctx.left = (int)size;
824
825 tgsi_iterate_shader( tokens, &ctx.base.iter );
826 }