Merge branch 'llvm-cliptest-viewport'
[mesa.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].depth_texture_swizzle = build_dts(tex->DepthMode);
81 state->unit[unit].texture_compare_func = build_func(tex->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.OutputDepth = FRAG_RESULT_DEPTH;
230 memset(compiler.OutputColor, 0, 4 * sizeof(unsigned));
231 compiler.OutputColor[0] = FRAG_RESULT_COLOR;
232 compiler.AllocateHwInputs = &allocate_hw_inputs;
233
234 if (compiler.Base.Debug) {
235 fflush(stderr);
236 printf("Fragment Program: Initial program:\n");
237 _mesa_print_program(&cont->Base.Base);
238 fflush(stderr);
239 }
240
241 radeon_mesa_to_rc_program(&compiler.Base, &cont->Base.Base);
242
243 insert_WPOS_trailer(&compiler, fp);
244
245 rewriteFog(&compiler, fp);
246
247 r3xx_compile_fragment_program(&compiler);
248
249 if (compiler.Base.is_r500) {
250 /* We need to support the non-KMS DRM interface, which
251 * artificially limits the number of instructions and
252 * constants which are available to us.
253 *
254 * See also the comment in r300_context.c where we
255 * set the MAX_NATIVE_xxx values.
256 */
257 if (fp->code.code.r500.inst_end >= 255 || fp->code.constants.Count > 255)
258 rc_error(&compiler.Base, "Program is too big (upgrade to r300g to avoid this limitation).\n");
259 }
260
261 fp->error = compiler.Base.Error;
262
263 fp->InputsRead = compiler.Base.Program.InputsRead;
264
265 /* Clear the fog/wpos_attr if code accessing these
266 * attributes has been removed during compilation
267 */
268 if (fp->fog_attr != FRAG_ATTRIB_MAX) {
269 if (!(fp->InputsRead & (1 << fp->fog_attr)))
270 fp->fog_attr = FRAG_ATTRIB_MAX;
271 }
272
273 if (fp->wpos_attr != FRAG_ATTRIB_MAX) {
274 if (!(fp->InputsRead & (1 << fp->wpos_attr)))
275 fp->wpos_attr = FRAG_ATTRIB_MAX;
276 }
277
278 rc_destroy(&compiler.Base);
279 }
280
281 struct r300_fragment_program *r300SelectAndTranslateFragmentShader(struct gl_context *ctx)
282 {
283 r300ContextPtr r300 = R300_CONTEXT(ctx);
284 struct r300_fragment_program_cont *fp_list;
285 struct r300_fragment_program *fp;
286 struct r300_fragment_program_external_state state;
287
288 fp_list = (struct r300_fragment_program_cont *)ctx->FragmentProgram._Current;
289 build_state(r300, ctx->FragmentProgram._Current, &state);
290
291 fp = fp_list->progs;
292 while (fp) {
293 if (memcmp(&fp->state, &state, sizeof(state)) == 0) {
294 return r300->selected_fp = fp;
295 }
296 fp = fp->next;
297 }
298
299 fp = calloc(1, sizeof(struct r300_fragment_program));
300
301 fp->state = state;
302
303 fp->next = fp_list->progs;
304 fp_list->progs = fp;
305
306 translate_fragment_program(ctx, fp_list, fp);
307
308 return r300->selected_fp = fp;
309 }