Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /* |
2 | * Copyright (C) 2010 Corbin Simpson |
||
3 | * Copyright (C) 2010 Marek Olšák |
||
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 | |||
35 | static 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 | |||
46 | static 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 | |||
57 | static 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 | |||
81 | static 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 | */ |
||
122 | int 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, |
||
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, |
||
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 | }>=>=>>=>>=>>=>>><> |