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