1/* 2 * Copyright (C) 2010 Corbin Simpson 3 * Copyright (C) 2010 Marek Olšák <maraeo@gmail.com> 4 * 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a 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, sublicense, 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 17 * portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 23 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 */ 28 29#include "radeon_program_tex.h" 30 31#include "radeon_compiler_util.h" 32 33/* Series of transformations to be done on textures. */ 34 35static struct rc_src_register shadow_fail_value(struct r300_fragment_program_compiler *compiler, 36 int tmu) 37{ 38 struct rc_src_register reg = { 0, 0, 0, 0, 0, 0 }; 39 40 reg.File = RC_FILE_NONE; 41 reg.Swizzle = combine_swizzles(RC_SWIZZLE_0000, 42 compiler->state.unit[tmu].texture_swizzle); 43 return reg; 44} 45 46static struct rc_src_register shadow_pass_value(struct r300_fragment_program_compiler *compiler, 47 int tmu) 48{ 49 struct rc_src_register reg = { 0, 0, 0, 0, 0, 0 }; 50 51 reg.File = RC_FILE_NONE; 52 reg.Swizzle = combine_swizzles(RC_SWIZZLE_1111, 53 compiler->state.unit[tmu].texture_swizzle); 54 return reg; 55} 56 57static void scale_texcoords(struct r300_fragment_program_compiler *compiler, 58 struct rc_instruction *inst, 59 unsigned state_constant) 60{ 61 struct rc_instruction *inst_mov; 62 63 unsigned temp = rc_find_free_temporary(&compiler->Base); 64 65 inst_mov = rc_insert_new_instruction(&compiler->Base, inst->Prev); 66 67 inst_mov->U.I.Opcode = RC_OPCODE_MUL; 68 inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; 69 inst_mov->U.I.DstReg.Index = temp; 70 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 71 inst_mov->U.I.SrcReg[1].File = RC_FILE_CONSTANT; 72 inst_mov->U.I.SrcReg[1].Index = 73 rc_constants_add_state(&compiler->Base.Program.Constants, 74 state_constant, inst->U.I.TexSrcUnit); 75 76 reset_srcreg(&inst->U.I.SrcReg[0]); 77 inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 78 inst->U.I.SrcReg[0].Index = temp; 79} 80 81static void projective_divide(struct r300_fragment_program_compiler *compiler, 82 struct rc_instruction *inst) 83{ 84 struct rc_instruction *inst_mul, *inst_rcp; 85 86 unsigned temp = rc_find_free_temporary(&compiler->Base); 87 88 inst_rcp = rc_insert_new_instruction(&compiler->Base, inst->Prev); 89 inst_rcp->U.I.Opcode = RC_OPCODE_RCP; 90 inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY; 91 inst_rcp->U.I.DstReg.Index = temp; 92 inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W; 93 inst_rcp->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 94 /* Because the input can be arbitrarily swizzled, 95 * read the component mapped to W. */ 96 inst_rcp->U.I.SrcReg[0].Swizzle = 97 RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 3)); 98 99 inst_mul = rc_insert_new_instruction(&compiler->Base, inst->Prev); 100 inst_mul->U.I.Opcode = RC_OPCODE_MUL; 101 inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY; 102 inst_mul->U.I.DstReg.Index = temp; 103 inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 104 inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; 105 inst_mul->U.I.SrcReg[1].Index = temp; 106 inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW; 107 108 reset_srcreg(&inst->U.I.SrcReg[0]); 109 inst->U.I.Opcode = RC_OPCODE_TEX; 110 inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 111 inst->U.I.SrcReg[0].Index = temp; 112} 113 114/** 115 * Transform TEX, TXP, TXB, and KIL instructions in the following ways: 116 * - implement texture compare (shadow extensions) 117 * - extract non-native source / destination operands 118 * - premultiply texture coordinates for RECT 119 * - extract operand swizzles 120 * - introduce a temporary register when write masks are needed 121 */ 122int radeonTransformTEX( 123 struct radeon_compiler * c, 124 struct rc_instruction * inst, 125 void* data) 126{ 127 struct r300_fragment_program_compiler *compiler = 128 (struct r300_fragment_program_compiler*)data; 129 rc_wrap_mode wrapmode = compiler->state.unit[inst->U.I.TexSrcUnit].wrap_mode; 130 int is_rect = inst->U.I.TexSrcTarget == RC_TEXTURE_RECT || 131 compiler->state.unit[inst->U.I.TexSrcUnit].non_normalized_coords; 132 133 if (inst->U.I.Opcode != RC_OPCODE_TEX && 134 inst->U.I.Opcode != RC_OPCODE_TXB && 135 inst->U.I.Opcode != RC_OPCODE_TXP && 136 inst->U.I.Opcode != RC_OPCODE_TXD && 137 inst->U.I.Opcode != RC_OPCODE_TXL && 138 inst->U.I.Opcode != RC_OPCODE_KIL) 139 return 0; 140 141 /* ARB_shadow & EXT_shadow_funcs */ 142 if (inst->U.I.Opcode != RC_OPCODE_KIL && 143 ((c->Program.ShadowSamplers & (1 << inst->U.I.TexSrcUnit)) || 144 (compiler->state.unit[inst->U.I.TexSrcUnit].compare_mode_enabled))) { 145 rc_compare_func comparefunc = compiler->state.unit[inst->U.I.TexSrcUnit].texture_compare_func; 146 147 if (comparefunc == RC_COMPARE_FUNC_NEVER || comparefunc == RC_COMPARE_FUNC_ALWAYS) { 148 inst->U.I.Opcode = RC_OPCODE_MOV; 149 150 if (comparefunc == RC_COMPARE_FUNC_ALWAYS) { 151 inst->U.I.SrcReg[0] = shadow_pass_value(compiler, inst->U.I.TexSrcUnit); 152 } else { 153 inst->U.I.SrcReg[0] = shadow_fail_value(compiler, inst->U.I.TexSrcUnit); 154 } 155 156 return 1; 157 } else { 158 struct rc_instruction * inst_rcp = NULL; 159 struct rc_instruction *inst_mul, *inst_add, *inst_cmp; 160 unsigned tmp_texsample; 161 unsigned tmp_sum; 162 int pass, fail; 163 164 /* Save the output register. */ 165 struct rc_dst_register output_reg = inst->U.I.DstReg; 166 unsigned saturate_mode = inst->U.I.SaturateMode; 167 168 /* Redirect TEX to a new temp. */ 169 tmp_texsample = rc_find_free_temporary(c); 170 inst->U.I.SaturateMode = 0; 171 inst->U.I.DstReg.File = RC_FILE_TEMPORARY; 172 inst->U.I.DstReg.Index = tmp_texsample; 173 inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; 174 175 tmp_sum = rc_find_free_temporary(c); 176 177 if (inst->U.I.Opcode == RC_OPCODE_TXP) { 178 /* Compute 1/W. */ 179 inst_rcp = rc_insert_new_instruction(c, inst); 180 inst_rcp->U.I.Opcode = RC_OPCODE_RCP; 181 inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY; 182 inst_rcp->U.I.DstReg.Index = tmp_sum; 183 inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W; 184 inst_rcp->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 185 inst_rcp->U.I.SrcReg[0].Swizzle = 186 RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 3)); 187 } 188 189 /* Divide Z by W (if it's TXP) and saturate. */ 190 inst_mul = rc_insert_new_instruction(c, inst_rcp ? inst_rcp : inst); 191 inst_mul->U.I.Opcode = inst->U.I.Opcode == RC_OPCODE_TXP ? RC_OPCODE_MUL : RC_OPCODE_MOV; 192 inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY; 193 inst_mul->U.I.DstReg.Index = tmp_sum; 194 inst_mul->U.I.DstReg.WriteMask = RC_MASK_W; 195 inst_mul->U.I.SaturateMode = RC_SATURATE_ZERO_ONE; 196 inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 197 inst_mul->U.I.SrcReg[0].Swizzle = 198 RC_MAKE_SWIZZLE_SMEAR(GET_SWZ(inst->U.I.SrcReg[0].Swizzle, 2)); 199 if (inst->U.I.Opcode == RC_OPCODE_TXP) { 200 inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; 201 inst_mul->U.I.SrcReg[1].Index = tmp_sum; 202 inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW; 203 } 204 205 /* Add the depth texture value. */ 206 inst_add = rc_insert_new_instruction(c, inst_mul); 207 inst_add->U.I.Opcode = RC_OPCODE_ADD; 208 inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY; 209 inst_add->U.I.DstReg.Index = tmp_sum; 210 inst_add->U.I.DstReg.WriteMask = RC_MASK_W; 211 inst_add->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 212 inst_add->U.I.SrcReg[0].Index = tmp_sum; 213 inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_WWWW; 214 inst_add->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; 215 inst_add->U.I.SrcReg[1].Index = tmp_texsample; 216 inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XXXX; 217 218 /* Note that SrcReg[0] is r, SrcReg[1] is tex and: 219 * LESS: r < tex <=> -tex+r < 0 220 * GEQUAL: r >= tex <=> not (-tex+r < 0) 221 * GREATER: r > tex <=> tex-r < 0 222 * LEQUAL: r <= tex <=> not ( tex-r < 0) 223 * EQUAL: GEQUAL 224 * NOTEQUAL:LESS 225 */ 226 227 /* This negates either r or tex: */ 228 if (comparefunc == RC_COMPARE_FUNC_LESS || comparefunc == RC_COMPARE_FUNC_GEQUAL || 229 comparefunc == RC_COMPARE_FUNC_EQUAL || comparefunc == RC_COMPARE_FUNC_NOTEQUAL) 230 inst_add->U.I.SrcReg[1].Negate = inst_add->U.I.SrcReg[1].Negate ^ RC_MASK_XYZW; 231 else 232 inst_add->U.I.SrcReg[0].Negate = inst_add->U.I.SrcReg[0].Negate ^ RC_MASK_XYZW; 233 234 /* This negates the whole expresion: */ 235 if (comparefunc == RC_COMPARE_FUNC_LESS || comparefunc == RC_COMPARE_FUNC_GREATER || 236 comparefunc == RC_COMPARE_FUNC_NOTEQUAL) { 237 pass = 1; 238 fail = 2; 239 } else { 240 pass = 2; 241 fail = 1; 242 } 243 244 inst_cmp = rc_insert_new_instruction(c, inst_add); 245 inst_cmp->U.I.Opcode = RC_OPCODE_CMP; 246 inst_cmp->U.I.SaturateMode = saturate_mode; 247 inst_cmp->U.I.DstReg = output_reg; 248 inst_cmp->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 249 inst_cmp->U.I.SrcReg[0].Index = tmp_sum; 250 inst_cmp->U.I.SrcReg[0].Swizzle = 251 combine_swizzles(RC_SWIZZLE_WWWW, 252 compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle); 253 inst_cmp->U.I.SrcReg[pass] = shadow_pass_value(compiler, inst->U.I.TexSrcUnit); 254 inst_cmp->U.I.SrcReg[fail] = shadow_fail_value(compiler, inst->U.I.TexSrcUnit); 255 256 assert(tmp_texsample != tmp_sum); 257 } 258 } 259 260 /* R300 cannot sample from rectangles and the wrap mode fallback needs 261 * normalized coordinates anyway. */ 262 if (inst->U.I.Opcode != RC_OPCODE_KIL && 263 is_rect && (!c->is_r500 || wrapmode != RC_WRAP_NONE)) { 264 scale_texcoords(compiler, inst, RC_STATE_R300_TEXRECT_FACTOR); 265 inst->U.I.TexSrcTarget = RC_TEXTURE_2D; 266 } 267 268 /* Divide by W if needed. */ 269 if (inst->U.I.Opcode == RC_OPCODE_TXP && 270 (wrapmode == RC_WRAP_REPEAT || wrapmode == RC_WRAP_MIRRORED_REPEAT || 271 compiler->state.unit[inst->U.I.TexSrcUnit].clamp_and_scale_before_fetch)) { 272 projective_divide(compiler, inst); 273 } 274 275 /* Texture wrap modes don't work on NPOT textures. 276 * 277 * Non-wrapped/clamped texcoords with NPOT are free in HW. Repeat and 278 * mirroring are not. If we need to repeat, we do: 279 * 280 * MUL temp, texcoord, <scaling factor constant> 281 * FRC temp, temp ; Discard integer portion of coords 282 * 283 * This gives us coords in [0, 1]. 284 * 285 * Mirroring is trickier. We're going to start out like repeat: 286 * 287 * MUL temp, texcoord, <scaling factor constant> ; De-mirror across axes 288 * MUL temp, temp, 0.5 ; Pattern repeats in [0, 2] 289 * ; so scale to [0, 1] 290 * FRC temp, temp ; Make the pattern repeat 291 * MAD temp, temp, 2, -1 ; Move the pattern to [-1, 1] 292 * ADD temp, 1, -abs(temp) ; Now comes a neat trick: use abs to mirror the pattern. 293 * ; The pattern is backwards, so reverse it (1-x). 294 * 295 * This gives us coords in [0, 1]. 296 * 297 * ~ C & M. ;) 298 */ 299 if (inst->U.I.Opcode != RC_OPCODE_KIL && 300 wrapmode != RC_WRAP_NONE) { 301 struct rc_instruction *inst_mov; 302 unsigned temp = rc_find_free_temporary(c); 303 304 if (wrapmode == RC_WRAP_REPEAT) { 305 /* Both instructions will be paired up. */ 306 struct rc_instruction *inst_frc = rc_insert_new_instruction(c, inst->Prev); 307 308 inst_frc->U.I.Opcode = RC_OPCODE_FRC; 309 inst_frc->U.I.DstReg.File = RC_FILE_TEMPORARY; 310 inst_frc->U.I.DstReg.Index = temp; 311 inst_frc->U.I.DstReg.WriteMask = RC_MASK_XYZ; 312 inst_frc->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 313 } else if (wrapmode == RC_WRAP_MIRRORED_REPEAT) { 314 /* 315 * Function: 316 * f(v) = 1 - abs(frac(v * 0.5) * 2 - 1) 317 * 318 * Code: 319 * MUL temp, src0, 0.5 320 * FRC temp, temp 321 * MAD temp, temp, 2, -1 322 * ADD temp, 1, -abs(temp) 323 */ 324 325 struct rc_instruction *inst_mul, *inst_frc, *inst_mad, *inst_add; 326 unsigned two, two_swizzle; 327 328 inst_mul = rc_insert_new_instruction(c, inst->Prev); 329 330 inst_mul->U.I.Opcode = RC_OPCODE_MUL; 331 inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY; 332 inst_mul->U.I.DstReg.Index = temp; 333 inst_mul->U.I.DstReg.WriteMask = RC_MASK_XYZ; 334 inst_mul->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 335 inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_HHHH; 336 337 inst_frc = rc_insert_new_instruction(c, inst->Prev); 338 339 inst_frc->U.I.Opcode = RC_OPCODE_FRC; 340 inst_frc->U.I.DstReg.File = RC_FILE_TEMPORARY; 341 inst_frc->U.I.DstReg.Index = temp; 342 inst_frc->U.I.DstReg.WriteMask = RC_MASK_XYZ; 343 inst_frc->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 344 inst_frc->U.I.SrcReg[0].Index = temp; 345 inst_frc->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0; 346 347 two = rc_constants_add_immediate_scalar(&c->Program.Constants, 2, &two_swizzle); 348 inst_mad = rc_insert_new_instruction(c, inst->Prev); 349 350 inst_mad->U.I.Opcode = RC_OPCODE_MAD; 351 inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY; 352 inst_mad->U.I.DstReg.Index = temp; 353 inst_mad->U.I.DstReg.WriteMask = RC_MASK_XYZ; 354 inst_mad->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 355 inst_mad->U.I.SrcReg[0].Index = temp; 356 inst_mad->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0; 357 inst_mad->U.I.SrcReg[1].File = RC_FILE_CONSTANT; 358 inst_mad->U.I.SrcReg[1].Index = two; 359 inst_mad->U.I.SrcReg[1].Swizzle = two_swizzle; 360 inst_mad->U.I.SrcReg[2].Swizzle = RC_SWIZZLE_1111; 361 inst_mad->U.I.SrcReg[2].Negate = RC_MASK_XYZ; 362 363 inst_add = rc_insert_new_instruction(c, inst->Prev); 364 365 inst_add->U.I.Opcode = RC_OPCODE_ADD; 366 inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY; 367 inst_add->U.I.DstReg.Index = temp; 368 inst_add->U.I.DstReg.WriteMask = RC_MASK_XYZ; 369 inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111; 370 inst_add->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; 371 inst_add->U.I.SrcReg[1].Index = temp; 372 inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZ0; 373 inst_add->U.I.SrcReg[1].Abs = 1; 374 inst_add->U.I.SrcReg[1].Negate = RC_MASK_XYZ; 375 } else if (wrapmode == RC_WRAP_MIRRORED_CLAMP) { 376 /* 377 * Mirrored clamp modes are bloody simple, we just use abs 378 * to mirror [0, 1] into [-1, 0]. This works for 379 * all modes i.e. CLAMP, CLAMP_TO_EDGE, and CLAMP_TO_BORDER. 380 */ 381 struct rc_instruction *inst_mov; 382 383 inst_mov = rc_insert_new_instruction(c, inst->Prev); 384 385 inst_mov->U.I.Opcode = RC_OPCODE_MOV; 386 inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; 387 inst_mov->U.I.DstReg.Index = temp; 388 inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZ; 389 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 390 inst_mov->U.I.SrcReg[0].Abs = 1; 391 } 392 393 /* Preserve W for TXP/TXB. */ 394 inst_mov = rc_insert_new_instruction(c, inst->Prev); 395 396 inst_mov->U.I.Opcode = RC_OPCODE_MOV; 397 inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; 398 inst_mov->U.I.DstReg.Index = temp; 399 inst_mov->U.I.DstReg.WriteMask = RC_MASK_W; 400 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 401 402 reset_srcreg(&inst->U.I.SrcReg[0]); 403 inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 404 inst->U.I.SrcReg[0].Index = temp; 405 } 406 407 /* NPOT -> POT conversion for 3D textures. */ 408 if (inst->U.I.Opcode != RC_OPCODE_KIL && 409 compiler->state.unit[inst->U.I.TexSrcUnit].clamp_and_scale_before_fetch) { 410 struct rc_instruction *inst_mov; 411 unsigned temp = rc_find_free_temporary(c); 412 413 /* Saturate XYZ. */ 414 inst_mov = rc_insert_new_instruction(c, inst->Prev); 415 inst_mov->U.I.Opcode = RC_OPCODE_MOV; 416 inst_mov->U.I.SaturateMode = RC_SATURATE_ZERO_ONE; 417 inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; 418 inst_mov->U.I.DstReg.Index = temp; 419 inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZ; 420 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 421 422 /* Copy W. */ 423 inst_mov = rc_insert_new_instruction(c, inst->Prev); 424 inst_mov->U.I.Opcode = RC_OPCODE_MOV; 425 inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; 426 inst_mov->U.I.DstReg.Index = temp; 427 inst_mov->U.I.DstReg.WriteMask = RC_MASK_W; 428 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 429 430 reset_srcreg(&inst->U.I.SrcReg[0]); 431 inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 432 inst->U.I.SrcReg[0].Index = temp; 433 434 scale_texcoords(compiler, inst, RC_STATE_R300_TEXSCALE_FACTOR); 435 } 436 437 /* Convert SNORM-encoded ATI1N sampled as UNORM to SNORM. 438 * Formula: dst = tex > 0.5 ? tex*2-2 : tex*2 439 */ 440 if (inst->U.I.Opcode != RC_OPCODE_KIL && 441 compiler->state.unit[inst->U.I.TexSrcUnit].convert_unorm_to_snorm) { 442 unsigned two, two_swizzle; 443 struct rc_instruction *inst_mul, *inst_mad, *inst_cnd; 444 445 two = rc_constants_add_immediate_scalar(&c->Program.Constants, 2.35, &two_swizzle); 446 447 inst_mul = rc_insert_new_instruction(c, inst); 448 inst_mul->U.I.Opcode = RC_OPCODE_MUL; 449 inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY; 450 inst_mul->U.I.DstReg.Index = rc_find_free_temporary(c); 451 inst_mul->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 452 inst_mul->U.I.SrcReg[0].Index = rc_find_free_temporary(c); /* redirected TEX output */ 453 inst_mul->U.I.SrcReg[1].File = RC_FILE_CONSTANT; /* 2 */ 454 inst_mul->U.I.SrcReg[1].Index = two; 455 inst_mul->U.I.SrcReg[1].Swizzle = two_swizzle; 456 457 inst_mad = rc_insert_new_instruction(c, inst_mul); 458 inst_mad->U.I.Opcode = RC_OPCODE_MAD; 459 inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY; 460 inst_mad->U.I.DstReg.Index = rc_find_free_temporary(c); 461 inst_mad->U.I.SrcReg[0] = inst_mul->U.I.SrcReg[0]; /* redirected TEX output */ 462 inst_mad->U.I.SrcReg[1] = inst_mul->U.I.SrcReg[1]; /* 2 */ 463 inst_mad->U.I.SrcReg[2] = inst_mul->U.I.SrcReg[1]; /* 2 */ 464 inst_mad->U.I.SrcReg[2].Negate = RC_MASK_XYZW; 465 466 inst_cnd = rc_insert_new_instruction(c, inst_mad); 467 inst_cnd->U.I.Opcode = RC_OPCODE_CND; 468 inst_cnd->U.I.SaturateMode = inst->U.I.SaturateMode; 469 inst_cnd->U.I.DstReg = inst->U.I.DstReg; 470 inst_cnd->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 471 inst_cnd->U.I.SrcReg[0].Index = inst_mad->U.I.DstReg.Index; 472 inst_cnd->U.I.SrcReg[0].Swizzle = compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle; 473 inst_cnd->U.I.SrcReg[1].File = RC_FILE_TEMPORARY; 474 inst_cnd->U.I.SrcReg[1].Index = inst_mul->U.I.DstReg.Index; 475 inst_cnd->U.I.SrcReg[1].Swizzle = compiler->state.unit[inst->U.I.TexSrcUnit].texture_swizzle; 476 inst_cnd->U.I.SrcReg[2] = inst_mul->U.I.SrcReg[0]; /* redirected TEX output */ 477 478 inst->U.I.SaturateMode = 0; 479 inst->U.I.DstReg.File = RC_FILE_TEMPORARY; 480 inst->U.I.DstReg.Index = inst_mul->U.I.SrcReg[0].Index; 481 inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; 482 } 483 484 /* Cannot write texture to output registers or with saturate (all chips), 485 * or with masks (non-r500). */ 486 if (inst->U.I.Opcode != RC_OPCODE_KIL && 487 (inst->U.I.DstReg.File != RC_FILE_TEMPORARY || 488 inst->U.I.SaturateMode || 489 (!c->is_r500 && inst->U.I.DstReg.WriteMask != RC_MASK_XYZW))) { 490 struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst); 491 492 inst_mov->U.I.Opcode = RC_OPCODE_MOV; 493 inst_mov->U.I.SaturateMode = inst->U.I.SaturateMode; 494 inst_mov->U.I.DstReg = inst->U.I.DstReg; 495 inst_mov->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 496 inst_mov->U.I.SrcReg[0].Index = rc_find_free_temporary(c); 497 498 inst->U.I.SaturateMode = 0; 499 inst->U.I.DstReg.File = RC_FILE_TEMPORARY; 500 inst->U.I.DstReg.Index = inst_mov->U.I.SrcReg[0].Index; 501 inst->U.I.DstReg.WriteMask = RC_MASK_XYZW; 502 } 503 504 /* Cannot read texture coordinate from constants file */ 505 if (inst->U.I.SrcReg[0].File != RC_FILE_TEMPORARY && inst->U.I.SrcReg[0].File != RC_FILE_INPUT) { 506 struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev); 507 508 inst_mov->U.I.Opcode = RC_OPCODE_MOV; 509 inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY; 510 inst_mov->U.I.DstReg.Index = rc_find_free_temporary(c); 511 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0]; 512 513 reset_srcreg(&inst->U.I.SrcReg[0]); 514 inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY; 515 inst->U.I.SrcReg[0].Index = inst_mov->U.I.DstReg.Index; 516 } 517 518 return 1; 519} 520