r300: Add radeon_compiler as a base for compilation-related tasks
[mesa.git] / src / mesa / drivers / dri / r300 / compiler / r300_fragprog_emit.c
1 /*
2 * Copyright (C) 2005 Ben Skeggs.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a 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, sublicense, 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
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28 /**
29 * \file
30 *
31 * Emit the r300_fragment_program_code that can be understood by the hardware.
32 * Input is a pre-transformed radeon_program.
33 *
34 * \author Ben Skeggs <darktama@iinet.net.au>
35 *
36 * \author Jerome Glisse <j.glisse@gmail.com>
37 *
38 * \todo FogOption
39 */
40
41 #include "r300_fragprog.h"
42
43 #include "../r300_reg.h"
44
45 #include "radeon_program_pair.h"
46 #include "r300_fragprog_swizzle.h"
47
48
49 #define PROG_CODE \
50 struct r300_fragment_program_compiler *c = (struct r300_fragment_program_compiler*)data; \
51 struct r300_fragment_program_code *code = &c->code->code.r300
52
53 #define error(fmt, args...) do { \
54 fprintf(stderr, "%s::%s(): " fmt "\n", \
55 __FILE__, __FUNCTION__, ##args); \
56 } while(0)
57
58
59 static GLboolean emit_const(void* data, GLuint file, GLuint index, GLuint *hwindex)
60 {
61 PROG_CODE;
62
63 for (*hwindex = 0; *hwindex < code->const_nr; ++*hwindex) {
64 if (code->constant[*hwindex].File == file &&
65 code->constant[*hwindex].Index == index)
66 break;
67 }
68
69 if (*hwindex >= code->const_nr) {
70 if (*hwindex >= R300_PFS_NUM_CONST_REGS) {
71 error("Out of hw constants!\n");
72 return GL_FALSE;
73 }
74
75 code->const_nr++;
76 code->constant[*hwindex].File = file;
77 code->constant[*hwindex].Index = index;
78 }
79
80 return GL_TRUE;
81 }
82
83
84 /**
85 * Mark a temporary register as used.
86 */
87 static void use_temporary(struct r300_fragment_program_code *code, GLuint index)
88 {
89 if (index > code->max_temp_idx)
90 code->max_temp_idx = index;
91 }
92
93
94 static GLuint translate_rgb_opcode(GLuint opcode)
95 {
96 switch(opcode) {
97 case OPCODE_CMP: return R300_ALU_OUTC_CMP;
98 case OPCODE_DP3: return R300_ALU_OUTC_DP3;
99 case OPCODE_DP4: return R300_ALU_OUTC_DP4;
100 case OPCODE_FRC: return R300_ALU_OUTC_FRC;
101 default:
102 error("translate_rgb_opcode(%i): Unknown opcode", opcode);
103 /* fall through */
104 case OPCODE_NOP:
105 /* fall through */
106 case OPCODE_MAD: return R300_ALU_OUTC_MAD;
107 case OPCODE_MAX: return R300_ALU_OUTC_MAX;
108 case OPCODE_MIN: return R300_ALU_OUTC_MIN;
109 case OPCODE_REPL_ALPHA: return R300_ALU_OUTC_REPL_ALPHA;
110 }
111 }
112
113 static GLuint translate_alpha_opcode(GLuint opcode)
114 {
115 switch(opcode) {
116 case OPCODE_CMP: return R300_ALU_OUTA_CMP;
117 case OPCODE_DP3: return R300_ALU_OUTA_DP4;
118 case OPCODE_DP4: return R300_ALU_OUTA_DP4;
119 case OPCODE_EX2: return R300_ALU_OUTA_EX2;
120 case OPCODE_FRC: return R300_ALU_OUTA_FRC;
121 case OPCODE_LG2: return R300_ALU_OUTA_LG2;
122 default:
123 error("translate_rgb_opcode(%i): Unknown opcode", opcode);
124 /* fall through */
125 case OPCODE_NOP:
126 /* fall through */
127 case OPCODE_MAD: return R300_ALU_OUTA_MAD;
128 case OPCODE_MAX: return R300_ALU_OUTA_MAX;
129 case OPCODE_MIN: return R300_ALU_OUTA_MIN;
130 case OPCODE_RCP: return R300_ALU_OUTA_RCP;
131 case OPCODE_RSQ: return R300_ALU_OUTA_RSQ;
132 }
133 }
134
135 /**
136 * Emit one paired ALU instruction.
137 */
138 static GLboolean emit_alu(void* data, struct radeon_pair_instruction* inst)
139 {
140 PROG_CODE;
141
142 if (code->alu.length >= R300_PFS_MAX_ALU_INST) {
143 error("Too many ALU instructions");
144 return GL_FALSE;
145 }
146
147 int ip = code->alu.length++;
148 int j;
149 code->node[code->cur_node].alu_end++;
150
151 code->alu.inst[ip].inst0 = translate_rgb_opcode(inst->RGB.Opcode);
152 code->alu.inst[ip].inst2 = translate_alpha_opcode(inst->Alpha.Opcode);
153
154 for(j = 0; j < 3; ++j) {
155 GLuint src = inst->RGB.Src[j].Index | (inst->RGB.Src[j].Constant << 5);
156 if (!inst->RGB.Src[j].Constant)
157 use_temporary(code, inst->RGB.Src[j].Index);
158 code->alu.inst[ip].inst1 |= src << (6*j);
159
160 src = inst->Alpha.Src[j].Index | (inst->Alpha.Src[j].Constant << 5);
161 if (!inst->Alpha.Src[j].Constant)
162 use_temporary(code, inst->Alpha.Src[j].Index);
163 code->alu.inst[ip].inst3 |= src << (6*j);
164
165 GLuint arg = r300FPTranslateRGBSwizzle(inst->RGB.Arg[j].Source, inst->RGB.Arg[j].Swizzle);
166 arg |= inst->RGB.Arg[j].Abs << 6;
167 arg |= inst->RGB.Arg[j].Negate << 5;
168 code->alu.inst[ip].inst0 |= arg << (7*j);
169
170 arg = r300FPTranslateAlphaSwizzle(inst->Alpha.Arg[j].Source, inst->Alpha.Arg[j].Swizzle);
171 arg |= inst->Alpha.Arg[j].Abs << 6;
172 arg |= inst->Alpha.Arg[j].Negate << 5;
173 code->alu.inst[ip].inst2 |= arg << (7*j);
174 }
175
176 if (inst->RGB.Saturate)
177 code->alu.inst[ip].inst0 |= R300_ALU_OUTC_CLAMP;
178 if (inst->Alpha.Saturate)
179 code->alu.inst[ip].inst2 |= R300_ALU_OUTA_CLAMP;
180
181 if (inst->RGB.WriteMask) {
182 use_temporary(code, inst->RGB.DestIndex);
183 code->alu.inst[ip].inst1 |=
184 (inst->RGB.DestIndex << R300_ALU_DSTC_SHIFT) |
185 (inst->RGB.WriteMask << R300_ALU_DSTC_REG_MASK_SHIFT);
186 }
187 if (inst->RGB.OutputWriteMask) {
188 code->alu.inst[ip].inst1 |= (inst->RGB.OutputWriteMask << R300_ALU_DSTC_OUTPUT_MASK_SHIFT);
189 code->node[code->cur_node].flags |= R300_RGBA_OUT;
190 }
191
192 if (inst->Alpha.WriteMask) {
193 use_temporary(code, inst->Alpha.DestIndex);
194 code->alu.inst[ip].inst3 |=
195 (inst->Alpha.DestIndex << R300_ALU_DSTA_SHIFT) |
196 R300_ALU_DSTA_REG;
197 }
198 if (inst->Alpha.OutputWriteMask) {
199 code->alu.inst[ip].inst3 |= R300_ALU_DSTA_OUTPUT;
200 code->node[code->cur_node].flags |= R300_RGBA_OUT;
201 }
202 if (inst->Alpha.DepthWriteMask) {
203 code->alu.inst[ip].inst3 |= R300_ALU_DSTA_DEPTH;
204 code->node[code->cur_node].flags |= R300_W_OUT;
205 c->code->writes_depth = GL_TRUE;
206 }
207
208 return GL_TRUE;
209 }
210
211
212 /**
213 * Finish the current node without advancing to the next one.
214 */
215 static GLboolean finish_node(struct r300_fragment_program_compiler *c)
216 {
217 struct r300_fragment_program_code *code = &c->code->code.r300;
218 struct r300_fragment_program_node *node = &code->node[code->cur_node];
219
220 if (node->alu_end < 0) {
221 /* Generate a single NOP for this node */
222 struct radeon_pair_instruction inst;
223 _mesa_bzero(&inst, sizeof(inst));
224 if (!emit_alu(c, &inst))
225 return GL_FALSE;
226 }
227
228 if (node->tex_end < 0) {
229 if (code->cur_node == 0) {
230 node->tex_end = 0;
231 } else {
232 error("Node %i has no TEX instructions", code->cur_node);
233 return GL_FALSE;
234 }
235 } else {
236 if (code->cur_node == 0)
237 code->first_node_has_tex = 1;
238 }
239
240 return GL_TRUE;
241 }
242
243
244 /**
245 * Begin a block of texture instructions.
246 * Create the necessary indirection.
247 */
248 static GLboolean begin_tex(void* data)
249 {
250 PROG_CODE;
251
252 if (code->cur_node == 0) {
253 if (code->node[0].alu_end < 0 &&
254 code->node[0].tex_end < 0)
255 return GL_TRUE;
256 }
257
258 if (code->cur_node == 3) {
259 error("Too many texture indirections");
260 return GL_FALSE;
261 }
262
263 if (!finish_node(c))
264 return GL_FALSE;
265
266 struct r300_fragment_program_node *node = &code->node[++code->cur_node];
267 node->alu_offset = code->alu.length;
268 node->alu_end = -1;
269 node->tex_offset = code->tex.length;
270 node->tex_end = -1;
271 return GL_TRUE;
272 }
273
274
275 static GLboolean emit_tex(void* data, struct radeon_pair_texture_instruction* inst)
276 {
277 PROG_CODE;
278
279 if (code->tex.length >= R300_PFS_MAX_TEX_INST) {
280 error("Too many TEX instructions");
281 return GL_FALSE;
282 }
283
284 GLuint unit = inst->TexSrcUnit;
285 GLuint dest = inst->DestIndex;
286 GLuint opcode;
287
288 switch(inst->Opcode) {
289 case RADEON_OPCODE_KIL: opcode = R300_TEX_OP_KIL; break;
290 case RADEON_OPCODE_TEX: opcode = R300_TEX_OP_LD; break;
291 case RADEON_OPCODE_TXB: opcode = R300_TEX_OP_TXB; break;
292 case RADEON_OPCODE_TXP: opcode = R300_TEX_OP_TXP; break;
293 default:
294 error("Unknown texture opcode %i", inst->Opcode);
295 return GL_FALSE;
296 }
297
298 if (inst->Opcode == RADEON_OPCODE_KIL) {
299 unit = 0;
300 dest = 0;
301 } else {
302 use_temporary(code, dest);
303 }
304
305 use_temporary(code, inst->SrcIndex);
306
307 code->node[code->cur_node].tex_end++;
308 code->tex.inst[code->tex.length++] =
309 (inst->SrcIndex << R300_SRC_ADDR_SHIFT) |
310 (dest << R300_DST_ADDR_SHIFT) |
311 (unit << R300_TEX_ID_SHIFT) |
312 (opcode << R300_TEX_INST_SHIFT);
313 return GL_TRUE;
314 }
315
316
317 static const struct radeon_pair_handler pair_handler = {
318 .EmitConst = &emit_const,
319 .EmitPaired = &emit_alu,
320 .EmitTex = &emit_tex,
321 .BeginTexBlock = &begin_tex,
322 .MaxHwTemps = R300_PFS_NUM_TEMP_REGS
323 };
324
325 /**
326 * Final compilation step: Turn the intermediate radeon_program into
327 * machine-readable instructions.
328 */
329 GLboolean r300BuildFragmentProgramHwCode(struct r300_fragment_program_compiler *compiler)
330 {
331 struct r300_fragment_program_code *code = &compiler->code->code.r300;
332
333 _mesa_bzero(code, sizeof(struct r300_fragment_program_code));
334 code->node[0].alu_end = -1;
335 code->node[0].tex_end = -1;
336
337 if (!radeonPairProgram(&compiler->Base, compiler->program, &pair_handler, compiler))
338 return GL_FALSE;
339
340 if (!finish_node(compiler))
341 return GL_FALSE;
342
343 return GL_TRUE;
344 }
345