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 "r300_fragprog.h"
43 #include "radeon_program_pair.h"
44 #include "r300_fragprog_swizzle.h"
49 struct r300_fragment_program_compiler *c = (struct r300_fragment_program_compiler*)data; \
50 struct r300_fragment_program_code *code = &c->code->r300
52 #define error(fmt, args...) do { \
53 fprintf(stderr, "%s::%s(): " fmt "\n", \
54 __FILE__, __FUNCTION__, ##args); \
58 static GLboolean
emit_const(void* data
, GLuint file
, GLuint index
, GLuint
*hwindex
)
62 for (*hwindex
= 0; *hwindex
< code
->const_nr
; ++*hwindex
) {
63 if (code
->constant
[*hwindex
].File
== file
&&
64 code
->constant
[*hwindex
].Index
== index
)
68 if (*hwindex
>= code
->const_nr
) {
69 if (*hwindex
>= PFS_NUM_CONST_REGS
) {
70 error("Out of hw constants!\n");
75 code
->constant
[*hwindex
].File
= file
;
76 code
->constant
[*hwindex
].Index
= index
;
84 * Mark a temporary register as used.
86 static void use_temporary(struct r300_fragment_program_code
*code
, GLuint index
)
88 if (index
> code
->max_temp_idx
)
89 code
->max_temp_idx
= index
;
93 static GLuint
translate_rgb_opcode(GLuint opcode
)
96 case OPCODE_CMP
: return R300_ALU_OUTC_CMP
;
97 case OPCODE_DP3
: return R300_ALU_OUTC_DP3
;
98 case OPCODE_DP4
: return R300_ALU_OUTC_DP4
;
99 case OPCODE_FRC
: return R300_ALU_OUTC_FRC
;
101 error("translate_rgb_opcode(%i): Unknown opcode", opcode
);
105 case OPCODE_MAD
: return R300_ALU_OUTC_MAD
;
106 case OPCODE_MAX
: return R300_ALU_OUTC_MAX
;
107 case OPCODE_MIN
: return R300_ALU_OUTC_MIN
;
108 case OPCODE_REPL_ALPHA
: return R300_ALU_OUTC_REPL_ALPHA
;
112 static GLuint
translate_alpha_opcode(GLuint opcode
)
115 case OPCODE_CMP
: return R300_ALU_OUTA_CMP
;
116 case OPCODE_DP3
: return R300_ALU_OUTA_DP4
;
117 case OPCODE_DP4
: return R300_ALU_OUTA_DP4
;
118 case OPCODE_EX2
: return R300_ALU_OUTA_EX2
;
119 case OPCODE_FRC
: return R300_ALU_OUTA_FRC
;
120 case OPCODE_LG2
: return R300_ALU_OUTA_LG2
;
122 error("translate_rgb_opcode(%i): Unknown opcode", opcode
);
126 case OPCODE_MAD
: return R300_ALU_OUTA_MAD
;
127 case OPCODE_MAX
: return R300_ALU_OUTA_MAX
;
128 case OPCODE_MIN
: return R300_ALU_OUTA_MIN
;
129 case OPCODE_RCP
: return R300_ALU_OUTA_RCP
;
130 case OPCODE_RSQ
: return R300_ALU_OUTA_RSQ
;
135 * Emit one paired ALU instruction.
137 static GLboolean
emit_alu(void* data
, struct radeon_pair_instruction
* inst
)
141 if (code
->alu
.length
>= PFS_MAX_ALU_INST
) {
142 error("Too many ALU instructions");
146 int ip
= code
->alu
.length
++;
148 code
->node
[code
->cur_node
].alu_end
++;
150 code
->alu
.inst
[ip
].inst0
= translate_rgb_opcode(inst
->RGB
.Opcode
);
151 code
->alu
.inst
[ip
].inst2
= translate_alpha_opcode(inst
->Alpha
.Opcode
);
153 for(j
= 0; j
< 3; ++j
) {
154 GLuint src
= inst
->RGB
.Src
[j
].Index
| (inst
->RGB
.Src
[j
].Constant
<< 5);
155 if (!inst
->RGB
.Src
[j
].Constant
)
156 use_temporary(code
, inst
->RGB
.Src
[j
].Index
);
157 code
->alu
.inst
[ip
].inst1
|= src
<< (6*j
);
159 src
= inst
->Alpha
.Src
[j
].Index
| (inst
->Alpha
.Src
[j
].Constant
<< 5);
160 if (!inst
->Alpha
.Src
[j
].Constant
)
161 use_temporary(code
, inst
->Alpha
.Src
[j
].Index
);
162 code
->alu
.inst
[ip
].inst3
|= src
<< (6*j
);
164 GLuint arg
= r300FPTranslateRGBSwizzle(inst
->RGB
.Arg
[j
].Source
, inst
->RGB
.Arg
[j
].Swizzle
);
165 arg
|= inst
->RGB
.Arg
[j
].Abs
<< 6;
166 arg
|= inst
->RGB
.Arg
[j
].Negate
<< 5;
167 code
->alu
.inst
[ip
].inst0
|= arg
<< (7*j
);
169 arg
= r300FPTranslateAlphaSwizzle(inst
->Alpha
.Arg
[j
].Source
, inst
->Alpha
.Arg
[j
].Swizzle
);
170 arg
|= inst
->Alpha
.Arg
[j
].Abs
<< 6;
171 arg
|= inst
->Alpha
.Arg
[j
].Negate
<< 5;
172 code
->alu
.inst
[ip
].inst2
|= arg
<< (7*j
);
175 if (inst
->RGB
.Saturate
)
176 code
->alu
.inst
[ip
].inst0
|= R300_ALU_OUTC_CLAMP
;
177 if (inst
->Alpha
.Saturate
)
178 code
->alu
.inst
[ip
].inst2
|= R300_ALU_OUTA_CLAMP
;
180 if (inst
->RGB
.WriteMask
) {
181 use_temporary(code
, inst
->RGB
.DestIndex
);
182 code
->alu
.inst
[ip
].inst1
|=
183 (inst
->RGB
.DestIndex
<< R300_ALU_DSTC_SHIFT
) |
184 (inst
->RGB
.WriteMask
<< R300_ALU_DSTC_REG_MASK_SHIFT
);
186 if (inst
->RGB
.OutputWriteMask
) {
187 code
->alu
.inst
[ip
].inst1
|= (inst
->RGB
.OutputWriteMask
<< R300_ALU_DSTC_OUTPUT_MASK_SHIFT
);
188 code
->node
[code
->cur_node
].flags
|= R300_RGBA_OUT
;
191 if (inst
->Alpha
.WriteMask
) {
192 use_temporary(code
, inst
->Alpha
.DestIndex
);
193 code
->alu
.inst
[ip
].inst3
|=
194 (inst
->Alpha
.DestIndex
<< R300_ALU_DSTA_SHIFT
) |
197 if (inst
->Alpha
.OutputWriteMask
) {
198 code
->alu
.inst
[ip
].inst3
|= R300_ALU_DSTA_OUTPUT
;
199 code
->node
[code
->cur_node
].flags
|= R300_RGBA_OUT
;
201 if (inst
->Alpha
.DepthWriteMask
) {
202 code
->alu
.inst
[ip
].inst3
|= R300_ALU_DSTA_DEPTH
;
203 code
->node
[code
->cur_node
].flags
|= R300_W_OUT
;
204 c
->fp
->writes_depth
= GL_TRUE
;
212 * Finish the current node without advancing to the next one.
214 static GLboolean
finish_node(struct r300_fragment_program_compiler
*c
)
216 struct r300_fragment_program_code
*code
= &c
->code
->r300
;
217 struct r300_fragment_program_node
*node
= &code
->node
[code
->cur_node
];
219 if (node
->alu_end
< 0) {
220 /* Generate a single NOP for this node */
221 struct radeon_pair_instruction inst
;
222 _mesa_bzero(&inst
, sizeof(inst
));
223 if (!emit_alu(c
, &inst
))
227 if (node
->tex_end
< 0) {
228 if (code
->cur_node
== 0) {
231 error("Node %i has no TEX instructions", code
->cur_node
);
235 if (code
->cur_node
== 0)
236 code
->first_node_has_tex
= 1;
244 * Begin a block of texture instructions.
245 * Create the necessary indirection.
247 static GLboolean
begin_tex(void* data
)
251 if (code
->cur_node
== 0) {
252 if (code
->node
[0].alu_end
< 0 &&
253 code
->node
[0].tex_end
< 0)
257 if (code
->cur_node
== 3) {
258 error("Too many texture indirections");
265 struct r300_fragment_program_node
*node
= &code
->node
[++code
->cur_node
];
266 node
->alu_offset
= code
->alu
.length
;
268 node
->tex_offset
= code
->tex
.length
;
274 static GLboolean
emit_tex(void* data
, struct prog_instruction
* inst
)
278 if (code
->tex
.length
>= PFS_MAX_TEX_INST
) {
279 error("Too many TEX instructions");
283 GLuint unit
= inst
->TexSrcUnit
;
284 GLuint dest
= inst
->DstReg
.Index
;
287 switch(inst
->Opcode
) {
288 case OPCODE_KIL
: opcode
= R300_TEX_OP_KIL
; break;
289 case OPCODE_TEX
: opcode
= R300_TEX_OP_LD
; break;
290 case OPCODE_TXB
: opcode
= R300_TEX_OP_TXB
; break;
291 case OPCODE_TXP
: opcode
= R300_TEX_OP_TXP
; break;
293 error("Unknown texture opcode %i", inst
->Opcode
);
297 if (inst
->Opcode
== OPCODE_KIL
) {
301 use_temporary(code
, dest
);
304 use_temporary(code
, inst
->SrcReg
[0].Index
);
306 code
->node
[code
->cur_node
].tex_end
++;
307 code
->tex
.inst
[code
->tex
.length
++] =
308 (inst
->SrcReg
[0].Index
<< R300_SRC_ADDR_SHIFT
) |
309 (dest
<< R300_DST_ADDR_SHIFT
) |
310 (unit
<< R300_TEX_ID_SHIFT
) |
311 (opcode
<< R300_TEX_INST_SHIFT
);
316 static const struct radeon_pair_handler pair_handler
= {
317 .EmitConst
= &emit_const
,
318 .EmitPaired
= &emit_alu
,
319 .EmitTex
= &emit_tex
,
320 .BeginTexBlock
= &begin_tex
,
321 .MaxHwTemps
= PFS_NUM_TEMP_REGS
325 * Final compilation step: Turn the intermediate radeon_program into
326 * machine-readable instructions.
328 GLboolean
r300FragmentProgramEmit(struct r300_fragment_program_compiler
*compiler
)
330 struct r300_fragment_program_code
*code
= &compiler
->code
->r300
;
332 _mesa_bzero(code
, sizeof(struct r300_fragment_program_code
));
333 code
->node
[0].alu_end
= -1;
334 code
->node
[0].tex_end
= -1;
336 if (!radeonPairProgram(compiler
->r300
->radeon
.glCtx
, compiler
->program
, &pair_handler
, compiler
))
339 if (!finish_node(compiler
))