2 * Copyright (C) 2010 Corbin Simpson
3 * Copyright (C) 2010 Marek Olšák <maraeo@gmail.com>
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:
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.
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.
29 #include "radeon_program_tex.h"
31 #include "radeon_compiler_util.h"
33 /* Series of transformations to be done on textures. */
35 static struct rc_src_register
shadow_fail_value(struct r300_fragment_program_compiler
*compiler
,
38 struct rc_src_register reg
= { 0, 0, 0, 0, 0, 0 };
40 reg
.File
= RC_FILE_NONE
;
41 reg
.Swizzle
= combine_swizzles(RC_SWIZZLE_0000
,
42 compiler
->state
.unit
[tmu
].texture_swizzle
);
46 static struct rc_src_register
shadow_pass_value(struct r300_fragment_program_compiler
*compiler
,
49 struct rc_src_register reg
= { 0, 0, 0, 0, 0, 0 };
51 reg
.File
= RC_FILE_NONE
;
52 reg
.Swizzle
= combine_swizzles(RC_SWIZZLE_1111
,
53 compiler
->state
.unit
[tmu
].texture_swizzle
);
57 static void scale_texcoords(struct r300_fragment_program_compiler
*compiler
,
58 struct rc_instruction
*inst
,
59 unsigned state_constant
)
61 struct rc_instruction
*inst_mov
;
63 unsigned temp
= rc_find_free_temporary(&compiler
->Base
);
65 inst_mov
= rc_insert_new_instruction(&compiler
->Base
, inst
->Prev
);
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
);
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
;
81 static void projective_divide(struct r300_fragment_program_compiler
*compiler
,
82 struct rc_instruction
*inst
)
84 struct rc_instruction
*inst_mul
, *inst_rcp
;
86 unsigned temp
= rc_find_free_temporary(&compiler
->Base
);
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));
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
;
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
;
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
122 int radeonTransformTEX(
123 struct radeon_compiler
* c
,
124 struct rc_instruction
* inst
,
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
;
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
)
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
;
147 if (comparefunc
== RC_COMPARE_FUNC_NEVER
|| comparefunc
== RC_COMPARE_FUNC_ALWAYS
) {
148 inst
->U
.I
.Opcode
= RC_OPCODE_MOV
;
150 if (comparefunc
== RC_COMPARE_FUNC_ALWAYS
) {
151 inst
->U
.I
.SrcReg
[0] = shadow_pass_value(compiler
, inst
->U
.I
.TexSrcUnit
);
153 inst
->U
.I
.SrcReg
[0] = shadow_fail_value(compiler
, inst
->U
.I
.TexSrcUnit
);
158 struct rc_instruction
* inst_rcp
= NULL
;
159 struct rc_instruction
*inst_mul
, *inst_add
, *inst_cmp
;
160 unsigned tmp_texsample
;
164 /* Save the output register. */
165 struct rc_dst_register output_reg
= inst
->U
.I
.DstReg
;
166 unsigned saturate_mode
= inst
->U
.I
.SaturateMode
;
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
;
175 tmp_sum
= rc_find_free_temporary(c
);
177 if (inst
->U
.I
.Opcode
== RC_OPCODE_TXP
) {
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));
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
;
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
;
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)
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
;
232 inst_add
->U
.I
.SrcReg
[0].Negate
= inst_add
->U
.I
.SrcReg
[0].Negate
^ RC_MASK_XYZW
;
234 /* This negates the whole expresion: */
235 if (comparefunc
== RC_COMPARE_FUNC_LESS
|| comparefunc
== RC_COMPARE_FUNC_GREATER
||
236 comparefunc
== RC_COMPARE_FUNC_NOTEQUAL
) {
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
);
256 assert(tmp_texsample
!= tmp_sum
);
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
;
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
);
275 /* Texture wrap modes don't work on NPOT textures.
277 * Non-wrapped/clamped texcoords with NPOT are free in HW. Repeat and
278 * mirroring are not. If we need to repeat, we do:
280 * MUL temp, texcoord, <scaling factor constant>
281 * FRC temp, temp ; Discard integer portion of coords
283 * This gives us coords in [0, 1].
285 * Mirroring is trickier. We're going to start out like repeat:
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).
295 * This gives us coords in [0, 1].
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
);
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
);
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
) {
316 * f(v) = 1 - abs(frac(v * 0.5) * 2 - 1)
319 * MUL temp, src0, 0.5
321 * MAD temp, temp, 2, -1
322 * ADD temp, 1, -abs(temp)
325 struct rc_instruction
*inst_mul
, *inst_frc
, *inst_mad
, *inst_add
;
326 unsigned two
, two_swizzle
;
328 inst_mul
= rc_insert_new_instruction(c
, inst
->Prev
);
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
;
337 inst_frc
= rc_insert_new_instruction(c
, inst
->Prev
);
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
;
347 two
= rc_constants_add_immediate_scalar(&c
->Program
.Constants
, 2, &two_swizzle
);
348 inst_mad
= rc_insert_new_instruction(c
, inst
->Prev
);
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
;
363 inst_add
= rc_insert_new_instruction(c
, inst
->Prev
);
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
) {
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.
381 struct rc_instruction
*inst_mov
;
383 inst_mov
= rc_insert_new_instruction(c
, inst
->Prev
);
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;
393 /* Preserve W for TXP/TXB. */
394 inst_mov
= rc_insert_new_instruction(c
, inst
->Prev
);
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];
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
;
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
);
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];
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];
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
;
434 scale_texcoords(compiler
, inst
, RC_STATE_R300_TEXSCALE_FACTOR
);
437 /* Convert SNORM-encoded ATI1N sampled as UNORM to SNORM.
438 * Formula: dst = tex > 0.5 ? tex*2-2 : tex*2
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
;
445 two
= rc_constants_add_immediate_scalar(&c
->Program
.Constants
, 2.35, &two_swizzle
);
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
;
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
;
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 */
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
;
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
);
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
);
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
;
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
);
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];
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
;