tgsi/scan: add basic info about tessellation OUT and IN uses
[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_info.h"
42 #include "tgsi/tgsi_parse.h"
43 #include "tgsi/tgsi_util.h"
44 #include "tgsi/tgsi_scan.h"
45
46
47 static bool
48 is_memory_file(unsigned file)
49 {
50 return file == TGSI_FILE_SAMPLER ||
51 file == TGSI_FILE_SAMPLER_VIEW ||
52 file == TGSI_FILE_IMAGE ||
53 file == TGSI_FILE_BUFFER;
54 }
55
56
57 static bool
58 is_mem_query_inst(unsigned opcode)
59 {
60 return opcode == TGSI_OPCODE_RESQ ||
61 opcode == TGSI_OPCODE_TXQ ||
62 opcode == TGSI_OPCODE_TXQS ||
63 opcode == TGSI_OPCODE_TXQ_LZ ||
64 opcode == TGSI_OPCODE_LODQ;
65 }
66
67 /**
68 * Is the opcode a "true" texture instruction which samples from a
69 * texture map?
70 */
71 static bool
72 is_texture_inst(unsigned opcode)
73 {
74 return (!is_mem_query_inst(opcode) &&
75 tgsi_get_opcode_info(opcode)->is_tex);
76 }
77
78
79 /**
80 * Is the opcode an instruction which computes a derivative explicitly or
81 * implicitly?
82 */
83 static bool
84 computes_derivative(unsigned opcode)
85 {
86 if (tgsi_get_opcode_info(opcode)->is_tex) {
87 return opcode != TGSI_OPCODE_TG4 &&
88 opcode != TGSI_OPCODE_TXD &&
89 opcode != TGSI_OPCODE_TXF &&
90 opcode != TGSI_OPCODE_TXL &&
91 opcode != TGSI_OPCODE_TXL2 &&
92 opcode != TGSI_OPCODE_TXQ &&
93 opcode != TGSI_OPCODE_TXQ_LZ &&
94 opcode != TGSI_OPCODE_TXQS;
95 }
96
97 return opcode == TGSI_OPCODE_DDX || opcode == TGSI_OPCODE_DDX_FINE ||
98 opcode == TGSI_OPCODE_DDY || opcode == TGSI_OPCODE_DDY_FINE ||
99 opcode == TGSI_OPCODE_SAMPLE ||
100 opcode == TGSI_OPCODE_SAMPLE_B ||
101 opcode == TGSI_OPCODE_SAMPLE_C;
102 }
103
104
105 static void
106 scan_src_operand(struct tgsi_shader_info *info,
107 const struct tgsi_full_instruction *fullinst,
108 const struct tgsi_full_src_register *src,
109 unsigned src_index,
110 unsigned usage_mask,
111 bool is_interp_instruction,
112 bool *is_mem_inst)
113 {
114 int ind = src->Register.Index;
115
116 /* Mark which inputs are effectively used */
117 if (src->Register.File == TGSI_FILE_INPUT) {
118 if (src->Register.Indirect) {
119 for (ind = 0; ind < info->num_inputs; ++ind) {
120 info->input_usage_mask[ind] |= usage_mask;
121 }
122 } else {
123 assert(ind >= 0);
124 assert(ind < PIPE_MAX_SHADER_INPUTS);
125 info->input_usage_mask[ind] |= usage_mask;
126 }
127
128 if (info->processor == PIPE_SHADER_FRAGMENT) {
129 unsigned name, index, input;
130
131 if (src->Register.Indirect && src->Indirect.ArrayID)
132 input = info->input_array_first[src->Indirect.ArrayID];
133 else
134 input = src->Register.Index;
135
136 name = info->input_semantic_name[input];
137 index = info->input_semantic_index[input];
138
139 if (name == TGSI_SEMANTIC_POSITION &&
140 (src->Register.SwizzleX == TGSI_SWIZZLE_Z ||
141 src->Register.SwizzleY == TGSI_SWIZZLE_Z ||
142 src->Register.SwizzleZ == TGSI_SWIZZLE_Z ||
143 src->Register.SwizzleW == TGSI_SWIZZLE_Z))
144 info->reads_z = TRUE;
145
146 if (name == TGSI_SEMANTIC_COLOR) {
147 unsigned mask =
148 (1 << src->Register.SwizzleX) |
149 (1 << src->Register.SwizzleY) |
150 (1 << src->Register.SwizzleZ) |
151 (1 << src->Register.SwizzleW);
152
153 info->colors_read |= mask << (index * 4);
154 }
155
156 /* Process only interpolated varyings. Don't include POSITION.
157 * Don't include integer varyings, because they are not
158 * interpolated. Don't process inputs interpolated by INTERP
159 * opcodes. Those are tracked separately.
160 */
161 if ((!is_interp_instruction || src_index != 0) &&
162 (name == TGSI_SEMANTIC_GENERIC ||
163 name == TGSI_SEMANTIC_TEXCOORD ||
164 name == TGSI_SEMANTIC_COLOR ||
165 name == TGSI_SEMANTIC_BCOLOR ||
166 name == TGSI_SEMANTIC_FOG ||
167 name == TGSI_SEMANTIC_CLIPDIST)) {
168 switch (info->input_interpolate[input]) {
169 case TGSI_INTERPOLATE_COLOR:
170 case TGSI_INTERPOLATE_PERSPECTIVE:
171 switch (info->input_interpolate_loc[input]) {
172 case TGSI_INTERPOLATE_LOC_CENTER:
173 info->uses_persp_center = TRUE;
174 break;
175 case TGSI_INTERPOLATE_LOC_CENTROID:
176 info->uses_persp_centroid = TRUE;
177 break;
178 case TGSI_INTERPOLATE_LOC_SAMPLE:
179 info->uses_persp_sample = TRUE;
180 break;
181 }
182 break;
183 case TGSI_INTERPOLATE_LINEAR:
184 switch (info->input_interpolate_loc[input]) {
185 case TGSI_INTERPOLATE_LOC_CENTER:
186 info->uses_linear_center = TRUE;
187 break;
188 case TGSI_INTERPOLATE_LOC_CENTROID:
189 info->uses_linear_centroid = TRUE;
190 break;
191 case TGSI_INTERPOLATE_LOC_SAMPLE:
192 info->uses_linear_sample = TRUE;
193 break;
194 }
195 break;
196 /* TGSI_INTERPOLATE_CONSTANT doesn't do any interpolation. */
197 }
198 }
199 }
200 }
201
202 if (info->processor == PIPE_SHADER_TESS_CTRL &&
203 src->Register.File == TGSI_FILE_OUTPUT) {
204 unsigned input;
205
206 if (src->Register.Indirect && src->Indirect.ArrayID)
207 input = info->output_array_first[src->Indirect.ArrayID];
208 else
209 input = src->Register.Index;
210
211 switch (info->output_semantic_name[input]) {
212 case TGSI_SEMANTIC_PATCH:
213 info->reads_perpatch_outputs = true;
214 break;
215 case TGSI_SEMANTIC_TESSINNER:
216 case TGSI_SEMANTIC_TESSOUTER:
217 info->reads_tessfactor_outputs = true;
218 break;
219 default:
220 info->reads_pervertex_outputs = true;
221 }
222 }
223
224 /* check for indirect register reads */
225 if (src->Register.Indirect) {
226 info->indirect_files |= (1 << src->Register.File);
227 info->indirect_files_read |= (1 << src->Register.File);
228
229 /* record indirect constant buffer indexing */
230 if (src->Register.File == TGSI_FILE_CONSTANT) {
231 if (src->Register.Dimension) {
232 if (src->Dimension.Indirect)
233 info->const_buffers_indirect = info->const_buffers_declared;
234 else
235 info->const_buffers_indirect |= 1u << src->Dimension.Index;
236 } else {
237 info->const_buffers_indirect |= 1;
238 }
239 }
240 }
241
242 if (src->Register.Dimension && src->Dimension.Indirect)
243 info->dim_indirect_files |= 1u << src->Register.File;
244
245 /* Texture samplers */
246 if (src->Register.File == TGSI_FILE_SAMPLER) {
247 const unsigned index = src->Register.Index;
248
249 assert(fullinst->Instruction.Texture);
250 assert(index < ARRAY_SIZE(info->is_msaa_sampler));
251 assert(index < PIPE_MAX_SAMPLERS);
252
253 if (is_texture_inst(fullinst->Instruction.Opcode)) {
254 const unsigned target = fullinst->Texture.Texture;
255 assert(target < TGSI_TEXTURE_UNKNOWN);
256 /* for texture instructions, check that the texture instruction
257 * target matches the previous sampler view declaration (if there
258 * was one.)
259 */
260 if (info->sampler_targets[index] == TGSI_TEXTURE_UNKNOWN) {
261 /* probably no sampler view declaration */
262 info->sampler_targets[index] = target;
263 } else {
264 /* Make sure the texture instruction's sampler/target info
265 * agrees with the sampler view declaration.
266 */
267 assert(info->sampler_targets[index] == target);
268 }
269 /* MSAA samplers */
270 if (target == TGSI_TEXTURE_2D_MSAA ||
271 target == TGSI_TEXTURE_2D_ARRAY_MSAA) {
272 info->is_msaa_sampler[src->Register.Index] = TRUE;
273 }
274 }
275 }
276
277 if (is_memory_file(src->Register.File) &&
278 !is_mem_query_inst(fullinst->Instruction.Opcode)) {
279 *is_mem_inst = true;
280
281 if (tgsi_get_opcode_info(fullinst->Instruction.Opcode)->is_store) {
282 info->writes_memory = TRUE;
283
284 if (src->Register.File == TGSI_FILE_IMAGE) {
285 if (src->Register.Indirect)
286 info->images_writemask = info->images_declared;
287 else
288 info->images_writemask |= 1 << src->Register.Index;
289 } else if (src->Register.File == TGSI_FILE_BUFFER) {
290 if (src->Register.Indirect)
291 info->shader_buffers_atomic = info->shader_buffers_declared;
292 else
293 info->shader_buffers_atomic |= 1 << src->Register.Index;
294 }
295 } else {
296 if (src->Register.File == TGSI_FILE_BUFFER) {
297 if (src->Register.Indirect)
298 info->shader_buffers_load = info->shader_buffers_declared;
299 else
300 info->shader_buffers_load |= 1 << src->Register.Index;
301 }
302 }
303 }
304 }
305
306
307 static void
308 scan_instruction(struct tgsi_shader_info *info,
309 const struct tgsi_full_instruction *fullinst,
310 unsigned *current_depth)
311 {
312 unsigned i;
313 bool is_mem_inst = false;
314 bool is_interp_instruction = false;
315
316 assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST);
317 info->opcode_count[fullinst->Instruction.Opcode]++;
318
319 switch (fullinst->Instruction.Opcode) {
320 case TGSI_OPCODE_IF:
321 case TGSI_OPCODE_UIF:
322 case TGSI_OPCODE_BGNLOOP:
323 (*current_depth)++;
324 info->max_depth = MAX2(info->max_depth, *current_depth);
325 break;
326 case TGSI_OPCODE_ENDIF:
327 case TGSI_OPCODE_ENDLOOP:
328 (*current_depth)--;
329 break;
330 default:
331 break;
332 }
333
334 if (fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_CENTROID ||
335 fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
336 fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) {
337 const struct tgsi_full_src_register *src0 = &fullinst->Src[0];
338 unsigned input;
339
340 is_interp_instruction = true;
341
342 if (src0->Register.Indirect && src0->Indirect.ArrayID)
343 input = info->input_array_first[src0->Indirect.ArrayID];
344 else
345 input = src0->Register.Index;
346
347 /* For the INTERP opcodes, the interpolation is always
348 * PERSPECTIVE unless LINEAR is specified.
349 */
350 switch (info->input_interpolate[input]) {
351 case TGSI_INTERPOLATE_COLOR:
352 case TGSI_INTERPOLATE_CONSTANT:
353 case TGSI_INTERPOLATE_PERSPECTIVE:
354 switch (fullinst->Instruction.Opcode) {
355 case TGSI_OPCODE_INTERP_CENTROID:
356 info->uses_persp_opcode_interp_centroid = TRUE;
357 break;
358 case TGSI_OPCODE_INTERP_OFFSET:
359 info->uses_persp_opcode_interp_offset = TRUE;
360 break;
361 case TGSI_OPCODE_INTERP_SAMPLE:
362 info->uses_persp_opcode_interp_sample = TRUE;
363 break;
364 }
365 break;
366
367 case TGSI_INTERPOLATE_LINEAR:
368 switch (fullinst->Instruction.Opcode) {
369 case TGSI_OPCODE_INTERP_CENTROID:
370 info->uses_linear_opcode_interp_centroid = TRUE;
371 break;
372 case TGSI_OPCODE_INTERP_OFFSET:
373 info->uses_linear_opcode_interp_offset = TRUE;
374 break;
375 case TGSI_OPCODE_INTERP_SAMPLE:
376 info->uses_linear_opcode_interp_sample = TRUE;
377 break;
378 }
379 break;
380 }
381 }
382
383 if (fullinst->Instruction.Opcode >= TGSI_OPCODE_F2D &&
384 fullinst->Instruction.Opcode <= TGSI_OPCODE_DSSG)
385 info->uses_doubles = TRUE;
386
387 for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
388 scan_src_operand(info, fullinst, &fullinst->Src[i], i,
389 tgsi_util_get_inst_usage_mask(fullinst, i),
390 is_interp_instruction, &is_mem_inst);
391 }
392
393 if (fullinst->Instruction.Texture) {
394 for (i = 0; i < fullinst->Texture.NumOffsets; i++) {
395 struct tgsi_full_src_register src = {{0}};
396
397 src.Register.File = fullinst->TexOffsets[i].File;
398 src.Register.Index = fullinst->TexOffsets[i].Index;
399 src.Register.SwizzleX = fullinst->TexOffsets[i].SwizzleX;
400 src.Register.SwizzleY = fullinst->TexOffsets[i].SwizzleY;
401 src.Register.SwizzleZ = fullinst->TexOffsets[i].SwizzleZ;
402
403 /* The usage mask is suboptimal but should be safe. */
404 scan_src_operand(info, fullinst, &src, 0, TGSI_WRITEMASK_XYZ,
405 false, &is_mem_inst);
406 }
407 }
408
409 /* check for indirect register writes */
410 for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) {
411 const struct tgsi_full_dst_register *dst = &fullinst->Dst[i];
412 if (dst->Register.Indirect) {
413 info->indirect_files |= (1 << dst->Register.File);
414 info->indirect_files_written |= (1 << dst->Register.File);
415 }
416
417 if (dst->Register.Dimension && dst->Dimension.Indirect)
418 info->dim_indirect_files |= 1u << dst->Register.File;
419
420 if (is_memory_file(dst->Register.File)) {
421 assert(fullinst->Instruction.Opcode == TGSI_OPCODE_STORE);
422
423 is_mem_inst = true;
424 info->writes_memory = TRUE;
425
426 if (dst->Register.File == TGSI_FILE_IMAGE) {
427 if (dst->Register.Indirect)
428 info->images_writemask = info->images_declared;
429 else
430 info->images_writemask |= 1 << dst->Register.Index;
431 } else if (dst->Register.File == TGSI_FILE_BUFFER) {
432 if (dst->Register.Indirect)
433 info->shader_buffers_store = info->shader_buffers_declared;
434 else
435 info->shader_buffers_store |= 1 << dst->Register.Index;
436 }
437 }
438 }
439
440 if (is_mem_inst)
441 info->num_memory_instructions++;
442
443 if (computes_derivative(fullinst->Instruction.Opcode))
444 info->uses_derivatives = true;
445
446 info->num_instructions++;
447 }
448
449
450 static void
451 scan_declaration(struct tgsi_shader_info *info,
452 const struct tgsi_full_declaration *fulldecl)
453 {
454 const uint file = fulldecl->Declaration.File;
455 const unsigned procType = info->processor;
456 uint reg;
457
458 if (fulldecl->Declaration.Array) {
459 unsigned array_id = fulldecl->Array.ArrayID;
460
461 switch (file) {
462 case TGSI_FILE_INPUT:
463 assert(array_id < ARRAY_SIZE(info->input_array_first));
464 info->input_array_first[array_id] = fulldecl->Range.First;
465 info->input_array_last[array_id] = fulldecl->Range.Last;
466 break;
467 case TGSI_FILE_OUTPUT:
468 assert(array_id < ARRAY_SIZE(info->output_array_first));
469 info->output_array_first[array_id] = fulldecl->Range.First;
470 info->output_array_last[array_id] = fulldecl->Range.Last;
471 break;
472 }
473 info->array_max[file] = MAX2(info->array_max[file], array_id);
474 }
475
476 for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) {
477 unsigned semName = fulldecl->Semantic.Name;
478 unsigned semIndex = fulldecl->Semantic.Index +
479 (reg - fulldecl->Range.First);
480 int buffer;
481 unsigned index, target, type;
482
483 /* only first 32 regs will appear in this bitfield */
484 info->file_mask[file] |= (1 << reg);
485 info->file_count[file]++;
486 info->file_max[file] = MAX2(info->file_max[file], (int)reg);
487
488 switch (file) {
489 case TGSI_FILE_CONSTANT:
490 buffer = 0;
491
492 if (fulldecl->Declaration.Dimension)
493 buffer = fulldecl->Dim.Index2D;
494
495 info->const_file_max[buffer] =
496 MAX2(info->const_file_max[buffer], (int)reg);
497 info->const_buffers_declared |= 1u << buffer;
498 break;
499
500 case TGSI_FILE_IMAGE:
501 info->images_declared |= 1u << reg;
502 if (fulldecl->Image.Resource == TGSI_TEXTURE_BUFFER)
503 info->images_buffers |= 1 << reg;
504 break;
505
506 case TGSI_FILE_BUFFER:
507 info->shader_buffers_declared |= 1u << reg;
508 break;
509
510 case TGSI_FILE_INPUT:
511 info->input_semantic_name[reg] = (ubyte) semName;
512 info->input_semantic_index[reg] = (ubyte) semIndex;
513 info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate;
514 info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location;
515 info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap;
516
517 /* Vertex shaders can have inputs with holes between them. */
518 info->num_inputs = MAX2(info->num_inputs, reg + 1);
519
520 if (semName == TGSI_SEMANTIC_PRIMID)
521 info->uses_primid = TRUE;
522 else if (procType == PIPE_SHADER_FRAGMENT) {
523 if (semName == TGSI_SEMANTIC_POSITION)
524 info->reads_position = TRUE;
525 else if (semName == TGSI_SEMANTIC_FACE)
526 info->uses_frontface = TRUE;
527 }
528 break;
529
530 case TGSI_FILE_SYSTEM_VALUE:
531 index = fulldecl->Range.First;
532
533 info->system_value_semantic_name[index] = semName;
534 info->num_system_values = MAX2(info->num_system_values, index + 1);
535
536 switch (semName) {
537 case TGSI_SEMANTIC_INSTANCEID:
538 info->uses_instanceid = TRUE;
539 break;
540 case TGSI_SEMANTIC_VERTEXID:
541 info->uses_vertexid = TRUE;
542 break;
543 case TGSI_SEMANTIC_VERTEXID_NOBASE:
544 info->uses_vertexid_nobase = TRUE;
545 break;
546 case TGSI_SEMANTIC_BASEVERTEX:
547 info->uses_basevertex = TRUE;
548 break;
549 case TGSI_SEMANTIC_PRIMID:
550 info->uses_primid = TRUE;
551 break;
552 case TGSI_SEMANTIC_INVOCATIONID:
553 info->uses_invocationid = TRUE;
554 break;
555 case TGSI_SEMANTIC_POSITION:
556 info->reads_position = TRUE;
557 break;
558 case TGSI_SEMANTIC_FACE:
559 info->uses_frontface = TRUE;
560 break;
561 case TGSI_SEMANTIC_SAMPLEMASK:
562 info->reads_samplemask = TRUE;
563 break;
564 case TGSI_SEMANTIC_TESSINNER:
565 case TGSI_SEMANTIC_TESSOUTER:
566 info->reads_tess_factors = true;
567 break;
568 }
569 break;
570
571 case TGSI_FILE_OUTPUT:
572 info->output_semantic_name[reg] = (ubyte) semName;
573 info->output_semantic_index[reg] = (ubyte) semIndex;
574 info->output_usagemask[reg] |= fulldecl->Declaration.UsageMask;
575 info->num_outputs = MAX2(info->num_outputs, reg + 1);
576
577 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_X) {
578 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamX;
579 info->num_stream_output_components[fulldecl->Semantic.StreamX]++;
580 }
581 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Y) {
582 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamY << 2;
583 info->num_stream_output_components[fulldecl->Semantic.StreamY]++;
584 }
585 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Z) {
586 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamZ << 4;
587 info->num_stream_output_components[fulldecl->Semantic.StreamZ]++;
588 }
589 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_W) {
590 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamW << 6;
591 info->num_stream_output_components[fulldecl->Semantic.StreamW]++;
592 }
593
594 switch (semName) {
595 case TGSI_SEMANTIC_PRIMID:
596 info->writes_primid = true;
597 break;
598 case TGSI_SEMANTIC_VIEWPORT_INDEX:
599 info->writes_viewport_index = true;
600 break;
601 case TGSI_SEMANTIC_LAYER:
602 info->writes_layer = true;
603 break;
604 case TGSI_SEMANTIC_PSIZE:
605 info->writes_psize = true;
606 break;
607 case TGSI_SEMANTIC_CLIPVERTEX:
608 info->writes_clipvertex = true;
609 break;
610 case TGSI_SEMANTIC_COLOR:
611 info->colors_written |= 1 << semIndex;
612 break;
613 case TGSI_SEMANTIC_STENCIL:
614 info->writes_stencil = true;
615 break;
616 case TGSI_SEMANTIC_SAMPLEMASK:
617 info->writes_samplemask = true;
618 break;
619 case TGSI_SEMANTIC_EDGEFLAG:
620 info->writes_edgeflag = true;
621 break;
622 case TGSI_SEMANTIC_POSITION:
623 if (procType == PIPE_SHADER_FRAGMENT)
624 info->writes_z = true;
625 else
626 info->writes_position = true;
627 break;
628 }
629 break;
630
631 case TGSI_FILE_SAMPLER:
632 STATIC_ASSERT(sizeof(info->samplers_declared) * 8 >= PIPE_MAX_SAMPLERS);
633 info->samplers_declared |= 1u << reg;
634 break;
635
636 case TGSI_FILE_SAMPLER_VIEW:
637 target = fulldecl->SamplerView.Resource;
638 type = fulldecl->SamplerView.ReturnTypeX;
639
640 assert(target < TGSI_TEXTURE_UNKNOWN);
641 if (info->sampler_targets[reg] == TGSI_TEXTURE_UNKNOWN) {
642 /* Save sampler target for this sampler index */
643 info->sampler_targets[reg] = target;
644 info->sampler_type[reg] = type;
645 } else {
646 /* if previously declared, make sure targets agree */
647 assert(info->sampler_targets[reg] == target);
648 assert(info->sampler_type[reg] == type);
649 }
650 break;
651 }
652 }
653 }
654
655
656 static void
657 scan_immediate(struct tgsi_shader_info *info)
658 {
659 uint reg = info->immediate_count++;
660 uint file = TGSI_FILE_IMMEDIATE;
661
662 info->file_mask[file] |= (1 << reg);
663 info->file_count[file]++;
664 info->file_max[file] = MAX2(info->file_max[file], (int)reg);
665 }
666
667
668 static void
669 scan_property(struct tgsi_shader_info *info,
670 const struct tgsi_full_property *fullprop)
671 {
672 unsigned name = fullprop->Property.PropertyName;
673 unsigned value = fullprop->u[0].Data;
674
675 assert(name < ARRAY_SIZE(info->properties));
676 info->properties[name] = value;
677
678 switch (name) {
679 case TGSI_PROPERTY_NUM_CLIPDIST_ENABLED:
680 info->num_written_clipdistance = value;
681 info->clipdist_writemask |= (1 << value) - 1;
682 break;
683 case TGSI_PROPERTY_NUM_CULLDIST_ENABLED:
684 info->num_written_culldistance = value;
685 info->culldist_writemask |= (1 << value) - 1;
686 break;
687 }
688 }
689
690
691 /**
692 * Scan the given TGSI shader to collect information such as number of
693 * registers used, special instructions used, etc.
694 * \return info the result of the scan
695 */
696 void
697 tgsi_scan_shader(const struct tgsi_token *tokens,
698 struct tgsi_shader_info *info)
699 {
700 uint procType, i;
701 struct tgsi_parse_context parse;
702 unsigned current_depth = 0;
703
704 memset(info, 0, sizeof(*info));
705 for (i = 0; i < TGSI_FILE_COUNT; i++)
706 info->file_max[i] = -1;
707 for (i = 0; i < ARRAY_SIZE(info->const_file_max); i++)
708 info->const_file_max[i] = -1;
709 info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1;
710 for (i = 0; i < ARRAY_SIZE(info->sampler_targets); i++)
711 info->sampler_targets[i] = TGSI_TEXTURE_UNKNOWN;
712
713 /**
714 ** Setup to begin parsing input shader
715 **/
716 if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) {
717 debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n");
718 return;
719 }
720 procType = parse.FullHeader.Processor.Processor;
721 assert(procType == PIPE_SHADER_FRAGMENT ||
722 procType == PIPE_SHADER_VERTEX ||
723 procType == PIPE_SHADER_GEOMETRY ||
724 procType == PIPE_SHADER_TESS_CTRL ||
725 procType == PIPE_SHADER_TESS_EVAL ||
726 procType == PIPE_SHADER_COMPUTE);
727 info->processor = procType;
728
729 /**
730 ** Loop over incoming program tokens/instructions
731 */
732 while (!tgsi_parse_end_of_tokens(&parse)) {
733 info->num_tokens++;
734
735 tgsi_parse_token( &parse );
736
737 switch( parse.FullToken.Token.Type ) {
738 case TGSI_TOKEN_TYPE_INSTRUCTION:
739 scan_instruction(info, &parse.FullToken.FullInstruction,
740 &current_depth);
741 break;
742 case TGSI_TOKEN_TYPE_DECLARATION:
743 scan_declaration(info, &parse.FullToken.FullDeclaration);
744 break;
745 case TGSI_TOKEN_TYPE_IMMEDIATE:
746 scan_immediate(info);
747 break;
748 case TGSI_TOKEN_TYPE_PROPERTY:
749 scan_property(info, &parse.FullToken.FullProperty);
750 break;
751 default:
752 assert(!"Unexpected TGSI token type");
753 }
754 }
755
756 info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] ||
757 info->opcode_count[TGSI_OPCODE_KILL]);
758
759 /* The dimensions of the IN decleration in geometry shader have
760 * to be deduced from the type of the input primitive.
761 */
762 if (procType == PIPE_SHADER_GEOMETRY) {
763 unsigned input_primitive =
764 info->properties[TGSI_PROPERTY_GS_INPUT_PRIM];
765 int num_verts = u_vertices_per_prim(input_primitive);
766 int j;
767 info->file_count[TGSI_FILE_INPUT] = num_verts;
768 info->file_max[TGSI_FILE_INPUT] =
769 MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1);
770 for (j = 0; j < num_verts; ++j) {
771 info->file_mask[TGSI_FILE_INPUT] |= (1 << j);
772 }
773 }
774
775 tgsi_parse_free(&parse);
776 }
777
778 /**
779 * Collect information about the arrays of a given register file.
780 *
781 * @param tokens TGSI shader
782 * @param file the register file to scan through
783 * @param max_array_id number of entries in @p arrays; should be equal to the
784 * highest array id, i.e. tgsi_shader_info::array_max[file].
785 * @param arrays info for array of each ID will be written to arrays[ID - 1].
786 */
787 void
788 tgsi_scan_arrays(const struct tgsi_token *tokens,
789 unsigned file,
790 unsigned max_array_id,
791 struct tgsi_array_info *arrays)
792 {
793 struct tgsi_parse_context parse;
794
795 if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
796 debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n");
797 return;
798 }
799
800 memset(arrays, 0, sizeof(arrays[0]) * max_array_id);
801
802 while (!tgsi_parse_end_of_tokens(&parse)) {
803 struct tgsi_full_instruction *inst;
804
805 tgsi_parse_token(&parse);
806
807 if (parse.FullToken.Token.Type == TGSI_TOKEN_TYPE_DECLARATION) {
808 struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration;
809
810 if (decl->Declaration.Array && decl->Declaration.File == file &&
811 decl->Array.ArrayID > 0 && decl->Array.ArrayID <= max_array_id) {
812 struct tgsi_array_info *array = &arrays[decl->Array.ArrayID - 1];
813 assert(!array->declared);
814 array->declared = true;
815 array->range = decl->Range;
816 }
817 }
818
819 if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION)
820 continue;
821
822 inst = &parse.FullToken.FullInstruction;
823 for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {
824 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
825 if (dst->Register.File != file)
826 continue;
827
828 if (dst->Register.Indirect) {
829 if (dst->Indirect.ArrayID > 0 &&
830 dst->Indirect.ArrayID <= max_array_id) {
831 arrays[dst->Indirect.ArrayID - 1].writemask |= dst->Register.WriteMask;
832 } else {
833 /* Indirect writes without an ArrayID can write anywhere. */
834 for (unsigned j = 0; j < max_array_id; ++j)
835 arrays[j].writemask |= dst->Register.WriteMask;
836 }
837 } else {
838 /* Check whether the write falls into any of the arrays anyway. */
839 for (unsigned j = 0; j < max_array_id; ++j) {
840 struct tgsi_array_info *array = &arrays[j];
841 if (array->declared &&
842 dst->Register.Index >= array->range.First &&
843 dst->Register.Index <= array->range.Last)
844 array->writemask |= dst->Register.WriteMask;
845 }
846 }
847 }
848 }
849
850 tgsi_parse_free(&parse);
851
852 return;
853 }
854
855
856 /**
857 * Check if the given shader is a "passthrough" shader consisting of only
858 * MOV instructions of the form: MOV OUT[n], IN[n]
859 *
860 */
861 boolean
862 tgsi_is_passthrough_shader(const struct tgsi_token *tokens)
863 {
864 struct tgsi_parse_context parse;
865
866 /**
867 ** Setup to begin parsing input shader
868 **/
869 if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
870 debug_printf("tgsi_parse_init() failed in tgsi_is_passthrough_shader()!\n");
871 return FALSE;
872 }
873
874 /**
875 ** Loop over incoming program tokens/instructions
876 */
877 while (!tgsi_parse_end_of_tokens(&parse)) {
878
879 tgsi_parse_token(&parse);
880
881 switch (parse.FullToken.Token.Type) {
882 case TGSI_TOKEN_TYPE_INSTRUCTION:
883 {
884 struct tgsi_full_instruction *fullinst =
885 &parse.FullToken.FullInstruction;
886 const struct tgsi_full_src_register *src =
887 &fullinst->Src[0];
888 const struct tgsi_full_dst_register *dst =
889 &fullinst->Dst[0];
890
891 /* Do a whole bunch of checks for a simple move */
892 if (fullinst->Instruction.Opcode != TGSI_OPCODE_MOV ||
893 (src->Register.File != TGSI_FILE_INPUT &&
894 src->Register.File != TGSI_FILE_SYSTEM_VALUE) ||
895 dst->Register.File != TGSI_FILE_OUTPUT ||
896 src->Register.Index != dst->Register.Index ||
897
898 src->Register.Negate ||
899 src->Register.Absolute ||
900
901 src->Register.SwizzleX != TGSI_SWIZZLE_X ||
902 src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
903 src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
904 src->Register.SwizzleW != TGSI_SWIZZLE_W ||
905
906 dst->Register.WriteMask != TGSI_WRITEMASK_XYZW)
907 {
908 tgsi_parse_free(&parse);
909 return FALSE;
910 }
911 }
912 break;
913
914 case TGSI_TOKEN_TYPE_DECLARATION:
915 /* fall-through */
916 case TGSI_TOKEN_TYPE_IMMEDIATE:
917 /* fall-through */
918 case TGSI_TOKEN_TYPE_PROPERTY:
919 /* fall-through */
920 default:
921 ; /* no-op */
922 }
923 }
924
925 tgsi_parse_free(&parse);
926
927 /* if we get here, it's a pass-through shader */
928 return TRUE;
929 }