1/************************************************************************** 2 * 3 * Copyright 2003 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 above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28#include "util/u_math.h" 29#include "i915_context.h" 30#include "i915_fpc.h" 31#include "i915_reg.h" 32 33uint32_t 34i915_get_temp(struct i915_fp_compile *p) 35{ 36 int bit = ffs(~p->temp_flag); 37 if (!bit) { 38 i915_program_error(p, "i915_get_temp: out of temporaries"); 39 return 0; 40 } 41 42 p->temp_flag |= 1 << (bit - 1); 43 return bit - 1; 44} 45 46static void 47i915_release_temp(struct i915_fp_compile *p, int reg) 48{ 49 p->temp_flag &= ~(1 << reg); 50} 51 52/** 53 * Get unpreserved temporary, a temp whose value is not preserved between 54 * PS program phases. 55 */ 56uint32_t 57i915_get_utemp(struct i915_fp_compile *p) 58{ 59 int bit = ffs(~p->utemp_flag); 60 if (!bit) { 61 i915_program_error(p, "i915_get_utemp: out of temporaries"); 62 return 0; 63 } 64 65 p->utemp_flag |= 1 << (bit - 1); 66 return UREG(REG_TYPE_U, (bit - 1)); 67} 68 69void 70i915_release_utemps(struct i915_fp_compile *p) 71{ 72 p->utemp_flag = ~0x7; 73} 74 75uint32_t 76i915_emit_decl(struct i915_fp_compile *p, uint32_t type, uint32_t nr, 77 uint32_t d0_flags) 78{ 79 uint32_t reg = UREG(type, nr); 80 81 if (type == REG_TYPE_T) { 82 if (p->decl_t & (1 << nr)) 83 return reg; 84 85 p->decl_t |= (1 << nr); 86 } else if (type == REG_TYPE_S) { 87 if (p->decl_s & (1 << nr)) 88 return reg; 89 90 p->decl_s |= (1 << nr); 91 } else 92 return reg; 93 94 if (p->decl < p->declarations + I915_PROGRAM_SIZE) { 95 *(p->decl++) = (D0_DCL | D0_DEST(reg) | d0_flags); 96 *(p->decl++) = D1_MBZ; 97 *(p->decl++) = D2_MBZ; 98 } else 99 i915_program_error(p, "Out of declarations"); 100 101 p->nr_decl_insn++; 102 return reg; 103} 104 105uint32_t 106i915_emit_arith(struct i915_fp_compile *p, uint32_t op, uint32_t dest, 107 uint32_t mask, uint32_t saturate, uint32_t src0, uint32_t src1, 108 uint32_t src2) 109{ 110 uint32_t c[3]; 111 uint32_t nr_const = 0; 112 113 assert(GET_UREG_TYPE(dest) != REG_TYPE_CONST); 114 dest = UREG(GET_UREG_TYPE(dest), GET_UREG_NR(dest)); 115 assert(dest); 116 117 if (GET_UREG_TYPE(src0) == REG_TYPE_CONST) 118 c[nr_const++] = 0; 119 if (GET_UREG_TYPE(src1) == REG_TYPE_CONST) 120 c[nr_const++] = 1; 121 if (GET_UREG_TYPE(src2) == REG_TYPE_CONST) 122 c[nr_const++] = 2; 123 124 /* Recursively call this function to MOV additional const values 125 * into temporary registers. Use utemp registers for this - 126 * currently shouldn't be possible to run out, but keep an eye on 127 * this. 128 */ 129 if (nr_const > 1) { 130 uint32_t s[3], first, i, old_utemp_flag; 131 132 s[0] = src0; 133 s[1] = src1; 134 s[2] = src2; 135 old_utemp_flag = p->utemp_flag; 136 137 first = GET_UREG_NR(s[c[0]]); 138 for (i = 1; i < nr_const; i++) { 139 if (GET_UREG_NR(s[c[i]]) != first) { 140 uint32_t tmp = i915_get_utemp(p); 141 142 i915_emit_arith(p, A0_MOV, tmp, A0_DEST_CHANNEL_ALL, 0, s[c[i]], 0, 143 0); 144 s[c[i]] = tmp; 145 } 146 } 147 148 src0 = s[0]; 149 src1 = s[1]; 150 src2 = s[2]; 151 p->utemp_flag = old_utemp_flag; /* restore */ 152 } 153 154 if (p->csr < p->program + I915_PROGRAM_SIZE) { 155 *(p->csr++) = (op | A0_DEST(dest) | mask | saturate | A0_SRC0(src0)); 156 *(p->csr++) = (A1_SRC0(src0) | A1_SRC1(src1)); 157 *(p->csr++) = (A2_SRC1(src1) | A2_SRC2(src2)); 158 } else 159 i915_program_error(p, "Out of instructions"); 160 161 if (GET_UREG_TYPE(dest) == REG_TYPE_R) 162 p->register_phases[GET_UREG_NR(dest)] = p->nr_tex_indirect; 163 164 p->nr_alu_insn++; 165 return dest; 166} 167 168/** 169 * Emit a texture load or texkill instruction. 170 * \param dest the dest i915 register 171 * \param destmask the dest register writemask 172 * \param sampler the i915 sampler register 173 * \param coord the i915 source texcoord operand 174 * \param opcode the instruction opcode 175 */ 176uint32_t 177i915_emit_texld(struct i915_fp_compile *p, uint32_t dest, uint32_t destmask, 178 uint32_t sampler, uint32_t coord, uint32_t opcode, 179 uint32_t coord_mask) 180{ 181 const uint32_t k = UREG(GET_UREG_TYPE(coord), GET_UREG_NR(coord)); 182 183 int temp = -1; 184 185 uint32_t coord_used = 0xf << UREG_CHANNEL_X_SHIFT; 186 if (coord_mask & TGSI_WRITEMASK_Y) 187 coord_used |= 0xf << UREG_CHANNEL_Y_SHIFT; 188 if (coord_mask & TGSI_WRITEMASK_Z) 189 coord_used |= 0xf << UREG_CHANNEL_Z_SHIFT; 190 if (coord_mask & TGSI_WRITEMASK_W) 191 coord_used |= 0xf << UREG_CHANNEL_W_SHIFT; 192 193 if ((coord & coord_used) != (k & coord_used) || 194 GET_UREG_TYPE(coord) == REG_TYPE_CONST) { 195 /* texcoord is swizzled or negated. Need to allocate a new temporary 196 * register (a utemp / unpreserved temp) won't do. 197 */ 198 uint32_t tempReg; 199 200 temp = i915_get_temp(p); /* get temp reg index */ 201 tempReg = UREG(REG_TYPE_R, temp); /* make i915 register */ 202 203 i915_emit_arith(p, A0_MOV, tempReg, 204 A0_DEST_CHANNEL_ALL, /* dest reg, writemask */ 205 0, /* saturate */ 206 coord, 0, 0); /* src0, src1, src2 */ 207 208 /* new src texcoord is tempReg */ 209 coord = tempReg; 210 } 211 212 /* Don't worry about saturate as we only support 213 */ 214 if (destmask != A0_DEST_CHANNEL_ALL) { 215 /* if not writing to XYZW... */ 216 uint32_t tmp = i915_get_utemp(p); 217 i915_emit_texld(p, tmp, A0_DEST_CHANNEL_ALL, sampler, coord, opcode, 218 coord_mask); 219 i915_emit_arith(p, A0_MOV, dest, destmask, 0, tmp, 0, 0); 220 /* XXX release utemp here? */ 221 } else { 222 assert(GET_UREG_TYPE(dest) != REG_TYPE_CONST); 223 assert(dest == UREG(GET_UREG_TYPE(dest), GET_UREG_NR(dest))); 224 225 /* Output register being oC or oD defines a phase boundary */ 226 if (GET_UREG_TYPE(dest) == REG_TYPE_OC || 227 GET_UREG_TYPE(dest) == REG_TYPE_OD) 228 p->nr_tex_indirect++; 229 230 /* Reading from an r# register whose contents depend on output of the 231 * current phase defines a phase boundary. 232 */ 233 if (GET_UREG_TYPE(coord) == REG_TYPE_R && 234 p->register_phases[GET_UREG_NR(coord)] == p->nr_tex_indirect) 235 p->nr_tex_indirect++; 236 237 if (p->csr < p->program + I915_PROGRAM_SIZE) { 238 *(p->csr++) = (opcode | T0_DEST(dest) | T0_SAMPLER(sampler)); 239 240 *(p->csr++) = T1_ADDRESS_REG(coord); 241 *(p->csr++) = T2_MBZ; 242 } else 243 i915_program_error(p, "Out of instructions"); 244 245 if (GET_UREG_TYPE(dest) == REG_TYPE_R) 246 p->register_phases[GET_UREG_NR(dest)] = p->nr_tex_indirect; 247 248 p->nr_tex_insn++; 249 } 250 251 if (temp >= 0) 252 i915_release_temp(p, temp); 253 254 return dest; 255} 256 257uint32_t 258i915_emit_const1f(struct i915_fp_compile *p, float c0) 259{ 260 struct i915_fragment_shader *ifs = p->shader; 261 unsigned reg, idx; 262 263 if (c0 == 0.0) 264 return swizzle(UREG(REG_TYPE_R, 0), ZERO, ZERO, ZERO, ZERO); 265 if (c0 == 1.0) 266 return swizzle(UREG(REG_TYPE_R, 0), ONE, ONE, ONE, ONE); 267 268 for (reg = 0; reg < I915_MAX_CONSTANT; reg++) { 269 if (ifs->constant_flags[reg] == I915_CONSTFLAG_USER) 270 continue; 271 for (idx = 0; idx < 4; idx++) { 272 if (!(ifs->constant_flags[reg] & (1 << idx)) || 273 ifs->constants[reg][idx] == c0) { 274 ifs->constants[reg][idx] = c0; 275 ifs->constant_flags[reg] |= 1 << idx; 276 if (reg + 1 > ifs->num_constants) 277 ifs->num_constants = reg + 1; 278 return swizzle(UREG(REG_TYPE_CONST, reg), idx, ZERO, ZERO, ONE); 279 } 280 } 281 } 282 283 i915_program_error(p, "i915_emit_const1f: out of constants"); 284 return 0; 285} 286 287uint32_t 288i915_emit_const2f(struct i915_fp_compile *p, float c0, float c1) 289{ 290 struct i915_fragment_shader *ifs = p->shader; 291 unsigned reg, idx; 292 293 if (c0 == 0.0) 294 return swizzle(i915_emit_const1f(p, c1), ZERO, X, Z, W); 295 if (c0 == 1.0) 296 return swizzle(i915_emit_const1f(p, c1), ONE, X, Z, W); 297 298 if (c1 == 0.0) 299 return swizzle(i915_emit_const1f(p, c0), X, ZERO, Z, W); 300 if (c1 == 1.0) 301 return swizzle(i915_emit_const1f(p, c0), X, ONE, Z, W); 302 303 // XXX emit swizzle here for 0, 1, -1 and any combination thereof 304 // we can use swizzle + neg for that 305 for (reg = 0; reg < I915_MAX_CONSTANT; reg++) { 306 if (ifs->constant_flags[reg] == 0xf || 307 ifs->constant_flags[reg] == I915_CONSTFLAG_USER) 308 continue; 309 for (idx = 0; idx < 3; idx++) { 310 if (!(ifs->constant_flags[reg] & (3 << idx))) { 311 ifs->constants[reg][idx + 0] = c0; 312 ifs->constants[reg][idx + 1] = c1; 313 ifs->constant_flags[reg] |= 3 << idx; 314 if (reg + 1 > ifs->num_constants) 315 ifs->num_constants = reg + 1; 316 return swizzle(UREG(REG_TYPE_CONST, reg), idx, idx + 1, ZERO, ONE); 317 } 318 } 319 } 320 321 i915_program_error(p, "i915_emit_const2f: out of constants"); 322 return 0; 323} 324 325uint32_t 326i915_emit_const4f(struct i915_fp_compile *p, float c0, float c1, float c2, 327 float c3) 328{ 329 struct i915_fragment_shader *ifs = p->shader; 330 unsigned reg; 331 332 // XXX emit swizzle here for 0, 1, -1 and any combination thereof 333 // we can use swizzle + neg for that 334 for (reg = 0; reg < I915_MAX_CONSTANT; reg++) { 335 if (ifs->constant_flags[reg] == 0xf && ifs->constants[reg][0] == c0 && 336 ifs->constants[reg][1] == c1 && ifs->constants[reg][2] == c2 && 337 ifs->constants[reg][3] == c3) { 338 return UREG(REG_TYPE_CONST, reg); 339 } else if (ifs->constant_flags[reg] == 0) { 340 341 ifs->constants[reg][0] = c0; 342 ifs->constants[reg][1] = c1; 343 ifs->constants[reg][2] = c2; 344 ifs->constants[reg][3] = c3; 345 ifs->constant_flags[reg] = 0xf; 346 if (reg + 1 > ifs->num_constants) 347 ifs->num_constants = reg + 1; 348 return UREG(REG_TYPE_CONST, reg); 349 } 350 } 351 352 i915_program_error(p, "i915_emit_const4f: out of constants"); 353 return 0; 354} 355 356uint32_t 357i915_emit_const4fv(struct i915_fp_compile *p, const float *c) 358{ 359 return i915_emit_const4f(p, c[0], c[1], c[2], c[3]); 360} 361