r300/compiler: Refactor local transforms to use rc_program
[mesa.git] / src / mesa / drivers / dri / r300 / compiler / r3xx_fragprog.c
1 /*
2 * Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 #include "radeon_compiler.h"
24
25 #include "shader/prog_parameter.h"
26 #include "shader/prog_print.h"
27 #include "shader/prog_statevars.h"
28
29 #include "radeon_nqssadce.h"
30 #include "radeon_program_alu.h"
31 #include "r300_fragprog.h"
32 #include "r300_fragprog_swizzle.h"
33 #include "r500_fragprog.h"
34
35
36 static void nqssadce_init(struct nqssadce_state* s)
37 {
38 s->Outputs[FRAG_RESULT_COLOR].Sourced = WRITEMASK_XYZW;
39 s->Outputs[FRAG_RESULT_DEPTH].Sourced = WRITEMASK_W;
40 }
41
42 /**
43 * Transform the program to support fragment.position.
44 *
45 * Introduce a small fragment at the start of the program that will be
46 * the only code that directly reads the FRAG_ATTRIB_WPOS input.
47 * All other code pieces that reference that input will be rewritten
48 * to read from a newly allocated temporary.
49 *
50 */
51 static void insert_WPOS_trailer(struct r300_fragment_program_compiler *compiler)
52 {
53 GLuint InputsRead = compiler->program->InputsRead;
54
55 if (!(InputsRead & FRAG_BIT_WPOS)) {
56 compiler->code->wpos_attr = FRAG_ATTRIB_MAX;
57 return;
58 }
59
60 static gl_state_index tokens[STATE_LENGTH] = {
61 STATE_INTERNAL, STATE_R300_WINDOW_DIMENSION, 0, 0, 0
62 };
63 struct prog_instruction *fpi;
64 GLuint window_index;
65 int i = 0;
66
67 for (i = FRAG_ATTRIB_TEX0; i <= FRAG_ATTRIB_TEX7; ++i)
68 {
69 if (!(InputsRead & (1 << i))) {
70 InputsRead &= ~(1 << FRAG_ATTRIB_WPOS);
71 InputsRead |= 1 << i;
72 compiler->program->InputsRead = InputsRead;
73 compiler->code->wpos_attr = i;
74 break;
75 }
76 }
77
78 GLuint tempregi = _mesa_find_free_register(compiler->program, PROGRAM_TEMPORARY);
79
80 _mesa_insert_instructions(compiler->program, 0, 3);
81 fpi = compiler->program->Instructions;
82 i = 0;
83
84 /* perspective divide */
85 fpi[i].Opcode = OPCODE_RCP;
86
87 fpi[i].DstReg.File = PROGRAM_TEMPORARY;
88 fpi[i].DstReg.Index = tempregi;
89 fpi[i].DstReg.WriteMask = WRITEMASK_W;
90 fpi[i].DstReg.CondMask = COND_TR;
91
92 fpi[i].SrcReg[0].File = PROGRAM_INPUT;
93 fpi[i].SrcReg[0].Index = compiler->code->wpos_attr;
94 fpi[i].SrcReg[0].Swizzle = SWIZZLE_WWWW;
95 i++;
96
97 fpi[i].Opcode = OPCODE_MUL;
98
99 fpi[i].DstReg.File = PROGRAM_TEMPORARY;
100 fpi[i].DstReg.Index = tempregi;
101 fpi[i].DstReg.WriteMask = WRITEMASK_XYZ;
102 fpi[i].DstReg.CondMask = COND_TR;
103
104 fpi[i].SrcReg[0].File = PROGRAM_INPUT;
105 fpi[i].SrcReg[0].Index = compiler->code->wpos_attr;
106 fpi[i].SrcReg[0].Swizzle = SWIZZLE_XYZW;
107
108 fpi[i].SrcReg[1].File = PROGRAM_TEMPORARY;
109 fpi[i].SrcReg[1].Index = tempregi;
110 fpi[i].SrcReg[1].Swizzle = SWIZZLE_WWWW;
111 i++;
112
113 /* viewport transformation */
114 window_index = _mesa_add_state_reference(compiler->program->Parameters, tokens);
115
116 fpi[i].Opcode = OPCODE_MAD;
117
118 fpi[i].DstReg.File = PROGRAM_TEMPORARY;
119 fpi[i].DstReg.Index = tempregi;
120 fpi[i].DstReg.WriteMask = WRITEMASK_XYZ;
121 fpi[i].DstReg.CondMask = COND_TR;
122
123 fpi[i].SrcReg[0].File = PROGRAM_TEMPORARY;
124 fpi[i].SrcReg[0].Index = tempregi;
125 fpi[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO);
126
127 fpi[i].SrcReg[1].File = PROGRAM_STATE_VAR;
128 fpi[i].SrcReg[1].Index = window_index;
129 fpi[i].SrcReg[1].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO);
130
131 fpi[i].SrcReg[2].File = PROGRAM_STATE_VAR;
132 fpi[i].SrcReg[2].Index = window_index;
133 fpi[i].SrcReg[2].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_ZERO);
134 i++;
135
136 for (; i < compiler->program->NumInstructions; ++i) {
137 int reg;
138 for (reg = 0; reg < 3; reg++) {
139 if (fpi[i].SrcReg[reg].File == PROGRAM_INPUT &&
140 fpi[i].SrcReg[reg].Index == FRAG_ATTRIB_WPOS) {
141 fpi[i].SrcReg[reg].File = PROGRAM_TEMPORARY;
142 fpi[i].SrcReg[reg].Index = tempregi;
143 }
144 }
145 }
146 }
147
148
149 /**
150 * Rewrite fragment.fogcoord to use a texture coordinate slot.
151 * Note that fogcoord is forced into an X001 pattern, and this enforcement
152 * is done here.
153 *
154 * See also the counterpart rewriting for vertex programs.
155 */
156 static void rewriteFog(struct r300_fragment_program_compiler *compiler)
157 {
158 struct rX00_fragment_program_code *code = compiler->code;
159 GLuint InputsRead = compiler->program->InputsRead;
160 int i;
161
162 if (!(InputsRead & FRAG_BIT_FOGC)) {
163 code->fog_attr = FRAG_ATTRIB_MAX;
164 return;
165 }
166
167 for (i = FRAG_ATTRIB_TEX0; i <= FRAG_ATTRIB_TEX7; ++i)
168 {
169 if (!(InputsRead & (1 << i))) {
170 InputsRead &= ~(1 << FRAG_ATTRIB_FOGC);
171 InputsRead |= 1 << i;
172 compiler->program->InputsRead = InputsRead;
173 code->fog_attr = i;
174 break;
175 }
176 }
177
178 {
179 struct prog_instruction *inst;
180
181 inst = compiler->program->Instructions;
182 while (inst->Opcode != OPCODE_END) {
183 const int src_regs = _mesa_num_inst_src_regs(inst->Opcode);
184 for (i = 0; i < src_regs; ++i) {
185 if (inst->SrcReg[i].File == PROGRAM_INPUT && inst->SrcReg[i].Index == FRAG_ATTRIB_FOGC) {
186 inst->SrcReg[i].Index = code->fog_attr;
187 inst->SrcReg[i].Swizzle = combine_swizzles(
188 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE),
189 inst->SrcReg[i].Swizzle);
190 }
191 }
192 ++inst;
193 }
194 }
195 }
196
197
198 static void rewrite_depth_out(struct gl_program *prog)
199 {
200 struct prog_instruction *inst;
201
202 for (inst = prog->Instructions; inst->Opcode != OPCODE_END; ++inst) {
203 if (inst->DstReg.File != PROGRAM_OUTPUT || inst->DstReg.Index != FRAG_RESULT_DEPTH)
204 continue;
205
206 if (inst->DstReg.WriteMask & WRITEMASK_Z) {
207 inst->DstReg.WriteMask = WRITEMASK_W;
208 } else {
209 inst->DstReg.WriteMask = 0;
210 continue;
211 }
212
213 switch (inst->Opcode) {
214 case OPCODE_FRC:
215 case OPCODE_MOV:
216 inst->SrcReg[0] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[0]);
217 break;
218 case OPCODE_ADD:
219 case OPCODE_MAX:
220 case OPCODE_MIN:
221 case OPCODE_MUL:
222 inst->SrcReg[0] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[0]);
223 inst->SrcReg[1] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[1]);
224 break;
225 case OPCODE_CMP:
226 case OPCODE_MAD:
227 inst->SrcReg[0] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[0]);
228 inst->SrcReg[1] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[1]);
229 inst->SrcReg[2] = lmul_swizzle(SWIZZLE_ZZZZ, inst->SrcReg[2]);
230 break;
231 default:
232 // Scalar instructions needn't be reswizzled
233 break;
234 }
235 }
236 }
237
238 void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c)
239 {
240 if (c->Base.Debug) {
241 fflush(stdout);
242 _mesa_printf("Fragment Program: Initial program:\n");
243 _mesa_print_program(c->program);
244 fflush(stdout);
245 }
246
247 insert_WPOS_trailer(c);
248
249 rewriteFog(c);
250
251 rewrite_depth_out(c->program);
252
253 rc_mesa_to_rc_program(&c->Base, c->program);
254
255 if (c->is_r500) {
256 struct radeon_program_transformation transformations[] = {
257 { &r500_transform_TEX, c },
258 { &radeonTransformALU, 0 },
259 { &radeonTransformDeriv, 0 },
260 { &radeonTransformTrigScale, 0 }
261 };
262 radeonLocalTransform(&c->Base, 4, transformations);
263 } else {
264 struct radeon_program_transformation transformations[] = {
265 { &r300_transform_TEX, c },
266 { &radeonTransformALU, 0 },
267 { &radeonTransformTrigSimple, 0 }
268 };
269 radeonLocalTransform(&c->Base, 3, transformations);
270 }
271
272 if (c->Base.Debug) {
273 _mesa_printf("Fragment Program: After native rewrite:\n");
274 rc_print_program(&c->Base.Program);
275 fflush(stdout);
276 }
277
278 if (c->is_r500) {
279 struct radeon_nqssadce_descr nqssadce = {
280 .Init = &nqssadce_init,
281 .IsNativeSwizzle = &r500FPIsNativeSwizzle,
282 .BuildSwizzle = &r500FPBuildSwizzle
283 };
284 radeonNqssaDce(&c->Base, &nqssadce, 0);
285 } else {
286 struct radeon_nqssadce_descr nqssadce = {
287 .Init = &nqssadce_init,
288 .IsNativeSwizzle = &r300FPIsNativeSwizzle,
289 .BuildSwizzle = &r300FPBuildSwizzle
290 };
291 radeonNqssaDce(&c->Base, &nqssadce, 0);
292 }
293
294 if (c->Base.Debug) {
295 _mesa_printf("Compiler: after NqSSA-DCE:\n");
296 rc_print_program(&c->Base.Program);
297 fflush(stdout);
298 }
299
300 if (c->is_r500) {
301 r500BuildFragmentProgramHwCode(c);
302 } else {
303 r300BuildFragmentProgramHwCode(c);
304 }
305
306 rc_constants_copy(&c->code->constants, &c->Base.Program.Constants);
307
308 if (c->Base.Debug) {
309 if (c->is_r500) {
310 r500FragmentProgramDump(c->code);
311 } else {
312 r300FragmentProgramDump(c->code);
313 }
314 }
315 }