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