lp_bld_tgsi_info.c revision d8452a0be810d7176b0cbfe6632fc0f8016b5733
1/************************************************************************** 2 * 3 * Copyright 2010 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 * USE OR OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * The above copyright notice and this permission notice (including the 23 * next paragraph) shall be included in all copies or substantial portions 24 * of the Software. 25 * 26 **************************************************************************/ 27 28 29#include "util/u_memory.h" 30#include "util/u_math.h" 31#include "tgsi/tgsi_parse.h" 32#include "tgsi/tgsi_util.h" 33#include "tgsi/tgsi_dump.h" 34#include "lp_bld_debug.h" 35#include "lp_bld_tgsi.h" 36 37 38/** 39 * Analysis context. 40 * 41 * This is where we keep store the value of each channel of the IMM/TEMP/OUT 42 * register values, as we walk the shader. 43 */ 44struct analysis_context 45{ 46 struct lp_tgsi_info *info; 47 48 unsigned num_imms; 49 float imm[32][4]; 50 51 struct lp_tgsi_channel_info temp[32][4]; 52}; 53 54 55/** 56 * Describe the specified channel of the src register. 57 */ 58static void 59analyse_src(struct analysis_context *ctx, 60 struct lp_tgsi_channel_info *chan_info, 61 const struct tgsi_src_register *src, 62 unsigned chan) 63{ 64 chan_info->file = TGSI_FILE_NULL; 65 if (!src->Indirect && !src->Absolute && !src->Negate) { 66 unsigned swizzle = tgsi_util_get_src_register_swizzle(src, chan); 67 if (src->File == TGSI_FILE_TEMPORARY) { 68 if (src->Index < Elements(ctx->temp)) { 69 *chan_info = ctx->temp[src->Index][swizzle]; 70 } 71 } else { 72 chan_info->file = src->File; 73 if (src->File == TGSI_FILE_IMMEDIATE) { 74 assert(src->Index < Elements(ctx->imm)); 75 if (src->Index < Elements(ctx->imm)) { 76 chan_info->u.value = ctx->imm[src->Index][swizzle]; 77 } 78 } else { 79 chan_info->u.index = src->Index; 80 chan_info->swizzle = swizzle; 81 } 82 } 83 } 84} 85 86 87/** 88 * Whether this register channel refers to a specific immediate value. 89 */ 90static boolean 91is_immediate(const struct lp_tgsi_channel_info *chan_info, float value) 92{ 93 return chan_info->file == TGSI_FILE_IMMEDIATE && 94 chan_info->u.value == value; 95} 96 97 98static void 99analyse_tex(struct analysis_context *ctx, 100 const struct tgsi_full_instruction *inst, 101 enum lp_build_tex_modifier modifier) 102{ 103 struct lp_tgsi_info *info = ctx->info; 104 unsigned chan; 105 106 if (info->num_texs < Elements(info->tex)) { 107 struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs]; 108 boolean indirect = FALSE; 109 unsigned readmask = 0; 110 111 tex_info->target = inst->Texture.Texture; 112 switch (inst->Texture.Texture) { 113 case TGSI_TEXTURE_1D: 114 readmask = TGSI_WRITEMASK_X; 115 break; 116 case TGSI_TEXTURE_1D_ARRAY: 117 case TGSI_TEXTURE_2D: 118 case TGSI_TEXTURE_RECT: 119 readmask = TGSI_WRITEMASK_XY; 120 break; 121 case TGSI_TEXTURE_SHADOW1D: 122 case TGSI_TEXTURE_SHADOW1D_ARRAY: 123 case TGSI_TEXTURE_SHADOW2D: 124 case TGSI_TEXTURE_SHADOWRECT: 125 case TGSI_TEXTURE_2D_ARRAY: 126 case TGSI_TEXTURE_3D: 127 case TGSI_TEXTURE_CUBE: 128 readmask = TGSI_WRITEMASK_XYZ; 129 break; 130 case TGSI_TEXTURE_SHADOW2D_ARRAY: 131 readmask = TGSI_WRITEMASK_XYZW; 132 break; 133 default: 134 assert(0); 135 return; 136 } 137 138 if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) { 139 /* We don't track explicit derivatives, although we could */ 140 indirect = TRUE; 141 tex_info->unit = inst->Src[3].Register.Index; 142 } else { 143 if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED || 144 modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS || 145 modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) { 146 readmask |= TGSI_WRITEMASK_W; 147 } 148 tex_info->unit = inst->Src[1].Register.Index; 149 } 150 151 for (chan = 0; chan < 4; ++chan) { 152 struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan]; 153 if (readmask & (1 << chan)) { 154 analyse_src(ctx, chan_info, &inst->Src[0].Register, chan); 155 if (chan_info->file != TGSI_FILE_INPUT) { 156 indirect = TRUE; 157 } 158 } else { 159 memset(chan_info, 0, sizeof *chan_info); 160 } 161 } 162 163 if (indirect) { 164 info->indirect_textures = TRUE; 165 } 166 167 ++info->num_texs; 168 } else { 169 info->indirect_textures = TRUE; 170 } 171} 172 173 174/** 175 * Process an instruction, and update the register values accordingly. 176 */ 177static void 178analyse_instruction(struct analysis_context *ctx, 179 struct tgsi_full_instruction *inst) 180{ 181 struct lp_tgsi_info *info = ctx->info; 182 struct lp_tgsi_channel_info (*regs)[4]; 183 unsigned max_regs; 184 unsigned i; 185 unsigned index; 186 unsigned chan; 187 188 for (i = 0; i < inst->Instruction.NumDstRegs; ++i) { 189 const struct tgsi_dst_register *dst = &inst->Dst[i].Register; 190 191 /* 192 * Get the lp_tgsi_channel_info array corresponding to the destination 193 * register file. 194 */ 195 196 if (dst->File == TGSI_FILE_TEMPORARY) { 197 regs = ctx->temp; 198 max_regs = Elements(ctx->temp); 199 } else if (dst->File == TGSI_FILE_OUTPUT) { 200 regs = info->output; 201 max_regs = Elements(info->output); 202 } else if (dst->File == TGSI_FILE_ADDRESS || 203 dst->File == TGSI_FILE_PREDICATE) { 204 continue; 205 } else { 206 assert(0); 207 continue; 208 } 209 210 /* 211 * Detect direct TEX instructions 212 */ 213 214 switch (inst->Instruction.Opcode) { 215 case TGSI_OPCODE_TEX: 216 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE); 217 break; 218 case TGSI_OPCODE_TXD: 219 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV); 220 break; 221 case TGSI_OPCODE_TXB: 222 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS); 223 break; 224 case TGSI_OPCODE_TXL: 225 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD); 226 break; 227 case TGSI_OPCODE_TXP: 228 analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED); 229 break; 230 default: 231 break; 232 } 233 234 /* 235 * Keep track of assignments and writes 236 */ 237 238 if (dst->Indirect) { 239 /* 240 * It could be any register index so clear all register indices. 241 */ 242 243 for (chan = 0; chan < 4; ++chan) { 244 if (dst->WriteMask & (1 << chan)) { 245 for (index = 0; index < max_regs; ++index) { 246 regs[index][chan].file = TGSI_FILE_NULL; 247 } 248 } 249 } 250 } else if (dst->Index < max_regs) { 251 /* 252 * Update this destination register value. 253 */ 254 255 struct lp_tgsi_channel_info res[4]; 256 257 memset(res, 0, sizeof res); 258 259 if (!inst->Instruction.Predicate && 260 !inst->Instruction.Saturate) { 261 for (chan = 0; chan < 4; ++chan) { 262 if (dst->WriteMask & (1 << chan)) { 263 if (inst->Instruction.Opcode == TGSI_OPCODE_MOV) { 264 analyse_src(ctx, &res[chan], 265 &inst->Src[0].Register, chan); 266 } else if (inst->Instruction.Opcode == TGSI_OPCODE_MUL) { 267 /* 268 * Propagate values across 1.0 and 0.0 multiplications. 269 */ 270 271 struct lp_tgsi_channel_info src0; 272 struct lp_tgsi_channel_info src1; 273 274 analyse_src(ctx, &src0, &inst->Src[0].Register, chan); 275 analyse_src(ctx, &src1, &inst->Src[1].Register, chan); 276 277 if (is_immediate(&src0, 0.0f)) { 278 res[chan] = src0; 279 } else if (is_immediate(&src1, 0.0f)) { 280 res[chan] = src1; 281 } else if (is_immediate(&src0, 1.0f)) { 282 res[chan] = src1; 283 } else if (is_immediate(&src1, 1.0f)) { 284 res[chan] = src0; 285 } 286 } 287 } 288 } 289 } 290 291 for (chan = 0; chan < 4; ++chan) { 292 if (dst->WriteMask & (1 << chan)) { 293 regs[dst->Index][chan] = res[chan]; 294 } 295 } 296 } 297 } 298 299 /* 300 * Clear all temporaries information in presence of a control flow opcode. 301 */ 302 303 switch (inst->Instruction.Opcode) { 304 case TGSI_OPCODE_IF: 305 case TGSI_OPCODE_IFC: 306 case TGSI_OPCODE_ELSE: 307 case TGSI_OPCODE_ENDIF: 308 case TGSI_OPCODE_BGNLOOP: 309 case TGSI_OPCODE_BRK: 310 case TGSI_OPCODE_BREAKC: 311 case TGSI_OPCODE_CONT: 312 case TGSI_OPCODE_ENDLOOP: 313 case TGSI_OPCODE_CALLNZ: 314 case TGSI_OPCODE_CAL: 315 case TGSI_OPCODE_BGNSUB: 316 case TGSI_OPCODE_ENDSUB: 317 case TGSI_OPCODE_SWITCH: 318 case TGSI_OPCODE_CASE: 319 case TGSI_OPCODE_DEFAULT: 320 case TGSI_OPCODE_ENDSWITCH: 321 case TGSI_OPCODE_RET: 322 case TGSI_OPCODE_END: 323 /* XXX: Are there more cases? */ 324 memset(&ctx->temp, 0, sizeof ctx->temp); 325 memset(&info->output, 0, sizeof info->output); 326 default: 327 break; 328 } 329} 330 331 332static INLINE void 333dump_info(const struct tgsi_token *tokens, 334 struct lp_tgsi_info *info) 335{ 336 unsigned index; 337 unsigned chan; 338 339 tgsi_dump(tokens, 0); 340 341 for (index = 0; index < info->num_texs; ++index) { 342 const struct lp_tgsi_texture_info *tex_info = &info->tex[index]; 343 debug_printf("TEX[%u] =", index); 344 for (chan = 0; chan < 4; ++chan) { 345 const struct lp_tgsi_channel_info *chan_info = 346 &tex_info->coord[chan]; 347 if (chan_info->file != TGSI_FILE_NULL) { 348 debug_printf(" %s[%u].%c", 349 tgsi_file_names[chan_info->file], 350 chan_info->u.index, 351 "xyzw01"[chan_info->swizzle]); 352 } else { 353 debug_printf(" _"); 354 } 355 } 356 debug_printf(", SAMP[%u], %s\n", 357 tex_info->unit, 358 tgsi_texture_names[tex_info->target]); 359 } 360 361 for (index = 0; index < PIPE_MAX_SHADER_OUTPUTS; ++index) { 362 for (chan = 0; chan < 4; ++chan) { 363 const struct lp_tgsi_channel_info *chan_info = 364 &info->output[index][chan]; 365 if (chan_info->file != TGSI_FILE_NULL) { 366 debug_printf("OUT[%u].%c = ", index, "xyzw"[chan]); 367 if (chan_info->file == TGSI_FILE_IMMEDIATE) { 368 debug_printf("%f", chan_info->u.value); 369 } else { 370 const char *file_name; 371 switch (chan_info->file) { 372 case TGSI_FILE_CONSTANT: 373 file_name = "CONST"; 374 break; 375 case TGSI_FILE_INPUT: 376 file_name = "IN"; 377 break; 378 default: 379 file_name = "???"; 380 break; 381 } 382 debug_printf("%s[%u].%c", 383 file_name, 384 chan_info->u.index, 385 "xyzw01"[chan_info->swizzle]); 386 } 387 debug_printf("\n"); 388 } 389 } 390 } 391} 392 393 394/** 395 * Detect any direct relationship between the output color 396 */ 397void 398lp_build_tgsi_info(const struct tgsi_token *tokens, 399 struct lp_tgsi_info *info) 400{ 401 struct tgsi_parse_context parse; 402 struct analysis_context ctx; 403 unsigned index; 404 unsigned chan; 405 406 memset(info, 0, sizeof *info); 407 408 tgsi_scan_shader(tokens, &info->base); 409 410 memset(&ctx, 0, sizeof ctx); 411 ctx.info = info; 412 413 tgsi_parse_init(&parse, tokens); 414 415 while (!tgsi_parse_end_of_tokens(&parse)) { 416 tgsi_parse_token(&parse); 417 418 switch (parse.FullToken.Token.Type) { 419 case TGSI_TOKEN_TYPE_DECLARATION: 420 break; 421 422 case TGSI_TOKEN_TYPE_INSTRUCTION: 423 { 424 struct tgsi_full_instruction *inst = 425 &parse.FullToken.FullInstruction; 426 427 if (inst->Instruction.Opcode == TGSI_OPCODE_END || 428 inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) { 429 /* We reached the end of main function body. */ 430 goto finished; 431 } 432 433 analyse_instruction(&ctx, inst); 434 } 435 break; 436 437 case TGSI_TOKEN_TYPE_IMMEDIATE: 438 { 439 const unsigned size = 440 parse.FullToken.FullImmediate.Immediate.NrTokens - 1; 441 assert(size <= 4); 442 if (ctx.num_imms < Elements(ctx.imm)) { 443 for (chan = 0; chan < size; ++chan) { 444 ctx.imm[ctx.num_imms][chan] = 445 parse.FullToken.FullImmediate.u[chan].Float; 446 } 447 ++ctx.num_imms; 448 } 449 } 450 break; 451 452 case TGSI_TOKEN_TYPE_PROPERTY: 453 break; 454 455 default: 456 assert(0); 457 } 458 } 459finished: 460 461 tgsi_parse_free(&parse); 462 463 464 /* 465 * Link the output color values. 466 */ 467 468 for (index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) { 469 const struct lp_tgsi_channel_info null_output[4]; 470 info->cbuf[index] = null_output; 471 } 472 473 for (index = 0; index < info->base.num_outputs; ++index) { 474 unsigned semantic_name = info->base.output_semantic_name[index]; 475 unsigned semantic_index = info->base.output_semantic_index[index]; 476 if (semantic_name == TGSI_SEMANTIC_COLOR && 477 semantic_index < PIPE_MAX_COLOR_BUFS) { 478 info->cbuf[semantic_index] = info->output[index]; 479 } 480 } 481 482 if (gallivm_debug & GALLIVM_DEBUG_TGSI) { 483 dump_info(tokens, info); 484 } 485} 486