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