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 if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File)) 372 info->uses_bindless_images = true; 373 break; 374 case TGSI_OPCODE_LOAD: 375 if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File)) { 376 info->uses_bindless_images = true; 377 378 if (fullinst->Memory.Texture == TGSI_TEXTURE_BUFFER) 379 info->uses_bindless_buffer_load = true; 380 else 381 info->uses_bindless_image_load = true; 382 } 383 break; 384 case TGSI_OPCODE_ATOMUADD: 385 case TGSI_OPCODE_ATOMXCHG: 386 case TGSI_OPCODE_ATOMCAS: 387 case TGSI_OPCODE_ATOMAND: 388 case TGSI_OPCODE_ATOMOR: 389 case TGSI_OPCODE_ATOMXOR: 390 case TGSI_OPCODE_ATOMUMIN: 391 case TGSI_OPCODE_ATOMUMAX: 392 case TGSI_OPCODE_ATOMIMIN: 393 case TGSI_OPCODE_ATOMIMAX: 394 case TGSI_OPCODE_ATOMFADD: 395 if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File)) { 396 info->uses_bindless_images = true; 397 398 if (fullinst->Memory.Texture == TGSI_TEXTURE_BUFFER) 399 info->uses_bindless_buffer_atomic = true; 400 else 401 info->uses_bindless_image_atomic = true; 402 } 403 break; 404 case TGSI_OPCODE_STORE: 405 if (tgsi_is_bindless_image_file(fullinst->Dst[0].Register.File)) { 406 info->uses_bindless_images = true; 407 408 if (fullinst->Memory.Texture == TGSI_TEXTURE_BUFFER) 409 info->uses_bindless_buffer_store = true; 410 else 411 info->uses_bindless_image_store = true; 412 } 413 break; 414 default: 415 break; 416 } 417 418 if (fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_CENTROID || 419 fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET || 420 fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) { 421 const struct tgsi_full_src_register *src0 = &fullinst->Src[0]; 422 unsigned input; 423 424 is_interp_instruction = true; 425 426 if (src0->Register.Indirect && src0->Indirect.ArrayID) 427 input = info->input_array_first[src0->Indirect.ArrayID]; 428 else 429 input = src0->Register.Index; 430 431 /* For the INTERP opcodes, the interpolation is always 432 * PERSPECTIVE unless LINEAR is specified. 433 */ 434 switch (info->input_interpolate[input]) { 435 case TGSI_INTERPOLATE_COLOR: 436 case TGSI_INTERPOLATE_CONSTANT: 437 case TGSI_INTERPOLATE_PERSPECTIVE: 438 switch (fullinst->Instruction.Opcode) { 439 case TGSI_OPCODE_INTERP_CENTROID: 440 info->uses_persp_opcode_interp_centroid = TRUE; 441 break; 442 case TGSI_OPCODE_INTERP_OFFSET: 443 info->uses_persp_opcode_interp_offset = TRUE; 444 break; 445 case TGSI_OPCODE_INTERP_SAMPLE: 446 info->uses_persp_opcode_interp_sample = TRUE; 447 break; 448 } 449 break; 450 451 case TGSI_INTERPOLATE_LINEAR: 452 switch (fullinst->Instruction.Opcode) { 453 case TGSI_OPCODE_INTERP_CENTROID: 454 info->uses_linear_opcode_interp_centroid = TRUE; 455 break; 456 case TGSI_OPCODE_INTERP_OFFSET: 457 info->uses_linear_opcode_interp_offset = TRUE; 458 break; 459 case TGSI_OPCODE_INTERP_SAMPLE: 460 info->uses_linear_opcode_interp_sample = TRUE; 461 break; 462 } 463 break; 464 } 465 } 466 467 if ((fullinst->Instruction.Opcode >= TGSI_OPCODE_F2D && 468 fullinst->Instruction.Opcode <= TGSI_OPCODE_DSSG) || 469 fullinst->Instruction.Opcode == TGSI_OPCODE_DFMA || 470 fullinst->Instruction.Opcode == TGSI_OPCODE_DDIV || 471 fullinst->Instruction.Opcode == TGSI_OPCODE_D2U64 || 472 fullinst->Instruction.Opcode == TGSI_OPCODE_D2I64 || 473 fullinst->Instruction.Opcode == TGSI_OPCODE_U642D || 474 fullinst->Instruction.Opcode == TGSI_OPCODE_I642D) 475 info->uses_doubles = TRUE; 476 477 for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) { 478 scan_src_operand(info, fullinst, &fullinst->Src[i], i, 479 tgsi_util_get_inst_usage_mask(fullinst, i), 480 is_interp_instruction, &is_mem_inst); 481 482 if (fullinst->Src[i].Register.Indirect) { 483 struct tgsi_full_src_register src = {{0}}; 484 485 src.Register.File = fullinst->Src[i].Indirect.File; 486 src.Register.Index = fullinst->Src[i].Indirect.Index; 487 488 scan_src_operand(info, fullinst, &src, -1, 489 1 << fullinst->Src[i].Indirect.Swizzle, 490 false, NULL); 491 } 492 493 if (fullinst->Src[i].Register.Dimension && 494 fullinst->Src[i].Dimension.Indirect) { 495 struct tgsi_full_src_register src = {{0}}; 496 497 src.Register.File = fullinst->Src[i].DimIndirect.File; 498 src.Register.Index = fullinst->Src[i].DimIndirect.Index; 499 500 scan_src_operand(info, fullinst, &src, -1, 501 1 << fullinst->Src[i].DimIndirect.Swizzle, 502 false, NULL); 503 } 504 } 505 506 if (fullinst->Instruction.Texture) { 507 for (i = 0; i < fullinst->Texture.NumOffsets; i++) { 508 struct tgsi_full_src_register src = {{0}}; 509 510 src.Register.File = fullinst->TexOffsets[i].File; 511 src.Register.Index = fullinst->TexOffsets[i].Index; 512 513 /* The usage mask is suboptimal but should be safe. */ 514 scan_src_operand(info, fullinst, &src, -1, 515 (1 << fullinst->TexOffsets[i].SwizzleX) | 516 (1 << fullinst->TexOffsets[i].SwizzleY) | 517 (1 << fullinst->TexOffsets[i].SwizzleZ), 518 false, &is_mem_inst); 519 } 520 } 521 522 /* check for indirect register writes */ 523 for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) { 524 const struct tgsi_full_dst_register *dst = &fullinst->Dst[i]; 525 526 if (dst->Register.Indirect) { 527 struct tgsi_full_src_register src = {{0}}; 528 529 src.Register.File = dst->Indirect.File; 530 src.Register.Index = dst->Indirect.Index; 531 532 scan_src_operand(info, fullinst, &src, -1, 533 1 << dst->Indirect.Swizzle, false, NULL); 534 535 info->indirect_files |= (1 << dst->Register.File); 536 info->indirect_files_written |= (1 << dst->Register.File); 537 } 538 539 if (dst->Register.Dimension && dst->Dimension.Indirect) { 540 struct tgsi_full_src_register src = {{0}}; 541 542 src.Register.File = dst->DimIndirect.File; 543 src.Register.Index = dst->DimIndirect.Index; 544 545 scan_src_operand(info, fullinst, &src, -1, 546 1 << dst->DimIndirect.Swizzle, false, NULL); 547 548 info->dim_indirect_files |= 1u << dst->Register.File; 549 } 550 551 if (is_memory_file(dst->Register.File)) { 552 assert(fullinst->Instruction.Opcode == TGSI_OPCODE_STORE); 553 554 is_mem_inst = true; 555 info->writes_memory = TRUE; 556 557 if (dst->Register.File == TGSI_FILE_IMAGE) { 558 if (dst->Register.Indirect) 559 info->images_store = info->images_declared; 560 else 561 info->images_store |= 1 << dst->Register.Index; 562 } else if (dst->Register.File == TGSI_FILE_BUFFER) { 563 if (dst->Register.Indirect) 564 info->shader_buffers_store = info->shader_buffers_declared; 565 else 566 info->shader_buffers_store |= 1 << dst->Register.Index; 567 } 568 } 569 } 570 571 if (is_mem_inst) 572 info->num_memory_instructions++; 573 574 if (computes_derivative(fullinst->Instruction.Opcode)) 575 info->uses_derivatives = true; 576 577 info->num_instructions++; 578} 579 580 581static void 582scan_declaration(struct tgsi_shader_info *info, 583 const struct tgsi_full_declaration *fulldecl) 584{ 585 const uint file = fulldecl->Declaration.File; 586 const unsigned procType = info->processor; 587 uint reg; 588 589 if (fulldecl->Declaration.Array) { 590 unsigned array_id = fulldecl->Array.ArrayID; 591 592 switch (file) { 593 case TGSI_FILE_INPUT: 594 assert(array_id < ARRAY_SIZE(info->input_array_first)); 595 info->input_array_first[array_id] = fulldecl->Range.First; 596 info->input_array_last[array_id] = fulldecl->Range.Last; 597 break; 598 case TGSI_FILE_OUTPUT: 599 assert(array_id < ARRAY_SIZE(info->output_array_first)); 600 info->output_array_first[array_id] = fulldecl->Range.First; 601 info->output_array_last[array_id] = fulldecl->Range.Last; 602 break; 603 } 604 info->array_max[file] = MAX2(info->array_max[file], array_id); 605 } 606 607 for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) { 608 unsigned semName = fulldecl->Semantic.Name; 609 unsigned semIndex = fulldecl->Semantic.Index + 610 (reg - fulldecl->Range.First); 611 int buffer; 612 unsigned index, target, type; 613 614 /* 615 * only first 32 regs will appear in this bitfield, if larger 616 * bits will wrap around. 617 */ 618 info->file_mask[file] |= (1u << (reg & 31)); 619 info->file_count[file]++; 620 info->file_max[file] = MAX2(info->file_max[file], (int)reg); 621 622 switch (file) { 623 case TGSI_FILE_CONSTANT: 624 buffer = 0; 625 626 if (fulldecl->Declaration.Dimension) 627 buffer = fulldecl->Dim.Index2D; 628 629 info->const_file_max[buffer] = 630 MAX2(info->const_file_max[buffer], (int)reg); 631 info->const_buffers_declared |= 1u << buffer; 632 break; 633 634 case TGSI_FILE_IMAGE: 635 info->images_declared |= 1u << reg; 636 if (fulldecl->Image.Resource == TGSI_TEXTURE_BUFFER) 637 info->images_buffers |= 1 << reg; 638 break; 639 640 case TGSI_FILE_BUFFER: 641 info->shader_buffers_declared |= 1u << reg; 642 break; 643 644 case TGSI_FILE_INPUT: 645 info->input_semantic_name[reg] = (ubyte) semName; 646 info->input_semantic_index[reg] = (ubyte) semIndex; 647 info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate; 648 info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location; 649 info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap; 650 651 /* Vertex shaders can have inputs with holes between them. */ 652 info->num_inputs = MAX2(info->num_inputs, reg + 1); 653 654 switch (semName) { 655 case TGSI_SEMANTIC_PRIMID: 656 info->uses_primid = true; 657 break; 658 case TGSI_SEMANTIC_POSITION: 659 info->reads_position = true; 660 break; 661 case TGSI_SEMANTIC_FACE: 662 info->uses_frontface = true; 663 break; 664 } 665 break; 666 667 case TGSI_FILE_SYSTEM_VALUE: 668 index = fulldecl->Range.First; 669 670 info->system_value_semantic_name[index] = semName; 671 info->num_system_values = MAX2(info->num_system_values, index + 1); 672 673 switch (semName) { 674 case TGSI_SEMANTIC_INSTANCEID: 675 info->uses_instanceid = TRUE; 676 break; 677 case TGSI_SEMANTIC_VERTEXID: 678 info->uses_vertexid = TRUE; 679 break; 680 case TGSI_SEMANTIC_VERTEXID_NOBASE: 681 info->uses_vertexid_nobase = TRUE; 682 break; 683 case TGSI_SEMANTIC_BASEVERTEX: 684 info->uses_basevertex = TRUE; 685 break; 686 case TGSI_SEMANTIC_DRAWID: 687 info->uses_drawid = TRUE; 688 break; 689 case TGSI_SEMANTIC_PRIMID: 690 info->uses_primid = TRUE; 691 break; 692 case TGSI_SEMANTIC_INVOCATIONID: 693 info->uses_invocationid = TRUE; 694 break; 695 case TGSI_SEMANTIC_POSITION: 696 info->reads_position = TRUE; 697 break; 698 case TGSI_SEMANTIC_FACE: 699 info->uses_frontface = TRUE; 700 break; 701 case TGSI_SEMANTIC_SAMPLEMASK: 702 info->reads_samplemask = TRUE; 703 break; 704 case TGSI_SEMANTIC_TESSINNER: 705 case TGSI_SEMANTIC_TESSOUTER: 706 info->reads_tess_factors = true; 707 break; 708 } 709 break; 710 711 case TGSI_FILE_OUTPUT: 712 info->output_semantic_name[reg] = (ubyte) semName; 713 info->output_semantic_index[reg] = (ubyte) semIndex; 714 info->output_usagemask[reg] |= fulldecl->Declaration.UsageMask; 715 info->num_outputs = MAX2(info->num_outputs, reg + 1); 716 717 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_X) { 718 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamX; 719 info->num_stream_output_components[fulldecl->Semantic.StreamX]++; 720 } 721 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Y) { 722 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamY << 2; 723 info->num_stream_output_components[fulldecl->Semantic.StreamY]++; 724 } 725 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Z) { 726 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamZ << 4; 727 info->num_stream_output_components[fulldecl->Semantic.StreamZ]++; 728 } 729 if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_W) { 730 info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamW << 6; 731 info->num_stream_output_components[fulldecl->Semantic.StreamW]++; 732 } 733 734 switch (semName) { 735 case TGSI_SEMANTIC_PRIMID: 736 info->writes_primid = true; 737 break; 738 case TGSI_SEMANTIC_VIEWPORT_INDEX: 739 info->writes_viewport_index = true; 740 break; 741 case TGSI_SEMANTIC_LAYER: 742 info->writes_layer = true; 743 break; 744 case TGSI_SEMANTIC_PSIZE: 745 info->writes_psize = true; 746 break; 747 case TGSI_SEMANTIC_CLIPVERTEX: 748 info->writes_clipvertex = true; 749 break; 750 case TGSI_SEMANTIC_COLOR: 751 info->colors_written |= 1 << semIndex; 752 break; 753 case TGSI_SEMANTIC_STENCIL: 754 info->writes_stencil = true; 755 break; 756 case TGSI_SEMANTIC_SAMPLEMASK: 757 info->writes_samplemask = true; 758 break; 759 case TGSI_SEMANTIC_EDGEFLAG: 760 info->writes_edgeflag = true; 761 break; 762 case TGSI_SEMANTIC_POSITION: 763 if (procType == PIPE_SHADER_FRAGMENT) 764 info->writes_z = true; 765 else 766 info->writes_position = true; 767 break; 768 } 769 break; 770 771 case TGSI_FILE_SAMPLER: 772 STATIC_ASSERT(sizeof(info->samplers_declared) * 8 >= PIPE_MAX_SAMPLERS); 773 info->samplers_declared |= 1u << reg; 774 break; 775 776 case TGSI_FILE_SAMPLER_VIEW: 777 target = fulldecl->SamplerView.Resource; 778 type = fulldecl->SamplerView.ReturnTypeX; 779 780 assert(target < TGSI_TEXTURE_UNKNOWN); 781 if (info->sampler_targets[reg] == TGSI_TEXTURE_UNKNOWN) { 782 /* Save sampler target for this sampler index */ 783 info->sampler_targets[reg] = target; 784 info->sampler_type[reg] = type; 785 } else { 786 /* if previously declared, make sure targets agree */ 787 assert(info->sampler_targets[reg] == target); 788 assert(info->sampler_type[reg] == type); 789 } 790 break; 791 } 792 } 793} 794 795 796static void 797scan_immediate(struct tgsi_shader_info *info) 798{ 799 uint reg = info->immediate_count++; 800 uint file = TGSI_FILE_IMMEDIATE; 801 802 info->file_mask[file] |= (1 << reg); 803 info->file_count[file]++; 804 info->file_max[file] = MAX2(info->file_max[file], (int)reg); 805} 806 807 808static void 809scan_property(struct tgsi_shader_info *info, 810 const struct tgsi_full_property *fullprop) 811{ 812 unsigned name = fullprop->Property.PropertyName; 813 unsigned value = fullprop->u[0].Data; 814 815 assert(name < ARRAY_SIZE(info->properties)); 816 info->properties[name] = value; 817 818 switch (name) { 819 case TGSI_PROPERTY_NUM_CLIPDIST_ENABLED: 820 info->num_written_clipdistance = value; 821 info->clipdist_writemask |= (1 << value) - 1; 822 break; 823 case TGSI_PROPERTY_NUM_CULLDIST_ENABLED: 824 info->num_written_culldistance = value; 825 info->culldist_writemask |= (1 << value) - 1; 826 break; 827 } 828} 829 830 831/** 832 * Scan the given TGSI shader to collect information such as number of 833 * registers used, special instructions used, etc. 834 * \return info the result of the scan 835 */ 836void 837tgsi_scan_shader(const struct tgsi_token *tokens, 838 struct tgsi_shader_info *info) 839{ 840 uint procType, i; 841 struct tgsi_parse_context parse; 842 unsigned current_depth = 0; 843 844 memset(info, 0, sizeof(*info)); 845 for (i = 0; i < TGSI_FILE_COUNT; i++) 846 info->file_max[i] = -1; 847 for (i = 0; i < ARRAY_SIZE(info->const_file_max); i++) 848 info->const_file_max[i] = -1; 849 info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1; 850 for (i = 0; i < ARRAY_SIZE(info->sampler_targets); i++) 851 info->sampler_targets[i] = TGSI_TEXTURE_UNKNOWN; 852 853 /** 854 ** Setup to begin parsing input shader 855 **/ 856 if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) { 857 debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n"); 858 return; 859 } 860 procType = parse.FullHeader.Processor.Processor; 861 assert(procType == PIPE_SHADER_FRAGMENT || 862 procType == PIPE_SHADER_VERTEX || 863 procType == PIPE_SHADER_GEOMETRY || 864 procType == PIPE_SHADER_TESS_CTRL || 865 procType == PIPE_SHADER_TESS_EVAL || 866 procType == PIPE_SHADER_COMPUTE); 867 info->processor = procType; 868 info->num_tokens = tgsi_num_tokens(parse.Tokens); 869 870 /** 871 ** Loop over incoming program tokens/instructions 872 */ 873 while (!tgsi_parse_end_of_tokens(&parse)) { 874 tgsi_parse_token( &parse ); 875 876 switch( parse.FullToken.Token.Type ) { 877 case TGSI_TOKEN_TYPE_INSTRUCTION: 878 scan_instruction(info, &parse.FullToken.FullInstruction, 879 ¤t_depth); 880 break; 881 case TGSI_TOKEN_TYPE_DECLARATION: 882 scan_declaration(info, &parse.FullToken.FullDeclaration); 883 break; 884 case TGSI_TOKEN_TYPE_IMMEDIATE: 885 scan_immediate(info); 886 break; 887 case TGSI_TOKEN_TYPE_PROPERTY: 888 scan_property(info, &parse.FullToken.FullProperty); 889 break; 890 default: 891 assert(!"Unexpected TGSI token type"); 892 } 893 } 894 895 info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] || 896 info->opcode_count[TGSI_OPCODE_KILL]); 897 898 /* The dimensions of the IN decleration in geometry shader have 899 * to be deduced from the type of the input primitive. 900 */ 901 if (procType == PIPE_SHADER_GEOMETRY) { 902 unsigned input_primitive = 903 info->properties[TGSI_PROPERTY_GS_INPUT_PRIM]; 904 int num_verts = u_vertices_per_prim(input_primitive); 905 int j; 906 info->file_count[TGSI_FILE_INPUT] = num_verts; 907 info->file_max[TGSI_FILE_INPUT] = 908 MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1); 909 for (j = 0; j < num_verts; ++j) { 910 info->file_mask[TGSI_FILE_INPUT] |= (1 << j); 911 } 912 } 913 914 tgsi_parse_free(&parse); 915} 916 917/** 918 * Collect information about the arrays of a given register file. 919 * 920 * @param tokens TGSI shader 921 * @param file the register file to scan through 922 * @param max_array_id number of entries in @p arrays; should be equal to the 923 * highest array id, i.e. tgsi_shader_info::array_max[file]. 924 * @param arrays info for array of each ID will be written to arrays[ID - 1]. 925 */ 926void 927tgsi_scan_arrays(const struct tgsi_token *tokens, 928 unsigned file, 929 unsigned max_array_id, 930 struct tgsi_array_info *arrays) 931{ 932 struct tgsi_parse_context parse; 933 934 if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) { 935 debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n"); 936 return; 937 } 938 939 memset(arrays, 0, sizeof(arrays[0]) * max_array_id); 940 941 while (!tgsi_parse_end_of_tokens(&parse)) { 942 struct tgsi_full_instruction *inst; 943 944 tgsi_parse_token(&parse); 945 946 if (parse.FullToken.Token.Type == TGSI_TOKEN_TYPE_DECLARATION) { 947 struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration; 948 949 if (decl->Declaration.Array && decl->Declaration.File == file && 950 decl->Array.ArrayID > 0 && decl->Array.ArrayID <= max_array_id) { 951 struct tgsi_array_info *array = &arrays[decl->Array.ArrayID - 1]; 952 assert(!array->declared); 953 array->declared = true; 954 array->range = decl->Range; 955 } 956 } 957 958 if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION) 959 continue; 960 961 inst = &parse.FullToken.FullInstruction; 962 for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) { 963 const struct tgsi_full_dst_register *dst = &inst->Dst[i]; 964 if (dst->Register.File != file) 965 continue; 966 967 if (dst->Register.Indirect) { 968 if (dst->Indirect.ArrayID > 0 && 969 dst->Indirect.ArrayID <= max_array_id) { 970 arrays[dst->Indirect.ArrayID - 1].writemask |= dst->Register.WriteMask; 971 } else { 972 /* Indirect writes without an ArrayID can write anywhere. */ 973 for (unsigned j = 0; j < max_array_id; ++j) 974 arrays[j].writemask |= dst->Register.WriteMask; 975 } 976 } else { 977 /* Check whether the write falls into any of the arrays anyway. */ 978 for (unsigned j = 0; j < max_array_id; ++j) { 979 struct tgsi_array_info *array = &arrays[j]; 980 if (array->declared && 981 dst->Register.Index >= array->range.First && 982 dst->Register.Index <= array->range.Last) 983 array->writemask |= dst->Register.WriteMask; 984 } 985 } 986 } 987 } 988 989 tgsi_parse_free(&parse); 990 991 return; 992} 993 994static void 995check_no_subroutines(const struct tgsi_full_instruction *inst) 996{ 997 switch (inst->Instruction.Opcode) { 998 case TGSI_OPCODE_BGNSUB: 999 case TGSI_OPCODE_ENDSUB: 1000 case TGSI_OPCODE_CAL: 1001 unreachable("subroutines unhandled"); 1002 } 1003} 1004 1005static unsigned 1006get_inst_tessfactor_writemask(const struct tgsi_shader_info *info, 1007 const struct tgsi_full_instruction *inst) 1008{ 1009 unsigned writemask = 0; 1010 1011 for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) { 1012 const struct tgsi_full_dst_register *dst = &inst->Dst[i]; 1013 1014 if (dst->Register.File == TGSI_FILE_OUTPUT && 1015 !dst->Register.Indirect) { 1016 unsigned name = info->output_semantic_name[dst->Register.Index]; 1017 1018 if (name == TGSI_SEMANTIC_TESSINNER) 1019 writemask |= dst->Register.WriteMask; 1020 else if (name == TGSI_SEMANTIC_TESSOUTER) 1021 writemask |= dst->Register.WriteMask << 4; 1022 } 1023 } 1024 return writemask; 1025} 1026 1027static unsigned 1028get_block_tessfactor_writemask(const struct tgsi_shader_info *info, 1029 struct tgsi_parse_context *parse, 1030 unsigned end_opcode) 1031{ 1032 struct tgsi_full_instruction *inst; 1033 unsigned writemask = 0; 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 while (inst->Instruction.Opcode != end_opcode) { 1041 1042 /* Recursively process nested blocks. */ 1043 switch (inst->Instruction.Opcode) { 1044 case TGSI_OPCODE_IF: 1045 case TGSI_OPCODE_UIF: 1046 writemask |= 1047 get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDIF); 1048 break; 1049 1050 case TGSI_OPCODE_BGNLOOP: 1051 writemask |= 1052 get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP); 1053 break; 1054 1055 case TGSI_OPCODE_BARRIER: 1056 unreachable("nested BARRIER is illegal"); 1057 break; 1058 1059 default: 1060 writemask |= get_inst_tessfactor_writemask(info, inst); 1061 } 1062 1063 tgsi_parse_token(parse); 1064 assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 1065 inst = &parse->FullToken.FullInstruction; 1066 check_no_subroutines(inst); 1067 } 1068 1069 return writemask; 1070} 1071 1072static void 1073get_if_block_tessfactor_writemask(const struct tgsi_shader_info *info, 1074 struct tgsi_parse_context *parse, 1075 unsigned *upper_block_tf_writemask, 1076 unsigned *cond_block_tf_writemask) 1077{ 1078 struct tgsi_full_instruction *inst; 1079 unsigned then_tessfactor_writemask = 0; 1080 unsigned else_tessfactor_writemask = 0; 1081 unsigned writemask; 1082 bool is_then = true; 1083 1084 tgsi_parse_token(parse); 1085 assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 1086 inst = &parse->FullToken.FullInstruction; 1087 check_no_subroutines(inst); 1088 1089 while (inst->Instruction.Opcode != TGSI_OPCODE_ENDIF) { 1090 1091 switch (inst->Instruction.Opcode) { 1092 case TGSI_OPCODE_ELSE: 1093 is_then = false; 1094 break; 1095 1096 /* Recursively process nested blocks. */ 1097 case TGSI_OPCODE_IF: 1098 case TGSI_OPCODE_UIF: 1099 get_if_block_tessfactor_writemask(info, parse, 1100 is_then ? &then_tessfactor_writemask : 1101 &else_tessfactor_writemask, 1102 cond_block_tf_writemask); 1103 break; 1104 1105 case TGSI_OPCODE_BGNLOOP: 1106 *cond_block_tf_writemask |= 1107 get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP); 1108 break; 1109 1110 case TGSI_OPCODE_BARRIER: 1111 unreachable("nested BARRIER is illegal"); 1112 break; 1113 default: 1114 /* Process an instruction in the current block. */ 1115 writemask = get_inst_tessfactor_writemask(info, inst); 1116 1117 if (writemask) { 1118 if (is_then) 1119 then_tessfactor_writemask |= writemask; 1120 else 1121 else_tessfactor_writemask |= writemask; 1122 } 1123 } 1124 1125 tgsi_parse_token(parse); 1126 assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 1127 inst = &parse->FullToken.FullInstruction; 1128 check_no_subroutines(inst); 1129 } 1130 1131 if (then_tessfactor_writemask || else_tessfactor_writemask) { 1132 /* If both statements write the same tess factor channels, 1133 * we can say that the upper block writes them too. */ 1134 *upper_block_tf_writemask |= then_tessfactor_writemask & 1135 else_tessfactor_writemask; 1136 *cond_block_tf_writemask |= then_tessfactor_writemask | 1137 else_tessfactor_writemask; 1138 } 1139} 1140 1141void 1142tgsi_scan_tess_ctrl(const struct tgsi_token *tokens, 1143 const struct tgsi_shader_info *info, 1144 struct tgsi_tessctrl_info *out) 1145{ 1146 memset(out, 0, sizeof(*out)); 1147 1148 if (info->processor != PIPE_SHADER_TESS_CTRL) 1149 return; 1150 1151 struct tgsi_parse_context parse; 1152 if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) { 1153 debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n"); 1154 return; 1155 } 1156 1157 /* The pass works as follows: 1158 * If all codepaths write tess factors, we can say that all invocations 1159 * define tess factors. 1160 * 1161 * Each tess factor channel is tracked separately. 1162 */ 1163 unsigned main_block_tf_writemask = 0; /* if main block writes tess factors */ 1164 unsigned cond_block_tf_writemask = 0; /* if cond block writes tess factors */ 1165 1166 /* Initial value = true. Here the pass will accumulate results from multiple 1167 * segments surrounded by barriers. If tess factors aren't written at all, 1168 * it's a shader bug and we don't care if this will be true. 1169 */ 1170 out->tessfactors_are_def_in_all_invocs = true; 1171 1172 while (!tgsi_parse_end_of_tokens(&parse)) { 1173 tgsi_parse_token(&parse); 1174 1175 if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION) 1176 continue; 1177 1178 struct tgsi_full_instruction *inst = &parse.FullToken.FullInstruction; 1179 check_no_subroutines(inst); 1180 1181 /* Process nested blocks. */ 1182 switch (inst->Instruction.Opcode) { 1183 case TGSI_OPCODE_IF: 1184 case TGSI_OPCODE_UIF: 1185 get_if_block_tessfactor_writemask(info, &parse, 1186 &main_block_tf_writemask, 1187 &cond_block_tf_writemask); 1188 continue; 1189 1190 case TGSI_OPCODE_BGNLOOP: 1191 cond_block_tf_writemask |= 1192 get_block_tessfactor_writemask(info, &parse, TGSI_OPCODE_ENDLOOP); 1193 continue; 1194 1195 case TGSI_OPCODE_BARRIER: 1196 /* The following case must be prevented: 1197 * gl_TessLevelInner = ...; 1198 * barrier(); 1199 * if (gl_InvocationID == 1) 1200 * gl_TessLevelInner = ...; 1201 * 1202 * If you consider disjoint code segments separated by barriers, each 1203 * such segment that writes tess factor channels should write the same 1204 * channels in all codepaths within that segment. 1205 */ 1206 if (main_block_tf_writemask || cond_block_tf_writemask) { 1207 /* Accumulate the result: */ 1208 out->tessfactors_are_def_in_all_invocs &= 1209 !(cond_block_tf_writemask & ~main_block_tf_writemask); 1210 1211 /* Analyze the next code segment from scratch. */ 1212 main_block_tf_writemask = 0; 1213 cond_block_tf_writemask = 0; 1214 } 1215 continue; 1216 } 1217 1218 main_block_tf_writemask |= get_inst_tessfactor_writemask(info, inst); 1219 } 1220 1221 /* Accumulate the result for the last code segment separated by a barrier. */ 1222 if (main_block_tf_writemask || cond_block_tf_writemask) { 1223 out->tessfactors_are_def_in_all_invocs &= 1224 !(cond_block_tf_writemask & ~main_block_tf_writemask); 1225 } 1226 1227 tgsi_parse_free(&parse); 1228} 1229