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