Merge branch 'glsl2-head' into glsl2
[mesa.git] / src / mesa / drivers / dri / nouveau / nv10_state_frag.c
1 /*
2 * Copyright (C) 2009-2010 Francisco Jerez.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27 #include "nouveau_driver.h"
28 #include "nouveau_context.h"
29 #include "nouveau_gldefs.h"
30 #include "nouveau_class.h"
31 #include "nouveau_util.h"
32 #include "nv10_driver.h"
33 #include "nv20_driver.h"
34
35 #define RC_IN_SHIFT_A 24
36 #define RC_IN_SHIFT_B 16
37 #define RC_IN_SHIFT_C 8
38 #define RC_IN_SHIFT_D 0
39 #define RC_IN_SHIFT_E 56
40 #define RC_IN_SHIFT_F 48
41 #define RC_IN_SHIFT_G 40
42
43 #define RC_IN_SOURCE(source) \
44 ((uint64_t)NV10TCL_RC_IN_RGB_D_INPUT_##source)
45 #define RC_IN_USAGE(usage) \
46 ((uint64_t)NV10TCL_RC_IN_RGB_D_COMPONENT_USAGE_##usage)
47 #define RC_IN_MAPPING(mapping) \
48 ((uint64_t)NV10TCL_RC_IN_RGB_D_MAPPING_##mapping)
49
50 #define RC_OUT_BIAS NV10TCL_RC_OUT_RGB_BIAS_BIAS_BY_NEGATIVE_ONE_HALF
51 #define RC_OUT_SCALE_1 NV10TCL_RC_OUT_RGB_SCALE_NONE
52 #define RC_OUT_SCALE_2 NV10TCL_RC_OUT_RGB_SCALE_SCALE_BY_TWO
53 #define RC_OUT_SCALE_4 NV10TCL_RC_OUT_RGB_SCALE_SCALE_BY_FOUR
54
55 /* Make the combiner do: spare0_i = A_i * B_i */
56 #define RC_OUT_AB NV10TCL_RC_OUT_RGB_AB_OUTPUT_SPARE0
57 /* spare0_i = dot3(A, B) */
58 #define RC_OUT_DOT_AB (NV10TCL_RC_OUT_RGB_AB_OUTPUT_SPARE0 | \
59 NV10TCL_RC_OUT_RGB_AB_DOT_PRODUCT)
60 /* spare0_i = A_i * B_i + C_i * D_i */
61 #define RC_OUT_SUM NV10TCL_RC_OUT_RGB_SUM_OUTPUT_SPARE0
62
63 struct combiner_state {
64 GLcontext *ctx;
65 int unit;
66
67 /* GL state */
68 GLenum mode;
69 GLenum *source;
70 GLenum *operand;
71 GLuint logscale;
72
73 /* Derived HW state */
74 uint64_t in;
75 uint32_t out;
76 };
77
78 /* Initialize a combiner_state struct from the texture unit
79 * context. */
80 #define INIT_COMBINER(chan, ctx, rc, i) do { \
81 struct gl_tex_env_combine_state *c = \
82 ctx->Texture.Unit[i]._CurrentCombine; \
83 (rc)->ctx = ctx; \
84 (rc)->unit = i; \
85 (rc)->mode = c->Mode##chan; \
86 (rc)->source = c->Source##chan; \
87 (rc)->operand = c->Operand##chan; \
88 (rc)->logscale = c->ScaleShift##chan; \
89 (rc)->in = (rc)->out = 0; \
90 } while (0)
91
92 /* Get the RC input source for the specified EXT_texture_env_combine
93 * source. */
94 static uint32_t
95 get_input_source(struct combiner_state *rc, int source)
96 {
97 switch (source) {
98 case GL_TEXTURE:
99 return RC_IN_SOURCE(TEXTURE0) + rc->unit;
100
101 case GL_TEXTURE0:
102 return RC_IN_SOURCE(TEXTURE0);
103
104 case GL_TEXTURE1:
105 return RC_IN_SOURCE(TEXTURE1);
106
107 case GL_TEXTURE2:
108 return RC_IN_SOURCE(TEXTURE2);
109
110 case GL_TEXTURE3:
111 return RC_IN_SOURCE(TEXTURE3);
112
113 case GL_CONSTANT:
114 return context_chipset(rc->ctx) >= 0x20 ?
115 RC_IN_SOURCE(CONSTANT_COLOR0) :
116 RC_IN_SOURCE(CONSTANT_COLOR0) + rc->unit;
117
118 case GL_PRIMARY_COLOR:
119 return RC_IN_SOURCE(PRIMARY_COLOR);
120
121 case GL_PREVIOUS:
122 return rc->unit ? RC_IN_SOURCE(SPARE0)
123 : RC_IN_SOURCE(PRIMARY_COLOR);
124
125 default:
126 assert(0);
127 }
128 }
129
130 /* Get the RC input mapping for the specified texture_env_combine
131 * operand, possibly inverted or biased. */
132 #define INVERT 0x1
133 #define HALF_BIAS 0x2
134
135 static uint32_t
136 get_input_mapping(struct combiner_state *rc, int operand, int flags)
137 {
138 int map = 0;
139
140 if (is_color_operand(operand))
141 map |= RC_IN_USAGE(RGB);
142 else
143 map |= RC_IN_USAGE(ALPHA);
144
145 if (is_negative_operand(operand) == !(flags & INVERT))
146 map |= flags & HALF_BIAS ?
147 RC_IN_MAPPING(HALF_BIAS_NEGATE) :
148 RC_IN_MAPPING(UNSIGNED_INVERT);
149 else
150 map |= flags & HALF_BIAS ?
151 RC_IN_MAPPING(HALF_BIAS_NORMAL) :
152 RC_IN_MAPPING(UNSIGNED_IDENTITY);
153
154 return map;
155 }
156
157 static uint32_t
158 get_input_arg(struct combiner_state *rc, int arg, int flags)
159 {
160 int source = rc->source[arg];
161 int operand = rc->operand[arg];
162
163 /* Fake several unsupported texture formats. */
164 if (is_texture_source(source)) {
165 int i = (source == GL_TEXTURE ?
166 rc->unit : source - GL_TEXTURE0);
167 struct gl_texture_object *t = rc->ctx->Texture.Unit[i]._Current;
168 gl_format format = t->Image[0][t->BaseLevel]->TexFormat;
169
170 if (format == MESA_FORMAT_A8) {
171 /* Emulated using I8. */
172 if (is_color_operand(operand))
173 return RC_IN_SOURCE(ZERO) |
174 get_input_mapping(rc, operand, flags);
175
176 } else if (format == MESA_FORMAT_L8) {
177 /* Sometimes emulated using I8. */
178 if (!is_color_operand(operand))
179 return RC_IN_SOURCE(ZERO) |
180 get_input_mapping(rc, operand,
181 flags ^ INVERT);
182
183 } else if (format == MESA_FORMAT_XRGB8888) {
184 /* Sometimes emulated using ARGB8888. */
185 if (!is_color_operand(operand))
186 return RC_IN_SOURCE(ZERO) |
187 get_input_mapping(rc, operand,
188 flags ^ INVERT);
189 }
190 }
191
192 return get_input_source(rc, source) |
193 get_input_mapping(rc, operand, flags);
194 }
195
196 /* Bind the RC input variable <var> to the EXT_texture_env_combine
197 * argument <arg>, possibly inverted or biased. */
198 #define INPUT_ARG(rc, var, arg, flags) \
199 (rc)->in |= get_input_arg(rc, arg, flags) << RC_IN_SHIFT_##var
200
201 /* Bind the RC input variable <var> to the RC source <src>. */
202 #define INPUT_SRC(rc, var, src, chan) \
203 (rc)->in |= (RC_IN_SOURCE(src) | \
204 RC_IN_USAGE(chan)) << RC_IN_SHIFT_##var
205
206 /* Bind the RC input variable <var> to a constant +/-1 */
207 #define INPUT_ONE(rc, var, flags) \
208 (rc)->in |= (RC_IN_SOURCE(ZERO) | \
209 (flags & INVERT ? RC_IN_MAPPING(EXPAND_NORMAL) : \
210 RC_IN_MAPPING(UNSIGNED_INVERT))) << RC_IN_SHIFT_##var
211
212 static void
213 setup_combiner(struct combiner_state *rc)
214 {
215 switch (rc->mode) {
216 case GL_REPLACE:
217 INPUT_ARG(rc, A, 0, 0);
218 INPUT_ONE(rc, B, 0);
219
220 rc->out = RC_OUT_AB;
221 break;
222
223 case GL_MODULATE:
224 INPUT_ARG(rc, A, 0, 0);
225 INPUT_ARG(rc, B, 1, 0);
226
227 rc->out = RC_OUT_AB;
228 break;
229
230 case GL_ADD:
231 INPUT_ARG(rc, A, 0, 0);
232 INPUT_ONE(rc, B, 0);
233 INPUT_ARG(rc, C, 1, 0);
234 INPUT_ONE(rc, D, 0);
235
236 rc->out = RC_OUT_SUM;
237 break;
238
239 case GL_ADD_SIGNED:
240 INPUT_ARG(rc, A, 0, 0);
241 INPUT_ONE(rc, B, 0);
242 INPUT_ARG(rc, C, 1, 0);
243 INPUT_ONE(rc, D, 0);
244
245 rc->out = RC_OUT_SUM | RC_OUT_BIAS;
246 break;
247
248 case GL_INTERPOLATE:
249 INPUT_ARG(rc, A, 0, 0);
250 INPUT_ARG(rc, B, 2, 0);
251 INPUT_ARG(rc, C, 1, 0);
252 INPUT_ARG(rc, D, 2, INVERT);
253
254 rc->out = RC_OUT_SUM;
255 break;
256
257 case GL_SUBTRACT:
258 INPUT_ARG(rc, A, 0, 0);
259 INPUT_ONE(rc, B, 0);
260 INPUT_ARG(rc, C, 1, 0);
261 INPUT_ONE(rc, D, INVERT);
262
263 rc->out = RC_OUT_SUM;
264 break;
265
266 case GL_DOT3_RGB:
267 case GL_DOT3_RGBA:
268 INPUT_ARG(rc, A, 0, HALF_BIAS);
269 INPUT_ARG(rc, B, 1, HALF_BIAS);
270
271 rc->out = RC_OUT_DOT_AB | RC_OUT_SCALE_4;
272
273 assert(!rc->logscale);
274 break;
275
276 default:
277 assert(0);
278 }
279
280 switch (rc->logscale) {
281 case 0:
282 rc->out |= RC_OUT_SCALE_1;
283 break;
284 case 1:
285 rc->out |= RC_OUT_SCALE_2;
286 break;
287 case 2:
288 rc->out |= RC_OUT_SCALE_4;
289 break;
290 default:
291 assert(0);
292 }
293 }
294
295 void
296 nv10_get_general_combiner(GLcontext *ctx, int i,
297 uint32_t *a_in, uint32_t *a_out,
298 uint32_t *c_in, uint32_t *c_out, uint32_t *k)
299 {
300 struct combiner_state rc_a, rc_c;
301
302 if (ctx->Texture.Unit[i]._ReallyEnabled) {
303 INIT_COMBINER(RGB, ctx, &rc_c, i);
304
305 if (rc_c.mode == GL_DOT3_RGBA)
306 rc_a = rc_c;
307 else
308 INIT_COMBINER(A, ctx, &rc_a, i);
309
310 setup_combiner(&rc_c);
311 setup_combiner(&rc_a);
312
313 } else {
314 rc_a.in = rc_a.out = rc_c.in = rc_c.out = 0;
315 }
316
317 *k = pack_rgba_f(MESA_FORMAT_ARGB8888,
318 ctx->Texture.Unit[i].EnvColor);
319 *a_in = rc_a.in;
320 *a_out = rc_a.out;
321 *c_in = rc_c.in;
322 *c_out = rc_c.out;
323 }
324
325 void
326 nv10_get_final_combiner(GLcontext *ctx, uint64_t *in, int *n)
327 {
328 struct combiner_state rc = {};
329
330 /*
331 * The final fragment value equation is something like:
332 * x_i = A_i * B_i + (1 - A_i) * C_i + D_i
333 * x_alpha = G_alpha
334 * where D_i = E_i * F_i, i one of {red, green, blue}.
335 */
336 if (ctx->Fog.ColorSumEnabled || ctx->Light.Enabled) {
337 INPUT_SRC(&rc, D, E_TIMES_F, RGB);
338 INPUT_SRC(&rc, F, SECONDARY_COLOR, RGB);
339 }
340
341 if (ctx->Fog.Enabled) {
342 INPUT_SRC(&rc, A, FOG, ALPHA);
343 INPUT_SRC(&rc, C, FOG, RGB);
344 INPUT_SRC(&rc, E, FOG, ALPHA);
345 } else {
346 INPUT_ONE(&rc, A, 0);
347 INPUT_ONE(&rc, C, 0);
348 INPUT_ONE(&rc, E, 0);
349 }
350
351 if (ctx->Texture._EnabledUnits) {
352 INPUT_SRC(&rc, B, SPARE0, RGB);
353 INPUT_SRC(&rc, G, SPARE0, ALPHA);
354 } else {
355 INPUT_SRC(&rc, B, PRIMARY_COLOR, RGB);
356 INPUT_SRC(&rc, G, PRIMARY_COLOR, ALPHA);
357 }
358
359 *in = rc.in;
360 *n = log2i(ctx->Texture._EnabledUnits) + 1;
361 }
362
363 void
364 nv10_emit_tex_env(GLcontext *ctx, int emit)
365 {
366 const int i = emit - NOUVEAU_STATE_TEX_ENV0;
367 struct nouveau_channel *chan = context_chan(ctx);
368 struct nouveau_grobj *celsius = context_eng3d(ctx);
369 uint32_t a_in, a_out, c_in, c_out, k;
370
371 nv10_get_general_combiner(ctx, i, &a_in, &a_out, &c_in, &c_out, &k);
372
373 /* Enable the combiners we're going to need. */
374 if (i == 1) {
375 if (c_out || a_out)
376 c_out |= 0x5 << 27;
377 else
378 c_out |= 0x3 << 27;
379 }
380
381 BEGIN_RING(chan, celsius, NV10TCL_RC_IN_ALPHA(i), 1);
382 OUT_RING(chan, a_in);
383 BEGIN_RING(chan, celsius, NV10TCL_RC_IN_RGB(i), 1);
384 OUT_RING(chan, c_in);
385 BEGIN_RING(chan, celsius, NV10TCL_RC_COLOR(i), 1);
386 OUT_RING(chan, k);
387 BEGIN_RING(chan, celsius, NV10TCL_RC_OUT_ALPHA(i), 1);
388 OUT_RING(chan, a_out);
389 BEGIN_RING(chan, celsius, NV10TCL_RC_OUT_RGB(i), 1);
390 OUT_RING(chan, c_out);
391
392 context_dirty(ctx, FRAG);
393 }
394
395 void
396 nv10_emit_frag(GLcontext *ctx, int emit)
397 {
398 struct nouveau_channel *chan = context_chan(ctx);
399 struct nouveau_grobj *celsius = context_eng3d(ctx);
400 uint64_t in;
401 int n;
402
403 nv10_get_final_combiner(ctx, &in, &n);
404
405 BEGIN_RING(chan, celsius, NV10TCL_RC_FINAL0, 2);
406 OUT_RING(chan, in);
407 OUT_RING(chan, in >> 32);
408 }