1 /**************************************************************************
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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 TUNGSTEN GRAPHICS 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.
26 **************************************************************************/
29 #include "i915_context.h"
31 #include "util/u_math.h"
34 i915_get_temp(struct i915_fp_compile
*p
)
36 int bit
= ffs(~p
->temp_flag
);
38 i915_program_error(p
, "i915_get_temp: out of temporaries");
42 p
->temp_flag
|= 1 << (bit
- 1);
48 i915_release_temp(struct i915_fp_compile
*p
, int reg
)
50 p
->temp_flag
&= ~(1 << reg
);
55 * Get unpreserved temporary, a temp whose value is not preserved between
59 i915_get_utemp(struct i915_fp_compile
* p
)
61 int bit
= ffs(~p
->utemp_flag
);
63 i915_program_error(p
, "i915_get_utemp: out of temporaries");
67 p
->utemp_flag
|= 1 << (bit
- 1);
68 return UREG(REG_TYPE_U
, (bit
- 1));
72 i915_release_utemps(struct i915_fp_compile
*p
)
79 i915_emit_decl(struct i915_fp_compile
*p
,
80 uint type
, uint nr
, uint d0_flags
)
82 uint reg
= UREG(type
, nr
);
84 if (type
== REG_TYPE_T
) {
85 if (p
->decl_t
& (1 << nr
))
88 p
->decl_t
|= (1 << nr
);
90 else if (type
== REG_TYPE_S
) {
91 if (p
->decl_s
& (1 << nr
))
94 p
->decl_s
|= (1 << nr
);
99 if (p
->decl
< p
->declarations
+ I915_PROGRAM_SIZE
) {
100 *(p
->decl
++) = (D0_DCL
| D0_DEST(reg
) | d0_flags
);
101 *(p
->decl
++) = D1_MBZ
;
102 *(p
->decl
++) = D2_MBZ
;
105 i915_program_error(p
, "Out of declarations");
112 i915_emit_arith(struct i915_fp_compile
* p
,
116 uint saturate
, uint src0
, uint src1
, uint src2
)
121 assert(GET_UREG_TYPE(dest
) != REG_TYPE_CONST
);
122 dest
= UREG(GET_UREG_TYPE(dest
), GET_UREG_NR(dest
));
125 if (GET_UREG_TYPE(src0
) == REG_TYPE_CONST
)
127 if (GET_UREG_TYPE(src1
) == REG_TYPE_CONST
)
129 if (GET_UREG_TYPE(src2
) == REG_TYPE_CONST
)
132 /* Recursively call this function to MOV additional const values
133 * into temporary registers. Use utemp registers for this -
134 * currently shouldn't be possible to run out, but keep an eye on
138 uint s
[3], first
, i
, old_utemp_flag
;
143 old_utemp_flag
= p
->utemp_flag
;
145 first
= GET_UREG_NR(s
[c
[0]]);
146 for (i
= 1; i
< nr_const
; i
++) {
147 if (GET_UREG_NR(s
[c
[i
]]) != first
) {
148 uint tmp
= i915_get_utemp(p
);
150 i915_emit_arith(p
, A0_MOV
, tmp
, A0_DEST_CHANNEL_ALL
, 0,
159 p
->utemp_flag
= old_utemp_flag
; /* restore */
162 if (p
->csr
< p
->program
+ I915_PROGRAM_SIZE
) {
163 *(p
->csr
++) = (op
| A0_DEST(dest
) | mask
| saturate
| A0_SRC0(src0
));
164 *(p
->csr
++) = (A1_SRC0(src0
) | A1_SRC1(src1
));
165 *(p
->csr
++) = (A2_SRC1(src1
) | A2_SRC2(src2
));
168 i915_program_error(p
, "Out of instructions");
170 if (GET_UREG_TYPE(dest
) == REG_TYPE_R
)
171 p
->register_phases
[GET_UREG_NR(dest
)] = p
->nr_tex_indirect
;
179 * Emit a texture load or texkill instruction.
180 * \param dest the dest i915 register
181 * \param destmask the dest register writemask
182 * \param sampler the i915 sampler register
183 * \param coord the i915 source texcoord operand
184 * \param opcode the instruction opcode
186 uint
i915_emit_texld( struct i915_fp_compile
*p
,
194 const uint k
= UREG(GET_UREG_TYPE(coord
), GET_UREG_NR(coord
));
199 /* Eliminate the useless texture coordinates. Otherwise we end up generating
200 * a swizzle for no reason below. */
204 ignore
|= (0xf << UREG_CHANNEL_X_SHIFT
);
207 ignore
|= (0xf << UREG_CHANNEL_Y_SHIFT
);
210 ignore
|= (0xf << UREG_CHANNEL_Z_SHIFT
);
213 ignore
|= (0xf << UREG_CHANNEL_W_SHIFT
);
216 if ( (coord
& ~ignore
) != (k
& ~ignore
) ) {
217 /* texcoord is swizzled or negated. Need to allocate a new temporary
218 * register (a utemp / unpreserved temp) won't do.
222 temp
= i915_get_temp(p
); /* get temp reg index */
223 tempReg
= UREG(REG_TYPE_R
, temp
); /* make i915 register */
225 i915_emit_arith( p
, A0_MOV
,
226 tempReg
, A0_DEST_CHANNEL_ALL
, /* dest reg, writemask */
228 coord
, 0, 0 ); /* src0, src1, src2 */
230 /* new src texcoord is tempReg */
234 /* Don't worry about saturate as we only support
236 if (destmask
!= A0_DEST_CHANNEL_ALL
) {
237 /* if not writing to XYZW... */
238 uint tmp
= i915_get_utemp(p
);
239 i915_emit_texld( p
, tmp
, A0_DEST_CHANNEL_ALL
, sampler
, coord
, opcode
, num_coord
);
240 i915_emit_arith( p
, A0_MOV
, dest
, destmask
, 0, tmp
, 0, 0 );
241 /* XXX release utemp here? */
244 assert(GET_UREG_TYPE(dest
) != REG_TYPE_CONST
);
245 assert(dest
== UREG(GET_UREG_TYPE(dest
), GET_UREG_NR(dest
)));
247 /* Output register being oC or oD defines a phase boundary */
248 if (GET_UREG_TYPE(dest
) == REG_TYPE_OC
||
249 GET_UREG_TYPE(dest
) == REG_TYPE_OD
)
250 p
->nr_tex_indirect
++;
252 /* Reading from an r# register whose contents depend on output of the
253 * current phase defines a phase boundary.
255 if (GET_UREG_TYPE(coord
) == REG_TYPE_R
&&
256 p
->register_phases
[GET_UREG_NR(coord
)] == p
->nr_tex_indirect
)
257 p
->nr_tex_indirect
++;
259 if (p
->csr
< p
->program
+ I915_PROGRAM_SIZE
) {
260 *(p
->csr
++) = (opcode
|
262 T0_SAMPLER( sampler
));
264 *(p
->csr
++) = T1_ADDRESS_REG( coord
);
265 *(p
->csr
++) = T2_MBZ
;
268 i915_program_error(p
, "Out of instructions");
270 if (GET_UREG_TYPE(dest
) == REG_TYPE_R
)
271 p
->register_phases
[GET_UREG_NR(dest
)] = p
->nr_tex_indirect
;
277 i915_release_temp(p
, temp
);
284 i915_emit_const1f(struct i915_fp_compile
* p
, float c0
)
286 struct i915_fragment_shader
*ifs
= p
->shader
;
290 return swizzle(UREG(REG_TYPE_R
, 0), ZERO
, ZERO
, ZERO
, ZERO
);
292 return swizzle(UREG(REG_TYPE_R
, 0), ONE
, ONE
, ONE
, ONE
);
294 for (reg
= 0; reg
< I915_MAX_CONSTANT
; reg
++) {
295 if (ifs
->constant_flags
[reg
] == I915_CONSTFLAG_USER
)
297 for (idx
= 0; idx
< 4; idx
++) {
298 if (!(ifs
->constant_flags
[reg
] & (1 << idx
)) ||
299 ifs
->constants
[reg
][idx
] == c0
) {
300 ifs
->constants
[reg
][idx
] = c0
;
301 ifs
->constant_flags
[reg
] |= 1 << idx
;
302 if (reg
+ 1 > ifs
->num_constants
)
303 ifs
->num_constants
= reg
+ 1;
304 return swizzle(UREG(REG_TYPE_CONST
, reg
), idx
, ZERO
, ZERO
, ONE
);
309 i915_program_error(p
, "i915_emit_const1f: out of constants");
314 i915_emit_const2f(struct i915_fp_compile
* p
, float c0
, float c1
)
316 struct i915_fragment_shader
*ifs
= p
->shader
;
320 return swizzle(i915_emit_const1f(p
, c1
), ZERO
, X
, Z
, W
);
322 return swizzle(i915_emit_const1f(p
, c1
), ONE
, X
, Z
, W
);
325 return swizzle(i915_emit_const1f(p
, c0
), X
, ZERO
, Z
, W
);
327 return swizzle(i915_emit_const1f(p
, c0
), X
, ONE
, Z
, W
);
329 // XXX emit swizzle here for 0, 1, -1 and any combination thereof
330 // we can use swizzle + neg for that
331 for (reg
= 0; reg
< I915_MAX_CONSTANT
; reg
++) {
332 if (ifs
->constant_flags
[reg
] == 0xf ||
333 ifs
->constant_flags
[reg
] == I915_CONSTFLAG_USER
)
335 for (idx
= 0; idx
< 3; idx
++) {
336 if (!(ifs
->constant_flags
[reg
] & (3 << idx
))) {
337 ifs
->constants
[reg
][idx
+ 0] = c0
;
338 ifs
->constants
[reg
][idx
+ 1] = c1
;
339 ifs
->constant_flags
[reg
] |= 3 << idx
;
340 if (reg
+ 1 > ifs
->num_constants
)
341 ifs
->num_constants
= reg
+ 1;
342 return swizzle(UREG(REG_TYPE_CONST
, reg
), idx
, idx
+ 1, ZERO
, ONE
);
347 i915_program_error(p
, "i915_emit_const2f: out of constants");
352 i915_emit_const4f(struct i915_fp_compile
* p
,
353 float c0
, float c1
, float c2
, float c3
)
355 struct i915_fragment_shader
*ifs
= p
->shader
;
358 // XXX emit swizzle here for 0, 1, -1 and any combination thereof
359 // we can use swizzle + neg for that
360 for (reg
= 0; reg
< I915_MAX_CONSTANT
; reg
++) {
361 if (ifs
->constant_flags
[reg
] == 0xf &&
362 ifs
->constants
[reg
][0] == c0
&&
363 ifs
->constants
[reg
][1] == c1
&&
364 ifs
->constants
[reg
][2] == c2
&&
365 ifs
->constants
[reg
][3] == c3
) {
366 return UREG(REG_TYPE_CONST
, reg
);
368 else if (ifs
->constant_flags
[reg
] == 0) {
370 ifs
->constants
[reg
][0] = c0
;
371 ifs
->constants
[reg
][1] = c1
;
372 ifs
->constants
[reg
][2] = c2
;
373 ifs
->constants
[reg
][3] = c3
;
374 ifs
->constant_flags
[reg
] = 0xf;
375 if (reg
+ 1 > ifs
->num_constants
)
376 ifs
->num_constants
= reg
+ 1;
377 return UREG(REG_TYPE_CONST
, reg
);
381 i915_program_error(p
, "i915_emit_const4f: out of constants");
387 i915_emit_const4fv(struct i915_fp_compile
* p
, const float * c
)
389 return i915_emit_const4f(p
, c
[0], c
[1], c
[2], c
[3]);