tgsi_scan.c revision 848b8605
1/**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * All Rights Reserved.
5 * Copyright 2008 VMware, Inc.  All rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29/**
30 * TGSI program scan utility.
31 * Used to determine which registers and instructions are used by a shader.
32 *
33 * Authors:  Brian Paul
34 */
35
36
37#include "util/u_debug.h"
38#include "util/u_math.h"
39#include "util/u_memory.h"
40#include "util/u_prim.h"
41#include "tgsi/tgsi_parse.h"
42#include "tgsi/tgsi_util.h"
43#include "tgsi/tgsi_scan.h"
44
45
46
47
48/**
49 * Scan the given TGSI shader to collect information such as number of
50 * registers used, special instructions used, etc.
51 * \return info  the result of the scan
52 */
53void
54tgsi_scan_shader(const struct tgsi_token *tokens,
55                 struct tgsi_shader_info *info)
56{
57   uint procType, i;
58   struct tgsi_parse_context parse;
59
60   memset(info, 0, sizeof(*info));
61   for (i = 0; i < TGSI_FILE_COUNT; i++)
62      info->file_max[i] = -1;
63   for (i = 0; i < Elements(info->const_file_max); i++)
64      info->const_file_max[i] = -1;
65
66   /**
67    ** Setup to begin parsing input shader
68    **/
69   if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) {
70      debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n");
71      return;
72   }
73   procType = parse.FullHeader.Processor.Processor;
74   assert(procType == TGSI_PROCESSOR_FRAGMENT ||
75          procType == TGSI_PROCESSOR_VERTEX ||
76          procType == TGSI_PROCESSOR_GEOMETRY ||
77          procType == TGSI_PROCESSOR_COMPUTE);
78   info->processor = procType;
79
80
81   /**
82    ** Loop over incoming program tokens/instructions
83    */
84   while( !tgsi_parse_end_of_tokens( &parse ) ) {
85
86      info->num_tokens++;
87
88      tgsi_parse_token( &parse );
89
90      switch( parse.FullToken.Token.Type ) {
91      case TGSI_TOKEN_TYPE_INSTRUCTION:
92         {
93            const struct tgsi_full_instruction *fullinst
94               = &parse.FullToken.FullInstruction;
95            uint i;
96
97            assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST);
98            info->opcode_count[fullinst->Instruction.Opcode]++;
99
100            for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
101               const struct tgsi_full_src_register *src =
102                  &fullinst->Src[i];
103               int ind = src->Register.Index;
104
105               /* Mark which inputs are effectively used */
106               if (src->Register.File == TGSI_FILE_INPUT) {
107                  unsigned usage_mask;
108                  usage_mask = tgsi_util_get_inst_usage_mask(fullinst, i);
109                  if (src->Register.Indirect) {
110                     for (ind = 0; ind < info->num_inputs; ++ind) {
111                        info->input_usage_mask[ind] |= usage_mask;
112                     }
113                  } else {
114                     assert(ind >= 0);
115                     assert(ind < PIPE_MAX_SHADER_INPUTS);
116                     info->input_usage_mask[ind] |= usage_mask;
117                  }
118
119                  if (procType == TGSI_PROCESSOR_FRAGMENT &&
120                      info->reads_position &&
121                      src->Register.Index == 0 &&
122                      (src->Register.SwizzleX == TGSI_SWIZZLE_Z ||
123                       src->Register.SwizzleY == TGSI_SWIZZLE_Z ||
124                       src->Register.SwizzleZ == TGSI_SWIZZLE_Z ||
125                       src->Register.SwizzleW == TGSI_SWIZZLE_Z)) {
126                     info->reads_z = TRUE;
127                  }
128               }
129
130               /* check for indirect register reads */
131               if (src->Register.Indirect) {
132                  info->indirect_files |= (1 << src->Register.File);
133               }
134
135               /* MSAA samplers */
136               if (src->Register.File == TGSI_FILE_SAMPLER) {
137                  assert(fullinst->Instruction.Texture);
138                  assert(src->Register.Index < Elements(info->is_msaa_sampler));
139
140                  if (fullinst->Instruction.Texture &&
141                      (fullinst->Texture.Texture == TGSI_TEXTURE_2D_MSAA ||
142                       fullinst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA)) {
143                     info->is_msaa_sampler[src->Register.Index] = TRUE;
144                  }
145               }
146            }
147
148            /* check for indirect register writes */
149            for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) {
150               const struct tgsi_full_dst_register *dst = &fullinst->Dst[i];
151               if (dst->Register.Indirect) {
152                  info->indirect_files |= (1 << dst->Register.File);
153               }
154            }
155
156            info->num_instructions++;
157         }
158         break;
159
160      case TGSI_TOKEN_TYPE_DECLARATION:
161         {
162            const struct tgsi_full_declaration *fulldecl
163               = &parse.FullToken.FullDeclaration;
164            const uint file = fulldecl->Declaration.File;
165            uint reg;
166            for (reg = fulldecl->Range.First;
167                 reg <= fulldecl->Range.Last;
168                 reg++) {
169               unsigned semName = fulldecl->Semantic.Name;
170               unsigned semIndex = fulldecl->Semantic.Index;
171
172               /* only first 32 regs will appear in this bitfield */
173               info->file_mask[file] |= (1 << reg);
174               info->file_count[file]++;
175               info->file_max[file] = MAX2(info->file_max[file], (int)reg);
176
177               if (file == TGSI_FILE_CONSTANT) {
178                  int buffer = 0;
179
180                  if (fulldecl->Declaration.Dimension)
181                     buffer = fulldecl->Dim.Index2D;
182
183                  info->const_file_max[buffer] =
184                        MAX2(info->const_file_max[buffer], (int)reg);
185               }
186               else if (file == TGSI_FILE_INPUT) {
187                  info->input_semantic_name[reg] = (ubyte) semName;
188                  info->input_semantic_index[reg] = (ubyte) semIndex;
189                  info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate;
190                  info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location;
191                  info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap;
192                  info->num_inputs++;
193
194                  if (semName == TGSI_SEMANTIC_PRIMID)
195                     info->uses_primid = TRUE;
196                  else if (procType == TGSI_PROCESSOR_FRAGMENT) {
197                     if (semName == TGSI_SEMANTIC_POSITION)
198                        info->reads_position = TRUE;
199                     else if (semName == TGSI_SEMANTIC_FACE)
200                        info->uses_frontface = TRUE;
201                  }
202               }
203               else if (file == TGSI_FILE_SYSTEM_VALUE) {
204                  unsigned index = fulldecl->Range.First;
205
206                  info->system_value_semantic_name[index] = semName;
207                  info->num_system_values = MAX2(info->num_system_values,
208                                                 index + 1);
209
210                  if (semName == TGSI_SEMANTIC_INSTANCEID) {
211                     info->uses_instanceid = TRUE;
212                  }
213                  else if (semName == TGSI_SEMANTIC_VERTEXID) {
214                     info->uses_vertexid = TRUE;
215                  }
216                  else if (semName == TGSI_SEMANTIC_PRIMID) {
217                     info->uses_primid = TRUE;
218                  }
219               }
220               else if (file == TGSI_FILE_OUTPUT) {
221                  info->output_semantic_name[reg] = (ubyte) semName;
222                  info->output_semantic_index[reg] = (ubyte) semIndex;
223                  info->num_outputs++;
224
225                  if (procType == TGSI_PROCESSOR_VERTEX ||
226                      procType == TGSI_PROCESSOR_GEOMETRY) {
227                     if (semName == TGSI_SEMANTIC_CLIPDIST) {
228                        info->num_written_clipdistance +=
229                           util_bitcount(fulldecl->Declaration.UsageMask);
230                     }
231                     else if (semName == TGSI_SEMANTIC_CULLDIST) {
232                        info->num_written_culldistance +=
233                           util_bitcount(fulldecl->Declaration.UsageMask);
234                     }
235                  }
236
237                  if (procType == TGSI_PROCESSOR_FRAGMENT) {
238                     if (semName == TGSI_SEMANTIC_POSITION) {
239                        info->writes_z = TRUE;
240                     }
241                     else if (semName == TGSI_SEMANTIC_STENCIL) {
242                        info->writes_stencil = TRUE;
243                     }
244                  }
245
246                  if (procType == TGSI_PROCESSOR_VERTEX) {
247                     if (semName == TGSI_SEMANTIC_EDGEFLAG) {
248                        info->writes_edgeflag = TRUE;
249                     }
250                  }
251
252                  if (procType == TGSI_PROCESSOR_GEOMETRY) {
253                     if (semName == TGSI_SEMANTIC_VIEWPORT_INDEX) {
254                        info->writes_viewport_index = TRUE;
255                     }
256                     else if (semName == TGSI_SEMANTIC_LAYER) {
257                        info->writes_layer = TRUE;
258                     }
259                  }
260               }
261            }
262         }
263         break;
264
265      case TGSI_TOKEN_TYPE_IMMEDIATE:
266         {
267            uint reg = info->immediate_count++;
268            uint file = TGSI_FILE_IMMEDIATE;
269
270            info->file_mask[file] |= (1 << reg);
271            info->file_count[file]++;
272            info->file_max[file] = MAX2(info->file_max[file], (int)reg);
273         }
274         break;
275
276      case TGSI_TOKEN_TYPE_PROPERTY:
277         {
278            const struct tgsi_full_property *fullprop
279               = &parse.FullToken.FullProperty;
280
281            info->properties[info->num_properties].name =
282               fullprop->Property.PropertyName;
283            memcpy(info->properties[info->num_properties].data,
284                   fullprop->u, 8 * sizeof(unsigned));;
285
286            ++info->num_properties;
287         }
288         break;
289
290      default:
291         assert( 0 );
292      }
293   }
294
295   info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] ||
296                      info->opcode_count[TGSI_OPCODE_KILL]);
297
298   /* extract simple properties */
299   for (i = 0; i < info->num_properties; ++i) {
300      switch (info->properties[i].name) {
301      case TGSI_PROPERTY_FS_COORD_ORIGIN:
302         info->origin_lower_left = info->properties[i].data[0];
303         break;
304      case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
305         info->pixel_center_integer = info->properties[i].data[0];
306         break;
307      case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
308         info->color0_writes_all_cbufs = info->properties[i].data[0];
309         break;
310      case TGSI_PROPERTY_GS_INPUT_PRIM:
311         /* The dimensions of the IN decleration in geometry shader have
312          * to be deduced from the type of the input primitive.
313          */
314         if (procType == TGSI_PROCESSOR_GEOMETRY) {
315            unsigned input_primitive = info->properties[i].data[0];
316            int num_verts = u_vertices_per_prim(input_primitive);
317            int j;
318            info->file_count[TGSI_FILE_INPUT] = num_verts;
319            info->file_max[TGSI_FILE_INPUT] =
320               MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1);
321            for (j = 0; j < num_verts; ++j) {
322               info->file_mask[TGSI_FILE_INPUT] |= (1 << j);
323            }
324         }
325         break;
326      default:
327         ;
328      }
329   }
330
331   tgsi_parse_free (&parse);
332}
333
334
335
336/**
337 * Check if the given shader is a "passthrough" shader consisting of only
338 * MOV instructions of the form:  MOV OUT[n], IN[n]
339 *
340 */
341boolean
342tgsi_is_passthrough_shader(const struct tgsi_token *tokens)
343{
344   struct tgsi_parse_context parse;
345
346   /**
347    ** Setup to begin parsing input shader
348    **/
349   if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
350      debug_printf("tgsi_parse_init() failed in tgsi_is_passthrough_shader()!\n");
351      return FALSE;
352   }
353
354   /**
355    ** Loop over incoming program tokens/instructions
356    */
357   while (!tgsi_parse_end_of_tokens(&parse)) {
358
359      tgsi_parse_token(&parse);
360
361      switch (parse.FullToken.Token.Type) {
362      case TGSI_TOKEN_TYPE_INSTRUCTION:
363         {
364            struct tgsi_full_instruction *fullinst =
365               &parse.FullToken.FullInstruction;
366            const struct tgsi_full_src_register *src =
367               &fullinst->Src[0];
368            const struct tgsi_full_dst_register *dst =
369               &fullinst->Dst[0];
370
371            /* Do a whole bunch of checks for a simple move */
372            if (fullinst->Instruction.Opcode != TGSI_OPCODE_MOV ||
373                (src->Register.File != TGSI_FILE_INPUT &&
374                 src->Register.File != TGSI_FILE_SYSTEM_VALUE) ||
375                dst->Register.File != TGSI_FILE_OUTPUT ||
376                src->Register.Index != dst->Register.Index ||
377
378                src->Register.Negate ||
379                src->Register.Absolute ||
380
381                src->Register.SwizzleX != TGSI_SWIZZLE_X ||
382                src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
383                src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
384                src->Register.SwizzleW != TGSI_SWIZZLE_W ||
385
386                dst->Register.WriteMask != TGSI_WRITEMASK_XYZW)
387            {
388               tgsi_parse_free(&parse);
389               return FALSE;
390            }
391         }
392         break;
393
394      case TGSI_TOKEN_TYPE_DECLARATION:
395         /* fall-through */
396      case TGSI_TOKEN_TYPE_IMMEDIATE:
397         /* fall-through */
398      case TGSI_TOKEN_TYPE_PROPERTY:
399         /* fall-through */
400      default:
401         ; /* no-op */
402      }
403   }
404
405   tgsi_parse_free(&parse);
406
407   /* if we get here, it's a pass-through shader */
408   return TRUE;
409}
410