tgsi/scan: take advantage of already swizzled usage mask in scan_src_operand
[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_LODQ;
64 }
65
66 /**
67 * Is the opcode a "true" texture instruction which samples from a
68 * texture map?
69 */
70 static bool
71 is_texture_inst(unsigned opcode)
72 {
73 return (!is_mem_query_inst(opcode) &&
74 tgsi_get_opcode_info(opcode)->is_tex);
75 }
76
77
78 /**
79 * Is the opcode an instruction which computes a derivative explicitly or
80 * implicitly?
81 */
82 static bool
83 computes_derivative(unsigned opcode)
84 {
85 if (tgsi_get_opcode_info(opcode)->is_tex) {
86 return opcode != TGSI_OPCODE_TG4 &&
87 opcode != TGSI_OPCODE_TXD &&
88 opcode != TGSI_OPCODE_TXF &&
89 opcode != TGSI_OPCODE_TXF_LZ &&
90 opcode != TGSI_OPCODE_TEX_LZ &&
91 opcode != TGSI_OPCODE_TXL &&
92 opcode != TGSI_OPCODE_TXL2 &&
93 opcode != TGSI_OPCODE_TXQ &&
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_after_swizzle,
111 bool is_interp_instruction,
112 bool *is_mem_inst)
113 {
114 int ind = src->Register.Index;
115
116 if (info->processor == PIPE_SHADER_COMPUTE &&
117 src->Register.File == TGSI_FILE_SYSTEM_VALUE) {
118 unsigned name, mask;
119
120 name = info->system_value_semantic_name[src->Register.Index];
121
122 switch (name) {
123 case TGSI_SEMANTIC_THREAD_ID:
124 case TGSI_SEMANTIC_BLOCK_ID:
125 mask = usage_mask_after_swizzle & TGSI_WRITEMASK_XYZ;
126 while (mask) {
127 unsigned i = u_bit_scan(&mask);
128
129 if (name == TGSI_SEMANTIC_THREAD_ID)
130 info->uses_thread_id[i] = true;
131 else
132 info->uses_block_id[i] = true;
133 }
134 break;
135 case TGSI_SEMANTIC_BLOCK_SIZE:
136 /* The block size is translated to IMM with a fixed block size. */
137 if (info->properties[TGSI_PROPERTY_CS_FIXED_BLOCK_WIDTH] == 0)
138 info->uses_block_size = true;
139 break;
140 case TGSI_SEMANTIC_GRID_SIZE:
141 info->uses_grid_size = true;
142 break;
143 }
144 }
145
146 /* Mark which inputs are effectively used */
147 if (src->Register.File == TGSI_FILE_INPUT) {
148 if (src->Register.Indirect) {
149 for (ind = 0; ind < info->num_inputs; ++ind) {
150 info->input_usage_mask[ind] |= usage_mask_after_swizzle;
151 }
152 } else {
153 assert(ind >= 0);
154 assert(ind < PIPE_MAX_SHADER_INPUTS);
155 info->input_usage_mask[ind] |= usage_mask_after_swizzle;
156 }
157
158 if (info->processor == PIPE_SHADER_FRAGMENT) {
159 unsigned name, index, input;
160
161 if (src->Register.Indirect && src->Indirect.ArrayID)
162 input = info->input_array_first[src->Indirect.ArrayID];
163 else
164 input = src->Register.Index;
165
166 name = info->input_semantic_name[input];
167 index = info->input_semantic_index[input];
168
169 if (name == TGSI_SEMANTIC_POSITION &&
170 usage_mask_after_swizzle & TGSI_WRITEMASK_Z)
171 info->reads_z = true;
172
173 if (name == TGSI_SEMANTIC_COLOR)
174 info->colors_read |= usage_mask_after_swizzle << (index * 4);
175
176 /* Process only interpolated varyings. Don't include POSITION.
177 * Don't include integer varyings, because they are not
178 * interpolated. Don't process inputs interpolated by INTERP
179 * opcodes. Those are tracked separately.
180 */
181 if ((!is_interp_instruction || src_index != 0) &&
182 (name == TGSI_SEMANTIC_GENERIC ||
183 name == TGSI_SEMANTIC_TEXCOORD ||
184 name == TGSI_SEMANTIC_COLOR ||
185 name == TGSI_SEMANTIC_BCOLOR ||
186 name == TGSI_SEMANTIC_FOG ||
187 name == TGSI_SEMANTIC_CLIPDIST)) {
188 switch (info->input_interpolate[input]) {
189 case TGSI_INTERPOLATE_COLOR:
190 case TGSI_INTERPOLATE_PERSPECTIVE:
191 switch (info->input_interpolate_loc[input]) {
192 case TGSI_INTERPOLATE_LOC_CENTER:
193 info->uses_persp_center = TRUE;
194 break;
195 case TGSI_INTERPOLATE_LOC_CENTROID:
196 info->uses_persp_centroid = TRUE;
197 break;
198 case TGSI_INTERPOLATE_LOC_SAMPLE:
199 info->uses_persp_sample = TRUE;
200 break;
201 }
202 break;
203 case TGSI_INTERPOLATE_LINEAR:
204 switch (info->input_interpolate_loc[input]) {
205 case TGSI_INTERPOLATE_LOC_CENTER:
206 info->uses_linear_center = TRUE;
207 break;
208 case TGSI_INTERPOLATE_LOC_CENTROID:
209 info->uses_linear_centroid = TRUE;
210 break;
211 case TGSI_INTERPOLATE_LOC_SAMPLE:
212 info->uses_linear_sample = TRUE;
213 break;
214 }
215 break;
216 /* TGSI_INTERPOLATE_CONSTANT doesn't do any interpolation. */
217 }
218 }
219 }
220 }
221
222 if (info->processor == PIPE_SHADER_TESS_CTRL &&
223 src->Register.File == TGSI_FILE_OUTPUT) {
224 unsigned input;
225
226 if (src->Register.Indirect && src->Indirect.ArrayID)
227 input = info->output_array_first[src->Indirect.ArrayID];
228 else
229 input = src->Register.Index;
230
231 switch (info->output_semantic_name[input]) {
232 case TGSI_SEMANTIC_PATCH:
233 info->reads_perpatch_outputs = true;
234 break;
235 case TGSI_SEMANTIC_TESSINNER:
236 case TGSI_SEMANTIC_TESSOUTER:
237 info->reads_tessfactor_outputs = true;
238 break;
239 default:
240 info->reads_pervertex_outputs = true;
241 }
242 }
243
244 /* check for indirect register reads */
245 if (src->Register.Indirect) {
246 info->indirect_files |= (1 << src->Register.File);
247 info->indirect_files_read |= (1 << src->Register.File);
248
249 /* record indirect constant buffer indexing */
250 if (src->Register.File == TGSI_FILE_CONSTANT) {
251 if (src->Register.Dimension) {
252 if (src->Dimension.Indirect)
253 info->const_buffers_indirect = info->const_buffers_declared;
254 else
255 info->const_buffers_indirect |= 1u << src->Dimension.Index;
256 } else {
257 info->const_buffers_indirect |= 1;
258 }
259 }
260 }
261
262 if (src->Register.Dimension && src->Dimension.Indirect)
263 info->dim_indirect_files |= 1u << src->Register.File;
264
265 /* Texture samplers */
266 if (src->Register.File == TGSI_FILE_SAMPLER) {
267 const unsigned index = src->Register.Index;
268
269 assert(fullinst->Instruction.Texture);
270 assert(index < ARRAY_SIZE(info->is_msaa_sampler));
271 assert(index < PIPE_MAX_SAMPLERS);
272
273 if (is_texture_inst(fullinst->Instruction.Opcode)) {
274 const unsigned target = fullinst->Texture.Texture;
275 assert(target < TGSI_TEXTURE_UNKNOWN);
276 /* for texture instructions, check that the texture instruction
277 * target matches the previous sampler view declaration (if there
278 * was one.)
279 */
280 if (info->sampler_targets[index] == TGSI_TEXTURE_UNKNOWN) {
281 /* probably no sampler view declaration */
282 info->sampler_targets[index] = target;
283 } else {
284 /* Make sure the texture instruction's sampler/target info
285 * agrees with the sampler view declaration.
286 */
287 assert(info->sampler_targets[index] == target);
288 }
289 /* MSAA samplers */
290 if (target == TGSI_TEXTURE_2D_MSAA ||
291 target == TGSI_TEXTURE_2D_ARRAY_MSAA) {
292 info->is_msaa_sampler[src->Register.Index] = TRUE;
293 }
294 }
295 }
296
297 if (is_memory_file(src->Register.File) &&
298 !is_mem_query_inst(fullinst->Instruction.Opcode)) {
299 *is_mem_inst = true;
300
301 if (tgsi_get_opcode_info(fullinst->Instruction.Opcode)->is_store) {
302 info->writes_memory = TRUE;
303
304 if (src->Register.File == TGSI_FILE_IMAGE) {
305 if (src->Register.Indirect)
306 info->images_atomic = info->images_declared;
307 else
308 info->images_atomic |= 1 << src->Register.Index;
309 } else if (src->Register.File == TGSI_FILE_BUFFER) {
310 if (src->Register.Indirect)
311 info->shader_buffers_atomic = info->shader_buffers_declared;
312 else
313 info->shader_buffers_atomic |= 1 << src->Register.Index;
314 }
315 } else {
316 if (src->Register.File == TGSI_FILE_IMAGE) {
317 if (src->Register.Indirect)
318 info->images_load = info->images_declared;
319 else
320 info->images_load |= 1 << src->Register.Index;
321 } else if (src->Register.File == TGSI_FILE_BUFFER) {
322 if (src->Register.Indirect)
323 info->shader_buffers_load = info->shader_buffers_declared;
324 else
325 info->shader_buffers_load |= 1 << src->Register.Index;
326 }
327 }
328 }
329 }
330
331
332 static void
333 scan_instruction(struct tgsi_shader_info *info,
334 const struct tgsi_full_instruction *fullinst,
335 unsigned *current_depth)
336 {
337 unsigned i;
338 bool is_mem_inst = false;
339 bool is_interp_instruction = false;
340 unsigned sampler_src;
341
342 assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST);
343 info->opcode_count[fullinst->Instruction.Opcode]++;
344
345 switch (fullinst->Instruction.Opcode) {
346 case TGSI_OPCODE_IF:
347 case TGSI_OPCODE_UIF:
348 case TGSI_OPCODE_BGNLOOP:
349 (*current_depth)++;
350 info->max_depth = MAX2(info->max_depth, *current_depth);
351 break;
352 case TGSI_OPCODE_ENDIF:
353 case TGSI_OPCODE_ENDLOOP:
354 (*current_depth)--;
355 break;
356 case TGSI_OPCODE_TEX:
357 case TGSI_OPCODE_TEX_LZ:
358 case TGSI_OPCODE_TXB:
359 case TGSI_OPCODE_TXD:
360 case TGSI_OPCODE_TXL:
361 case TGSI_OPCODE_TXP:
362 case TGSI_OPCODE_TXQ:
363 case TGSI_OPCODE_TXQS:
364 case TGSI_OPCODE_TXF:
365 case TGSI_OPCODE_TXF_LZ:
366 case TGSI_OPCODE_TEX2:
367 case TGSI_OPCODE_TXB2:
368 case TGSI_OPCODE_TXL2:
369 case TGSI_OPCODE_TG4:
370 case TGSI_OPCODE_LODQ:
371 sampler_src = fullinst->Instruction.NumSrcRegs - 1;
372 if (fullinst->Src[sampler_src].Register.File != TGSI_FILE_SAMPLER)
373 info->uses_bindless_samplers = true;
374 break;
375 case TGSI_OPCODE_RESQ:
376 case TGSI_OPCODE_LOAD:
377 case TGSI_OPCODE_ATOMUADD:
378 case TGSI_OPCODE_ATOMXCHG:
379 case TGSI_OPCODE_ATOMCAS:
380 case TGSI_OPCODE_ATOMAND:
381 case TGSI_OPCODE_ATOMOR:
382 case TGSI_OPCODE_ATOMXOR:
383 case TGSI_OPCODE_ATOMUMIN:
384 case TGSI_OPCODE_ATOMUMAX:
385 case TGSI_OPCODE_ATOMIMIN:
386 case TGSI_OPCODE_ATOMIMAX:
387 if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File))
388 info->uses_bindless_images = true;
389 break;
390 case TGSI_OPCODE_STORE:
391 if (tgsi_is_bindless_image_file(fullinst->Dst[0].Register.File))
392 info->uses_bindless_images = true;
393 break;
394 default:
395 break;
396 }
397
398 if (fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_CENTROID ||
399 fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET ||
400 fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) {
401 const struct tgsi_full_src_register *src0 = &fullinst->Src[0];
402 unsigned input;
403
404 is_interp_instruction = true;
405
406 if (src0->Register.Indirect && src0->Indirect.ArrayID)
407 input = info->input_array_first[src0->Indirect.ArrayID];
408 else
409 input = src0->Register.Index;
410
411 /* For the INTERP opcodes, the interpolation is always
412 * PERSPECTIVE unless LINEAR is specified.
413 */
414 switch (info->input_interpolate[input]) {
415 case TGSI_INTERPOLATE_COLOR:
416 case TGSI_INTERPOLATE_CONSTANT:
417 case TGSI_INTERPOLATE_PERSPECTIVE:
418 switch (fullinst->Instruction.Opcode) {
419 case TGSI_OPCODE_INTERP_CENTROID:
420 info->uses_persp_opcode_interp_centroid = TRUE;
421 break;
422 case TGSI_OPCODE_INTERP_OFFSET:
423 info->uses_persp_opcode_interp_offset = TRUE;
424 break;
425 case TGSI_OPCODE_INTERP_SAMPLE:
426 info->uses_persp_opcode_interp_sample = TRUE;
427 break;
428 }
429 break;
430
431 case TGSI_INTERPOLATE_LINEAR:
432 switch (fullinst->Instruction.Opcode) {
433 case TGSI_OPCODE_INTERP_CENTROID:
434 info->uses_linear_opcode_interp_centroid = TRUE;
435 break;
436 case TGSI_OPCODE_INTERP_OFFSET:
437 info->uses_linear_opcode_interp_offset = TRUE;
438 break;
439 case TGSI_OPCODE_INTERP_SAMPLE:
440 info->uses_linear_opcode_interp_sample = TRUE;
441 break;
442 }
443 break;
444 }
445 }
446
447 if ((fullinst->Instruction.Opcode >= TGSI_OPCODE_F2D &&
448 fullinst->Instruction.Opcode <= TGSI_OPCODE_DSSG) ||
449 fullinst->Instruction.Opcode == TGSI_OPCODE_DFMA ||
450 fullinst->Instruction.Opcode == TGSI_OPCODE_DDIV ||
451 fullinst->Instruction.Opcode == TGSI_OPCODE_D2U64 ||
452 fullinst->Instruction.Opcode == TGSI_OPCODE_D2I64 ||
453 fullinst->Instruction.Opcode == TGSI_OPCODE_U642D ||
454 fullinst->Instruction.Opcode == TGSI_OPCODE_I642D)
455 info->uses_doubles = TRUE;
456
457 for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
458 scan_src_operand(info, fullinst, &fullinst->Src[i], i,
459 tgsi_util_get_inst_usage_mask(fullinst, i),
460 is_interp_instruction, &is_mem_inst);
461 }
462
463 if (fullinst->Instruction.Texture) {
464 for (i = 0; i < fullinst->Texture.NumOffsets; i++) {
465 struct tgsi_full_src_register src = {{0}};
466
467 src.Register.File = fullinst->TexOffsets[i].File;
468 src.Register.Index = fullinst->TexOffsets[i].Index;
469 src.Register.SwizzleX = fullinst->TexOffsets[i].SwizzleX;
470 src.Register.SwizzleY = fullinst->TexOffsets[i].SwizzleY;
471 src.Register.SwizzleZ = fullinst->TexOffsets[i].SwizzleZ;
472
473 /* The usage mask is suboptimal but should be safe. */
474 scan_src_operand(info, fullinst, &src, -1, TGSI_WRITEMASK_XYZ,
475 false, &is_mem_inst);
476 }
477 }
478
479 /* check for indirect register writes */
480 for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) {
481 const struct tgsi_full_dst_register *dst = &fullinst->Dst[i];
482 if (dst->Register.Indirect) {
483 info->indirect_files |= (1 << dst->Register.File);
484 info->indirect_files_written |= (1 << dst->Register.File);
485 }
486
487 if (dst->Register.Dimension && dst->Dimension.Indirect)
488 info->dim_indirect_files |= 1u << dst->Register.File;
489
490 if (is_memory_file(dst->Register.File)) {
491 assert(fullinst->Instruction.Opcode == TGSI_OPCODE_STORE);
492
493 is_mem_inst = true;
494 info->writes_memory = TRUE;
495
496 if (dst->Register.File == TGSI_FILE_IMAGE) {
497 if (dst->Register.Indirect)
498 info->images_store = info->images_declared;
499 else
500 info->images_store |= 1 << dst->Register.Index;
501 } else if (dst->Register.File == TGSI_FILE_BUFFER) {
502 if (dst->Register.Indirect)
503 info->shader_buffers_store = info->shader_buffers_declared;
504 else
505 info->shader_buffers_store |= 1 << dst->Register.Index;
506 }
507 }
508 }
509
510 if (is_mem_inst)
511 info->num_memory_instructions++;
512
513 if (computes_derivative(fullinst->Instruction.Opcode))
514 info->uses_derivatives = true;
515
516 info->num_instructions++;
517 }
518
519
520 static void
521 scan_declaration(struct tgsi_shader_info *info,
522 const struct tgsi_full_declaration *fulldecl)
523 {
524 const uint file = fulldecl->Declaration.File;
525 const unsigned procType = info->processor;
526 uint reg;
527
528 if (fulldecl->Declaration.Array) {
529 unsigned array_id = fulldecl->Array.ArrayID;
530
531 switch (file) {
532 case TGSI_FILE_INPUT:
533 assert(array_id < ARRAY_SIZE(info->input_array_first));
534 info->input_array_first[array_id] = fulldecl->Range.First;
535 info->input_array_last[array_id] = fulldecl->Range.Last;
536 break;
537 case TGSI_FILE_OUTPUT:
538 assert(array_id < ARRAY_SIZE(info->output_array_first));
539 info->output_array_first[array_id] = fulldecl->Range.First;
540 info->output_array_last[array_id] = fulldecl->Range.Last;
541 break;
542 }
543 info->array_max[file] = MAX2(info->array_max[file], array_id);
544 }
545
546 for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) {
547 unsigned semName = fulldecl->Semantic.Name;
548 unsigned semIndex = fulldecl->Semantic.Index +
549 (reg - fulldecl->Range.First);
550 int buffer;
551 unsigned index, target, type;
552
553 /* only first 32 regs will appear in this bitfield */
554 info->file_mask[file] |= (1 << reg);
555 info->file_count[file]++;
556 info->file_max[file] = MAX2(info->file_max[file], (int)reg);
557
558 switch (file) {
559 case TGSI_FILE_CONSTANT:
560 buffer = 0;
561
562 if (fulldecl->Declaration.Dimension)
563 buffer = fulldecl->Dim.Index2D;
564
565 info->const_file_max[buffer] =
566 MAX2(info->const_file_max[buffer], (int)reg);
567 info->const_buffers_declared |= 1u << buffer;
568 break;
569
570 case TGSI_FILE_IMAGE:
571 info->images_declared |= 1u << reg;
572 if (fulldecl->Image.Resource == TGSI_TEXTURE_BUFFER)
573 info->images_buffers |= 1 << reg;
574 break;
575
576 case TGSI_FILE_BUFFER:
577 info->shader_buffers_declared |= 1u << reg;
578 break;
579
580 case TGSI_FILE_INPUT:
581 info->input_semantic_name[reg] = (ubyte) semName;
582 info->input_semantic_index[reg] = (ubyte) semIndex;
583 info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate;
584 info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location;
585 info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap;
586
587 /* Vertex shaders can have inputs with holes between them. */
588 info->num_inputs = MAX2(info->num_inputs, reg + 1);
589
590 switch (semName) {
591 case TGSI_SEMANTIC_PRIMID:
592 info->uses_primid = true;
593 break;
594 case TGSI_SEMANTIC_POSITION:
595 info->reads_position = true;
596 break;
597 case TGSI_SEMANTIC_FACE:
598 info->uses_frontface = true;
599 break;
600 }
601 break;
602
603 case TGSI_FILE_SYSTEM_VALUE:
604 index = fulldecl->Range.First;
605
606 info->system_value_semantic_name[index] = semName;
607 info->num_system_values = MAX2(info->num_system_values, index + 1);
608
609 switch (semName) {
610 case TGSI_SEMANTIC_INSTANCEID:
611 info->uses_instanceid = TRUE;
612 break;
613 case TGSI_SEMANTIC_VERTEXID:
614 info->uses_vertexid = TRUE;
615 break;
616 case TGSI_SEMANTIC_VERTEXID_NOBASE:
617 info->uses_vertexid_nobase = TRUE;
618 break;
619 case TGSI_SEMANTIC_BASEVERTEX:
620 info->uses_basevertex = TRUE;
621 break;
622 case TGSI_SEMANTIC_PRIMID:
623 info->uses_primid = TRUE;
624 break;
625 case TGSI_SEMANTIC_INVOCATIONID:
626 info->uses_invocationid = TRUE;
627 break;
628 case TGSI_SEMANTIC_POSITION:
629 info->reads_position = TRUE;
630 break;
631 case TGSI_SEMANTIC_FACE:
632 info->uses_frontface = TRUE;
633 break;
634 case TGSI_SEMANTIC_SAMPLEMASK:
635 info->reads_samplemask = TRUE;
636 break;
637 case TGSI_SEMANTIC_TESSINNER:
638 case TGSI_SEMANTIC_TESSOUTER:
639 info->reads_tess_factors = true;
640 break;
641 }
642 break;
643
644 case TGSI_FILE_OUTPUT:
645 info->output_semantic_name[reg] = (ubyte) semName;
646 info->output_semantic_index[reg] = (ubyte) semIndex;
647 info->output_usagemask[reg] |= fulldecl->Declaration.UsageMask;
648 info->num_outputs = MAX2(info->num_outputs, reg + 1);
649
650 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_X) {
651 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamX;
652 info->num_stream_output_components[fulldecl->Semantic.StreamX]++;
653 }
654 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Y) {
655 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamY << 2;
656 info->num_stream_output_components[fulldecl->Semantic.StreamY]++;
657 }
658 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Z) {
659 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamZ << 4;
660 info->num_stream_output_components[fulldecl->Semantic.StreamZ]++;
661 }
662 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_W) {
663 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamW << 6;
664 info->num_stream_output_components[fulldecl->Semantic.StreamW]++;
665 }
666
667 switch (semName) {
668 case TGSI_SEMANTIC_PRIMID:
669 info->writes_primid = true;
670 break;
671 case TGSI_SEMANTIC_VIEWPORT_INDEX:
672 info->writes_viewport_index = true;
673 break;
674 case TGSI_SEMANTIC_LAYER:
675 info->writes_layer = true;
676 break;
677 case TGSI_SEMANTIC_PSIZE:
678 info->writes_psize = true;
679 break;
680 case TGSI_SEMANTIC_CLIPVERTEX:
681 info->writes_clipvertex = true;
682 break;
683 case TGSI_SEMANTIC_COLOR:
684 info->colors_written |= 1 << semIndex;
685 break;
686 case TGSI_SEMANTIC_STENCIL:
687 info->writes_stencil = true;
688 break;
689 case TGSI_SEMANTIC_SAMPLEMASK:
690 info->writes_samplemask = true;
691 break;
692 case TGSI_SEMANTIC_EDGEFLAG:
693 info->writes_edgeflag = true;
694 break;
695 case TGSI_SEMANTIC_POSITION:
696 if (procType == PIPE_SHADER_FRAGMENT)
697 info->writes_z = true;
698 else
699 info->writes_position = true;
700 break;
701 }
702 break;
703
704 case TGSI_FILE_SAMPLER:
705 STATIC_ASSERT(sizeof(info->samplers_declared) * 8 >= PIPE_MAX_SAMPLERS);
706 info->samplers_declared |= 1u << reg;
707 break;
708
709 case TGSI_FILE_SAMPLER_VIEW:
710 target = fulldecl->SamplerView.Resource;
711 type = fulldecl->SamplerView.ReturnTypeX;
712
713 assert(target < TGSI_TEXTURE_UNKNOWN);
714 if (info->sampler_targets[reg] == TGSI_TEXTURE_UNKNOWN) {
715 /* Save sampler target for this sampler index */
716 info->sampler_targets[reg] = target;
717 info->sampler_type[reg] = type;
718 } else {
719 /* if previously declared, make sure targets agree */
720 assert(info->sampler_targets[reg] == target);
721 assert(info->sampler_type[reg] == type);
722 }
723 break;
724 }
725 }
726 }
727
728
729 static void
730 scan_immediate(struct tgsi_shader_info *info)
731 {
732 uint reg = info->immediate_count++;
733 uint file = TGSI_FILE_IMMEDIATE;
734
735 info->file_mask[file] |= (1 << reg);
736 info->file_count[file]++;
737 info->file_max[file] = MAX2(info->file_max[file], (int)reg);
738 }
739
740
741 static void
742 scan_property(struct tgsi_shader_info *info,
743 const struct tgsi_full_property *fullprop)
744 {
745 unsigned name = fullprop->Property.PropertyName;
746 unsigned value = fullprop->u[0].Data;
747
748 assert(name < ARRAY_SIZE(info->properties));
749 info->properties[name] = value;
750
751 switch (name) {
752 case TGSI_PROPERTY_NUM_CLIPDIST_ENABLED:
753 info->num_written_clipdistance = value;
754 info->clipdist_writemask |= (1 << value) - 1;
755 break;
756 case TGSI_PROPERTY_NUM_CULLDIST_ENABLED:
757 info->num_written_culldistance = value;
758 info->culldist_writemask |= (1 << value) - 1;
759 break;
760 }
761 }
762
763
764 /**
765 * Scan the given TGSI shader to collect information such as number of
766 * registers used, special instructions used, etc.
767 * \return info the result of the scan
768 */
769 void
770 tgsi_scan_shader(const struct tgsi_token *tokens,
771 struct tgsi_shader_info *info)
772 {
773 uint procType, i;
774 struct tgsi_parse_context parse;
775 unsigned current_depth = 0;
776
777 memset(info, 0, sizeof(*info));
778 for (i = 0; i < TGSI_FILE_COUNT; i++)
779 info->file_max[i] = -1;
780 for (i = 0; i < ARRAY_SIZE(info->const_file_max); i++)
781 info->const_file_max[i] = -1;
782 info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1;
783 for (i = 0; i < ARRAY_SIZE(info->sampler_targets); i++)
784 info->sampler_targets[i] = TGSI_TEXTURE_UNKNOWN;
785
786 /**
787 ** Setup to begin parsing input shader
788 **/
789 if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) {
790 debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n");
791 return;
792 }
793 procType = parse.FullHeader.Processor.Processor;
794 assert(procType == PIPE_SHADER_FRAGMENT ||
795 procType == PIPE_SHADER_VERTEX ||
796 procType == PIPE_SHADER_GEOMETRY ||
797 procType == PIPE_SHADER_TESS_CTRL ||
798 procType == PIPE_SHADER_TESS_EVAL ||
799 procType == PIPE_SHADER_COMPUTE);
800 info->processor = procType;
801
802 /**
803 ** Loop over incoming program tokens/instructions
804 */
805 while (!tgsi_parse_end_of_tokens(&parse)) {
806 info->num_tokens++;
807
808 tgsi_parse_token( &parse );
809
810 switch( parse.FullToken.Token.Type ) {
811 case TGSI_TOKEN_TYPE_INSTRUCTION:
812 scan_instruction(info, &parse.FullToken.FullInstruction,
813 &current_depth);
814 break;
815 case TGSI_TOKEN_TYPE_DECLARATION:
816 scan_declaration(info, &parse.FullToken.FullDeclaration);
817 break;
818 case TGSI_TOKEN_TYPE_IMMEDIATE:
819 scan_immediate(info);
820 break;
821 case TGSI_TOKEN_TYPE_PROPERTY:
822 scan_property(info, &parse.FullToken.FullProperty);
823 break;
824 default:
825 assert(!"Unexpected TGSI token type");
826 }
827 }
828
829 info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] ||
830 info->opcode_count[TGSI_OPCODE_KILL]);
831
832 /* The dimensions of the IN decleration in geometry shader have
833 * to be deduced from the type of the input primitive.
834 */
835 if (procType == PIPE_SHADER_GEOMETRY) {
836 unsigned input_primitive =
837 info->properties[TGSI_PROPERTY_GS_INPUT_PRIM];
838 int num_verts = u_vertices_per_prim(input_primitive);
839 int j;
840 info->file_count[TGSI_FILE_INPUT] = num_verts;
841 info->file_max[TGSI_FILE_INPUT] =
842 MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1);
843 for (j = 0; j < num_verts; ++j) {
844 info->file_mask[TGSI_FILE_INPUT] |= (1 << j);
845 }
846 }
847
848 tgsi_parse_free(&parse);
849 }
850
851 /**
852 * Collect information about the arrays of a given register file.
853 *
854 * @param tokens TGSI shader
855 * @param file the register file to scan through
856 * @param max_array_id number of entries in @p arrays; should be equal to the
857 * highest array id, i.e. tgsi_shader_info::array_max[file].
858 * @param arrays info for array of each ID will be written to arrays[ID - 1].
859 */
860 void
861 tgsi_scan_arrays(const struct tgsi_token *tokens,
862 unsigned file,
863 unsigned max_array_id,
864 struct tgsi_array_info *arrays)
865 {
866 struct tgsi_parse_context parse;
867
868 if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
869 debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n");
870 return;
871 }
872
873 memset(arrays, 0, sizeof(arrays[0]) * max_array_id);
874
875 while (!tgsi_parse_end_of_tokens(&parse)) {
876 struct tgsi_full_instruction *inst;
877
878 tgsi_parse_token(&parse);
879
880 if (parse.FullToken.Token.Type == TGSI_TOKEN_TYPE_DECLARATION) {
881 struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration;
882
883 if (decl->Declaration.Array && decl->Declaration.File == file &&
884 decl->Array.ArrayID > 0 && decl->Array.ArrayID <= max_array_id) {
885 struct tgsi_array_info *array = &arrays[decl->Array.ArrayID - 1];
886 assert(!array->declared);
887 array->declared = true;
888 array->range = decl->Range;
889 }
890 }
891
892 if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION)
893 continue;
894
895 inst = &parse.FullToken.FullInstruction;
896 for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {
897 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
898 if (dst->Register.File != file)
899 continue;
900
901 if (dst->Register.Indirect) {
902 if (dst->Indirect.ArrayID > 0 &&
903 dst->Indirect.ArrayID <= max_array_id) {
904 arrays[dst->Indirect.ArrayID - 1].writemask |= dst->Register.WriteMask;
905 } else {
906 /* Indirect writes without an ArrayID can write anywhere. */
907 for (unsigned j = 0; j < max_array_id; ++j)
908 arrays[j].writemask |= dst->Register.WriteMask;
909 }
910 } else {
911 /* Check whether the write falls into any of the arrays anyway. */
912 for (unsigned j = 0; j < max_array_id; ++j) {
913 struct tgsi_array_info *array = &arrays[j];
914 if (array->declared &&
915 dst->Register.Index >= array->range.First &&
916 dst->Register.Index <= array->range.Last)
917 array->writemask |= dst->Register.WriteMask;
918 }
919 }
920 }
921 }
922
923 tgsi_parse_free(&parse);
924
925 return;
926 }
927
928 static void
929 check_no_subroutines(const struct tgsi_full_instruction *inst)
930 {
931 switch (inst->Instruction.Opcode) {
932 case TGSI_OPCODE_BGNSUB:
933 case TGSI_OPCODE_ENDSUB:
934 case TGSI_OPCODE_CAL:
935 unreachable("subroutines unhandled");
936 }
937 }
938
939 static unsigned
940 get_inst_tessfactor_writemask(const struct tgsi_shader_info *info,
941 const struct tgsi_full_instruction *inst)
942 {
943 unsigned writemask = 0;
944
945 for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) {
946 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
947
948 if (dst->Register.File == TGSI_FILE_OUTPUT &&
949 !dst->Register.Indirect) {
950 unsigned name = info->output_semantic_name[dst->Register.Index];
951
952 if (name == TGSI_SEMANTIC_TESSINNER)
953 writemask |= dst->Register.WriteMask;
954 else if (name == TGSI_SEMANTIC_TESSOUTER)
955 writemask |= dst->Register.WriteMask << 4;
956 }
957 }
958 return writemask;
959 }
960
961 static unsigned
962 get_block_tessfactor_writemask(const struct tgsi_shader_info *info,
963 struct tgsi_parse_context *parse,
964 unsigned end_opcode)
965 {
966 struct tgsi_full_instruction *inst;
967 unsigned writemask = 0;
968
969 do {
970 tgsi_parse_token(parse);
971 assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
972 inst = &parse->FullToken.FullInstruction;
973 check_no_subroutines(inst);
974
975 /* Recursively process nested blocks. */
976 switch (inst->Instruction.Opcode) {
977 case TGSI_OPCODE_IF:
978 case TGSI_OPCODE_UIF:
979 writemask |=
980 get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDIF);
981 continue;
982
983 case TGSI_OPCODE_BGNLOOP:
984 writemask |=
985 get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP);
986 continue;
987
988 case TGSI_OPCODE_BARRIER:
989 unreachable("nested BARRIER is illegal");
990 continue;
991 }
992
993 writemask |= get_inst_tessfactor_writemask(info, inst);
994 } while (inst->Instruction.Opcode != end_opcode);
995
996 return writemask;
997 }
998
999 static void
1000 get_if_block_tessfactor_writemask(const struct tgsi_shader_info *info,
1001 struct tgsi_parse_context *parse,
1002 unsigned *upper_block_tf_writemask,
1003 unsigned *cond_block_tf_writemask)
1004 {
1005 struct tgsi_full_instruction *inst;
1006 unsigned then_tessfactor_writemask = 0;
1007 unsigned else_tessfactor_writemask = 0;
1008 bool is_then = true;
1009
1010 do {
1011 tgsi_parse_token(parse);
1012 assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION);
1013 inst = &parse->FullToken.FullInstruction;
1014 check_no_subroutines(inst);
1015
1016 switch (inst->Instruction.Opcode) {
1017 case TGSI_OPCODE_ELSE:
1018 is_then = false;
1019 continue;
1020
1021 /* Recursively process nested blocks. */
1022 case TGSI_OPCODE_IF:
1023 case TGSI_OPCODE_UIF:
1024 get_if_block_tessfactor_writemask(info, parse,
1025 is_then ? &then_tessfactor_writemask :
1026 &else_tessfactor_writemask,
1027 cond_block_tf_writemask);
1028 continue;
1029
1030 case TGSI_OPCODE_BGNLOOP:
1031 *cond_block_tf_writemask |=
1032 get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP);
1033 continue;
1034
1035 case TGSI_OPCODE_BARRIER:
1036 unreachable("nested BARRIER is illegal");
1037 continue;
1038 }
1039
1040 /* Process an instruction in the current block. */
1041 unsigned writemask = get_inst_tessfactor_writemask(info, inst);
1042
1043 if (writemask) {
1044 if (is_then)
1045 then_tessfactor_writemask |= writemask;
1046 else
1047 else_tessfactor_writemask |= writemask;
1048 }
1049 } while (inst->Instruction.Opcode != TGSI_OPCODE_ENDIF);
1050
1051 if (then_tessfactor_writemask || else_tessfactor_writemask) {
1052 /* If both statements write the same tess factor channels,
1053 * we can say that the upper block writes them too. */
1054 *upper_block_tf_writemask |= then_tessfactor_writemask &
1055 else_tessfactor_writemask;
1056 *cond_block_tf_writemask |= then_tessfactor_writemask |
1057 else_tessfactor_writemask;
1058 }
1059 }
1060
1061 void
1062 tgsi_scan_tess_ctrl(const struct tgsi_token *tokens,
1063 const struct tgsi_shader_info *info,
1064 struct tgsi_tessctrl_info *out)
1065 {
1066 memset(out, 0, sizeof(*out));
1067
1068 if (info->processor != PIPE_SHADER_TESS_CTRL)
1069 return;
1070
1071 struct tgsi_parse_context parse;
1072 if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
1073 debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n");
1074 return;
1075 }
1076
1077 /* The pass works as follows:
1078 * If all codepaths write tess factors, we can say that all invocations
1079 * define tess factors.
1080 *
1081 * Each tess factor channel is tracked separately.
1082 */
1083 unsigned main_block_tf_writemask = 0; /* if main block writes tess factors */
1084 unsigned cond_block_tf_writemask = 0; /* if cond block writes tess factors */
1085
1086 /* Initial value = true. Here the pass will accumulate results from multiple
1087 * segments surrounded by barriers. If tess factors aren't written at all,
1088 * it's a shader bug and we don't care if this will be true.
1089 */
1090 out->tessfactors_are_def_in_all_invocs = true;
1091
1092 while (!tgsi_parse_end_of_tokens(&parse)) {
1093 tgsi_parse_token(&parse);
1094
1095 if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION)
1096 continue;
1097
1098 struct tgsi_full_instruction *inst = &parse.FullToken.FullInstruction;
1099 check_no_subroutines(inst);
1100
1101 /* Process nested blocks. */
1102 switch (inst->Instruction.Opcode) {
1103 case TGSI_OPCODE_IF:
1104 case TGSI_OPCODE_UIF:
1105 get_if_block_tessfactor_writemask(info, &parse,
1106 &main_block_tf_writemask,
1107 &cond_block_tf_writemask);
1108 continue;
1109
1110 case TGSI_OPCODE_BGNLOOP:
1111 cond_block_tf_writemask |=
1112 get_block_tessfactor_writemask(info, &parse, TGSI_OPCODE_ENDIF);
1113 continue;
1114
1115 case TGSI_OPCODE_BARRIER:
1116 /* The following case must be prevented:
1117 * gl_TessLevelInner = ...;
1118 * barrier();
1119 * if (gl_InvocationID == 1)
1120 * gl_TessLevelInner = ...;
1121 *
1122 * If you consider disjoint code segments separated by barriers, each
1123 * such segment that writes tess factor channels should write the same
1124 * channels in all codepaths within that segment.
1125 */
1126 if (main_block_tf_writemask || cond_block_tf_writemask) {
1127 /* Accumulate the result: */
1128 out->tessfactors_are_def_in_all_invocs &=
1129 !(cond_block_tf_writemask & ~main_block_tf_writemask);
1130
1131 /* Analyze the next code segment from scratch. */
1132 main_block_tf_writemask = 0;
1133 cond_block_tf_writemask = 0;
1134 }
1135 continue;
1136 }
1137
1138 main_block_tf_writemask |= get_inst_tessfactor_writemask(info, inst);
1139 }
1140
1141 /* Accumulate the result for the last code segment separated by a barrier. */
1142 if (main_block_tf_writemask || cond_block_tf_writemask) {
1143 out->tessfactors_are_def_in_all_invocs &=
1144 !(cond_block_tf_writemask & ~main_block_tf_writemask);
1145 }
1146
1147 tgsi_parse_free(&parse);
1148 }