tgsi: add const qualifier to silence warning
[mesa.git] / src / gallium / auxiliary / tgsi / tgsi_scan.c
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 */
53 void
54 tgsi_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 unsigned current_depth = 0;
60
61 memset(info, 0, sizeof(*info));
62 for (i = 0; i < TGSI_FILE_COUNT; i++)
63 info->file_max[i] = -1;
64 for (i = 0; i < Elements(info->const_file_max); i++)
65 info->const_file_max[i] = -1;
66 info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1;
67
68 /**
69 ** Setup to begin parsing input shader
70 **/
71 if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) {
72 debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n");
73 return;
74 }
75 procType = parse.FullHeader.Processor.Processor;
76 assert(procType == TGSI_PROCESSOR_FRAGMENT ||
77 procType == TGSI_PROCESSOR_VERTEX ||
78 procType == TGSI_PROCESSOR_GEOMETRY ||
79 procType == TGSI_PROCESSOR_TESS_CTRL ||
80 procType == TGSI_PROCESSOR_TESS_EVAL ||
81 procType == TGSI_PROCESSOR_COMPUTE);
82 info->processor = procType;
83
84
85 /**
86 ** Loop over incoming program tokens/instructions
87 */
88 while( !tgsi_parse_end_of_tokens( &parse ) ) {
89
90 info->num_tokens++;
91
92 tgsi_parse_token( &parse );
93
94 switch( parse.FullToken.Token.Type ) {
95 case TGSI_TOKEN_TYPE_INSTRUCTION:
96 {
97 const struct tgsi_full_instruction *fullinst
98 = &parse.FullToken.FullInstruction;
99 uint i;
100
101 assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST);
102 info->opcode_count[fullinst->Instruction.Opcode]++;
103
104 switch (fullinst->Instruction.Opcode) {
105 case TGSI_OPCODE_IF:
106 case TGSI_OPCODE_UIF:
107 case TGSI_OPCODE_BGNLOOP:
108 current_depth++;
109 info->max_depth = MAX2(info->max_depth, current_depth);
110 break;
111 case TGSI_OPCODE_ENDIF:
112 case TGSI_OPCODE_ENDLOOP:
113 current_depth--;
114 break;
115 default:
116 break;
117 }
118
119 if (fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_CENTROID ||
120 fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
121 fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) {
122 const struct tgsi_full_src_register *src0 = &fullinst->Src[0];
123 unsigned input;
124
125 if (src0->Register.Indirect && src0->Indirect.ArrayID)
126 input = info->input_array_first[src0->Indirect.ArrayID];
127 else
128 input = src0->Register.Index;
129
130 /* For the INTERP opcodes, the interpolation is always
131 * PERSPECTIVE unless LINEAR is specified.
132 */
133 switch (info->input_interpolate[input]) {
134 case TGSI_INTERPOLATE_COLOR:
135 case TGSI_INTERPOLATE_CONSTANT:
136 case TGSI_INTERPOLATE_PERSPECTIVE:
137 switch (fullinst->Instruction.Opcode) {
138 case TGSI_OPCODE_INTERP_CENTROID:
139 info->uses_persp_opcode_interp_centroid = true;
140 break;
141 case TGSI_OPCODE_INTERP_OFFSET:
142 info->uses_persp_opcode_interp_offset = true;
143 break;
144 case TGSI_OPCODE_INTERP_SAMPLE:
145 info->uses_persp_opcode_interp_sample = true;
146 break;
147 }
148 break;
149
150 case TGSI_INTERPOLATE_LINEAR:
151 switch (fullinst->Instruction.Opcode) {
152 case TGSI_OPCODE_INTERP_CENTROID:
153 info->uses_linear_opcode_interp_centroid = true;
154 break;
155 case TGSI_OPCODE_INTERP_OFFSET:
156 info->uses_linear_opcode_interp_offset = true;
157 break;
158 case TGSI_OPCODE_INTERP_SAMPLE:
159 info->uses_linear_opcode_interp_sample = true;
160 break;
161 }
162 break;
163 }
164 }
165
166 if (fullinst->Instruction.Opcode >= TGSI_OPCODE_F2D &&
167 fullinst->Instruction.Opcode <= TGSI_OPCODE_DSSG)
168 info->uses_doubles = true;
169
170 for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
171 const struct tgsi_full_src_register *src =
172 &fullinst->Src[i];
173 int ind = src->Register.Index;
174
175 /* Mark which inputs are effectively used */
176 if (src->Register.File == TGSI_FILE_INPUT) {
177 unsigned usage_mask;
178 usage_mask = tgsi_util_get_inst_usage_mask(fullinst, i);
179 if (src->Register.Indirect) {
180 for (ind = 0; ind < info->num_inputs; ++ind) {
181 info->input_usage_mask[ind] |= usage_mask;
182 }
183 } else {
184 assert(ind >= 0);
185 assert(ind < PIPE_MAX_SHADER_INPUTS);
186 info->input_usage_mask[ind] |= usage_mask;
187 }
188
189 if (procType == TGSI_PROCESSOR_FRAGMENT &&
190 info->reads_position &&
191 src->Register.Index == 0 &&
192 (src->Register.SwizzleX == TGSI_SWIZZLE_Z ||
193 src->Register.SwizzleY == TGSI_SWIZZLE_Z ||
194 src->Register.SwizzleZ == TGSI_SWIZZLE_Z ||
195 src->Register.SwizzleW == TGSI_SWIZZLE_Z)) {
196 info->reads_z = TRUE;
197 }
198 }
199
200 /* check for indirect register reads */
201 if (src->Register.Indirect) {
202 info->indirect_files |= (1 << src->Register.File);
203 info->indirect_files_read |= (1 << src->Register.File);
204 }
205
206 /* MSAA samplers */
207 if (src->Register.File == TGSI_FILE_SAMPLER) {
208 assert(fullinst->Instruction.Texture);
209 assert(src->Register.Index < Elements(info->is_msaa_sampler));
210
211 if (fullinst->Instruction.Texture &&
212 (fullinst->Texture.Texture == TGSI_TEXTURE_2D_MSAA ||
213 fullinst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA)) {
214 info->is_msaa_sampler[src->Register.Index] = TRUE;
215 }
216 }
217 }
218
219 /* check for indirect register writes */
220 for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) {
221 const struct tgsi_full_dst_register *dst = &fullinst->Dst[i];
222 if (dst->Register.Indirect) {
223 info->indirect_files |= (1 << dst->Register.File);
224 info->indirect_files_written |= (1 << dst->Register.File);
225 }
226 }
227
228 info->num_instructions++;
229 }
230 break;
231
232 case TGSI_TOKEN_TYPE_DECLARATION:
233 {
234 const struct tgsi_full_declaration *fulldecl
235 = &parse.FullToken.FullDeclaration;
236 const uint file = fulldecl->Declaration.File;
237 uint reg;
238
239 if (fulldecl->Declaration.Array) {
240 unsigned array_id = fulldecl->Array.ArrayID;
241
242 switch (file) {
243 case TGSI_FILE_INPUT:
244 assert(array_id < ARRAY_SIZE(info->input_array_first));
245 info->input_array_first[array_id] = fulldecl->Range.First;
246 info->input_array_last[array_id] = fulldecl->Range.Last;
247 break;
248 case TGSI_FILE_OUTPUT:
249 assert(array_id < ARRAY_SIZE(info->output_array_first));
250 info->output_array_first[array_id] = fulldecl->Range.First;
251 info->output_array_last[array_id] = fulldecl->Range.Last;
252 break;
253 }
254 info->array_max[file] = MAX2(info->array_max[file], array_id);
255 }
256
257 for (reg = fulldecl->Range.First;
258 reg <= fulldecl->Range.Last;
259 reg++) {
260 unsigned semName = fulldecl->Semantic.Name;
261 unsigned semIndex =
262 fulldecl->Semantic.Index + (reg - fulldecl->Range.First);
263
264 /* only first 32 regs will appear in this bitfield */
265 info->file_mask[file] |= (1 << reg);
266 info->file_count[file]++;
267 info->file_max[file] = MAX2(info->file_max[file], (int)reg);
268
269 if (file == TGSI_FILE_CONSTANT) {
270 int buffer = 0;
271
272 if (fulldecl->Declaration.Dimension)
273 buffer = fulldecl->Dim.Index2D;
274
275 info->const_file_max[buffer] =
276 MAX2(info->const_file_max[buffer], (int)reg);
277 }
278 else if (file == TGSI_FILE_INPUT) {
279 info->input_semantic_name[reg] = (ubyte) semName;
280 info->input_semantic_index[reg] = (ubyte) semIndex;
281 info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate;
282 info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location;
283 info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap;
284 info->num_inputs++;
285
286 /* Only interpolated varyings. Don't include POSITION.
287 * Don't include integer varyings, because they are not
288 * interpolated.
289 */
290 if (semName == TGSI_SEMANTIC_GENERIC ||
291 semName == TGSI_SEMANTIC_TEXCOORD ||
292 semName == TGSI_SEMANTIC_COLOR ||
293 semName == TGSI_SEMANTIC_BCOLOR ||
294 semName == TGSI_SEMANTIC_FOG ||
295 semName == TGSI_SEMANTIC_CLIPDIST ||
296 semName == TGSI_SEMANTIC_CULLDIST) {
297 switch (fulldecl->Interp.Interpolate) {
298 case TGSI_INTERPOLATE_COLOR:
299 case TGSI_INTERPOLATE_PERSPECTIVE:
300 switch (fulldecl->Interp.Location) {
301 case TGSI_INTERPOLATE_LOC_CENTER:
302 info->uses_persp_center = true;
303 break;
304 case TGSI_INTERPOLATE_LOC_CENTROID:
305 info->uses_persp_centroid = true;
306 break;
307 case TGSI_INTERPOLATE_LOC_SAMPLE:
308 info->uses_persp_sample = true;
309 break;
310 }
311 break;
312 case TGSI_INTERPOLATE_LINEAR:
313 switch (fulldecl->Interp.Location) {
314 case TGSI_INTERPOLATE_LOC_CENTER:
315 info->uses_linear_center = true;
316 break;
317 case TGSI_INTERPOLATE_LOC_CENTROID:
318 info->uses_linear_centroid = true;
319 break;
320 case TGSI_INTERPOLATE_LOC_SAMPLE:
321 info->uses_linear_sample = true;
322 break;
323 }
324 break;
325 /* TGSI_INTERPOLATE_CONSTANT doesn't do any interpolation. */
326 }
327 }
328
329 if (semName == TGSI_SEMANTIC_PRIMID)
330 info->uses_primid = TRUE;
331 else if (procType == TGSI_PROCESSOR_FRAGMENT) {
332 if (semName == TGSI_SEMANTIC_POSITION)
333 info->reads_position = TRUE;
334 else if (semName == TGSI_SEMANTIC_FACE)
335 info->uses_frontface = TRUE;
336 }
337 }
338 else if (file == TGSI_FILE_SYSTEM_VALUE) {
339 unsigned index = fulldecl->Range.First;
340
341 info->system_value_semantic_name[index] = semName;
342 info->num_system_values = MAX2(info->num_system_values,
343 index + 1);
344
345 if (semName == TGSI_SEMANTIC_INSTANCEID) {
346 info->uses_instanceid = TRUE;
347 }
348 else if (semName == TGSI_SEMANTIC_VERTEXID) {
349 info->uses_vertexid = TRUE;
350 }
351 else if (semName == TGSI_SEMANTIC_VERTEXID_NOBASE) {
352 info->uses_vertexid_nobase = TRUE;
353 }
354 else if (semName == TGSI_SEMANTIC_BASEVERTEX) {
355 info->uses_basevertex = TRUE;
356 }
357 else if (semName == TGSI_SEMANTIC_PRIMID) {
358 info->uses_primid = TRUE;
359 } else if (semName == TGSI_SEMANTIC_INVOCATIONID) {
360 info->uses_invocationid = TRUE;
361 }
362 }
363 else if (file == TGSI_FILE_OUTPUT) {
364 info->output_semantic_name[reg] = (ubyte) semName;
365 info->output_semantic_index[reg] = (ubyte) semIndex;
366 info->num_outputs++;
367
368 if (procType == TGSI_PROCESSOR_VERTEX ||
369 procType == TGSI_PROCESSOR_GEOMETRY ||
370 procType == TGSI_PROCESSOR_TESS_CTRL ||
371 procType == TGSI_PROCESSOR_TESS_EVAL) {
372 if (semName == TGSI_SEMANTIC_CLIPDIST) {
373 info->num_written_clipdistance +=
374 util_bitcount(fulldecl->Declaration.UsageMask);
375 info->clipdist_writemask |=
376 fulldecl->Declaration.UsageMask << (semIndex*4);
377 }
378 else if (semName == TGSI_SEMANTIC_CULLDIST) {
379 info->num_written_culldistance +=
380 util_bitcount(fulldecl->Declaration.UsageMask);
381 info->culldist_writemask |=
382 fulldecl->Declaration.UsageMask << (semIndex*4);
383 }
384 else if (semName == TGSI_SEMANTIC_VIEWPORT_INDEX) {
385 info->writes_viewport_index = TRUE;
386 }
387 else if (semName == TGSI_SEMANTIC_LAYER) {
388 info->writes_layer = TRUE;
389 }
390 else if (semName == TGSI_SEMANTIC_PSIZE) {
391 info->writes_psize = TRUE;
392 }
393 else if (semName == TGSI_SEMANTIC_CLIPVERTEX) {
394 info->writes_clipvertex = TRUE;
395 }
396 }
397
398 if (procType == TGSI_PROCESSOR_FRAGMENT) {
399 if (semName == TGSI_SEMANTIC_POSITION) {
400 info->writes_z = TRUE;
401 }
402 else if (semName == TGSI_SEMANTIC_STENCIL) {
403 info->writes_stencil = TRUE;
404 }
405 }
406
407 if (procType == TGSI_PROCESSOR_VERTEX) {
408 if (semName == TGSI_SEMANTIC_EDGEFLAG) {
409 info->writes_edgeflag = TRUE;
410 }
411 }
412 }
413 }
414 }
415 break;
416
417 case TGSI_TOKEN_TYPE_IMMEDIATE:
418 {
419 uint reg = info->immediate_count++;
420 uint file = TGSI_FILE_IMMEDIATE;
421
422 info->file_mask[file] |= (1 << reg);
423 info->file_count[file]++;
424 info->file_max[file] = MAX2(info->file_max[file], (int)reg);
425 }
426 break;
427
428 case TGSI_TOKEN_TYPE_PROPERTY:
429 {
430 const struct tgsi_full_property *fullprop
431 = &parse.FullToken.FullProperty;
432 unsigned name = fullprop->Property.PropertyName;
433
434 assert(name < Elements(info->properties));
435 info->properties[name] = fullprop->u[0].Data;
436 }
437 break;
438
439 default:
440 assert( 0 );
441 }
442 }
443
444 info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] ||
445 info->opcode_count[TGSI_OPCODE_KILL]);
446
447 /* The dimensions of the IN decleration in geometry shader have
448 * to be deduced from the type of the input primitive.
449 */
450 if (procType == TGSI_PROCESSOR_GEOMETRY) {
451 unsigned input_primitive =
452 info->properties[TGSI_PROPERTY_GS_INPUT_PRIM];
453 int num_verts = u_vertices_per_prim(input_primitive);
454 int j;
455 info->file_count[TGSI_FILE_INPUT] = num_verts;
456 info->file_max[TGSI_FILE_INPUT] =
457 MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1);
458 for (j = 0; j < num_verts; ++j) {
459 info->file_mask[TGSI_FILE_INPUT] |= (1 << j);
460 }
461 }
462
463 tgsi_parse_free (&parse);
464 }
465
466
467
468 /**
469 * Check if the given shader is a "passthrough" shader consisting of only
470 * MOV instructions of the form: MOV OUT[n], IN[n]
471 *
472 */
473 boolean
474 tgsi_is_passthrough_shader(const struct tgsi_token *tokens)
475 {
476 struct tgsi_parse_context parse;
477
478 /**
479 ** Setup to begin parsing input shader
480 **/
481 if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
482 debug_printf("tgsi_parse_init() failed in tgsi_is_passthrough_shader()!\n");
483 return FALSE;
484 }
485
486 /**
487 ** Loop over incoming program tokens/instructions
488 */
489 while (!tgsi_parse_end_of_tokens(&parse)) {
490
491 tgsi_parse_token(&parse);
492
493 switch (parse.FullToken.Token.Type) {
494 case TGSI_TOKEN_TYPE_INSTRUCTION:
495 {
496 struct tgsi_full_instruction *fullinst =
497 &parse.FullToken.FullInstruction;
498 const struct tgsi_full_src_register *src =
499 &fullinst->Src[0];
500 const struct tgsi_full_dst_register *dst =
501 &fullinst->Dst[0];
502
503 /* Do a whole bunch of checks for a simple move */
504 if (fullinst->Instruction.Opcode != TGSI_OPCODE_MOV ||
505 (src->Register.File != TGSI_FILE_INPUT &&
506 src->Register.File != TGSI_FILE_SYSTEM_VALUE) ||
507 dst->Register.File != TGSI_FILE_OUTPUT ||
508 src->Register.Index != dst->Register.Index ||
509
510 src->Register.Negate ||
511 src->Register.Absolute ||
512
513 src->Register.SwizzleX != TGSI_SWIZZLE_X ||
514 src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
515 src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
516 src->Register.SwizzleW != TGSI_SWIZZLE_W ||
517
518 dst->Register.WriteMask != TGSI_WRITEMASK_XYZW)
519 {
520 tgsi_parse_free(&parse);
521 return FALSE;
522 }
523 }
524 break;
525
526 case TGSI_TOKEN_TYPE_DECLARATION:
527 /* fall-through */
528 case TGSI_TOKEN_TYPE_IMMEDIATE:
529 /* fall-through */
530 case TGSI_TOKEN_TYPE_PROPERTY:
531 /* fall-through */
532 default:
533 ; /* no-op */
534 }
535 }
536
537 tgsi_parse_free(&parse);
538
539 /* if we get here, it's a pass-through shader */
540 return TRUE;
541 }