2 * Copyright (C) 2005 Ben Skeggs.
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:
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.
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.
31 * Emit the r300_fragment_program_code that can be understood by the hardware.
32 * Input is a pre-transformed radeon_program.
34 * \author Ben Skeggs <darktama@iinet.net.au>
36 * \author Jerome Glisse <j.glisse@gmail.com>
41 #include "compiler/r300_fragprog.h"
45 #include "compiler/radeon_program_pair.h"
46 #include "compiler/r300_fragprog_swizzle.h"
50 struct r300_fragment_program_compiler *c = (struct r300_fragment_program_compiler*)data; \
51 struct r300_fragment_program_code *code = &c->code->code.r300
53 #define error(fmt, args...) do { \
54 fprintf(stderr, "%s::%s(): " fmt "\n", \
55 __FILE__, __FUNCTION__, ##args); \
59 static GLboolean
emit_const(void* data
, GLuint file
, GLuint index
, GLuint
*hwindex
)
63 for (*hwindex
= 0; *hwindex
< code
->const_nr
; ++*hwindex
) {
64 if (code
->constant
[*hwindex
].File
== file
&&
65 code
->constant
[*hwindex
].Index
== index
)
69 if (*hwindex
>= code
->const_nr
) {
70 if (*hwindex
>= R300_PFS_NUM_CONST_REGS
) {
71 error("Out of hw constants!\n");
76 code
->constant
[*hwindex
].File
= file
;
77 code
->constant
[*hwindex
].Index
= index
;
85 * Mark a temporary register as used.
87 static void use_temporary(struct r300_fragment_program_code
*code
, GLuint index
)
89 if (index
> code
->max_temp_idx
)
90 code
->max_temp_idx
= index
;
94 static GLuint
translate_rgb_opcode(GLuint 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
;
102 error("translate_rgb_opcode(%i): Unknown opcode", opcode
);
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
;
113 static GLuint
translate_alpha_opcode(GLuint 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
;
123 error("translate_rgb_opcode(%i): Unknown opcode", opcode
);
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
;
136 * Emit one paired ALU instruction.
138 static GLboolean
emit_alu(void* data
, struct radeon_pair_instruction
* inst
)
142 if (code
->alu
.length
>= R300_PFS_MAX_ALU_INST
) {
143 error("Too many ALU instructions");
147 int ip
= code
->alu
.length
++;
149 code
->node
[code
->cur_node
].alu_end
++;
151 code
->alu
.inst
[ip
].inst0
= translate_rgb_opcode(inst
->RGB
.Opcode
);
152 code
->alu
.inst
[ip
].inst2
= translate_alpha_opcode(inst
->Alpha
.Opcode
);
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
);
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
);
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
);
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
);
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
;
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
);
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
;
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
) |
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
;
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
;
213 * Finish the current node without advancing to the next one.
215 static GLboolean
finish_node(struct r300_fragment_program_compiler
*c
)
217 struct r300_fragment_program_code
*code
= &c
->code
->code
.r300
;
218 struct r300_fragment_program_node
*node
= &code
->node
[code
->cur_node
];
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
))
228 if (node
->tex_end
< 0) {
229 if (code
->cur_node
== 0) {
232 error("Node %i has no TEX instructions", code
->cur_node
);
236 if (code
->cur_node
== 0)
237 code
->first_node_has_tex
= 1;
245 * Begin a block of texture instructions.
246 * Create the necessary indirection.
248 static GLboolean
begin_tex(void* data
)
252 if (code
->cur_node
== 0) {
253 if (code
->node
[0].alu_end
< 0 &&
254 code
->node
[0].tex_end
< 0)
258 if (code
->cur_node
== 3) {
259 error("Too many texture indirections");
266 struct r300_fragment_program_node
*node
= &code
->node
[++code
->cur_node
];
267 node
->alu_offset
= code
->alu
.length
;
269 node
->tex_offset
= code
->tex
.length
;
275 static GLboolean
emit_tex(void* data
, struct radeon_pair_texture_instruction
* inst
)
279 if (code
->tex
.length
>= R300_PFS_MAX_TEX_INST
) {
280 error("Too many TEX instructions");
284 GLuint unit
= inst
->TexSrcUnit
;
285 GLuint dest
= inst
->DestIndex
;
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;
294 error("Unknown texture opcode %i", inst
->Opcode
);
298 if (inst
->Opcode
== RADEON_OPCODE_KIL
) {
302 use_temporary(code
, dest
);
305 use_temporary(code
, inst
->SrcIndex
);
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
);
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
326 * Final compilation step: Turn the intermediate radeon_program into
327 * machine-readable instructions.
329 GLboolean
r300BuildFragmentProgramHwCode(struct r300_fragment_program_compiler
*compiler
)
331 struct r300_fragment_program_code
*code
= &compiler
->code
->code
.r300
;
333 _mesa_bzero(code
, sizeof(struct r300_fragment_program_code
));
334 code
->node
[0].alu_end
= -1;
335 code
->node
[0].tex_end
= -1;
337 if (!radeonPairProgram(compiler
->program
, &pair_handler
, compiler
))
340 if (!finish_node(compiler
))