1 /************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 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 TUNGSTEN GRAPHICS 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_math.h" 38 #include "tgsi/tgsi_parse.h" 39 #include "tgsi/tgsi_util.h" 40 #include "tgsi/tgsi_scan.h" 41 42 43 44 45 /** 46 * Scan the given TGSI shader to collect information such as number of 47 * registers used, special instructions used, etc. 48 * \return info the result of the scan 49 */ 50 void 51 tgsi_scan_shader(const struct tgsi_token *tokens, 52 struct tgsi_shader_info *info) 53 { 54 uint procType, i; 55 struct tgsi_parse_context parse; 56 57 memset(info, 0, sizeof(*info)); 58 for (i = 0; i < TGSI_FILE_COUNT; i++) 59 info->file_max[i] = -1; 60 61 /** 62 ** Setup to begin parsing input shader 63 **/ 64 if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) { 65 debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n"); 66 return; 67 } 68 procType = parse.FullHeader.Processor.Processor; 69 assert(procType == TGSI_PROCESSOR_FRAGMENT || 70 procType == TGSI_PROCESSOR_VERTEX || 71 procType == TGSI_PROCESSOR_GEOMETRY || 72 procType == TGSI_PROCESSOR_COMPUTE); 73 74 75 /** 76 ** Loop over incoming program tokens/instructions 77 */ 78 while( !tgsi_parse_end_of_tokens( &parse ) ) { 79 80 info->num_tokens++; 81 82 tgsi_parse_token( &parse ); 83 84 switch( parse.FullToken.Token.Type ) { 85 case TGSI_TOKEN_TYPE_INSTRUCTION: 86 { 87 const struct tgsi_full_instruction *fullinst 88 = &parse.FullToken.FullInstruction; 89 uint i; 90 91 assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST); 92 info->opcode_count[fullinst->Instruction.Opcode]++; 93 94 for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) { 95 const struct tgsi_full_src_register *src = 96 &fullinst->Src[i]; 97 int ind = src->Register.Index; 98 99 /* Mark which inputs are effectively used */ 100 if (src->Register.File == TGSI_FILE_INPUT) { 101 unsigned usage_mask; 102 usage_mask = tgsi_util_get_inst_usage_mask(fullinst, i); 103 if (src->Register.Indirect) { 104 for (ind = 0; ind < info->num_inputs; ++ind) { 105 info->input_usage_mask[ind] |= usage_mask; 106 } 107 } else { 108 assert(ind >= 0); 109 assert(ind < PIPE_MAX_SHADER_INPUTS); 110 info->input_usage_mask[ind] |= usage_mask; 111 } 112 113 if (procType == TGSI_PROCESSOR_FRAGMENT && 114 src->Register.File == TGSI_FILE_INPUT && 115 info->reads_position && 116 src->Register.Index == 0 && 117 (src->Register.SwizzleX == TGSI_SWIZZLE_Z || 118 src->Register.SwizzleY == TGSI_SWIZZLE_Z || 119 src->Register.SwizzleZ == TGSI_SWIZZLE_Z || 120 src->Register.SwizzleW == TGSI_SWIZZLE_Z)) { 121 info->reads_z = TRUE; 122 } 123 } 124 125 /* check for indirect register reads */ 126 if (src->Register.Indirect) { 127 info->indirect_files |= (1 << src->Register.File); 128 } 129 } 130 131 /* check for indirect register writes */ 132 for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) { 133 const struct tgsi_full_dst_register *dst = &fullinst->Dst[i]; 134 if (dst->Register.Indirect) { 135 info->indirect_files |= (1 << dst->Register.File); 136 } 137 } 138 139 info->num_instructions++; 140 } 141 break; 142 143 case TGSI_TOKEN_TYPE_DECLARATION: 144 { 145 const struct tgsi_full_declaration *fulldecl 146 = &parse.FullToken.FullDeclaration; 147 const uint file = fulldecl->Declaration.File; 148 uint reg; 149 for (reg = fulldecl->Range.First; 150 reg <= fulldecl->Range.Last; 151 reg++) { 152 153 /* only first 32 regs will appear in this bitfield */ 154 info->file_mask[file] |= (1 << reg); 155 info->file_count[file]++; 156 info->file_max[file] = MAX2(info->file_max[file], (int)reg); 157 158 if (file == TGSI_FILE_INPUT) { 159 info->input_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name; 160 info->input_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index; 161 info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate; 162 info->input_centroid[reg] = (ubyte)fulldecl->Interp.Centroid; 163 info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap; 164 info->num_inputs++; 165 166 if (procType == TGSI_PROCESSOR_FRAGMENT && 167 fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION) 168 info->reads_position = TRUE; 169 } 170 else if (file == TGSI_FILE_SYSTEM_VALUE) { 171 unsigned index = fulldecl->Range.First; 172 unsigned semName = fulldecl->Semantic.Name; 173 174 info->system_value_semantic_name[index] = semName; 175 info->num_system_values = MAX2(info->num_system_values, 176 index + 1); 177 178 /* 179 info->system_value_semantic_name[info->num_system_values++] = 180 fulldecl->Semantic.Name; 181 */ 182 183 if (fulldecl->Semantic.Name == TGSI_SEMANTIC_INSTANCEID) { 184 info->uses_instanceid = TRUE; 185 } 186 else if (fulldecl->Semantic.Name == TGSI_SEMANTIC_VERTEXID) { 187 info->uses_vertexid = TRUE; 188 } 189 } 190 else if (file == TGSI_FILE_OUTPUT) { 191 info->output_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name; 192 info->output_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index; 193 info->num_outputs++; 194 195 if (procType == TGSI_PROCESSOR_VERTEX && 196 fulldecl->Semantic.Name == TGSI_SEMANTIC_CLIPDIST) { 197 info->num_written_clipdistance += util_bitcount(fulldecl->Declaration.UsageMask); 198 } 199 /* extra info for special outputs */ 200 if (procType == TGSI_PROCESSOR_FRAGMENT && 201 fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION) 202 info->writes_z = TRUE; 203 if (procType == TGSI_PROCESSOR_FRAGMENT && 204 fulldecl->Semantic.Name == TGSI_SEMANTIC_STENCIL) 205 info->writes_stencil = TRUE; 206 if (procType == TGSI_PROCESSOR_VERTEX && 207 fulldecl->Semantic.Name == TGSI_SEMANTIC_EDGEFLAG) { 208 info->writes_edgeflag = TRUE; 209 } 210 } 211 212 } 213 } 214 break; 215 216 case TGSI_TOKEN_TYPE_IMMEDIATE: 217 { 218 uint reg = info->immediate_count++; 219 uint file = TGSI_FILE_IMMEDIATE; 220 221 info->file_mask[file] |= (1 << reg); 222 info->file_count[file]++; 223 info->file_max[file] = MAX2(info->file_max[file], (int)reg); 224 } 225 break; 226 227 case TGSI_TOKEN_TYPE_PROPERTY: 228 { 229 const struct tgsi_full_property *fullprop 230 = &parse.FullToken.FullProperty; 231 232 info->properties[info->num_properties].name = 233 fullprop->Property.PropertyName; 234 memcpy(info->properties[info->num_properties].data, 235 fullprop->u, 8 * sizeof(unsigned));; 236 237 ++info->num_properties; 238 } 239 break; 240 241 default: 242 assert( 0 ); 243 } 244 } 245 246 info->uses_kill = (info->opcode_count[TGSI_OPCODE_KIL] || 247 info->opcode_count[TGSI_OPCODE_KILP]); 248 249 /* extract simple properties */ 250 for (i = 0; i < info->num_properties; ++i) { 251 switch (info->properties[i].name) { 252 case TGSI_PROPERTY_FS_COORD_ORIGIN: 253 info->origin_lower_left = info->properties[i].data[0]; 254 break; 255 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: 256 info->pixel_center_integer = info->properties[i].data[0]; 257 break; 258 case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS: 259 info->color0_writes_all_cbufs = info->properties[i].data[0]; 260 break; 261 default: 262 ; 263 } 264 } 265 266 tgsi_parse_free (&parse); 267 } 268 269 270 271 /** 272 * Check if the given shader is a "passthrough" shader consisting of only 273 * MOV instructions of the form: MOV OUT[n], IN[n] 274 * 275 */ 276 boolean 277 tgsi_is_passthrough_shader(const struct tgsi_token *tokens) 278 { 279 struct tgsi_parse_context parse; 280 281 /** 282 ** Setup to begin parsing input shader 283 **/ 284 if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) { 285 debug_printf("tgsi_parse_init() failed in tgsi_is_passthrough_shader()!\n"); 286 return FALSE; 287 } 288 289 /** 290 ** Loop over incoming program tokens/instructions 291 */ 292 while (!tgsi_parse_end_of_tokens(&parse)) { 293 294 tgsi_parse_token(&parse); 295 296 switch (parse.FullToken.Token.Type) { 297 case TGSI_TOKEN_TYPE_INSTRUCTION: 298 { 299 struct tgsi_full_instruction *fullinst = 300 &parse.FullToken.FullInstruction; 301 const struct tgsi_full_src_register *src = 302 &fullinst->Src[0]; 303 const struct tgsi_full_dst_register *dst = 304 &fullinst->Dst[0]; 305 306 /* Do a whole bunch of checks for a simple move */ 307 if (fullinst->Instruction.Opcode != TGSI_OPCODE_MOV || 308 (src->Register.File != TGSI_FILE_INPUT && 309 src->Register.File != TGSI_FILE_SYSTEM_VALUE) || 310 dst->Register.File != TGSI_FILE_OUTPUT || 311 src->Register.Index != dst->Register.Index || 312 313 src->Register.Negate || 314 src->Register.Absolute || 315 316 src->Register.SwizzleX != TGSI_SWIZZLE_X || 317 src->Register.SwizzleY != TGSI_SWIZZLE_Y || 318 src->Register.SwizzleZ != TGSI_SWIZZLE_Z || 319 src->Register.SwizzleW != TGSI_SWIZZLE_W || 320 321 dst->Register.WriteMask != TGSI_WRITEMASK_XYZW) 322 { 323 tgsi_parse_free(&parse); 324 return FALSE; 325 } 326 } 327 break; 328 329 case TGSI_TOKEN_TYPE_DECLARATION: 330 /* fall-through */ 331 case TGSI_TOKEN_TYPE_IMMEDIATE: 332 /* fall-through */ 333 case TGSI_TOKEN_TYPE_PROPERTY: 334 /* fall-through */ 335 default: 336 ; /* no-op */ 337 } 338 } 339 340 tgsi_parse_free(&parse); 341 342 /* if we get here, it's a pass-through shader */ 343 return TRUE; 344 } 345