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 #include "tgsi_strings.h"
36
37
38 /** Number of spaces to indent for IF/LOOP/etc */
39 static const int indent_spaces = 3;
40
41
42 struct dump_ctx
43 {
44 struct tgsi_iterate_context iter;
45
46 uint instno;
47 int indent;
48
49 uint indentation;
50
51 void (*dump_printf)(struct dump_ctx *ctx, const char *format, ...);
52 };
53
54 static void
dump_ctx_printf(struct dump_ctx * ctx,const char * format,...)55 dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
56 {
57 va_list ap;
58 (void)ctx;
59 va_start(ap, format);
60 _debug_vprintf(format, ap);
61 va_end(ap);
62 }
63
64 static void
dump_enum(struct dump_ctx * ctx,uint e,const char ** enums,uint enum_count)65 dump_enum(
66 struct dump_ctx *ctx,
67 uint e,
68 const char **enums,
69 uint enum_count )
70 {
71 if (e >= enum_count)
72 ctx->dump_printf( ctx, "%u", e );
73 else
74 ctx->dump_printf( ctx, "%s", enums[e] );
75 }
76
77 #define EOL() ctx->dump_printf( ctx, "\n" )
78 #define TXT(S) ctx->dump_printf( ctx, "%s", S )
79 #define CHR(C) ctx->dump_printf( ctx, "%c", C )
80 #define UIX(I) ctx->dump_printf( ctx, "0x%x", I )
81 #define UID(I) ctx->dump_printf( ctx, "%u", I )
82 #define INSTID(I) ctx->dump_printf( ctx, "% 3u", I )
83 #define SID(I) ctx->dump_printf( ctx, "%d", I )
84 #define FLT(F) ctx->dump_printf( ctx, "%10.4f", F )
85 #define ENM(E,ENUMS) dump_enum( ctx, E, ENUMS, sizeof( ENUMS ) / sizeof( *ENUMS ) )
86
87 const char *
88 tgsi_swizzle_names[4] =
89 {
90 "x",
91 "y",
92 "z",
93 "w"
94 };
95
96 static void
_dump_register_src(struct dump_ctx * ctx,const struct tgsi_full_src_register * src)97 _dump_register_src(
98 struct dump_ctx *ctx,
99 const struct tgsi_full_src_register *src )
100 {
101 ENM(src->Register.File, tgsi_file_names);
102 if (src->Register.Dimension) {
103 if (src->Dimension.Indirect) {
104 CHR( '[' );
105 ENM( src->DimIndirect.File, tgsi_file_names );
106 CHR( '[' );
107 SID( src->DimIndirect.Index );
108 TXT( "]." );
109 ENM( src->DimIndirect.SwizzleX, tgsi_swizzle_names );
110 if (src->Dimension.Index != 0) {
111 if (src->Dimension.Index > 0)
112 CHR( '+' );
113 SID( src->Dimension.Index );
114 }
115 CHR( ']' );
116 } else {
117 CHR('[');
118 SID(src->Dimension.Index);
119 CHR(']');
120 }
121 }
122 if (src->Register.Indirect) {
123 CHR( '[' );
124 ENM( src->Indirect.File, tgsi_file_names );
125 CHR( '[' );
126 SID( src->Indirect.Index );
127 TXT( "]." );
128 ENM( src->Indirect.SwizzleX, tgsi_swizzle_names );
129 if (src->Register.Index != 0) {
130 if (src->Register.Index > 0)
131 CHR( '+' );
132 SID( src->Register.Index );
133 }
134 CHR( ']' );
135 } else {
136 CHR( '[' );
137 SID( src->Register.Index );
138 CHR( ']' );
139 }
140 }
141
142
143 static void
_dump_register_dst(struct dump_ctx * ctx,const struct tgsi_full_dst_register * dst)144 _dump_register_dst(
145 struct dump_ctx *ctx,
146 const struct tgsi_full_dst_register *dst )
147 {
148 ENM(dst->Register.File, tgsi_file_names);
149 if (dst->Register.Dimension) {
150 if (dst->Dimension.Indirect) {
151 CHR( '[' );
152 ENM( dst->DimIndirect.File, tgsi_file_names );
153 CHR( '[' );
154 SID( dst->DimIndirect.Index );
155 TXT( "]." );
156 ENM( dst->DimIndirect.SwizzleX, tgsi_swizzle_names );
157 if (dst->Dimension.Index != 0) {
158 if (dst->Dimension.Index > 0)
159 CHR( '+' );
160 SID( dst->Dimension.Index );
161 }
162 CHR( ']' );
163 } else {
164 CHR('[');
165 SID(dst->Dimension.Index);
166 CHR(']');
167 }
168 }
169 if (dst->Register.Indirect) {
170 CHR( '[' );
171 ENM( dst->Indirect.File, tgsi_file_names );
172 CHR( '[' );
173 SID( dst->Indirect.Index );
174 TXT( "]." );
175 ENM( dst->Indirect.SwizzleX, tgsi_swizzle_names );
176 if (dst->Register.Index != 0) {
177 if (dst->Register.Index > 0)
178 CHR( '+' );
179 SID( dst->Register.Index );
180 }
181 CHR( ']' );
182 } else {
183 CHR( '[' );
184 SID( dst->Register.Index );
185 CHR( ']' );
186 }
187 }
188 static void
_dump_writemask(struct dump_ctx * ctx,uint writemask)189 _dump_writemask(
190 struct dump_ctx *ctx,
191 uint writemask )
192 {
193 if (writemask != TGSI_WRITEMASK_XYZW) {
194 CHR( '.' );
195 if (writemask & TGSI_WRITEMASK_X)
196 CHR( 'x' );
197 if (writemask & TGSI_WRITEMASK_Y)
198 CHR( 'y' );
199 if (writemask & TGSI_WRITEMASK_Z)
200 CHR( 'z' );
201 if (writemask & TGSI_WRITEMASK_W)
202 CHR( 'w' );
203 }
204 }
205
206 static void
dump_imm_data(struct tgsi_iterate_context * iter,union tgsi_immediate_data * data,unsigned num_tokens,unsigned data_type)207 dump_imm_data(struct tgsi_iterate_context *iter,
208 union tgsi_immediate_data *data,
209 unsigned num_tokens,
210 unsigned data_type)
211 {
212 struct dump_ctx *ctx = (struct dump_ctx *)iter;
213 unsigned i ;
214
215 TXT( " {" );
216
217 assert( num_tokens <= 4 );
218 for (i = 0; i < num_tokens; i++) {
219 switch (data_type) {
220 case TGSI_IMM_FLOAT32:
221 FLT( data[i].Float );
222 break;
223 case TGSI_IMM_UINT32:
224 UID(data[i].Uint);
225 break;
226 case TGSI_IMM_INT32:
227 SID(data[i].Int);
228 break;
229 default:
230 assert( 0 );
231 }
232
233 if (i < num_tokens - 1)
234 TXT( ", " );
235 }
236 TXT( "}" );
237 }
238
239 static boolean
iter_declaration(struct tgsi_iterate_context * iter,struct tgsi_full_declaration * decl)240 iter_declaration(
241 struct tgsi_iterate_context *iter,
242 struct tgsi_full_declaration *decl )
243 {
244 struct dump_ctx *ctx = (struct dump_ctx *)iter;
245
246 TXT( "DCL " );
247
248 ENM(decl->Declaration.File, tgsi_file_names);
249
250 /* all geometry shader inputs are two dimensional */
251 if (decl->Declaration.File == TGSI_FILE_INPUT &&
252 iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) {
253 TXT("[]");
254 }
255
256 if (decl->Declaration.Dimension) {
257 CHR('[');
258 SID(decl->Dim.Index2D);
259 CHR(']');
260 }
261
262 CHR('[');
263 SID(decl->Range.First);
264 if (decl->Range.First != decl->Range.Last) {
265 TXT("..");
266 SID(decl->Range.Last);
267 }
268 CHR(']');
269
270 _dump_writemask(
271 ctx,
272 decl->Declaration.UsageMask );
273
274 if (decl->Declaration.Local)
275 TXT( ", LOCAL" );
276
277 if (decl->Declaration.Semantic) {
278 TXT( ", " );
279 ENM( decl->Semantic.Name, tgsi_semantic_names );
280 if (decl->Semantic.Index != 0 ||
281 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) {
282 CHR( '[' );
283 UID( decl->Semantic.Index );
284 CHR( ']' );
285 }
286 }
287
288 if (decl->Declaration.File == TGSI_FILE_RESOURCE) {
289 TXT(", ");
290 ENM(decl->Resource.Resource, tgsi_texture_names);
291 if (decl->Resource.Writable)
292 TXT(", WR");
293 if (decl->Resource.Raw)
294 TXT(", RAW");
295 }
296
297 if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) {
298 TXT(", ");
299 ENM(decl->SamplerView.Resource, tgsi_texture_names);
300 TXT(", ");
301 if ((decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeY) &&
302 (decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeZ) &&
303 (decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeW)) {
304 ENM(decl->SamplerView.ReturnTypeX, tgsi_type_names);
305 } else {
306 ENM(decl->SamplerView.ReturnTypeX, tgsi_type_names);
307 TXT(", ");
308 ENM(decl->SamplerView.ReturnTypeY, tgsi_type_names);
309 TXT(", ");
310 ENM(decl->SamplerView.ReturnTypeZ, tgsi_type_names);
311 TXT(", ");
312 ENM(decl->SamplerView.ReturnTypeW, tgsi_type_names);
313 }
314 }
315
316 if (decl->Declaration.Interpolate) {
317 if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
318 decl->Declaration.File == TGSI_FILE_INPUT)
319 {
320 TXT( ", " );
321 ENM( decl->Interp.Interpolate, tgsi_interpolate_names );
322 }
323
324 if (decl->Interp.Centroid) {
325 TXT( ", CENTROID" );
326 }
327
328 if (decl->Interp.CylindricalWrap) {
329 TXT(", CYLWRAP_");
330 if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) {
331 CHR('X');
332 }
333 if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) {
334 CHR('Y');
335 }
336 if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) {
337 CHR('Z');
338 }
339 if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) {
340 CHR('W');
341 }
342 }
343 }
344
345 if (decl->Declaration.Invariant) {
346 TXT( ", INVARIANT" );
347 }
348
349
350 if (decl->Declaration.File == TGSI_FILE_IMMEDIATE_ARRAY) {
351 unsigned i;
352 char range_indent[4];
353
354 TXT(" {");
355
356 if (decl->Range.Last < 10)
357 range_indent[0] = '\0';
358 else if (decl->Range.Last < 100) {
359 range_indent[0] = ' ';
360 range_indent[1] = '\0';
361 } else if (decl->Range.Last < 1000) {
362 range_indent[0] = ' ';
363 range_indent[1] = ' ';
364 range_indent[2] = '\0';
365 } else {
366 range_indent[0] = ' ';
367 range_indent[1] = ' ';
368 range_indent[2] = ' ';
369 range_indent[3] = '\0';
370 }
371
372 dump_imm_data(iter, decl->ImmediateData.u,
373 4, TGSI_IMM_FLOAT32);
374 for(i = 1; i <= decl->Range.Last; ++i) {
375 /* indent by strlen of:
376 * "DCL IMMX[0..1] {" */
377 CHR('\n');
378 TXT( " " );
379 TXT( range_indent );
380 dump_imm_data(iter, decl->ImmediateData.u + i,
381 4, TGSI_IMM_FLOAT32);
382 }
383
384 TXT(" }");
385 }
386
387 EOL();
388
389 return TRUE;
390 }
391
392 void
tgsi_dump_declaration(const struct tgsi_full_declaration * decl)393 tgsi_dump_declaration(
394 const struct tgsi_full_declaration *decl )
395 {
396 struct dump_ctx ctx;
397
398 ctx.dump_printf = dump_ctx_printf;
399
400 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
401 }
402
403 static boolean
iter_property(struct tgsi_iterate_context * iter,struct tgsi_full_property * prop)404 iter_property(
405 struct tgsi_iterate_context *iter,
406 struct tgsi_full_property *prop )
407 {
408 int i;
409 struct dump_ctx *ctx = (struct dump_ctx *)iter;
410
411 TXT( "PROPERTY " );
412 ENM(prop->Property.PropertyName, tgsi_property_names);
413
414 if (prop->Property.NrTokens > 1)
415 TXT(" ");
416
417 for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
418 switch (prop->Property.PropertyName) {
419 case TGSI_PROPERTY_GS_INPUT_PRIM:
420 case TGSI_PROPERTY_GS_OUTPUT_PRIM:
421 ENM(prop->u[i].Data, tgsi_primitive_names);
422 break;
423 case TGSI_PROPERTY_FS_COORD_ORIGIN:
424 ENM(prop->u[i].Data, tgsi_fs_coord_origin_names);
425 break;
426 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
427 ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names);
428 break;
429 default:
430 SID( prop->u[i].Data );
431 break;
432 }
433 if (i < prop->Property.NrTokens - 2)
434 TXT( ", " );
435 }
436 EOL();
437
438 return TRUE;
439 }
440
tgsi_dump_property(const struct tgsi_full_property * prop)441 void tgsi_dump_property(
442 const struct tgsi_full_property *prop )
443 {
444 struct dump_ctx ctx;
445
446 ctx.dump_printf = dump_ctx_printf;
447
448 iter_property( &ctx.iter, (struct tgsi_full_property *)prop );
449 }
450
451 static boolean
iter_immediate(struct tgsi_iterate_context * iter,struct tgsi_full_immediate * imm)452 iter_immediate(
453 struct tgsi_iterate_context *iter,
454 struct tgsi_full_immediate *imm )
455 {
456 struct dump_ctx *ctx = (struct dump_ctx *) iter;
457
458 TXT( "IMM " );
459 ENM( imm->Immediate.DataType, tgsi_immediate_type_names );
460
461 dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1,
462 imm->Immediate.DataType);
463
464 EOL();
465
466 return TRUE;
467 }
468
469 void
tgsi_dump_immediate(const struct tgsi_full_immediate * imm)470 tgsi_dump_immediate(
471 const struct tgsi_full_immediate *imm )
472 {
473 struct dump_ctx ctx;
474
475 ctx.dump_printf = dump_ctx_printf;
476
477 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
478 }
479
480 static boolean
iter_instruction(struct tgsi_iterate_context * iter,struct tgsi_full_instruction * inst)481 iter_instruction(
482 struct tgsi_iterate_context *iter,
483 struct tgsi_full_instruction *inst )
484 {
485 struct dump_ctx *ctx = (struct dump_ctx *) iter;
486 uint instno = ctx->instno++;
487 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
488 uint i;
489 boolean first_reg = TRUE;
490
491 INSTID( instno );
492 TXT( ": " );
493
494 ctx->indent -= info->pre_dedent;
495 for(i = 0; (int)i < ctx->indent; ++i)
496 TXT( " " );
497 ctx->indent += info->post_indent;
498
499 if (inst->Instruction.Predicate) {
500 CHR( '(' );
501
502 if (inst->Predicate.Negate)
503 CHR( '!' );
504
505 TXT( "PRED[" );
506 SID( inst->Predicate.Index );
507 CHR( ']' );
508
509 if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X ||
510 inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y ||
511 inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
512 inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
513 CHR( '.' );
514 ENM( inst->Predicate.SwizzleX, tgsi_swizzle_names );
515 ENM( inst->Predicate.SwizzleY, tgsi_swizzle_names );
516 ENM( inst->Predicate.SwizzleZ, tgsi_swizzle_names );
517 ENM( inst->Predicate.SwizzleW, tgsi_swizzle_names );
518 }
519
520 TXT( ") " );
521 }
522
523 TXT( info->mnemonic );
524
525 switch (inst->Instruction.Saturate) {
526 case TGSI_SAT_NONE:
527 break;
528 case TGSI_SAT_ZERO_ONE:
529 TXT( "_SAT" );
530 break;
531 case TGSI_SAT_MINUS_PLUS_ONE:
532 TXT( "_SATNV" );
533 break;
534 default:
535 assert( 0 );
536 }
537
538 for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
539 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
540
541 if (!first_reg)
542 CHR( ',' );
543 CHR( ' ' );
544
545 _dump_register_dst( ctx, dst );
546 _dump_writemask( ctx, dst->Register.WriteMask );
547
548 first_reg = FALSE;
549 }
550
551 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
552 const struct tgsi_full_src_register *src = &inst->Src[i];
553
554 if (!first_reg)
555 CHR( ',' );
556 CHR( ' ' );
557
558 if (src->Register.Negate)
559 CHR( '-' );
560 if (src->Register.Absolute)
561 CHR( '|' );
562
563 _dump_register_src(ctx, src);
564
565 if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
566 src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
567 src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
568 src->Register.SwizzleW != TGSI_SWIZZLE_W) {
569 CHR( '.' );
570 ENM( src->Register.SwizzleX, tgsi_swizzle_names );
571 ENM( src->Register.SwizzleY, tgsi_swizzle_names );
572 ENM( src->Register.SwizzleZ, tgsi_swizzle_names );
573 ENM( src->Register.SwizzleW, tgsi_swizzle_names );
574 }
575
576 if (src->Register.Absolute)
577 CHR( '|' );
578
579 first_reg = FALSE;
580 }
581
582 if (inst->Instruction.Texture) {
583 TXT( ", " );
584 ENM( inst->Texture.Texture, tgsi_texture_names );
585 for (i = 0; i < inst->Texture.NumOffsets; i++) {
586 TXT( ", " );
587 ENM( inst->TexOffsets[i].File, tgsi_file_names);
588 CHR( '[' );
589 SID( inst->TexOffsets[i].Index );
590 CHR( ']' );
591 CHR( '.' );
592 ENM( inst->TexOffsets[i].SwizzleX, tgsi_swizzle_names);
593 ENM( inst->TexOffsets[i].SwizzleY, tgsi_swizzle_names);
594 ENM( inst->TexOffsets[i].SwizzleZ, tgsi_swizzle_names);
595 }
596 }
597
598 switch (inst->Instruction.Opcode) {
599 case TGSI_OPCODE_IF:
600 case TGSI_OPCODE_ELSE:
601 case TGSI_OPCODE_BGNLOOP:
602 case TGSI_OPCODE_ENDLOOP:
603 case TGSI_OPCODE_CAL:
604 TXT( " :" );
605 UID( inst->Label.Label );
606 break;
607 }
608
609 /* update indentation */
610 if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
611 inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
612 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
613 ctx->indentation += indent_spaces;
614 }
615
616 EOL();
617
618 return TRUE;
619 }
620
621 void
tgsi_dump_instruction(const struct tgsi_full_instruction * inst,uint instno)622 tgsi_dump_instruction(
623 const struct tgsi_full_instruction *inst,
624 uint instno )
625 {
626 struct dump_ctx ctx;
627
628 ctx.instno = instno;
629 ctx.indent = 0;
630 ctx.dump_printf = dump_ctx_printf;
631 ctx.indentation = 0;
632
633 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
634 }
635
636 static boolean
prolog(struct tgsi_iterate_context * iter)637 prolog(
638 struct tgsi_iterate_context *iter )
639 {
640 struct dump_ctx *ctx = (struct dump_ctx *) iter;
641 ENM( iter->processor.Processor, tgsi_processor_type_names );
642 EOL();
643 return TRUE;
644 }
645
646 void
tgsi_dump(const struct tgsi_token * tokens,uint flags)647 tgsi_dump(
648 const struct tgsi_token *tokens,
649 uint flags )
650 {
651 struct dump_ctx ctx;
652
653 ctx.iter.prolog = prolog;
654 ctx.iter.iterate_instruction = iter_instruction;
655 ctx.iter.iterate_declaration = iter_declaration;
656 ctx.iter.iterate_immediate = iter_immediate;
657 ctx.iter.iterate_property = iter_property;
658 ctx.iter.epilog = NULL;
659
660 ctx.instno = 0;
661 ctx.indent = 0;
662 ctx.dump_printf = dump_ctx_printf;
663 ctx.indentation = 0;
664
665 tgsi_iterate_shader( tokens, &ctx.iter );
666 }
667
668 struct str_dump_ctx
669 {
670 struct dump_ctx base;
671 char *str;
672 char *ptr;
673 int left;
674 };
675
676 static void
str_dump_ctx_printf(struct dump_ctx * ctx,const char * format,...)677 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
678 {
679 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
680
681 if(sctx->left > 1) {
682 int written;
683 va_list ap;
684 va_start(ap, format);
685 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
686 va_end(ap);
687
688 /* Some complicated logic needed to handle the return value of
689 * vsnprintf:
690 */
691 if (written > 0) {
692 written = MIN2(sctx->left, written);
693 sctx->ptr += written;
694 sctx->left -= written;
695 }
696 }
697 }
698
699 void
tgsi_dump_str(const struct tgsi_token * tokens,uint flags,char * str,size_t size)700 tgsi_dump_str(
701 const struct tgsi_token *tokens,
702 uint flags,
703 char *str,
704 size_t size)
705 {
706 struct str_dump_ctx ctx;
707
708 ctx.base.iter.prolog = prolog;
709 ctx.base.iter.iterate_instruction = iter_instruction;
710 ctx.base.iter.iterate_declaration = iter_declaration;
711 ctx.base.iter.iterate_immediate = iter_immediate;
712 ctx.base.iter.iterate_property = iter_property;
713 ctx.base.iter.epilog = NULL;
714
715 ctx.base.instno = 0;
716 ctx.base.indent = 0;
717 ctx.base.dump_printf = &str_dump_ctx_printf;
718 ctx.base.indentation = 0;
719
720 ctx.str = str;
721 ctx.str[0] = 0;
722 ctx.ptr = str;
723 ctx.left = (int)size;
724
725 tgsi_iterate_shader( tokens, &ctx.base.iter );
726 }
727