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