1848b8605Smrg/************************************************************************** 2848b8605Smrg * 3848b8605Smrg * Copyright 2008 VMware, Inc. 4848b8605Smrg * All Rights Reserved. 5848b8605Smrg * Copyright 2008 VMware, Inc. All rights Reserved. 6848b8605Smrg * 7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 8848b8605Smrg * copy of this software and associated documentation files (the 9848b8605Smrg * "Software"), to deal in the Software without restriction, including 10848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish, 11848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to 12848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to 13848b8605Smrg * the following conditions: 14848b8605Smrg * 15848b8605Smrg * The above copyright notice and this permission notice (including the 16848b8605Smrg * next paragraph) shall be included in all copies or substantial portions 17848b8605Smrg * of the Software. 18848b8605Smrg * 19848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 23848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26848b8605Smrg * 27848b8605Smrg **************************************************************************/ 28848b8605Smrg 29848b8605Smrg/** 30848b8605Smrg * TGSI program scan utility. 31848b8605Smrg * Used to determine which registers and instructions are used by a shader. 32848b8605Smrg * 33848b8605Smrg * Authors: Brian Paul 34848b8605Smrg */ 35848b8605Smrg 36848b8605Smrg 37848b8605Smrg#include "util/u_debug.h" 38848b8605Smrg#include "util/u_math.h" 39848b8605Smrg#include "util/u_memory.h" 40848b8605Smrg#include "util/u_prim.h" 41b8e80941Smrg#include "tgsi/tgsi_info.h" 42848b8605Smrg#include "tgsi/tgsi_parse.h" 43848b8605Smrg#include "tgsi/tgsi_util.h" 44848b8605Smrg#include "tgsi/tgsi_scan.h" 45848b8605Smrg 46848b8605Smrg 47b8e80941Smrgstatic bool 48b8e80941Smrgis_memory_file(unsigned file) 49b8e80941Smrg{ 50b8e80941Smrg return file == TGSI_FILE_SAMPLER || 51b8e80941Smrg file == TGSI_FILE_SAMPLER_VIEW || 52b8e80941Smrg file == TGSI_FILE_IMAGE || 53b8e80941Smrg file == TGSI_FILE_BUFFER || 54b8e80941Smrg file == TGSI_FILE_HW_ATOMIC; 55b8e80941Smrg} 56b8e80941Smrg 57b8e80941Smrg 58b8e80941Smrgstatic bool 59b8e80941Smrgis_mem_query_inst(enum tgsi_opcode opcode) 60b8e80941Smrg{ 61b8e80941Smrg return opcode == TGSI_OPCODE_RESQ || 62b8e80941Smrg opcode == TGSI_OPCODE_TXQ || 63b8e80941Smrg opcode == TGSI_OPCODE_TXQS || 64b8e80941Smrg opcode == TGSI_OPCODE_LODQ; 65b8e80941Smrg} 66b8e80941Smrg 67b8e80941Smrg/** 68b8e80941Smrg * Is the opcode a "true" texture instruction which samples from a 69b8e80941Smrg * texture map? 70b8e80941Smrg */ 71b8e80941Smrgstatic bool 72b8e80941Smrgis_texture_inst(enum tgsi_opcode opcode) 73b8e80941Smrg{ 74b8e80941Smrg return (!is_mem_query_inst(opcode) && 75b8e80941Smrg tgsi_get_opcode_info(opcode)->is_tex); 76b8e80941Smrg} 77b8e80941Smrg 78b8e80941Smrg 79b8e80941Smrg/** 80b8e80941Smrg * Is the opcode an instruction which computes a derivative explicitly or 81b8e80941Smrg * implicitly? 82b8e80941Smrg */ 83b8e80941Smrgstatic bool 84b8e80941Smrgcomputes_derivative(enum tgsi_opcode opcode) 85b8e80941Smrg{ 86b8e80941Smrg if (tgsi_get_opcode_info(opcode)->is_tex) { 87b8e80941Smrg return opcode != TGSI_OPCODE_TG4 && 88b8e80941Smrg opcode != TGSI_OPCODE_TXD && 89b8e80941Smrg opcode != TGSI_OPCODE_TXF && 90b8e80941Smrg opcode != TGSI_OPCODE_TXF_LZ && 91b8e80941Smrg opcode != TGSI_OPCODE_TEX_LZ && 92b8e80941Smrg opcode != TGSI_OPCODE_TXL && 93b8e80941Smrg opcode != TGSI_OPCODE_TXL2 && 94b8e80941Smrg opcode != TGSI_OPCODE_TXQ && 95b8e80941Smrg opcode != TGSI_OPCODE_TXQS; 96b8e80941Smrg } 97b8e80941Smrg 98b8e80941Smrg return opcode == TGSI_OPCODE_DDX || opcode == TGSI_OPCODE_DDX_FINE || 99b8e80941Smrg opcode == TGSI_OPCODE_DDY || opcode == TGSI_OPCODE_DDY_FINE || 100b8e80941Smrg opcode == TGSI_OPCODE_SAMPLE || 101b8e80941Smrg opcode == TGSI_OPCODE_SAMPLE_B || 102b8e80941Smrg opcode == TGSI_OPCODE_SAMPLE_C; 103b8e80941Smrg} 104b8e80941Smrg 105b8e80941Smrg 106b8e80941Smrgstatic void 107b8e80941Smrgscan_src_operand(struct tgsi_shader_info *info, 108b8e80941Smrg const struct tgsi_full_instruction *fullinst, 109b8e80941Smrg const struct tgsi_full_src_register *src, 110b8e80941Smrg unsigned src_index, 111b8e80941Smrg unsigned usage_mask_after_swizzle, 112b8e80941Smrg bool is_interp_instruction, 113b8e80941Smrg bool *is_mem_inst) 114b8e80941Smrg{ 115b8e80941Smrg int ind = src->Register.Index; 116b8e80941Smrg 117b8e80941Smrg if (info->processor == PIPE_SHADER_COMPUTE && 118b8e80941Smrg src->Register.File == TGSI_FILE_SYSTEM_VALUE) { 119b8e80941Smrg unsigned name, mask; 120b8e80941Smrg 121b8e80941Smrg name = info->system_value_semantic_name[src->Register.Index]; 122b8e80941Smrg 123b8e80941Smrg switch (name) { 124b8e80941Smrg case TGSI_SEMANTIC_THREAD_ID: 125b8e80941Smrg case TGSI_SEMANTIC_BLOCK_ID: 126b8e80941Smrg mask = usage_mask_after_swizzle & TGSI_WRITEMASK_XYZ; 127b8e80941Smrg while (mask) { 128b8e80941Smrg unsigned i = u_bit_scan(&mask); 129b8e80941Smrg 130b8e80941Smrg if (name == TGSI_SEMANTIC_THREAD_ID) 131b8e80941Smrg info->uses_thread_id[i] = true; 132b8e80941Smrg else 133b8e80941Smrg info->uses_block_id[i] = true; 134b8e80941Smrg } 135b8e80941Smrg break; 136b8e80941Smrg case TGSI_SEMANTIC_BLOCK_SIZE: 137b8e80941Smrg /* The block size is translated to IMM with a fixed block size. */ 138b8e80941Smrg if (info->properties[TGSI_PROPERTY_CS_FIXED_BLOCK_WIDTH] == 0) 139b8e80941Smrg info->uses_block_size = true; 140b8e80941Smrg break; 141b8e80941Smrg case TGSI_SEMANTIC_GRID_SIZE: 142b8e80941Smrg info->uses_grid_size = true; 143b8e80941Smrg break; 144b8e80941Smrg } 145b8e80941Smrg } 146b8e80941Smrg 147b8e80941Smrg /* Mark which inputs are effectively used */ 148b8e80941Smrg if (src->Register.File == TGSI_FILE_INPUT) { 149b8e80941Smrg if (src->Register.Indirect) { 150b8e80941Smrg for (ind = 0; ind < info->num_inputs; ++ind) { 151b8e80941Smrg info->input_usage_mask[ind] |= usage_mask_after_swizzle; 152b8e80941Smrg } 153b8e80941Smrg } else { 154b8e80941Smrg assert(ind >= 0); 155b8e80941Smrg assert(ind < PIPE_MAX_SHADER_INPUTS); 156b8e80941Smrg info->input_usage_mask[ind] |= usage_mask_after_swizzle; 157b8e80941Smrg } 158b8e80941Smrg 159b8e80941Smrg if (info->processor == PIPE_SHADER_FRAGMENT) { 160b8e80941Smrg unsigned name, index, input; 161b8e80941Smrg 162b8e80941Smrg if (src->Register.Indirect && src->Indirect.ArrayID) 163b8e80941Smrg input = info->input_array_first[src->Indirect.ArrayID]; 164b8e80941Smrg else 165b8e80941Smrg input = src->Register.Index; 166b8e80941Smrg 167b8e80941Smrg name = info->input_semantic_name[input]; 168b8e80941Smrg index = info->input_semantic_index[input]; 169b8e80941Smrg 170b8e80941Smrg if (name == TGSI_SEMANTIC_POSITION && 171b8e80941Smrg usage_mask_after_swizzle & TGSI_WRITEMASK_Z) 172b8e80941Smrg info->reads_z = true; 173b8e80941Smrg 174b8e80941Smrg if (name == TGSI_SEMANTIC_COLOR) 175b8e80941Smrg info->colors_read |= usage_mask_after_swizzle << (index * 4); 176b8e80941Smrg 177b8e80941Smrg /* Process only interpolated varyings. Don't include POSITION. 178b8e80941Smrg * Don't include integer varyings, because they are not 179b8e80941Smrg * interpolated. Don't process inputs interpolated by INTERP 180b8e80941Smrg * opcodes. Those are tracked separately. 181b8e80941Smrg */ 182b8e80941Smrg if ((!is_interp_instruction || src_index != 0) && 183b8e80941Smrg (name == TGSI_SEMANTIC_GENERIC || 184b8e80941Smrg name == TGSI_SEMANTIC_TEXCOORD || 185b8e80941Smrg name == TGSI_SEMANTIC_COLOR || 186b8e80941Smrg name == TGSI_SEMANTIC_BCOLOR || 187b8e80941Smrg name == TGSI_SEMANTIC_FOG || 188b8e80941Smrg name == TGSI_SEMANTIC_CLIPDIST)) { 189b8e80941Smrg switch (info->input_interpolate[input]) { 190b8e80941Smrg case TGSI_INTERPOLATE_COLOR: 191b8e80941Smrg case TGSI_INTERPOLATE_PERSPECTIVE: 192b8e80941Smrg switch (info->input_interpolate_loc[input]) { 193b8e80941Smrg case TGSI_INTERPOLATE_LOC_CENTER: 194b8e80941Smrg info->uses_persp_center = TRUE; 195b8e80941Smrg break; 196b8e80941Smrg case TGSI_INTERPOLATE_LOC_CENTROID: 197b8e80941Smrg info->uses_persp_centroid = TRUE; 198b8e80941Smrg break; 199b8e80941Smrg case TGSI_INTERPOLATE_LOC_SAMPLE: 200b8e80941Smrg info->uses_persp_sample = TRUE; 201b8e80941Smrg break; 202b8e80941Smrg } 203b8e80941Smrg break; 204b8e80941Smrg case TGSI_INTERPOLATE_LINEAR: 205b8e80941Smrg switch (info->input_interpolate_loc[input]) { 206b8e80941Smrg case TGSI_INTERPOLATE_LOC_CENTER: 207b8e80941Smrg info->uses_linear_center = TRUE; 208b8e80941Smrg break; 209b8e80941Smrg case TGSI_INTERPOLATE_LOC_CENTROID: 210b8e80941Smrg info->uses_linear_centroid = TRUE; 211b8e80941Smrg break; 212b8e80941Smrg case TGSI_INTERPOLATE_LOC_SAMPLE: 213b8e80941Smrg info->uses_linear_sample = TRUE; 214b8e80941Smrg break; 215b8e80941Smrg } 216b8e80941Smrg break; 217b8e80941Smrg /* TGSI_INTERPOLATE_CONSTANT doesn't do any interpolation. */ 218b8e80941Smrg } 219b8e80941Smrg } 220b8e80941Smrg } 221b8e80941Smrg } 222b8e80941Smrg 223b8e80941Smrg if (info->processor == PIPE_SHADER_TESS_CTRL && 224b8e80941Smrg src->Register.File == TGSI_FILE_OUTPUT) { 225b8e80941Smrg unsigned input; 226b8e80941Smrg 227b8e80941Smrg if (src->Register.Indirect && src->Indirect.ArrayID) 228b8e80941Smrg input = info->output_array_first[src->Indirect.ArrayID]; 229b8e80941Smrg else 230b8e80941Smrg input = src->Register.Index; 231b8e80941Smrg 232b8e80941Smrg switch (info->output_semantic_name[input]) { 233b8e80941Smrg case TGSI_SEMANTIC_PATCH: 234b8e80941Smrg info->reads_perpatch_outputs = true; 235b8e80941Smrg break; 236b8e80941Smrg case TGSI_SEMANTIC_TESSINNER: 237b8e80941Smrg case TGSI_SEMANTIC_TESSOUTER: 238b8e80941Smrg info->reads_tessfactor_outputs = true; 239b8e80941Smrg break; 240b8e80941Smrg default: 241b8e80941Smrg info->reads_pervertex_outputs = true; 242b8e80941Smrg } 243b8e80941Smrg } 244b8e80941Smrg 245b8e80941Smrg /* check for indirect register reads */ 246b8e80941Smrg if (src->Register.Indirect) { 247b8e80941Smrg info->indirect_files |= (1 << src->Register.File); 248b8e80941Smrg info->indirect_files_read |= (1 << src->Register.File); 249b8e80941Smrg 250b8e80941Smrg /* record indirect constant buffer indexing */ 251b8e80941Smrg if (src->Register.File == TGSI_FILE_CONSTANT) { 252b8e80941Smrg if (src->Register.Dimension) { 253b8e80941Smrg if (src->Dimension.Indirect) 254b8e80941Smrg info->const_buffers_indirect = info->const_buffers_declared; 255b8e80941Smrg else 256b8e80941Smrg info->const_buffers_indirect |= 1u << src->Dimension.Index; 257b8e80941Smrg } else { 258b8e80941Smrg info->const_buffers_indirect |= 1; 259b8e80941Smrg } 260b8e80941Smrg } 261b8e80941Smrg } 262b8e80941Smrg 263b8e80941Smrg if (src->Register.Dimension && src->Dimension.Indirect) 264b8e80941Smrg info->dim_indirect_files |= 1u << src->Register.File; 265b8e80941Smrg 266b8e80941Smrg /* Texture samplers */ 267b8e80941Smrg if (src->Register.File == TGSI_FILE_SAMPLER) { 268b8e80941Smrg const unsigned index = src->Register.Index; 269b8e80941Smrg 270b8e80941Smrg assert(fullinst->Instruction.Texture); 271b8e80941Smrg assert(index < PIPE_MAX_SAMPLERS); 272b8e80941Smrg 273b8e80941Smrg if (is_texture_inst(fullinst->Instruction.Opcode)) { 274b8e80941Smrg const unsigned target = fullinst->Texture.Texture; 275b8e80941Smrg assert(target < TGSI_TEXTURE_UNKNOWN); 276b8e80941Smrg /* for texture instructions, check that the texture instruction 277b8e80941Smrg * target matches the previous sampler view declaration (if there 278b8e80941Smrg * was one.) 279b8e80941Smrg */ 280b8e80941Smrg if (info->sampler_targets[index] == TGSI_TEXTURE_UNKNOWN) { 281b8e80941Smrg /* probably no sampler view declaration */ 282b8e80941Smrg info->sampler_targets[index] = target; 283b8e80941Smrg } else { 284b8e80941Smrg /* Make sure the texture instruction's sampler/target info 285b8e80941Smrg * agrees with the sampler view declaration. 286b8e80941Smrg */ 287b8e80941Smrg assert(info->sampler_targets[index] == target); 288b8e80941Smrg } 289b8e80941Smrg } 290b8e80941Smrg } 291b8e80941Smrg 292b8e80941Smrg if (is_memory_file(src->Register.File) && 293b8e80941Smrg !is_mem_query_inst(fullinst->Instruction.Opcode)) { 294b8e80941Smrg *is_mem_inst = true; 295b8e80941Smrg 296b8e80941Smrg if (tgsi_get_opcode_info(fullinst->Instruction.Opcode)->is_store) { 297b8e80941Smrg info->writes_memory = TRUE; 298b8e80941Smrg 299b8e80941Smrg if (src->Register.File == TGSI_FILE_IMAGE) { 300b8e80941Smrg if (src->Register.Indirect) 301b8e80941Smrg info->images_atomic = info->images_declared; 302b8e80941Smrg else 303b8e80941Smrg info->images_atomic |= 1 << src->Register.Index; 304b8e80941Smrg } else if (src->Register.File == TGSI_FILE_BUFFER) { 305b8e80941Smrg if (src->Register.Indirect) 306b8e80941Smrg info->shader_buffers_atomic = info->shader_buffers_declared; 307b8e80941Smrg else 308b8e80941Smrg info->shader_buffers_atomic |= 1 << src->Register.Index; 309b8e80941Smrg } 310b8e80941Smrg } else { 311b8e80941Smrg if (src->Register.File == TGSI_FILE_IMAGE) { 312b8e80941Smrg if (src->Register.Indirect) 313b8e80941Smrg info->images_load = info->images_declared; 314b8e80941Smrg else 315b8e80941Smrg info->images_load |= 1 << src->Register.Index; 316b8e80941Smrg } else if (src->Register.File == TGSI_FILE_BUFFER) { 317b8e80941Smrg if (src->Register.Indirect) 318b8e80941Smrg info->shader_buffers_load = info->shader_buffers_declared; 319b8e80941Smrg else 320b8e80941Smrg info->shader_buffers_load |= 1 << src->Register.Index; 321b8e80941Smrg } 322b8e80941Smrg } 323b8e80941Smrg } 324b8e80941Smrg} 325b8e80941Smrg 326b8e80941Smrg 327b8e80941Smrgstatic void 328b8e80941Smrgscan_instruction(struct tgsi_shader_info *info, 329b8e80941Smrg const struct tgsi_full_instruction *fullinst, 330b8e80941Smrg unsigned *current_depth) 331b8e80941Smrg{ 332b8e80941Smrg unsigned i; 333b8e80941Smrg bool is_mem_inst = false; 334b8e80941Smrg bool is_interp_instruction = false; 335b8e80941Smrg unsigned sampler_src; 336b8e80941Smrg 337b8e80941Smrg assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST); 338b8e80941Smrg info->opcode_count[fullinst->Instruction.Opcode]++; 339b8e80941Smrg 340b8e80941Smrg switch (fullinst->Instruction.Opcode) { 341b8e80941Smrg case TGSI_OPCODE_IF: 342b8e80941Smrg case TGSI_OPCODE_UIF: 343b8e80941Smrg case TGSI_OPCODE_BGNLOOP: 344b8e80941Smrg (*current_depth)++; 345b8e80941Smrg info->max_depth = MAX2(info->max_depth, *current_depth); 346b8e80941Smrg break; 347b8e80941Smrg case TGSI_OPCODE_ENDIF: 348b8e80941Smrg case TGSI_OPCODE_ENDLOOP: 349b8e80941Smrg (*current_depth)--; 350b8e80941Smrg break; 351b8e80941Smrg case TGSI_OPCODE_TEX: 352b8e80941Smrg case TGSI_OPCODE_TEX_LZ: 353b8e80941Smrg case TGSI_OPCODE_TXB: 354b8e80941Smrg case TGSI_OPCODE_TXD: 355b8e80941Smrg case TGSI_OPCODE_TXL: 356b8e80941Smrg case TGSI_OPCODE_TXP: 357b8e80941Smrg case TGSI_OPCODE_TXQ: 358b8e80941Smrg case TGSI_OPCODE_TXQS: 359b8e80941Smrg case TGSI_OPCODE_TXF: 360b8e80941Smrg case TGSI_OPCODE_TXF_LZ: 361b8e80941Smrg case TGSI_OPCODE_TEX2: 362b8e80941Smrg case TGSI_OPCODE_TXB2: 363b8e80941Smrg case TGSI_OPCODE_TXL2: 364b8e80941Smrg case TGSI_OPCODE_TG4: 365b8e80941Smrg case TGSI_OPCODE_LODQ: 366b8e80941Smrg sampler_src = fullinst->Instruction.NumSrcRegs - 1; 367b8e80941Smrg if (fullinst->Src[sampler_src].Register.File != TGSI_FILE_SAMPLER) 368b8e80941Smrg info->uses_bindless_samplers = true; 369b8e80941Smrg break; 370b8e80941Smrg case TGSI_OPCODE_RESQ: 371b8e80941Smrg if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File)) 372b8e80941Smrg info->uses_bindless_images = true; 373b8e80941Smrg break; 374b8e80941Smrg case TGSI_OPCODE_LOAD: 375b8e80941Smrg if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File)) { 376b8e80941Smrg info->uses_bindless_images = true; 377b8e80941Smrg 378b8e80941Smrg if (fullinst->Memory.Texture == TGSI_TEXTURE_BUFFER) 379b8e80941Smrg info->uses_bindless_buffer_load = true; 380b8e80941Smrg else 381b8e80941Smrg info->uses_bindless_image_load = true; 382b8e80941Smrg } 383b8e80941Smrg break; 384b8e80941Smrg case TGSI_OPCODE_ATOMUADD: 385b8e80941Smrg case TGSI_OPCODE_ATOMXCHG: 386b8e80941Smrg case TGSI_OPCODE_ATOMCAS: 387b8e80941Smrg case TGSI_OPCODE_ATOMAND: 388b8e80941Smrg case TGSI_OPCODE_ATOMOR: 389b8e80941Smrg case TGSI_OPCODE_ATOMXOR: 390b8e80941Smrg case TGSI_OPCODE_ATOMUMIN: 391b8e80941Smrg case TGSI_OPCODE_ATOMUMAX: 392b8e80941Smrg case TGSI_OPCODE_ATOMIMIN: 393b8e80941Smrg case TGSI_OPCODE_ATOMIMAX: 394b8e80941Smrg case TGSI_OPCODE_ATOMFADD: 395b8e80941Smrg if (tgsi_is_bindless_image_file(fullinst->Src[0].Register.File)) { 396b8e80941Smrg info->uses_bindless_images = true; 397b8e80941Smrg 398b8e80941Smrg if (fullinst->Memory.Texture == TGSI_TEXTURE_BUFFER) 399b8e80941Smrg info->uses_bindless_buffer_atomic = true; 400b8e80941Smrg else 401b8e80941Smrg info->uses_bindless_image_atomic = true; 402b8e80941Smrg } 403b8e80941Smrg break; 404b8e80941Smrg case TGSI_OPCODE_STORE: 405b8e80941Smrg if (tgsi_is_bindless_image_file(fullinst->Dst[0].Register.File)) { 406b8e80941Smrg info->uses_bindless_images = true; 407b8e80941Smrg 408b8e80941Smrg if (fullinst->Memory.Texture == TGSI_TEXTURE_BUFFER) 409b8e80941Smrg info->uses_bindless_buffer_store = true; 410b8e80941Smrg else 411b8e80941Smrg info->uses_bindless_image_store = true; 412b8e80941Smrg } 413b8e80941Smrg break; 414b8e80941Smrg default: 415b8e80941Smrg break; 416b8e80941Smrg } 417b8e80941Smrg 418b8e80941Smrg if (fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_CENTROID || 419b8e80941Smrg fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET || 420b8e80941Smrg fullinst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE) { 421b8e80941Smrg const struct tgsi_full_src_register *src0 = &fullinst->Src[0]; 422b8e80941Smrg unsigned input; 423b8e80941Smrg 424b8e80941Smrg is_interp_instruction = true; 425b8e80941Smrg 426b8e80941Smrg if (src0->Register.Indirect && src0->Indirect.ArrayID) 427b8e80941Smrg input = info->input_array_first[src0->Indirect.ArrayID]; 428b8e80941Smrg else 429b8e80941Smrg input = src0->Register.Index; 430b8e80941Smrg 431b8e80941Smrg /* For the INTERP opcodes, the interpolation is always 432b8e80941Smrg * PERSPECTIVE unless LINEAR is specified. 433b8e80941Smrg */ 434b8e80941Smrg switch (info->input_interpolate[input]) { 435b8e80941Smrg case TGSI_INTERPOLATE_COLOR: 436b8e80941Smrg case TGSI_INTERPOLATE_CONSTANT: 437b8e80941Smrg case TGSI_INTERPOLATE_PERSPECTIVE: 438b8e80941Smrg switch (fullinst->Instruction.Opcode) { 439b8e80941Smrg case TGSI_OPCODE_INTERP_CENTROID: 440b8e80941Smrg info->uses_persp_opcode_interp_centroid = TRUE; 441b8e80941Smrg break; 442b8e80941Smrg case TGSI_OPCODE_INTERP_OFFSET: 443b8e80941Smrg info->uses_persp_opcode_interp_offset = TRUE; 444b8e80941Smrg break; 445b8e80941Smrg case TGSI_OPCODE_INTERP_SAMPLE: 446b8e80941Smrg info->uses_persp_opcode_interp_sample = TRUE; 447b8e80941Smrg break; 448b8e80941Smrg } 449b8e80941Smrg break; 450b8e80941Smrg 451b8e80941Smrg case TGSI_INTERPOLATE_LINEAR: 452b8e80941Smrg switch (fullinst->Instruction.Opcode) { 453b8e80941Smrg case TGSI_OPCODE_INTERP_CENTROID: 454b8e80941Smrg info->uses_linear_opcode_interp_centroid = TRUE; 455b8e80941Smrg break; 456b8e80941Smrg case TGSI_OPCODE_INTERP_OFFSET: 457b8e80941Smrg info->uses_linear_opcode_interp_offset = TRUE; 458b8e80941Smrg break; 459b8e80941Smrg case TGSI_OPCODE_INTERP_SAMPLE: 460b8e80941Smrg info->uses_linear_opcode_interp_sample = TRUE; 461b8e80941Smrg break; 462b8e80941Smrg } 463b8e80941Smrg break; 464b8e80941Smrg } 465b8e80941Smrg } 466b8e80941Smrg 467b8e80941Smrg if ((fullinst->Instruction.Opcode >= TGSI_OPCODE_F2D && 468b8e80941Smrg fullinst->Instruction.Opcode <= TGSI_OPCODE_DSSG) || 469b8e80941Smrg fullinst->Instruction.Opcode == TGSI_OPCODE_DFMA || 470b8e80941Smrg fullinst->Instruction.Opcode == TGSI_OPCODE_DDIV || 471b8e80941Smrg fullinst->Instruction.Opcode == TGSI_OPCODE_D2U64 || 472b8e80941Smrg fullinst->Instruction.Opcode == TGSI_OPCODE_D2I64 || 473b8e80941Smrg fullinst->Instruction.Opcode == TGSI_OPCODE_U642D || 474b8e80941Smrg fullinst->Instruction.Opcode == TGSI_OPCODE_I642D) 475b8e80941Smrg info->uses_doubles = TRUE; 476b8e80941Smrg 477b8e80941Smrg for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) { 478b8e80941Smrg scan_src_operand(info, fullinst, &fullinst->Src[i], i, 479b8e80941Smrg tgsi_util_get_inst_usage_mask(fullinst, i), 480b8e80941Smrg is_interp_instruction, &is_mem_inst); 481b8e80941Smrg 482b8e80941Smrg if (fullinst->Src[i].Register.Indirect) { 483b8e80941Smrg struct tgsi_full_src_register src = {{0}}; 484b8e80941Smrg 485b8e80941Smrg src.Register.File = fullinst->Src[i].Indirect.File; 486b8e80941Smrg src.Register.Index = fullinst->Src[i].Indirect.Index; 487b8e80941Smrg 488b8e80941Smrg scan_src_operand(info, fullinst, &src, -1, 489b8e80941Smrg 1 << fullinst->Src[i].Indirect.Swizzle, 490b8e80941Smrg false, NULL); 491b8e80941Smrg } 492b8e80941Smrg 493b8e80941Smrg if (fullinst->Src[i].Register.Dimension && 494b8e80941Smrg fullinst->Src[i].Dimension.Indirect) { 495b8e80941Smrg struct tgsi_full_src_register src = {{0}}; 496b8e80941Smrg 497b8e80941Smrg src.Register.File = fullinst->Src[i].DimIndirect.File; 498b8e80941Smrg src.Register.Index = fullinst->Src[i].DimIndirect.Index; 499b8e80941Smrg 500b8e80941Smrg scan_src_operand(info, fullinst, &src, -1, 501b8e80941Smrg 1 << fullinst->Src[i].DimIndirect.Swizzle, 502b8e80941Smrg false, NULL); 503b8e80941Smrg } 504b8e80941Smrg } 505b8e80941Smrg 506b8e80941Smrg if (fullinst->Instruction.Texture) { 507b8e80941Smrg for (i = 0; i < fullinst->Texture.NumOffsets; i++) { 508b8e80941Smrg struct tgsi_full_src_register src = {{0}}; 509b8e80941Smrg 510b8e80941Smrg src.Register.File = fullinst->TexOffsets[i].File; 511b8e80941Smrg src.Register.Index = fullinst->TexOffsets[i].Index; 512b8e80941Smrg 513b8e80941Smrg /* The usage mask is suboptimal but should be safe. */ 514b8e80941Smrg scan_src_operand(info, fullinst, &src, -1, 515b8e80941Smrg (1 << fullinst->TexOffsets[i].SwizzleX) | 516b8e80941Smrg (1 << fullinst->TexOffsets[i].SwizzleY) | 517b8e80941Smrg (1 << fullinst->TexOffsets[i].SwizzleZ), 518b8e80941Smrg false, &is_mem_inst); 519b8e80941Smrg } 520b8e80941Smrg } 521b8e80941Smrg 522b8e80941Smrg /* check for indirect register writes */ 523b8e80941Smrg for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) { 524b8e80941Smrg const struct tgsi_full_dst_register *dst = &fullinst->Dst[i]; 525b8e80941Smrg 526b8e80941Smrg if (dst->Register.Indirect) { 527b8e80941Smrg struct tgsi_full_src_register src = {{0}}; 528b8e80941Smrg 529b8e80941Smrg src.Register.File = dst->Indirect.File; 530b8e80941Smrg src.Register.Index = dst->Indirect.Index; 531b8e80941Smrg 532b8e80941Smrg scan_src_operand(info, fullinst, &src, -1, 533b8e80941Smrg 1 << dst->Indirect.Swizzle, false, NULL); 534b8e80941Smrg 535b8e80941Smrg info->indirect_files |= (1 << dst->Register.File); 536b8e80941Smrg info->indirect_files_written |= (1 << dst->Register.File); 537b8e80941Smrg } 538b8e80941Smrg 539b8e80941Smrg if (dst->Register.Dimension && dst->Dimension.Indirect) { 540b8e80941Smrg struct tgsi_full_src_register src = {{0}}; 541b8e80941Smrg 542b8e80941Smrg src.Register.File = dst->DimIndirect.File; 543b8e80941Smrg src.Register.Index = dst->DimIndirect.Index; 544b8e80941Smrg 545b8e80941Smrg scan_src_operand(info, fullinst, &src, -1, 546b8e80941Smrg 1 << dst->DimIndirect.Swizzle, false, NULL); 547b8e80941Smrg 548b8e80941Smrg info->dim_indirect_files |= 1u << dst->Register.File; 549b8e80941Smrg } 550b8e80941Smrg 551b8e80941Smrg if (is_memory_file(dst->Register.File)) { 552b8e80941Smrg assert(fullinst->Instruction.Opcode == TGSI_OPCODE_STORE); 553b8e80941Smrg 554b8e80941Smrg is_mem_inst = true; 555b8e80941Smrg info->writes_memory = TRUE; 556b8e80941Smrg 557b8e80941Smrg if (dst->Register.File == TGSI_FILE_IMAGE) { 558b8e80941Smrg if (dst->Register.Indirect) 559b8e80941Smrg info->images_store = info->images_declared; 560b8e80941Smrg else 561b8e80941Smrg info->images_store |= 1 << dst->Register.Index; 562b8e80941Smrg } else if (dst->Register.File == TGSI_FILE_BUFFER) { 563b8e80941Smrg if (dst->Register.Indirect) 564b8e80941Smrg info->shader_buffers_store = info->shader_buffers_declared; 565b8e80941Smrg else 566b8e80941Smrg info->shader_buffers_store |= 1 << dst->Register.Index; 567b8e80941Smrg } 568b8e80941Smrg } 569b8e80941Smrg } 570b8e80941Smrg 571b8e80941Smrg if (is_mem_inst) 572b8e80941Smrg info->num_memory_instructions++; 573b8e80941Smrg 574b8e80941Smrg if (computes_derivative(fullinst->Instruction.Opcode)) 575b8e80941Smrg info->uses_derivatives = true; 576b8e80941Smrg 577b8e80941Smrg info->num_instructions++; 578b8e80941Smrg} 579b8e80941Smrg 580b8e80941Smrg 581b8e80941Smrgstatic void 582b8e80941Smrgscan_declaration(struct tgsi_shader_info *info, 583b8e80941Smrg const struct tgsi_full_declaration *fulldecl) 584b8e80941Smrg{ 585b8e80941Smrg const uint file = fulldecl->Declaration.File; 586b8e80941Smrg const unsigned procType = info->processor; 587b8e80941Smrg uint reg; 588b8e80941Smrg 589b8e80941Smrg if (fulldecl->Declaration.Array) { 590b8e80941Smrg unsigned array_id = fulldecl->Array.ArrayID; 591b8e80941Smrg 592b8e80941Smrg switch (file) { 593b8e80941Smrg case TGSI_FILE_INPUT: 594b8e80941Smrg assert(array_id < ARRAY_SIZE(info->input_array_first)); 595b8e80941Smrg info->input_array_first[array_id] = fulldecl->Range.First; 596b8e80941Smrg info->input_array_last[array_id] = fulldecl->Range.Last; 597b8e80941Smrg break; 598b8e80941Smrg case TGSI_FILE_OUTPUT: 599b8e80941Smrg assert(array_id < ARRAY_SIZE(info->output_array_first)); 600b8e80941Smrg info->output_array_first[array_id] = fulldecl->Range.First; 601b8e80941Smrg info->output_array_last[array_id] = fulldecl->Range.Last; 602b8e80941Smrg break; 603b8e80941Smrg } 604b8e80941Smrg info->array_max[file] = MAX2(info->array_max[file], array_id); 605b8e80941Smrg } 606b8e80941Smrg 607b8e80941Smrg for (reg = fulldecl->Range.First; reg <= fulldecl->Range.Last; reg++) { 608b8e80941Smrg unsigned semName = fulldecl->Semantic.Name; 609b8e80941Smrg unsigned semIndex = fulldecl->Semantic.Index + 610b8e80941Smrg (reg - fulldecl->Range.First); 611b8e80941Smrg int buffer; 612b8e80941Smrg unsigned index, target, type; 613b8e80941Smrg 614b8e80941Smrg /* 615b8e80941Smrg * only first 32 regs will appear in this bitfield, if larger 616b8e80941Smrg * bits will wrap around. 617b8e80941Smrg */ 618b8e80941Smrg info->file_mask[file] |= (1u << (reg & 31)); 619b8e80941Smrg info->file_count[file]++; 620b8e80941Smrg info->file_max[file] = MAX2(info->file_max[file], (int)reg); 621b8e80941Smrg 622b8e80941Smrg switch (file) { 623b8e80941Smrg case TGSI_FILE_CONSTANT: 624b8e80941Smrg buffer = 0; 625b8e80941Smrg 626b8e80941Smrg if (fulldecl->Declaration.Dimension) 627b8e80941Smrg buffer = fulldecl->Dim.Index2D; 628b8e80941Smrg 629b8e80941Smrg info->const_file_max[buffer] = 630b8e80941Smrg MAX2(info->const_file_max[buffer], (int)reg); 631b8e80941Smrg info->const_buffers_declared |= 1u << buffer; 632b8e80941Smrg break; 633b8e80941Smrg 634b8e80941Smrg case TGSI_FILE_IMAGE: 635b8e80941Smrg info->images_declared |= 1u << reg; 636b8e80941Smrg if (fulldecl->Image.Resource == TGSI_TEXTURE_BUFFER) 637b8e80941Smrg info->images_buffers |= 1 << reg; 638b8e80941Smrg break; 639b8e80941Smrg 640b8e80941Smrg case TGSI_FILE_BUFFER: 641b8e80941Smrg info->shader_buffers_declared |= 1u << reg; 642b8e80941Smrg break; 643b8e80941Smrg 644b8e80941Smrg case TGSI_FILE_INPUT: 645b8e80941Smrg info->input_semantic_name[reg] = (ubyte) semName; 646b8e80941Smrg info->input_semantic_index[reg] = (ubyte) semIndex; 647b8e80941Smrg info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate; 648b8e80941Smrg info->input_interpolate_loc[reg] = (ubyte)fulldecl->Interp.Location; 649b8e80941Smrg info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap; 650b8e80941Smrg 651b8e80941Smrg /* Vertex shaders can have inputs with holes between them. */ 652b8e80941Smrg info->num_inputs = MAX2(info->num_inputs, reg + 1); 653b8e80941Smrg 654b8e80941Smrg switch (semName) { 655b8e80941Smrg case TGSI_SEMANTIC_PRIMID: 656b8e80941Smrg info->uses_primid = true; 657b8e80941Smrg break; 658b8e80941Smrg case TGSI_SEMANTIC_POSITION: 659b8e80941Smrg info->reads_position = true; 660b8e80941Smrg break; 661b8e80941Smrg case TGSI_SEMANTIC_FACE: 662b8e80941Smrg info->uses_frontface = true; 663b8e80941Smrg break; 664b8e80941Smrg } 665b8e80941Smrg break; 666b8e80941Smrg 667b8e80941Smrg case TGSI_FILE_SYSTEM_VALUE: 668b8e80941Smrg index = fulldecl->Range.First; 669b8e80941Smrg 670b8e80941Smrg info->system_value_semantic_name[index] = semName; 671b8e80941Smrg info->num_system_values = MAX2(info->num_system_values, index + 1); 672b8e80941Smrg 673b8e80941Smrg switch (semName) { 674b8e80941Smrg case TGSI_SEMANTIC_INSTANCEID: 675b8e80941Smrg info->uses_instanceid = TRUE; 676b8e80941Smrg break; 677b8e80941Smrg case TGSI_SEMANTIC_VERTEXID: 678b8e80941Smrg info->uses_vertexid = TRUE; 679b8e80941Smrg break; 680b8e80941Smrg case TGSI_SEMANTIC_VERTEXID_NOBASE: 681b8e80941Smrg info->uses_vertexid_nobase = TRUE; 682b8e80941Smrg break; 683b8e80941Smrg case TGSI_SEMANTIC_BASEVERTEX: 684b8e80941Smrg info->uses_basevertex = TRUE; 685b8e80941Smrg break; 686b8e80941Smrg case TGSI_SEMANTIC_DRAWID: 687b8e80941Smrg info->uses_drawid = TRUE; 688b8e80941Smrg break; 689b8e80941Smrg case TGSI_SEMANTIC_PRIMID: 690b8e80941Smrg info->uses_primid = TRUE; 691b8e80941Smrg break; 692b8e80941Smrg case TGSI_SEMANTIC_INVOCATIONID: 693b8e80941Smrg info->uses_invocationid = TRUE; 694b8e80941Smrg break; 695b8e80941Smrg case TGSI_SEMANTIC_POSITION: 696b8e80941Smrg info->reads_position = TRUE; 697b8e80941Smrg break; 698b8e80941Smrg case TGSI_SEMANTIC_FACE: 699b8e80941Smrg info->uses_frontface = TRUE; 700b8e80941Smrg break; 701b8e80941Smrg case TGSI_SEMANTIC_SAMPLEMASK: 702b8e80941Smrg info->reads_samplemask = TRUE; 703b8e80941Smrg break; 704b8e80941Smrg case TGSI_SEMANTIC_TESSINNER: 705b8e80941Smrg case TGSI_SEMANTIC_TESSOUTER: 706b8e80941Smrg info->reads_tess_factors = true; 707b8e80941Smrg break; 708b8e80941Smrg } 709b8e80941Smrg break; 710b8e80941Smrg 711b8e80941Smrg case TGSI_FILE_OUTPUT: 712b8e80941Smrg info->output_semantic_name[reg] = (ubyte) semName; 713b8e80941Smrg info->output_semantic_index[reg] = (ubyte) semIndex; 714b8e80941Smrg info->output_usagemask[reg] |= fulldecl->Declaration.UsageMask; 715b8e80941Smrg info->num_outputs = MAX2(info->num_outputs, reg + 1); 716b8e80941Smrg 717b8e80941Smrg if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_X) { 718b8e80941Smrg info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamX; 719b8e80941Smrg info->num_stream_output_components[fulldecl->Semantic.StreamX]++; 720b8e80941Smrg } 721b8e80941Smrg if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Y) { 722b8e80941Smrg info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamY << 2; 723b8e80941Smrg info->num_stream_output_components[fulldecl->Semantic.StreamY]++; 724b8e80941Smrg } 725b8e80941Smrg if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_Z) { 726b8e80941Smrg info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamZ << 4; 727b8e80941Smrg info->num_stream_output_components[fulldecl->Semantic.StreamZ]++; 728b8e80941Smrg } 729b8e80941Smrg if (fulldecl->Declaration.UsageMask & TGSI_WRITEMASK_W) { 730b8e80941Smrg info->output_streams[reg] |= (ubyte)fulldecl->Semantic.StreamW << 6; 731b8e80941Smrg info->num_stream_output_components[fulldecl->Semantic.StreamW]++; 732b8e80941Smrg } 733b8e80941Smrg 734b8e80941Smrg switch (semName) { 735b8e80941Smrg case TGSI_SEMANTIC_PRIMID: 736b8e80941Smrg info->writes_primid = true; 737b8e80941Smrg break; 738b8e80941Smrg case TGSI_SEMANTIC_VIEWPORT_INDEX: 739b8e80941Smrg info->writes_viewport_index = true; 740b8e80941Smrg break; 741b8e80941Smrg case TGSI_SEMANTIC_LAYER: 742b8e80941Smrg info->writes_layer = true; 743b8e80941Smrg break; 744b8e80941Smrg case TGSI_SEMANTIC_PSIZE: 745b8e80941Smrg info->writes_psize = true; 746b8e80941Smrg break; 747b8e80941Smrg case TGSI_SEMANTIC_CLIPVERTEX: 748b8e80941Smrg info->writes_clipvertex = true; 749b8e80941Smrg break; 750b8e80941Smrg case TGSI_SEMANTIC_COLOR: 751b8e80941Smrg info->colors_written |= 1 << semIndex; 752b8e80941Smrg break; 753b8e80941Smrg case TGSI_SEMANTIC_STENCIL: 754b8e80941Smrg info->writes_stencil = true; 755b8e80941Smrg break; 756b8e80941Smrg case TGSI_SEMANTIC_SAMPLEMASK: 757b8e80941Smrg info->writes_samplemask = true; 758b8e80941Smrg break; 759b8e80941Smrg case TGSI_SEMANTIC_EDGEFLAG: 760b8e80941Smrg info->writes_edgeflag = true; 761b8e80941Smrg break; 762b8e80941Smrg case TGSI_SEMANTIC_POSITION: 763b8e80941Smrg if (procType == PIPE_SHADER_FRAGMENT) 764b8e80941Smrg info->writes_z = true; 765b8e80941Smrg else 766b8e80941Smrg info->writes_position = true; 767b8e80941Smrg break; 768b8e80941Smrg } 769b8e80941Smrg break; 770b8e80941Smrg 771b8e80941Smrg case TGSI_FILE_SAMPLER: 772b8e80941Smrg STATIC_ASSERT(sizeof(info->samplers_declared) * 8 >= PIPE_MAX_SAMPLERS); 773b8e80941Smrg info->samplers_declared |= 1u << reg; 774b8e80941Smrg break; 775b8e80941Smrg 776b8e80941Smrg case TGSI_FILE_SAMPLER_VIEW: 777b8e80941Smrg target = fulldecl->SamplerView.Resource; 778b8e80941Smrg type = fulldecl->SamplerView.ReturnTypeX; 779b8e80941Smrg 780b8e80941Smrg assert(target < TGSI_TEXTURE_UNKNOWN); 781b8e80941Smrg if (info->sampler_targets[reg] == TGSI_TEXTURE_UNKNOWN) { 782b8e80941Smrg /* Save sampler target for this sampler index */ 783b8e80941Smrg info->sampler_targets[reg] = target; 784b8e80941Smrg info->sampler_type[reg] = type; 785b8e80941Smrg } else { 786b8e80941Smrg /* if previously declared, make sure targets agree */ 787b8e80941Smrg assert(info->sampler_targets[reg] == target); 788b8e80941Smrg assert(info->sampler_type[reg] == type); 789b8e80941Smrg } 790b8e80941Smrg break; 791b8e80941Smrg } 792b8e80941Smrg } 793b8e80941Smrg} 794b8e80941Smrg 795b8e80941Smrg 796b8e80941Smrgstatic void 797b8e80941Smrgscan_immediate(struct tgsi_shader_info *info) 798b8e80941Smrg{ 799b8e80941Smrg uint reg = info->immediate_count++; 800b8e80941Smrg uint file = TGSI_FILE_IMMEDIATE; 801b8e80941Smrg 802b8e80941Smrg info->file_mask[file] |= (1 << reg); 803b8e80941Smrg info->file_count[file]++; 804b8e80941Smrg info->file_max[file] = MAX2(info->file_max[file], (int)reg); 805b8e80941Smrg} 806b8e80941Smrg 807b8e80941Smrg 808b8e80941Smrgstatic void 809b8e80941Smrgscan_property(struct tgsi_shader_info *info, 810b8e80941Smrg const struct tgsi_full_property *fullprop) 811b8e80941Smrg{ 812b8e80941Smrg unsigned name = fullprop->Property.PropertyName; 813b8e80941Smrg unsigned value = fullprop->u[0].Data; 814b8e80941Smrg 815b8e80941Smrg assert(name < ARRAY_SIZE(info->properties)); 816b8e80941Smrg info->properties[name] = value; 817b8e80941Smrg 818b8e80941Smrg switch (name) { 819b8e80941Smrg case TGSI_PROPERTY_NUM_CLIPDIST_ENABLED: 820b8e80941Smrg info->num_written_clipdistance = value; 821b8e80941Smrg info->clipdist_writemask |= (1 << value) - 1; 822b8e80941Smrg break; 823b8e80941Smrg case TGSI_PROPERTY_NUM_CULLDIST_ENABLED: 824b8e80941Smrg info->num_written_culldistance = value; 825b8e80941Smrg info->culldist_writemask |= (1 << value) - 1; 826b8e80941Smrg break; 827b8e80941Smrg } 828b8e80941Smrg} 829848b8605Smrg 830848b8605Smrg 831848b8605Smrg/** 832848b8605Smrg * Scan the given TGSI shader to collect information such as number of 833848b8605Smrg * registers used, special instructions used, etc. 834848b8605Smrg * \return info the result of the scan 835848b8605Smrg */ 836848b8605Smrgvoid 837848b8605Smrgtgsi_scan_shader(const struct tgsi_token *tokens, 838848b8605Smrg struct tgsi_shader_info *info) 839848b8605Smrg{ 840848b8605Smrg uint procType, i; 841848b8605Smrg struct tgsi_parse_context parse; 842b8e80941Smrg unsigned current_depth = 0; 843848b8605Smrg 844848b8605Smrg memset(info, 0, sizeof(*info)); 845848b8605Smrg for (i = 0; i < TGSI_FILE_COUNT; i++) 846848b8605Smrg info->file_max[i] = -1; 847b8e80941Smrg for (i = 0; i < ARRAY_SIZE(info->const_file_max); i++) 848848b8605Smrg info->const_file_max[i] = -1; 849b8e80941Smrg info->properties[TGSI_PROPERTY_GS_INVOCATIONS] = 1; 850b8e80941Smrg for (i = 0; i < ARRAY_SIZE(info->sampler_targets); i++) 851b8e80941Smrg info->sampler_targets[i] = TGSI_TEXTURE_UNKNOWN; 852848b8605Smrg 853848b8605Smrg /** 854848b8605Smrg ** Setup to begin parsing input shader 855848b8605Smrg **/ 856848b8605Smrg if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) { 857848b8605Smrg debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n"); 858848b8605Smrg return; 859848b8605Smrg } 860848b8605Smrg procType = parse.FullHeader.Processor.Processor; 861b8e80941Smrg assert(procType == PIPE_SHADER_FRAGMENT || 862b8e80941Smrg procType == PIPE_SHADER_VERTEX || 863b8e80941Smrg procType == PIPE_SHADER_GEOMETRY || 864b8e80941Smrg procType == PIPE_SHADER_TESS_CTRL || 865b8e80941Smrg procType == PIPE_SHADER_TESS_EVAL || 866b8e80941Smrg procType == PIPE_SHADER_COMPUTE); 867848b8605Smrg info->processor = procType; 868b8e80941Smrg info->num_tokens = tgsi_num_tokens(parse.Tokens); 869848b8605Smrg 870848b8605Smrg /** 871848b8605Smrg ** Loop over incoming program tokens/instructions 872848b8605Smrg */ 873b8e80941Smrg while (!tgsi_parse_end_of_tokens(&parse)) { 874848b8605Smrg tgsi_parse_token( &parse ); 875848b8605Smrg 876848b8605Smrg switch( parse.FullToken.Token.Type ) { 877848b8605Smrg case TGSI_TOKEN_TYPE_INSTRUCTION: 878b8e80941Smrg scan_instruction(info, &parse.FullToken.FullInstruction, 879b8e80941Smrg ¤t_depth); 880b8e80941Smrg break; 881b8e80941Smrg case TGSI_TOKEN_TYPE_DECLARATION: 882b8e80941Smrg scan_declaration(info, &parse.FullToken.FullDeclaration); 883b8e80941Smrg break; 884b8e80941Smrg case TGSI_TOKEN_TYPE_IMMEDIATE: 885b8e80941Smrg scan_immediate(info); 886b8e80941Smrg break; 887b8e80941Smrg case TGSI_TOKEN_TYPE_PROPERTY: 888b8e80941Smrg scan_property(info, &parse.FullToken.FullProperty); 889b8e80941Smrg break; 890b8e80941Smrg default: 891b8e80941Smrg assert(!"Unexpected TGSI token type"); 892b8e80941Smrg } 893b8e80941Smrg } 894848b8605Smrg 895b8e80941Smrg info->uses_kill = (info->opcode_count[TGSI_OPCODE_KILL_IF] || 896b8e80941Smrg info->opcode_count[TGSI_OPCODE_KILL]); 897848b8605Smrg 898b8e80941Smrg /* The dimensions of the IN decleration in geometry shader have 899b8e80941Smrg * to be deduced from the type of the input primitive. 900b8e80941Smrg */ 901b8e80941Smrg if (procType == PIPE_SHADER_GEOMETRY) { 902b8e80941Smrg unsigned input_primitive = 903b8e80941Smrg info->properties[TGSI_PROPERTY_GS_INPUT_PRIM]; 904b8e80941Smrg int num_verts = u_vertices_per_prim(input_primitive); 905b8e80941Smrg int j; 906b8e80941Smrg info->file_count[TGSI_FILE_INPUT] = num_verts; 907b8e80941Smrg info->file_max[TGSI_FILE_INPUT] = 908b8e80941Smrg MAX2(info->file_max[TGSI_FILE_INPUT], num_verts - 1); 909b8e80941Smrg for (j = 0; j < num_verts; ++j) { 910b8e80941Smrg info->file_mask[TGSI_FILE_INPUT] |= (1 << j); 911b8e80941Smrg } 912b8e80941Smrg } 913848b8605Smrg 914b8e80941Smrg tgsi_parse_free(&parse); 915b8e80941Smrg} 916848b8605Smrg 917b8e80941Smrg/** 918b8e80941Smrg * Collect information about the arrays of a given register file. 919b8e80941Smrg * 920b8e80941Smrg * @param tokens TGSI shader 921b8e80941Smrg * @param file the register file to scan through 922b8e80941Smrg * @param max_array_id number of entries in @p arrays; should be equal to the 923b8e80941Smrg * highest array id, i.e. tgsi_shader_info::array_max[file]. 924b8e80941Smrg * @param arrays info for array of each ID will be written to arrays[ID - 1]. 925b8e80941Smrg */ 926b8e80941Smrgvoid 927b8e80941Smrgtgsi_scan_arrays(const struct tgsi_token *tokens, 928b8e80941Smrg unsigned file, 929b8e80941Smrg unsigned max_array_id, 930b8e80941Smrg struct tgsi_array_info *arrays) 931b8e80941Smrg{ 932b8e80941Smrg struct tgsi_parse_context parse; 933b8e80941Smrg 934b8e80941Smrg if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) { 935b8e80941Smrg debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n"); 936b8e80941Smrg return; 937b8e80941Smrg } 938b8e80941Smrg 939b8e80941Smrg memset(arrays, 0, sizeof(arrays[0]) * max_array_id); 940b8e80941Smrg 941b8e80941Smrg while (!tgsi_parse_end_of_tokens(&parse)) { 942b8e80941Smrg struct tgsi_full_instruction *inst; 943b8e80941Smrg 944b8e80941Smrg tgsi_parse_token(&parse); 945848b8605Smrg 946b8e80941Smrg if (parse.FullToken.Token.Type == TGSI_TOKEN_TYPE_DECLARATION) { 947b8e80941Smrg struct tgsi_full_declaration *decl = &parse.FullToken.FullDeclaration; 948b8e80941Smrg 949b8e80941Smrg if (decl->Declaration.Array && decl->Declaration.File == file && 950b8e80941Smrg decl->Array.ArrayID > 0 && decl->Array.ArrayID <= max_array_id) { 951b8e80941Smrg struct tgsi_array_info *array = &arrays[decl->Array.ArrayID - 1]; 952b8e80941Smrg assert(!array->declared); 953b8e80941Smrg array->declared = true; 954b8e80941Smrg array->range = decl->Range; 955848b8605Smrg } 956b8e80941Smrg } 957848b8605Smrg 958b8e80941Smrg if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION) 959b8e80941Smrg continue; 960b8e80941Smrg 961b8e80941Smrg inst = &parse.FullToken.FullInstruction; 962b8e80941Smrg for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) { 963b8e80941Smrg const struct tgsi_full_dst_register *dst = &inst->Dst[i]; 964b8e80941Smrg if (dst->Register.File != file) 965b8e80941Smrg continue; 966b8e80941Smrg 967b8e80941Smrg if (dst->Register.Indirect) { 968b8e80941Smrg if (dst->Indirect.ArrayID > 0 && 969b8e80941Smrg dst->Indirect.ArrayID <= max_array_id) { 970b8e80941Smrg arrays[dst->Indirect.ArrayID - 1].writemask |= dst->Register.WriteMask; 971b8e80941Smrg } else { 972b8e80941Smrg /* Indirect writes without an ArrayID can write anywhere. */ 973b8e80941Smrg for (unsigned j = 0; j < max_array_id; ++j) 974b8e80941Smrg arrays[j].writemask |= dst->Register.WriteMask; 975b8e80941Smrg } 976b8e80941Smrg } else { 977b8e80941Smrg /* Check whether the write falls into any of the arrays anyway. */ 978b8e80941Smrg for (unsigned j = 0; j < max_array_id; ++j) { 979b8e80941Smrg struct tgsi_array_info *array = &arrays[j]; 980b8e80941Smrg if (array->declared && 981b8e80941Smrg dst->Register.Index >= array->range.First && 982b8e80941Smrg dst->Register.Index <= array->range.Last) 983b8e80941Smrg array->writemask |= dst->Register.WriteMask; 984848b8605Smrg } 985848b8605Smrg } 986b8e80941Smrg } 987b8e80941Smrg } 988848b8605Smrg 989b8e80941Smrg tgsi_parse_free(&parse); 990848b8605Smrg 991b8e80941Smrg return; 992b8e80941Smrg} 993848b8605Smrg 994b8e80941Smrgstatic void 995b8e80941Smrgcheck_no_subroutines(const struct tgsi_full_instruction *inst) 996b8e80941Smrg{ 997b8e80941Smrg switch (inst->Instruction.Opcode) { 998b8e80941Smrg case TGSI_OPCODE_BGNSUB: 999b8e80941Smrg case TGSI_OPCODE_ENDSUB: 1000b8e80941Smrg case TGSI_OPCODE_CAL: 1001b8e80941Smrg unreachable("subroutines unhandled"); 1002b8e80941Smrg } 1003b8e80941Smrg} 1004848b8605Smrg 1005b8e80941Smrgstatic unsigned 1006b8e80941Smrgget_inst_tessfactor_writemask(const struct tgsi_shader_info *info, 1007b8e80941Smrg const struct tgsi_full_instruction *inst) 1008b8e80941Smrg{ 1009b8e80941Smrg unsigned writemask = 0; 1010848b8605Smrg 1011b8e80941Smrg for (unsigned i = 0; i < inst->Instruction.NumDstRegs; i++) { 1012b8e80941Smrg const struct tgsi_full_dst_register *dst = &inst->Dst[i]; 1013b8e80941Smrg 1014b8e80941Smrg if (dst->Register.File == TGSI_FILE_OUTPUT && 1015b8e80941Smrg !dst->Register.Indirect) { 1016b8e80941Smrg unsigned name = info->output_semantic_name[dst->Register.Index]; 1017b8e80941Smrg 1018b8e80941Smrg if (name == TGSI_SEMANTIC_TESSINNER) 1019b8e80941Smrg writemask |= dst->Register.WriteMask; 1020b8e80941Smrg else if (name == TGSI_SEMANTIC_TESSOUTER) 1021b8e80941Smrg writemask |= dst->Register.WriteMask << 4; 1022b8e80941Smrg } 1023b8e80941Smrg } 1024b8e80941Smrg return writemask; 1025b8e80941Smrg} 1026b8e80941Smrg 1027b8e80941Smrgstatic unsigned 1028b8e80941Smrgget_block_tessfactor_writemask(const struct tgsi_shader_info *info, 1029b8e80941Smrg struct tgsi_parse_context *parse, 1030b8e80941Smrg unsigned end_opcode) 1031b8e80941Smrg{ 1032b8e80941Smrg struct tgsi_full_instruction *inst; 1033b8e80941Smrg unsigned writemask = 0; 1034b8e80941Smrg 1035b8e80941Smrg tgsi_parse_token(parse); 1036b8e80941Smrg assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 1037b8e80941Smrg inst = &parse->FullToken.FullInstruction; 1038b8e80941Smrg check_no_subroutines(inst); 1039b8e80941Smrg 1040b8e80941Smrg while (inst->Instruction.Opcode != end_opcode) { 1041b8e80941Smrg 1042b8e80941Smrg /* Recursively process nested blocks. */ 1043b8e80941Smrg switch (inst->Instruction.Opcode) { 1044b8e80941Smrg case TGSI_OPCODE_IF: 1045b8e80941Smrg case TGSI_OPCODE_UIF: 1046b8e80941Smrg writemask |= 1047b8e80941Smrg get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDIF); 1048b8e80941Smrg break; 1049b8e80941Smrg 1050b8e80941Smrg case TGSI_OPCODE_BGNLOOP: 1051b8e80941Smrg writemask |= 1052b8e80941Smrg get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP); 1053b8e80941Smrg break; 1054b8e80941Smrg 1055b8e80941Smrg case TGSI_OPCODE_BARRIER: 1056b8e80941Smrg unreachable("nested BARRIER is illegal"); 1057848b8605Smrg break; 1058848b8605Smrg 1059848b8605Smrg default: 1060b8e80941Smrg writemask |= get_inst_tessfactor_writemask(info, inst); 1061848b8605Smrg } 1062b8e80941Smrg 1063b8e80941Smrg tgsi_parse_token(parse); 1064b8e80941Smrg assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 1065b8e80941Smrg inst = &parse->FullToken.FullInstruction; 1066b8e80941Smrg check_no_subroutines(inst); 1067848b8605Smrg } 1068848b8605Smrg 1069b8e80941Smrg return writemask; 1070b8e80941Smrg} 1071b8e80941Smrg 1072b8e80941Smrgstatic void 1073b8e80941Smrgget_if_block_tessfactor_writemask(const struct tgsi_shader_info *info, 1074b8e80941Smrg struct tgsi_parse_context *parse, 1075b8e80941Smrg unsigned *upper_block_tf_writemask, 1076b8e80941Smrg unsigned *cond_block_tf_writemask) 1077b8e80941Smrg{ 1078b8e80941Smrg struct tgsi_full_instruction *inst; 1079b8e80941Smrg unsigned then_tessfactor_writemask = 0; 1080b8e80941Smrg unsigned else_tessfactor_writemask = 0; 1081b8e80941Smrg unsigned writemask; 1082b8e80941Smrg bool is_then = true; 1083b8e80941Smrg 1084b8e80941Smrg tgsi_parse_token(parse); 1085b8e80941Smrg assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 1086b8e80941Smrg inst = &parse->FullToken.FullInstruction; 1087b8e80941Smrg check_no_subroutines(inst); 1088848b8605Smrg 1089b8e80941Smrg while (inst->Instruction.Opcode != TGSI_OPCODE_ENDIF) { 1090b8e80941Smrg 1091b8e80941Smrg switch (inst->Instruction.Opcode) { 1092b8e80941Smrg case TGSI_OPCODE_ELSE: 1093b8e80941Smrg is_then = false; 1094848b8605Smrg break; 1095b8e80941Smrg 1096b8e80941Smrg /* Recursively process nested blocks. */ 1097b8e80941Smrg case TGSI_OPCODE_IF: 1098b8e80941Smrg case TGSI_OPCODE_UIF: 1099b8e80941Smrg get_if_block_tessfactor_writemask(info, parse, 1100b8e80941Smrg is_then ? &then_tessfactor_writemask : 1101b8e80941Smrg &else_tessfactor_writemask, 1102b8e80941Smrg cond_block_tf_writemask); 1103848b8605Smrg break; 1104b8e80941Smrg 1105b8e80941Smrg case TGSI_OPCODE_BGNLOOP: 1106b8e80941Smrg *cond_block_tf_writemask |= 1107b8e80941Smrg get_block_tessfactor_writemask(info, parse, TGSI_OPCODE_ENDLOOP); 1108848b8605Smrg break; 1109b8e80941Smrg 1110b8e80941Smrg case TGSI_OPCODE_BARRIER: 1111b8e80941Smrg unreachable("nested BARRIER is illegal"); 1112848b8605Smrg break; 1113848b8605Smrg default: 1114b8e80941Smrg /* Process an instruction in the current block. */ 1115b8e80941Smrg writemask = get_inst_tessfactor_writemask(info, inst); 1116b8e80941Smrg 1117b8e80941Smrg if (writemask) { 1118b8e80941Smrg if (is_then) 1119b8e80941Smrg then_tessfactor_writemask |= writemask; 1120b8e80941Smrg else 1121b8e80941Smrg else_tessfactor_writemask |= writemask; 1122b8e80941Smrg } 1123848b8605Smrg } 1124b8e80941Smrg 1125b8e80941Smrg tgsi_parse_token(parse); 1126b8e80941Smrg assert(parse->FullToken.Token.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 1127b8e80941Smrg inst = &parse->FullToken.FullInstruction; 1128b8e80941Smrg check_no_subroutines(inst); 1129848b8605Smrg } 1130848b8605Smrg 1131b8e80941Smrg if (then_tessfactor_writemask || else_tessfactor_writemask) { 1132b8e80941Smrg /* If both statements write the same tess factor channels, 1133b8e80941Smrg * we can say that the upper block writes them too. */ 1134b8e80941Smrg *upper_block_tf_writemask |= then_tessfactor_writemask & 1135b8e80941Smrg else_tessfactor_writemask; 1136b8e80941Smrg *cond_block_tf_writemask |= then_tessfactor_writemask | 1137b8e80941Smrg else_tessfactor_writemask; 1138b8e80941Smrg } 1139848b8605Smrg} 1140848b8605Smrg 1141b8e80941Smrgvoid 1142b8e80941Smrgtgsi_scan_tess_ctrl(const struct tgsi_token *tokens, 1143b8e80941Smrg const struct tgsi_shader_info *info, 1144b8e80941Smrg struct tgsi_tessctrl_info *out) 1145b8e80941Smrg{ 1146b8e80941Smrg memset(out, 0, sizeof(*out)); 1147848b8605Smrg 1148b8e80941Smrg if (info->processor != PIPE_SHADER_TESS_CTRL) 1149b8e80941Smrg return; 1150848b8605Smrg 1151848b8605Smrg struct tgsi_parse_context parse; 1152848b8605Smrg if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) { 1153b8e80941Smrg debug_printf("tgsi_parse_init() failed in tgsi_scan_arrays()!\n"); 1154b8e80941Smrg return; 1155848b8605Smrg } 1156848b8605Smrg 1157b8e80941Smrg /* The pass works as follows: 1158b8e80941Smrg * If all codepaths write tess factors, we can say that all invocations 1159b8e80941Smrg * define tess factors. 1160b8e80941Smrg * 1161b8e80941Smrg * Each tess factor channel is tracked separately. 1162848b8605Smrg */ 1163b8e80941Smrg unsigned main_block_tf_writemask = 0; /* if main block writes tess factors */ 1164b8e80941Smrg unsigned cond_block_tf_writemask = 0; /* if cond block writes tess factors */ 1165848b8605Smrg 1166b8e80941Smrg /* Initial value = true. Here the pass will accumulate results from multiple 1167b8e80941Smrg * segments surrounded by barriers. If tess factors aren't written at all, 1168b8e80941Smrg * it's a shader bug and we don't care if this will be true. 1169b8e80941Smrg */ 1170b8e80941Smrg out->tessfactors_are_def_in_all_invocs = true; 1171b8e80941Smrg 1172b8e80941Smrg while (!tgsi_parse_end_of_tokens(&parse)) { 1173848b8605Smrg tgsi_parse_token(&parse); 1174848b8605Smrg 1175b8e80941Smrg if (parse.FullToken.Token.Type != TGSI_TOKEN_TYPE_INSTRUCTION) 1176b8e80941Smrg continue; 1177848b8605Smrg 1178b8e80941Smrg struct tgsi_full_instruction *inst = &parse.FullToken.FullInstruction; 1179b8e80941Smrg check_no_subroutines(inst); 1180b8e80941Smrg 1181b8e80941Smrg /* Process nested blocks. */ 1182b8e80941Smrg switch (inst->Instruction.Opcode) { 1183b8e80941Smrg case TGSI_OPCODE_IF: 1184b8e80941Smrg case TGSI_OPCODE_UIF: 1185b8e80941Smrg get_if_block_tessfactor_writemask(info, &parse, 1186b8e80941Smrg &main_block_tf_writemask, 1187b8e80941Smrg &cond_block_tf_writemask); 1188b8e80941Smrg continue; 1189b8e80941Smrg 1190b8e80941Smrg case TGSI_OPCODE_BGNLOOP: 1191b8e80941Smrg cond_block_tf_writemask |= 1192b8e80941Smrg get_block_tessfactor_writemask(info, &parse, TGSI_OPCODE_ENDLOOP); 1193b8e80941Smrg continue; 1194b8e80941Smrg 1195b8e80941Smrg case TGSI_OPCODE_BARRIER: 1196b8e80941Smrg /* The following case must be prevented: 1197b8e80941Smrg * gl_TessLevelInner = ...; 1198b8e80941Smrg * barrier(); 1199b8e80941Smrg * if (gl_InvocationID == 1) 1200b8e80941Smrg * gl_TessLevelInner = ...; 1201b8e80941Smrg * 1202b8e80941Smrg * If you consider disjoint code segments separated by barriers, each 1203b8e80941Smrg * such segment that writes tess factor channels should write the same 1204b8e80941Smrg * channels in all codepaths within that segment. 1205b8e80941Smrg */ 1206b8e80941Smrg if (main_block_tf_writemask || cond_block_tf_writemask) { 1207b8e80941Smrg /* Accumulate the result: */ 1208b8e80941Smrg out->tessfactors_are_def_in_all_invocs &= 1209b8e80941Smrg !(cond_block_tf_writemask & ~main_block_tf_writemask); 1210b8e80941Smrg 1211b8e80941Smrg /* Analyze the next code segment from scratch. */ 1212b8e80941Smrg main_block_tf_writemask = 0; 1213b8e80941Smrg cond_block_tf_writemask = 0; 1214b8e80941Smrg } 1215b8e80941Smrg continue; 1216848b8605Smrg } 1217b8e80941Smrg 1218b8e80941Smrg main_block_tf_writemask |= get_inst_tessfactor_writemask(info, inst); 1219848b8605Smrg } 1220848b8605Smrg 1221b8e80941Smrg /* Accumulate the result for the last code segment separated by a barrier. */ 1222b8e80941Smrg if (main_block_tf_writemask || cond_block_tf_writemask) { 1223b8e80941Smrg out->tessfactors_are_def_in_all_invocs &= 1224b8e80941Smrg !(cond_block_tf_writemask & ~main_block_tf_writemask); 1225b8e80941Smrg } 1226848b8605Smrg 1227b8e80941Smrg tgsi_parse_free(&parse); 1228848b8605Smrg} 1229