34ee2962023ca2ee6a6238a0831b35fe91857cea
[mesa.git] / src / mesa / drivers / dri / nouveau / nv04_state_frag.c
1 /*
2 * Copyright (C) 2009 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_util.h"
30 #include "nouveau_class.h"
31 #include "nv04_driver.h"
32
33 #define COMBINER_SHIFT(in) \
34 (NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_ARGUMENT##in##_SHIFT \
35 - NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_ARGUMENT0_SHIFT)
36 #define COMBINER_SOURCE(reg) \
37 NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_ARGUMENT0_##reg
38 #define COMBINER_INVERT \
39 NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_INVERSE0
40 #define COMBINER_ALPHA \
41 NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_ALPHA0
42
43 struct combiner_state {
44 int unit;
45 GLboolean alpha;
46
47 /* GL state */
48 GLenum mode;
49 GLenum *source;
50 GLenum *operand;
51 GLuint logscale;
52
53 /* Derived HW state */
54 uint32_t hw;
55 };
56
57 #define __INIT_COMBINER_ALPHA_A GL_TRUE
58 #define __INIT_COMBINER_ALPHA_RGB GL_FALSE
59
60 /* Initialize a combiner_state struct from the texture unit
61 * context. */
62 #define INIT_COMBINER(chan, rc, i) do { \
63 struct gl_tex_env_combine_state *c = \
64 ctx->Texture.Unit[i]._CurrentCombine; \
65 (rc)->alpha = __INIT_COMBINER_ALPHA_##chan; \
66 (rc)->unit = i; \
67 (rc)->mode = c->Mode##chan; \
68 (rc)->source = c->Source##chan; \
69 (rc)->operand = c->Operand##chan; \
70 (rc)->logscale = c->ScaleShift##chan; \
71 (rc)->hw = 0; \
72 } while (0)
73
74 /* Get the combiner source for the specified EXT_texture_env_combine
75 * argument. */
76 static uint32_t
77 get_arg_source(struct combiner_state *rc, int arg)
78 {
79 switch (rc->source[arg]) {
80 case GL_TEXTURE:
81 return rc->unit ? COMBINER_SOURCE(TEXTURE1) :
82 COMBINER_SOURCE(TEXTURE0);
83
84 case GL_TEXTURE0:
85 return COMBINER_SOURCE(TEXTURE0);
86
87 case GL_TEXTURE1:
88 return COMBINER_SOURCE(TEXTURE1);
89
90 case GL_CONSTANT:
91 return COMBINER_SOURCE(CONSTANT);
92
93 case GL_PRIMARY_COLOR:
94 return COMBINER_SOURCE(PRIMARY_COLOR);
95
96 case GL_PREVIOUS:
97 return rc->unit ? COMBINER_SOURCE(PREVIOUS) :
98 COMBINER_SOURCE(PRIMARY_COLOR);
99
100 default:
101 assert(0);
102 }
103 }
104
105 /* Get the (possibly inverted) combiner input mapping for the
106 * specified argument. */
107 #define INVERT 0x1
108
109 static uint32_t
110 get_arg_mapping(struct combiner_state *rc, int arg, int flags)
111 {
112 int map = 0;
113
114 switch (rc->operand[arg]) {
115 case GL_SRC_COLOR:
116 case GL_ONE_MINUS_SRC_COLOR:
117 break;
118
119 case GL_SRC_ALPHA:
120 case GL_ONE_MINUS_SRC_ALPHA:
121 map |= rc->alpha ? 0 : COMBINER_ALPHA;
122 break;
123 }
124
125 switch (rc->operand[arg]) {
126 case GL_SRC_COLOR:
127 case GL_SRC_ALPHA:
128 map |= flags & INVERT ? COMBINER_INVERT : 0;
129 break;
130
131 case GL_ONE_MINUS_SRC_COLOR:
132 case GL_ONE_MINUS_SRC_ALPHA:
133 map |= flags & INVERT ? 0 : COMBINER_INVERT;
134 break;
135 }
136
137 return map;
138 }
139
140 /* Bind the combiner input <in> to the combiner source <src>,
141 * possibly inverted. */
142 #define INPUT_SRC(rc, in, src, flags) \
143 (rc)->hw |= ((flags & INVERT ? COMBINER_INVERT : 0) | \
144 COMBINER_SOURCE(src)) << COMBINER_SHIFT(in)
145
146 /* Bind the combiner input <in> to the EXT_texture_env_combine
147 * argument <arg>, possibly inverted. */
148 #define INPUT_ARG(rc, in, arg, flags) \
149 (rc)->hw |= (get_arg_source(rc, arg) | \
150 get_arg_mapping(rc, arg, flags)) << COMBINER_SHIFT(in)
151
152 #define UNSIGNED_OP(rc) \
153 (rc)->hw |= ((rc)->logscale ? \
154 NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_MAP_SCALE2 : \
155 NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_MAP_IDENTITY)
156 #define SIGNED_OP(rc) \
157 (rc)->hw |= ((rc)->logscale ? \
158 NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_MAP_BIAS_SCALE2 : \
159 NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_MAP_BIAS)
160
161 static void
162 setup_combiner(struct combiner_state *rc)
163 {
164 switch (rc->mode) {
165 case GL_REPLACE:
166 INPUT_ARG(rc, 0, 0, 0);
167 INPUT_SRC(rc, 1, ZERO, INVERT);
168 INPUT_SRC(rc, 2, ZERO, 0);
169 INPUT_SRC(rc, 3, ZERO, 0);
170 UNSIGNED_OP(rc);
171 break;
172
173 case GL_MODULATE:
174 INPUT_ARG(rc, 0, 0, 0);
175 INPUT_ARG(rc, 1, 1, 0);
176 INPUT_SRC(rc, 2, ZERO, 0);
177 INPUT_SRC(rc, 3, ZERO, 0);
178 UNSIGNED_OP(rc);
179 break;
180
181 case GL_ADD:
182 INPUT_ARG(rc, 0, 0, 0);
183 INPUT_SRC(rc, 1, ZERO, INVERT);
184 INPUT_ARG(rc, 2, 1, 0);
185 INPUT_SRC(rc, 3, ZERO, INVERT);
186 UNSIGNED_OP(rc);
187 break;
188
189 case GL_INTERPOLATE:
190 INPUT_ARG(rc, 0, 0, 0);
191 INPUT_ARG(rc, 1, 2, 0);
192 INPUT_ARG(rc, 2, 1, 0);
193 INPUT_ARG(rc, 3, 2, INVERT);
194 UNSIGNED_OP(rc);
195 break;
196
197 case GL_ADD_SIGNED:
198 INPUT_ARG(rc, 0, 0, 0);
199 INPUT_SRC(rc, 1, ZERO, INVERT);
200 INPUT_ARG(rc, 2, 1, 0);
201 INPUT_SRC(rc, 3, ZERO, INVERT);
202 SIGNED_OP(rc);
203 break;
204
205 default:
206 assert(0);
207 }
208 }
209
210 void
211 nv04_emit_tex_env(GLcontext *ctx, int emit)
212 {
213 const int i = emit - NOUVEAU_STATE_TEX_ENV0;
214 struct nouveau_channel *chan = context_chan(ctx);
215 struct nouveau_grobj *fahrenheit = nv04_context_engine(ctx);
216 struct combiner_state rc_a = {}, rc_c = {};
217
218 if (!nv04_mtex_engine(fahrenheit)) {
219 context_dirty(ctx, BLEND);
220 return;
221 }
222
223 /* Compute the new combiner state. */
224 if (ctx->Texture.Unit[i]._ReallyEnabled) {
225 INIT_COMBINER(A, &rc_a, i);
226 setup_combiner(&rc_a);
227
228 INIT_COMBINER(RGB, &rc_c, i);
229 setup_combiner(&rc_c);
230
231 } else {
232 if (i == 0) {
233 INPUT_SRC(&rc_a, 0, PRIMARY_COLOR, 0);
234 INPUT_SRC(&rc_c, 0, PRIMARY_COLOR, 0);
235 } else {
236 INPUT_SRC(&rc_a, 0, PREVIOUS, 0);
237 INPUT_SRC(&rc_c, 0, PREVIOUS, 0);
238 }
239
240 INPUT_SRC(&rc_a, 1, ZERO, INVERT);
241 INPUT_SRC(&rc_c, 1, ZERO, INVERT);
242 INPUT_SRC(&rc_a, 2, ZERO, 0);
243 INPUT_SRC(&rc_c, 2, ZERO, 0);
244 INPUT_SRC(&rc_a, 3, ZERO, 0);
245 INPUT_SRC(&rc_c, 3, ZERO, 0);
246
247 UNSIGNED_OP(&rc_a);
248 UNSIGNED_OP(&rc_c);
249 }
250
251 /* Write the register combiner state out to the hardware. */
252 BEGIN_RING(chan, fahrenheit,
253 NV04_MULTITEX_TRIANGLE_COMBINE_ALPHA(i), 2);
254 OUT_RING(chan, rc_a.hw);
255 OUT_RING(chan, rc_c.hw);
256
257 BEGIN_RING(chan, fahrenheit,
258 NV04_MULTITEX_TRIANGLE_COMBINE_FACTOR, 1);
259 OUT_RING(chan, pack_rgba_f(MESA_FORMAT_ARGB8888,
260 ctx->Texture.Unit[0].EnvColor));
261 }