Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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