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 "tgsi/tgsi_info.h"
41 #include "tgsi/tgsi_parse.h"
42 #include "tgsi/tgsi_util.h"
43 #include "tgsi/tgsi_scan.h"
44
45
46 static bool
is_memory_file(enum tgsi_file_type file)47 is_memory_file(enum tgsi_file_type file)
48 {
49 return file == TGSI_FILE_SAMPLER ||
50 file == TGSI_FILE_SAMPLER_VIEW ||
51 file == TGSI_FILE_IMAGE ||
52 file == TGSI_FILE_BUFFER ||
53 file == TGSI_FILE_HW_ATOMIC;
54 }
55
56
57 static bool
is_mem_query_inst(enum tgsi_opcode opcode)58 is_mem_query_inst(enum tgsi_opcode opcode)
59 {
60 return opcode == TGSI_OPCODE_RESQ ||
61 opcode == TGSI_OPCODE_TXQ ||
62 opcode == TGSI_OPCODE_TXQS ||
63 opcode == TGSI_OPCODE_LODQ;
64 }
65
66 /**
67 * Is the opcode a "true" texture instruction which samples from a
68 * texture map?
69 */
70 static bool
is_texture_inst(enum tgsi_opcode opcode)71 is_texture_inst(enum tgsi_opcode opcode)
72 {
73 return (!is_mem_query_inst(opcode) &&
74 tgsi_get_opcode_info(opcode)->is_tex);
75 }
76
77
78 static void
scan_src_operand(struct tgsi_shader_info * info,const struct tgsi_full_instruction * fullinst,const struct tgsi_full_src_register * src,unsigned src_index,unsigned usage_mask_after_swizzle,bool * is_mem_inst)79 scan_src_operand(struct tgsi_shader_info *info,
80 const struct tgsi_full_instruction *fullinst,
81 const struct tgsi_full_src_register *src,
82 unsigned src_index,
83 unsigned usage_mask_after_swizzle,
84 bool *is_mem_inst)
85 {
86 int ind = src->Register.Index;
87
88 if (info->processor == PIPE_SHADER_COMPUTE &&
89 src->Register.File == TGSI_FILE_SYSTEM_VALUE) {
90 unsigned name;
91
92 name = info->system_value_semantic_name[src->Register.Index];
93
94 switch (name) {
95 case TGSI_SEMANTIC_GRID_SIZE:
96 info->uses_grid_size = true;
97 break;
98 }
99 }
100
101 /* Mark which inputs are effectively used */
102 if (src->Register.File == TGSI_FILE_INPUT) {
103 if (src->Register.Indirect) {
104 for (ind = 0; ind < info->num_inputs; ++ind) {
105 info->input_usage_mask[ind] |= usage_mask_after_swizzle;
106 }
107 } else {
108 assert(ind >= 0);
109 assert(ind < PIPE_MAX_SHADER_INPUTS);
110 info->input_usage_mask[ind] |= usage_mask_after_swizzle;
111 }
112
113 if (info->processor == PIPE_SHADER_FRAGMENT) {
114 unsigned name, input;
115
116 if (src->Register.Indirect && src->Indirect.ArrayID)
117 input = info->input_array_first[src->Indirect.ArrayID];
118 else
119 input = src->Register.Index;
120
121 name = info->input_semantic_name[input];
122
123 if (name == TGSI_SEMANTIC_POSITION &&
124 usage_mask_after_swizzle & TGSI_WRITEMASK_Z)
125 info->reads_z = true;
126 }
127 }
128
129 if (info->processor == PIPE_SHADER_TESS_CTRL &&
130 src->Register.File == TGSI_FILE_OUTPUT) {
131 unsigned input;
132
133 if (src->Register.Indirect && src->Indirect.ArrayID)
134 input = info->output_array_first[src->Indirect.ArrayID];
135 else
136 input = src->Register.Index;
137
138 switch (info->output_semantic_name[input]) {
139 case TGSI_SEMANTIC_PATCH:
140 info->reads_perpatch_outputs = true;
141 break;
142 case TGSI_SEMANTIC_TESSINNER:
143 case TGSI_SEMANTIC_TESSOUTER:
144 info->reads_tessfactor_outputs = true;
145 break;
146 default:
147 info->reads_pervertex_outputs = true;
148 }
149 }
150
151 /* check for indirect register reads */
152 if (src->Register.Indirect)
153 info->indirect_files |= (1 << src->Register.File);
154
155 if (src->Register.Dimension && src->Dimension.Indirect)
156 info->dim_indirect_files |= 1u << src->Register.File;
157
158 /* Texture samplers */
159 if (src->Register.File == TGSI_FILE_SAMPLER) {
160 const unsigned index = src->Register.Index;
161
162 assert(fullinst->Instruction.Texture);
163 assert(index < PIPE_MAX_SAMPLERS);
164
165 if (is_texture_inst(fullinst->Instruction.Opcode)) {
166 const unsigned target = fullinst->Texture.Texture;
167 assert(target < TGSI_TEXTURE_UNKNOWN);
168 /* for texture instructions, check that the texture instruction
169 * target matches the previous sampler view declaration (if there
170 * was one.)
171 */
172 if (info->sampler_targets[index] == TGSI_TEXTURE_UNKNOWN) {
173 /* probably no sampler view declaration */
174 info->sampler_targets[index] = target;
175 } else {
176 /* Make sure the texture instruction's sampler/target info
177 * agrees with the sampler view declaration.
178 */
179 assert(info->sampler_targets[index] == target);
180 }
181 }
182 }
183
184 if (is_memory_file(src->Register.File) &&
185 !is_mem_query_inst(fullinst->Instruction.Opcode)) {
186 *is_mem_inst = true;
187
188 if (src->Register.File == TGSI_FILE_IMAGE &&
189 (fullinst->Memory.Texture == TGSI_TEXTURE_2D_MSAA ||
190 fullinst->Memory.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA)) {
191 if (src->Register.Indirect)
192 info->msaa_images_declared = info->images_declared;
193 else
194 info->msaa_images_declared |= 1 << src->Register.Index;
195 }
196
197 if (tgsi_get_opcode_info(fullinst->Instruction.Opcode)->is_store) {
198 info->writes_memory = true;
199
200 if (src->Register.File == TGSI_FILE_BUFFER) {
201 if (src->Register.Indirect)
202 info->shader_buffers_atomic = info->shader_buffers_declared;
203 else
204 info->shader_buffers_atomic |= 1 << src->Register.Index;
205 }
206 } else {
207 if (src->Register.File == TGSI_FILE_BUFFER) {
208 if (src->Register.Indirect)
209 info->shader_buffers_load = info->shader_buffers_declared;
210 else
211 info->shader_buffers_load |= 1 << src->Register.Index;
212 }
213 }
214 }
215 }
216
217
218 static void
scan_instruction(struct tgsi_shader_info * info,const struct tgsi_full_instruction * fullinst,unsigned * current_depth)219 scan_instruction(struct tgsi_shader_info *info,
220 const struct tgsi_full_instruction *fullinst,
221 unsigned *current_depth)
222 {
223 unsigned i;
224 bool is_mem_inst = false;
225
226 assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST);
227 info->opcode_count[fullinst->Instruction.Opcode]++;
228
229 switch (fullinst->Instruction.Opcode) {
230 case TGSI_OPCODE_IF:
231 case TGSI_OPCODE_UIF:
232 case TGSI_OPCODE_BGNLOOP:
233 (*current_depth)++;
234 break;
235 case TGSI_OPCODE_ENDIF:
236 case TGSI_OPCODE_ENDLOOP:
237 (*current_depth)--;
238 break;
239 case TGSI_OPCODE_FBFETCH:
240 info->uses_fbfetch = true;
241 break;
242 default:
243 break;
244 }
245
246 for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
247 scan_src_operand(info, fullinst, &fullinst->Src[i], i,
248 tgsi_util_get_inst_usage_mask(fullinst, i),
249 &is_mem_inst);
250
251 if (fullinst->Src[i].Register.Indirect) {
252 struct tgsi_full_src_register src = {{0}};
253
254 src.Register.File = fullinst->Src[i].Indirect.File;
255 src.Register.Index = fullinst->Src[i].Indirect.Index;
256
257 scan_src_operand(info, fullinst, &src, -1,
258 1 << fullinst->Src[i].Indirect.Swizzle,
259 NULL);
260 }
261
262 if (fullinst->Src[i].Register.Dimension &&
263 fullinst->Src[i].Dimension.Indirect) {
264 struct tgsi_full_src_register src = {{0}};
265
266 src.Register.File = fullinst->Src[i].DimIndirect.File;
267 src.Register.Index = fullinst->Src[i].DimIndirect.Index;
268
269 scan_src_operand(info, fullinst, &src, -1,
270 1 << fullinst->Src[i].DimIndirect.Swizzle,
271 NULL);
272 }
273 }
274
275 if (fullinst->Instruction.Texture) {
276 for (i = 0; i < fullinst->Texture.NumOffsets; i++) {
277 struct tgsi_full_src_register src = {{0}};
278
279 src.Register.File = fullinst->TexOffsets[i].File;
280 src.Register.Index = fullinst->TexOffsets[i].Index;
281
282 /* The usage mask is suboptimal but should be safe. */
283 scan_src_operand(info, fullinst, &src, -1,
284 (1 << fullinst->TexOffsets[i].SwizzleX) |
285 (1 << fullinst->TexOffsets[i].SwizzleY) |
286 (1 << fullinst->TexOffsets[i].SwizzleZ),
287 &is_mem_inst);
288 }
289 }
290
291 /* check for indirect register writes */
292 for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) {
293 const struct tgsi_full_dst_register *dst = &fullinst->Dst[i];
294
295 if (dst->Register.Indirect) {
296 struct tgsi_full_src_register src = {{0}};
297
298 src.Register.File = dst->Indirect.File;
299 src.Register.Index = dst->Indirect.Index;
300
301 scan_src_operand(info, fullinst, &src, -1,
302 1 << dst->Indirect.Swizzle, NULL);
303
304 info->indirect_files |= (1 << dst->Register.File);
305 }
306
307 if (dst->Register.Dimension && dst->Dimension.Indirect) {
308 struct tgsi_full_src_register src = {{0}};
309
310 src.Register.File = dst->DimIndirect.File;
311 src.Register.Index = dst->DimIndirect.Index;
312
313 scan_src_operand(info, fullinst, &src, -1,
314 1 << dst->DimIndirect.Swizzle, NULL);
315
316 info->dim_indirect_files |= 1u << dst->Register.File;
317 }
318
319 if (is_memory_file(dst->Register.File)) {
320 assert(fullinst->Instruction.Opcode == TGSI_OPCODE_STORE);
321
322 is_mem_inst = true;
323 info->writes_memory = true;
324
325 if (dst->Register.File == TGSI_FILE_IMAGE) {
326 if (fullinst->Memory.Texture == TGSI_TEXTURE_2D_MSAA ||
327 fullinst->Memory.Texture == TGSI_TEXTURE_2D_ARRAY_MSAA) {
328 if (dst->Register.Indirect)
329 info->msaa_images_declared = info->images_declared;
330 else
331 info->msaa_images_declared |= 1 << dst->Register.Index;
332 }
333 } else if (dst->Register.File == TGSI_FILE_BUFFER) {
334 if (dst->Register.Indirect)
335 info->shader_buffers_store = info->shader_buffers_declared;
336 else
337 info->shader_buffers_store |= 1 << dst->Register.Index;
338 }
339 }
340 }
341
342 info->num_instructions++;
343 }
344
345
346 static void
scan_declaration(struct tgsi_shader_info * info,const struct tgsi_full_declaration * fulldecl)347 scan_declaration(struct tgsi_shader_info *info,
348 const struct tgsi_full_declaration *fulldecl)
349 {
350 enum tgsi_file_type file = fulldecl->Declaration.File;
351 const unsigned procType = info->processor;
352 unsigned reg;
353
354 if (fulldecl->Declaration.Array) {
355 unsigned array_id = fulldecl->Array.ArrayID;
356
357 switch (file) {
358 case TGSI_FILE_INPUT:
359 assert(array_id < ARRAY_SIZE(info->input_array_first));
360 info->input_array_first[array_id] = fulldecl->Range.First;
361 break;
362 case TGSI_FILE_OUTPUT:
363 assert(array_id < ARRAY_SIZE(info->output_array_first));
364 info->output_array_first[array_id] = fulldecl->Range.First;
365 break;
366
367 case TGSI_FILE_NULL:
368 unreachable("unexpected file");
369
370 default:
371 break;
372 }
373 }
374
375 for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) {
376 unsigned semName = fulldecl->Semantic.Name;
377 unsigned semIndex = fulldecl->Semantic.Index +
378 (reg - fulldecl->Range.First);
379 int buffer;
380 unsigned index, target, type;
381
382 /*
383 * only first 32 regs will appear in this bitfield, if larger
384 * bits will wrap around.
385 */
386 info->file_mask[file] |= (1u << (reg & 31));
387 info->file_count[file]++;
388 info->file_max[file] = MAX2(info->file_max[file], (int)reg);
389
390 switch (file) {
391 case TGSI_FILE_CONSTANT:
392 buffer = 0;
393
394 if (fulldecl->Declaration.Dimension)
395 buffer = fulldecl->Dim.Index2D;
396
397 info->const_file_max[buffer] =
398 MAX2(info->const_file_max[buffer], (int)reg);
399 info->const_buffers_declared |= 1u << buffer;
400 break;
401
402 case TGSI_FILE_IMAGE:
403 info->images_declared |= 1u << reg;
404 if (fulldecl->Image.Resource == TGSI_TEXTURE_BUFFER)
405 info->images_buffers |= 1 << reg;
406 break;
407
408 case TGSI_FILE_BUFFER:
409 info->shader_buffers_declared |= 1u << reg;
410 break;
411
412 case TGSI_FILE_HW_ATOMIC:
413 info->hw_atomic_declared |= 1u << reg;
414 break;
415
416 case TGSI_FILE_INPUT:
417 info->input_semantic_name[reg] = (uint8_t) semName;
418 info->input_semantic_index[reg] = (uint8_t) semIndex;
419 info->input_interpolate[reg] = (uint8_t)fulldecl->Interp.Interpolate;
420 info->input_interpolate_loc[reg] = (uint8_t)fulldecl->Interp.Location;
421
422 /* Vertex shaders can have inputs with holes between them. */
423 info->num_inputs = MAX2(info->num_inputs, reg + 1);
424
425 switch (semName) {
426 case TGSI_SEMANTIC_PRIMID:
427 info->uses_primid = true;
428 break;
429 case TGSI_SEMANTIC_FACE:
430 info->uses_frontface = true;
431 break;
432 }
433 break;
434
435 case TGSI_FILE_SYSTEM_VALUE:
436 index = fulldecl->Range.First;
437
438 info->system_value_semantic_name[index] = semName;
439 info->num_system_values = MAX2(info->num_system_values, index + 1);
440
441 switch (semName) {
442 case TGSI_SEMANTIC_INSTANCEID:
443 info->uses_instanceid = true;
444 break;
445 case TGSI_SEMANTIC_VERTEXID:
446 info->uses_vertexid = true;
447 break;
448 case TGSI_SEMANTIC_VERTEXID_NOBASE:
449 info->uses_vertexid_nobase = true;
450 break;
451 case TGSI_SEMANTIC_BASEVERTEX:
452 info->uses_basevertex = true;
453 break;
454 case TGSI_SEMANTIC_PRIMID:
455 info->uses_primid = true;
456 break;
457 case TGSI_SEMANTIC_INVOCATIONID:
458 info->uses_invocationid = true;
459 break;
460 case TGSI_SEMANTIC_FACE:
461 info->uses_frontface = true;
462 break;
463 }
464 break;
465
466 case TGSI_FILE_OUTPUT:
467 info->output_semantic_name[reg] = (uint8_t) semName;
468 info->output_semantic_index[reg] = (uint8_t) semIndex;
469 info->output_usagemask[reg] |= fulldecl->Declaration.UsageMask;
470 info->num_outputs = MAX2(info->num_outputs, reg + 1);
471
472 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_X) {
473 info->output_streams[reg] |= (uint8_t)fulldecl->Semantic.StreamX;
474 info->num_stream_output_components[fulldecl->Semantic.StreamX]++;
475 }
476 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Y) {
477 info->output_streams[reg] |= (uint8_t)fulldecl->Semantic.StreamY << 2;
478 info->num_stream_output_components[fulldecl->Semantic.StreamY]++;
479 }
480 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Z) {
481 info->output_streams[reg] |= (uint8_t)fulldecl->Semantic.StreamZ << 4;
482 info->num_stream_output_components[fulldecl->Semantic.StreamZ]++;
483 }
484 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_W) {
485 info->output_streams[reg] |= (uint8_t)fulldecl->Semantic.StreamW << 6;
486 info->num_stream_output_components[fulldecl->Semantic.StreamW]++;
487 }
488
489 switch (semName) {
490 case TGSI_SEMANTIC_VIEWPORT_INDEX:
491 info->writes_viewport_index = true;
492 break;
493 case TGSI_SEMANTIC_LAYER:
494 info->writes_layer = true;
495 break;
496 case TGSI_SEMANTIC_PSIZE:
497 info->writes_psize = true;
498 break;
499 case TGSI_SEMANTIC_CLIPVERTEX:
500 info->writes_clipvertex = true;
501 break;
502 case TGSI_SEMANTIC_STENCIL:
503 info->writes_stencil = true;
504 break;
505 case TGSI_SEMANTIC_SAMPLEMASK:
506 info->writes_samplemask = true;
507 break;
508 case TGSI_SEMANTIC_EDGEFLAG:
509 info->writes_edgeflag = true;
510 break;
511 case TGSI_SEMANTIC_POSITION:
512 if (procType == PIPE_SHADER_FRAGMENT)
513 info->writes_z = true;
514 else
515 info->writes_position = true;
516 break;
517 }
518 break;
519
520 case TGSI_FILE_SAMPLER:
521 STATIC_ASSERT(sizeof(info->samplers_declared) * 8 >= PIPE_MAX_SAMPLERS);
522 info->samplers_declared |= 1u << reg;
523 break;
524
525 case TGSI_FILE_SAMPLER_VIEW:
526 target = fulldecl->SamplerView.Resource;
527 type = fulldecl->SamplerView.ReturnTypeX;
528
529 assert(target < TGSI_TEXTURE_UNKNOWN);
530 if (info->sampler_targets[reg] == TGSI_TEXTURE_UNKNOWN) {
531 /* Save sampler target for this sampler index */
532 info->sampler_targets[reg] = target;
533 info->sampler_type[reg] = type;
534 } else {
535 /* if previously declared, make sure targets agree */
536 assert(info->sampler_targets[reg] == target);
537 assert(info->sampler_type[reg] == type);
538 }
539 break;
540
541 case TGSI_FILE_NULL:
542 unreachable("unexpected file");
543
544 default:
545 break;
546 }
547 }
548 }
549
550
551 static void
scan_immediate(struct tgsi_shader_info * info)552 scan_immediate(struct tgsi_shader_info *info)
553 {
554 unsigned reg = info->immediate_count++;
555 enum tgsi_file_type file = TGSI_FILE_IMMEDIATE;
556
557 info->file_mask[file] |= (1 << reg);
558 info->file_count[file]++;
559 info->file_max[file] = MAX2(info->file_max[file], (int)reg);
560 }
561
562
563 static void
scan_property(struct tgsi_shader_info * info,const struct tgsi_full_property * fullprop)564 scan_property(struct tgsi_shader_info *info,
565 const struct tgsi_full_property *fullprop)
566 {
567 unsigned name = fullprop->Property.PropertyName;
568 unsigned value = fullprop->u[0].Data;
569
570 assert(name < ARRAY_SIZE(info->properties));
571 info->properties[name] = value;
572
573 switch (name) {
574 case TGSI_PROPERTY_NUM_CLIPDIST_ENABLED:
575 info->num_written_clipdistance = value;
576 break;
577 case TGSI_PROPERTY_NUM_CULLDIST_ENABLED:
578 info->num_written_culldistance = value;
579 break;
580 }
581 }
582
583
584 /**
585 * Scan the given TGSI shader to collect information such as number of
586 * registers used, special instructions used, etc.
587 * \return info the result of the scan
588 */
589 void
tgsi_scan_shader(const struct tgsi_token * tokens,struct tgsi_shader_info * info)590 tgsi_scan_shader(const struct tgsi_token *tokens,
591 struct tgsi_shader_info *info)
592 {
593 unsigned procType, i;
594 struct tgsi_parse_context parse;
595 unsigned current_depth = 0;
596
597 memset(info, 0, sizeof(*info));
598 for (i = 0; i < TGSI_FILE_COUNT; i++)
599 info->file_max[i] = -1;
600 for (i = 0; i < ARRAY_SIZE(info->const_file_max); i++)
601 info->const_file_max[i] = -1;
602 for (i = 0; i < ARRAY_SIZE(info->sampler_targets); i++)
603 info->sampler_targets[i] = TGSI_TEXTURE_UNKNOWN;
604
605 /**
606 ** Setup to begin parsing input shader
607 **/
608 if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) {
609 debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n");
610 return;
611 }
612 procType = parse.FullHeader.Processor.Processor;
613 assert(procType == PIPE_SHADER_FRAGMENT ||
614 procType == PIPE_SHADER_VERTEX ||
615 procType == PIPE_SHADER_GEOMETRY ||
616 procType == PIPE_SHADER_TESS_CTRL ||
617 procType == PIPE_SHADER_TESS_EVAL ||
618 procType == PIPE_SHADER_COMPUTE);
619 info->processor = procType;
620
621 if (procType == PIPE_SHADER_GEOMETRY)
622 info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1;
623
624 /**
625 ** Loop over incoming program tokens/instructions
626 */
627 while (!tgsi_parse_end_of_tokens(&parse)) {
628 tgsi_parse_token( &parse );
629
630 switch( parse.FullToken.Token.Type ) {
631 case TGSI_TOKEN_TYPE_INSTRUCTION:
632 scan_instruction(info, &parse.FullToken.FullInstruction,
633 ¤t_depth);
634 break;
635 case TGSI_TOKEN_TYPE_DECLARATION:
636 scan_declaration(info, &parse.FullToken.FullDeclaration);
637 break;
638 case TGSI_TOKEN_TYPE_IMMEDIATE:
639 scan_immediate(info);
640 break;
641 case TGSI_TOKEN_TYPE_PROPERTY:
642 scan_property(info, &parse.FullToken.FullProperty);
643 break;
644 default:
645 assert(!"Unexpected TGSI token type");
646 }
647 }
648
649 info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] ||
650 info->opcode_count[TGSI_OPCODE_KILL]);
651
652 /* The dimensions of the IN decleration in geometry shader have
653 * to be deduced from the type of the input primitive.
654 */
655 if (procType == PIPE_SHADER_GEOMETRY) {
656 unsigned input_primitive =
657 info->properties[TGSI_PROPERTY_GS_INPUT_PRIM];
658 int num_verts = mesa_vertices_per_prim(input_primitive);
659 int j;
660 info->file_count[TGSI_FILE_INPUT] = num_verts;
661 info->file_max[TGSI_FILE_INPUT] =
662 MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1);
663 for (j = 0; j < num_verts; ++j) {
664 info->file_mask[TGSI_FILE_INPUT] |= (1 << j);
665 }
666 }
667
668 tgsi_parse_free(&parse);
669 }
670
671