2 * Copyright (C) 2009 Maciej Cencora <m.cencora@gmail.com>
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 * Fragment program compiler. Perform transformations on the intermediate
32 * representation until the program is in a form where we can translate
33 * it more or less directly into machine-readable form.
35 * \author Ben Skeggs <darktama@iinet.net.au>
36 * \author Jerome Glisse <j.glisse@gmail.com>
39 #include "r300_fragprog_common.h"
41 #include "program/prog_print.h"
43 #include "compiler/radeon_compiler.h"
45 #include "radeon_mesa_to_rc.h"
48 static GLuint
build_dts(GLuint depthmode
)
52 case GL_LUMINANCE
: return RC_SWIZZLE_XYZZ
;
53 case GL_INTENSITY
: return RC_SWIZZLE_XYZW
;
54 case GL_ALPHA
: return RC_SWIZZLE_WWWW
;
58 static GLuint
build_func(GLuint comparefunc
)
60 return comparefunc
- GL_NEVER
;
64 * Collect all external state that is relevant for compiling the given
67 static void build_state(
69 struct gl_fragment_program
*fp
,
70 struct r300_fragment_program_external_state
*state
)
74 memset(state
, 0, sizeof(*state
));
76 for(unit
= 0; unit
< 16; ++unit
) {
77 if (fp
->Base
.ShadowSamplers
& (1 << unit
)) {
78 struct gl_texture_object
* tex
= r300
->radeon
.glCtx
->Texture
.Unit
[unit
]._Current
;
80 state
->unit
[unit
].texture_swizzle
= build_dts(tex
->Sampler
.DepthMode
);
81 state
->unit
[unit
].texture_compare_func
= build_func(tex
->Sampler
.CompareFunc
);
88 * Transform the program to support fragment.position.
90 * Introduce a small fragment at the start of the program that will be
91 * the only code that directly reads the FRAG_ATTRIB_WPOS input.
92 * All other code pieces that reference that input will be rewritten
93 * to read from a newly allocated temporary.
96 static void insert_WPOS_trailer(struct r300_fragment_program_compiler
*compiler
, struct r300_fragment_program
* fp
)
100 fp
->wpos_attr
= FRAG_ATTRIB_MAX
;
101 if (!(compiler
->Base
.Program
.InputsRead
& FRAG_BIT_WPOS
)) {
105 for (i
= FRAG_ATTRIB_TEX0
; i
<= FRAG_ATTRIB_TEX7
; ++i
)
107 if (!(compiler
->Base
.Program
.InputsRead
& (1 << i
))) {
113 /* No free texcoord found, fall-back to software rendering */
114 if (fp
->wpos_attr
== FRAG_ATTRIB_MAX
)
116 compiler
->Base
.Error
= 1;
120 rc_transform_fragment_wpos(&compiler
->Base
, FRAG_ATTRIB_WPOS
, fp
->wpos_attr
, GL_FALSE
);
124 * Rewrite fragment.fogcoord to use a texture coordinate slot.
125 * Note that fogcoord is forced into an X001 pattern, and this enforcement
128 * See also the counterpart rewriting for vertex programs.
130 static void rewriteFog(struct r300_fragment_program_compiler
*compiler
, struct r300_fragment_program
* fp
)
132 struct rc_src_register src
;
135 fp
->fog_attr
= FRAG_ATTRIB_MAX
;
136 if (!(compiler
->Base
.Program
.InputsRead
& FRAG_BIT_FOGC
)) {
140 for (i
= FRAG_ATTRIB_TEX0
; i
<= FRAG_ATTRIB_TEX7
; ++i
)
142 if (!(compiler
->Base
.Program
.InputsRead
& (1 << i
))) {
148 /* No free texcoord found, fall-back to software rendering */
149 if (fp
->fog_attr
== FRAG_ATTRIB_MAX
)
151 compiler
->Base
.Error
= 1;
155 memset(&src
, 0, sizeof(src
));
156 src
.File
= RC_FILE_INPUT
;
157 src
.Index
= fp
->fog_attr
;
158 src
.Swizzle
= MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_ZERO
, SWIZZLE_ZERO
, SWIZZLE_ONE
);
159 rc_move_input(&compiler
->Base
, FRAG_ATTRIB_FOGC
, src
);
164 * Reserve hardware temporary registers for the program inputs.
166 * @note This allocation is performed explicitly, because the order of inputs
167 * is determined by the RS hardware.
169 static void allocate_hw_inputs(
170 struct r300_fragment_program_compiler
* c
,
171 void (*allocate
)(void * data
, unsigned input
, unsigned hwreg
),
174 GLuint InputsRead
= c
->Base
.Program
.InputsRead
;
179 if (InputsRead
& FRAG_BIT_COL0
)
180 allocate(mydata
, FRAG_ATTRIB_COL0
, hwindex
++);
181 InputsRead
&= ~FRAG_BIT_COL0
;
183 /* Secondary color */
184 if (InputsRead
& FRAG_BIT_COL1
)
185 allocate(mydata
, FRAG_ATTRIB_COL1
, hwindex
++);
186 InputsRead
&= ~FRAG_BIT_COL1
;
189 for (i
= 0; i
< 8; i
++) {
190 if (InputsRead
& (FRAG_BIT_TEX0
<< i
))
191 allocate(mydata
, FRAG_ATTRIB_TEX0
+i
, hwindex
++);
193 InputsRead
&= ~FRAG_BITS_TEX_ANY
;
195 /* Fogcoords treated as a texcoord */
196 if (InputsRead
& FRAG_BIT_FOGC
)
197 allocate(mydata
, FRAG_ATTRIB_FOGC
, hwindex
++);
198 InputsRead
&= ~FRAG_BIT_FOGC
;
200 /* fragment position treated as a texcoord */
201 if (InputsRead
& FRAG_BIT_WPOS
)
202 allocate(mydata
, FRAG_ATTRIB_WPOS
, hwindex
++);
203 InputsRead
&= ~FRAG_BIT_WPOS
;
207 rc_error(&c
->Base
, "Don't know how to handle inputs 0x%x\n", InputsRead
);
211 static void translate_fragment_program(struct gl_context
*ctx
, struct r300_fragment_program_cont
*cont
, struct r300_fragment_program
*fp
)
213 r300ContextPtr r300
= R300_CONTEXT(ctx
);
214 struct r300_fragment_program_compiler compiler
;
216 memset(&compiler
, 0, sizeof(compiler
));
217 rc_init(&compiler
.Base
);
218 compiler
.Base
.Debug
= (RADEON_DEBUG
& RADEON_PIXEL
) ? GL_TRUE
: GL_FALSE
;
220 compiler
.code
= &fp
->code
;
221 compiler
.state
= fp
->state
;
222 compiler
.enable_shadow_ambient
= GL_TRUE
;
223 compiler
.Base
.is_r500
= (r300
->radeon
.radeonScreen
->chip_family
>= CHIP_FAMILY_RV515
) ? GL_TRUE
: GL_FALSE
;
224 compiler
.Base
.disable_optimizations
= 0;
225 compiler
.Base
.has_half_swizzles
= 1;
226 compiler
.Base
.max_temp_regs
= (compiler
.Base
.is_r500
) ? 128 : 32;
227 compiler
.Base
.max_constants
= compiler
.Base
.is_r500
? 256 : 32;
228 compiler
.Base
.max_alu_insts
= compiler
.Base
.is_r500
? 512 : 64;
229 compiler
.Base
.max_tex_insts
= compiler
.Base
.is_r500
? 512 : 32;
230 compiler
.OutputDepth
= FRAG_RESULT_DEPTH
;
231 memset(compiler
.OutputColor
, 0, 4 * sizeof(unsigned));
232 compiler
.OutputColor
[0] = FRAG_RESULT_COLOR
;
233 compiler
.AllocateHwInputs
= &allocate_hw_inputs
;
235 if (compiler
.Base
.Debug
) {
237 printf("Fragment Program: Initial program:\n");
238 _mesa_print_program(&cont
->Base
.Base
);
242 radeon_mesa_to_rc_program(&compiler
.Base
, &cont
->Base
.Base
);
244 insert_WPOS_trailer(&compiler
, fp
);
246 rewriteFog(&compiler
, fp
);
248 r3xx_compile_fragment_program(&compiler
);
250 if (compiler
.Base
.is_r500
) {
251 /* We need to support the non-KMS DRM interface, which
252 * artificially limits the number of instructions and
253 * constants which are available to us.
255 * See also the comment in r300_context.c where we
256 * set the MAX_NATIVE_xxx values.
258 if (fp
->code
.code
.r500
.inst_end
>= 255 || fp
->code
.constants
.Count
> 255)
259 rc_error(&compiler
.Base
, "Program is too big (upgrade to r300g to avoid this limitation).\n");
262 fp
->error
= compiler
.Base
.Error
;
264 fp
->InputsRead
= compiler
.Base
.Program
.InputsRead
;
266 /* Clear the fog/wpos_attr if code accessing these
267 * attributes has been removed during compilation
269 if (fp
->fog_attr
!= FRAG_ATTRIB_MAX
) {
270 if (!(fp
->InputsRead
& (1 << fp
->fog_attr
)))
271 fp
->fog_attr
= FRAG_ATTRIB_MAX
;
274 if (fp
->wpos_attr
!= FRAG_ATTRIB_MAX
) {
275 if (!(fp
->InputsRead
& (1 << fp
->wpos_attr
)))
276 fp
->wpos_attr
= FRAG_ATTRIB_MAX
;
279 rc_destroy(&compiler
.Base
);
282 struct r300_fragment_program
*r300SelectAndTranslateFragmentShader(struct gl_context
*ctx
)
284 r300ContextPtr r300
= R300_CONTEXT(ctx
);
285 struct r300_fragment_program_cont
*fp_list
;
286 struct r300_fragment_program
*fp
;
287 struct r300_fragment_program_external_state state
;
289 fp_list
= (struct r300_fragment_program_cont
*)ctx
->FragmentProgram
._Current
;
290 build_state(r300
, ctx
->FragmentProgram
._Current
, &state
);
294 if (memcmp(&fp
->state
, &state
, sizeof(state
)) == 0) {
295 return r300
->selected_fp
= fp
;
300 fp
= calloc(1, sizeof(struct r300_fragment_program
));
304 fp
->next
= fp_list
->progs
;
307 translate_fragment_program(ctx
, fp_list
, fp
);
309 return r300
->selected_fp
= fp
;