Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / r300 / r300_fragprog_common.c
1 /*
2  * Copyright (C) 2009 Maciej Cencora <m.cencora@gmail.com>
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  * 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.
34  *
35  * \author Ben Skeggs <darktama@iinet.net.au>
36  * \author Jerome Glisse <j.glisse@gmail.com>
37  */
38
39 #include "r300_fragprog_common.h"
40
41 #include "program/prog_print.h"
42
43 #include "compiler/radeon_compiler.h"
44
45 #include "radeon_mesa_to_rc.h"
46
47
48 static GLuint build_dts(GLuint depthmode)
49 {
50         switch(depthmode) {
51         default:
52         case GL_LUMINANCE: return RC_SWIZZLE_XYZZ;
53         case GL_INTENSITY: return RC_SWIZZLE_XYZW;
54         case GL_ALPHA: return RC_SWIZZLE_WWWW;
55         }
56 }
57
58 static GLuint build_func(GLuint comparefunc)
59 {
60         return comparefunc - GL_NEVER;
61 }
62
63 /**
64  * Collect all external state that is relevant for compiling the given
65  * fragment program.
66  */
67 static void build_state(
68         r300ContextPtr r300,
69         struct gl_fragment_program *fp,
70         struct r300_fragment_program_external_state *state)
71 {
72         int unit;
73
74         memset(state, 0, sizeof(*state));
75
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;
79
80                         state->unit[unit].texture_swizzle = build_dts(tex->Sampler.DepthMode);
81                         state->unit[unit].texture_compare_func = build_func(tex->Sampler.CompareFunc);
82                 }
83         }
84 }
85
86
87 /**
88  * Transform the program to support fragment.position.
89  *
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.
94  *
95  */
96 static void insert_WPOS_trailer(struct r300_fragment_program_compiler *compiler, struct r300_fragment_program * fp)
97 {
98         int i;
99
100         fp->wpos_attr = FRAG_ATTRIB_MAX;
101         if (!(compiler->Base.Program.InputsRead & FRAG_BIT_WPOS)) {
102                 return;
103         }
104
105         for (i = FRAG_ATTRIB_TEX0; i <= FRAG_ATTRIB_TEX7; ++i)
106         {
107                 if (!(compiler->Base.Program.InputsRead & (1 << i))) {
108                         fp->wpos_attr = i;
109                         break;
110                 }
111         }
112
113         /* No free texcoord found, fall-back to software rendering */
114         if (fp->wpos_attr == FRAG_ATTRIB_MAX)
115         {
116                 compiler->Base.Error = 1;
117                 return;
118         }
119
120         rc_transform_fragment_wpos(&compiler->Base, FRAG_ATTRIB_WPOS, fp->wpos_attr, GL_FALSE);
121 }
122
123 /**
124  * Rewrite fragment.fogcoord to use a texture coordinate slot.
125  * Note that fogcoord is forced into an X001 pattern, and this enforcement
126  * is done here.
127  *
128  * See also the counterpart rewriting for vertex programs.
129  */
130 static void rewriteFog(struct r300_fragment_program_compiler *compiler, struct r300_fragment_program * fp)
131 {
132         struct rc_src_register src;
133         int i;
134
135         fp->fog_attr = FRAG_ATTRIB_MAX;
136         if (!(compiler->Base.Program.InputsRead & FRAG_BIT_FOGC)) {
137                 return;
138         }
139
140         for (i = FRAG_ATTRIB_TEX0; i <= FRAG_ATTRIB_TEX7; ++i)
141         {
142                 if (!(compiler->Base.Program.InputsRead & (1 << i))) {
143                         fp->fog_attr = i;
144                         break;
145                 }
146         }
147
148         /* No free texcoord found, fall-back to software rendering */
149         if (fp->fog_attr == FRAG_ATTRIB_MAX)
150         {
151                 compiler->Base.Error = 1;
152                 return;
153         }
154
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);
160 }
161
162
163 /**
164  * Reserve hardware temporary registers for the program inputs.
165  *
166  * @note This allocation is performed explicitly, because the order of inputs
167  * is determined by the RS hardware.
168  */
169 static void allocate_hw_inputs(
170         struct r300_fragment_program_compiler * c,
171         void (*allocate)(void * data, unsigned input, unsigned hwreg),
172         void * mydata)
173 {
174         GLuint InputsRead = c->Base.Program.InputsRead;
175         int i;
176         GLuint hwindex = 0;
177
178         /* Primary colour */
179         if (InputsRead & FRAG_BIT_COL0)
180                 allocate(mydata, FRAG_ATTRIB_COL0, hwindex++);
181         InputsRead &= ~FRAG_BIT_COL0;
182
183         /* Secondary color */
184         if (InputsRead & FRAG_BIT_COL1)
185                 allocate(mydata, FRAG_ATTRIB_COL1, hwindex++);
186         InputsRead &= ~FRAG_BIT_COL1;
187
188         /* Texcoords */
189         for (i = 0; i < 8; i++) {
190                 if (InputsRead & (FRAG_BIT_TEX0 << i))
191                         allocate(mydata, FRAG_ATTRIB_TEX0+i, hwindex++);
192         }
193         InputsRead &= ~FRAG_BITS_TEX_ANY;
194
195         /* Fogcoords treated as a texcoord */
196         if (InputsRead & FRAG_BIT_FOGC)
197                 allocate(mydata, FRAG_ATTRIB_FOGC, hwindex++);
198         InputsRead &= ~FRAG_BIT_FOGC;
199
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;
204
205         /* Anything else */
206         if (InputsRead)
207                 rc_error(&c->Base, "Don't know how to handle inputs 0x%x\n", InputsRead);
208 }
209
210
211 static void translate_fragment_program(struct gl_context *ctx, struct r300_fragment_program_cont *cont, struct r300_fragment_program *fp)
212 {
213         r300ContextPtr r300 = R300_CONTEXT(ctx);
214         struct r300_fragment_program_compiler compiler;
215
216         memset(&compiler, 0, sizeof(compiler));
217         rc_init(&compiler.Base);
218         compiler.Base.Debug = (RADEON_DEBUG & RADEON_PIXEL) ? GL_TRUE : GL_FALSE;
219
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;
234
235         if (compiler.Base.Debug) {
236                 fflush(stderr);
237                 printf("Fragment Program: Initial program:\n");
238                 _mesa_print_program(&cont->Base.Base);
239                 fflush(stderr);
240         }
241
242         radeon_mesa_to_rc_program(&compiler.Base, &cont->Base.Base);
243
244         insert_WPOS_trailer(&compiler, fp);
245
246         rewriteFog(&compiler, fp);
247
248         r3xx_compile_fragment_program(&compiler);
249
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.
254                  *
255                  * See also the comment in r300_context.c where we
256                  * set the MAX_NATIVE_xxx values.
257                  */
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");
260         }
261
262         fp->error = compiler.Base.Error;
263
264         fp->InputsRead = compiler.Base.Program.InputsRead;
265
266         /* Clear the fog/wpos_attr if code accessing these
267          * attributes has been removed during compilation
268          */
269         if (fp->fog_attr != FRAG_ATTRIB_MAX) {
270                 if (!(fp->InputsRead & (1 << fp->fog_attr)))
271                         fp->fog_attr = FRAG_ATTRIB_MAX;
272         }
273
274         if (fp->wpos_attr != FRAG_ATTRIB_MAX) {
275                 if (!(fp->InputsRead & (1 << fp->wpos_attr)))
276                         fp->wpos_attr = FRAG_ATTRIB_MAX;
277         }
278
279         rc_destroy(&compiler.Base);
280 }
281
282 struct r300_fragment_program *r300SelectAndTranslateFragmentShader(struct gl_context *ctx)
283 {
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;
288
289         fp_list = (struct r300_fragment_program_cont *)ctx->FragmentProgram._Current;
290         build_state(r300, ctx->FragmentProgram._Current, &state);
291
292         fp = fp_list->progs;
293         while (fp) {
294                 if (memcmp(&fp->state, &state, sizeof(state)) == 0) {
295                         return r300->selected_fp = fp;
296                 }
297                 fp = fp->next;
298         }
299
300         fp = calloc(1, sizeof(struct r300_fragment_program));
301
302         fp->state = state;
303
304         fp->next = fp_list->progs;
305         fp_list->progs = fp;
306
307         translate_fragment_program(ctx, fp_list, fp);
308
309         return r300->selected_fp = fp;
310 }