2 * Copyright (C) 2009 Francisco Jerez.
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:
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.
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.
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"
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
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)
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
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
63 struct combiner_state
{
73 /* Derived HW state */
78 /* Initialize a combiner_state struct from the texture unit
80 #define INIT_COMBINER(chan, ctx, rc, i) do { \
81 struct gl_tex_env_combine_state *c = \
82 ctx->Texture.Unit[i]._CurrentCombine; \
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; \
92 /* Get the RC input source for the specified EXT_texture_env_combine
95 get_input_source(struct combiner_state
*rc
, int arg
)
97 switch (rc
->source
[arg
]) {
99 return RC_IN_SOURCE(TEXTURE0
) + rc
->unit
;
102 return RC_IN_SOURCE(TEXTURE0
);
105 return RC_IN_SOURCE(TEXTURE1
);
108 return RC_IN_SOURCE(TEXTURE2
);
111 return RC_IN_SOURCE(TEXTURE3
);
114 return context_chipset(rc
->ctx
) >= 0x20 ?
115 RC_IN_SOURCE(CONSTANT_COLOR0
) :
116 RC_IN_SOURCE(CONSTANT_COLOR0
) + rc
->unit
;
118 case GL_PRIMARY_COLOR
:
119 return RC_IN_SOURCE(PRIMARY_COLOR
);
122 return rc
->unit
? RC_IN_SOURCE(SPARE0
)
123 : RC_IN_SOURCE(PRIMARY_COLOR
);
130 /* Get the RC input mapping for the specified argument, possibly
131 * inverted or biased. */
133 #define HALF_BIAS 0x2
136 get_input_mapping(struct combiner_state
*rc
, int arg
, int flags
)
140 switch (rc
->operand
[arg
]) {
142 case GL_ONE_MINUS_SRC_COLOR
:
143 map
|= RC_IN_USAGE(RGB
);
147 case GL_ONE_MINUS_SRC_ALPHA
:
148 map
|= RC_IN_USAGE(ALPHA
);
152 switch (rc
->operand
[arg
]) {
155 map
|= (flags
& INVERT
? RC_IN_MAPPING(UNSIGNED_INVERT
) :
156 flags
& HALF_BIAS
? RC_IN_MAPPING(HALF_BIAS_NORMAL
) :
157 RC_IN_MAPPING(UNSIGNED_IDENTITY
));
160 case GL_ONE_MINUS_SRC_COLOR
:
161 case GL_ONE_MINUS_SRC_ALPHA
:
162 map
|= (flags
& INVERT
? RC_IN_MAPPING(UNSIGNED_IDENTITY
) :
163 flags
& HALF_BIAS
? RC_IN_MAPPING(HALF_BIAS_NEGATE
) :
164 RC_IN_MAPPING(UNSIGNED_INVERT
));
171 /* Bind the RC input variable <var> to the EXT_texture_env_combine
172 * argument <arg>, possibly inverted or biased. */
173 #define INPUT_ARG(rc, var, arg, flags) \
174 (rc)->in |= (get_input_mapping(rc, arg, flags) | \
175 get_input_source(rc, arg)) << RC_IN_SHIFT_##var
177 /* Bind the RC input variable <var> to the RC source <src>. */
178 #define INPUT_SRC(rc, var, src, chan) \
179 (rc)->in |= (RC_IN_SOURCE(src) | \
180 RC_IN_USAGE(chan)) << RC_IN_SHIFT_##var
182 /* Bind the RC input variable <var> to a constant +/-1 */
183 #define INPUT_ONE(rc, var, flags) \
184 (rc)->in |= (RC_IN_SOURCE(ZERO) | \
185 (flags & INVERT ? RC_IN_MAPPING(EXPAND_NORMAL) : \
186 RC_IN_MAPPING(UNSIGNED_INVERT))) << RC_IN_SHIFT_##var
189 setup_combiner(struct combiner_state
*rc
)
193 INPUT_ARG(rc
, A
, 0, 0);
200 INPUT_ARG(rc
, A
, 0, 0);
201 INPUT_ARG(rc
, B
, 1, 0);
207 INPUT_ARG(rc
, A
, 0, 0);
209 INPUT_ARG(rc
, C
, 1, 0);
212 rc
->out
= RC_OUT_SUM
;
216 INPUT_ARG(rc
, A
, 0, 0);
218 INPUT_ARG(rc
, C
, 1, 0);
221 rc
->out
= RC_OUT_SUM
| RC_OUT_BIAS
;
225 INPUT_ARG(rc
, A
, 0, 0);
226 INPUT_ARG(rc
, B
, 2, 0);
227 INPUT_ARG(rc
, C
, 1, 0);
228 INPUT_ARG(rc
, D
, 2, INVERT
);
230 rc
->out
= RC_OUT_SUM
;
234 INPUT_ARG(rc
, A
, 0, 0);
236 INPUT_ARG(rc
, C
, 1, 0);
237 INPUT_ONE(rc
, D
, INVERT
);
239 rc
->out
= RC_OUT_SUM
;
244 INPUT_ARG(rc
, A
, 0, HALF_BIAS
);
245 INPUT_ARG(rc
, B
, 1, HALF_BIAS
);
247 rc
->out
= RC_OUT_DOT_AB
| RC_OUT_SCALE_4
;
249 assert(!rc
->logscale
);
256 switch (rc
->logscale
) {
258 rc
->out
|= RC_OUT_SCALE_1
;
261 rc
->out
|= RC_OUT_SCALE_2
;
264 rc
->out
|= RC_OUT_SCALE_4
;
271 /* Write the register combiner state out to the hardware. */
273 nv10_load_combiner(GLcontext
*ctx
, int i
, struct combiner_state
*rc_a
,
274 struct combiner_state
*rc_c
, uint32_t rc_const
)
276 struct nouveau_channel
*chan
= context_chan(ctx
);
277 struct nouveau_grobj
*celsius
= context_eng3d(ctx
);
279 /* Enable the combiners we're going to need. */
281 if (rc_c
->out
|| rc_a
->out
)
282 rc_c
->out
|= 0x5 << 27;
284 rc_c
->out
|= 0x3 << 27;
287 BEGIN_RING(chan
, celsius
, NV10TCL_RC_IN_ALPHA(i
), 1);
288 OUT_RING(chan
, rc_a
->in
);
289 BEGIN_RING(chan
, celsius
, NV10TCL_RC_IN_RGB(i
), 1);
290 OUT_RING(chan
, rc_c
->in
);
291 BEGIN_RING(chan
, celsius
, NV10TCL_RC_COLOR(i
), 1);
292 OUT_RING(chan
, rc_const
);
293 BEGIN_RING(chan
, celsius
, NV10TCL_RC_OUT_ALPHA(i
), 1);
294 OUT_RING(chan
, rc_a
->out
);
295 BEGIN_RING(chan
, celsius
, NV10TCL_RC_OUT_RGB(i
), 1);
296 OUT_RING(chan
, rc_c
->out
);
300 nv10_load_final(GLcontext
*ctx
, struct combiner_state
*rc
, int n
)
302 struct nouveau_channel
*chan
= context_chan(ctx
);
303 struct nouveau_grobj
*celsius
= context_eng3d(ctx
);
305 BEGIN_RING(chan
, celsius
, NV10TCL_RC_FINAL0
, 2);
306 OUT_RING(chan
, rc
->in
);
307 OUT_RING(chan
, rc
->in
>> 32);
311 nv20_load_combiner(GLcontext
*ctx
, int i
, struct combiner_state
*rc_a
,
312 struct combiner_state
*rc_c
, uint32_t rc_const
)
314 struct nouveau_channel
*chan
= context_chan(ctx
);
315 struct nouveau_grobj
*kelvin
= context_eng3d(ctx
);
317 BEGIN_RING(chan
, kelvin
, NV20TCL_RC_IN_ALPHA(i
), 1);
318 OUT_RING(chan
, rc_a
->in
);
319 BEGIN_RING(chan
, kelvin
, NV20TCL_RC_OUT_ALPHA(i
), 1);
320 OUT_RING(chan
, rc_a
->out
);
321 BEGIN_RING(chan
, kelvin
, NV20TCL_RC_IN_RGB(i
), 1);
322 OUT_RING(chan
, rc_c
->in
);
323 BEGIN_RING(chan
, kelvin
, NV20TCL_RC_OUT_RGB(i
), 1);
324 OUT_RING(chan
, rc_c
->out
);
325 BEGIN_RING(chan
, kelvin
, NV20TCL_RC_CONSTANT_COLOR0(i
), 1);
326 OUT_RING(chan
, rc_const
);
330 nv20_load_final(GLcontext
*ctx
, struct combiner_state
*rc
, int n
)
332 struct nouveau_channel
*chan
= context_chan(ctx
);
333 struct nouveau_grobj
*kelvin
= context_eng3d(ctx
);
335 BEGIN_RING(chan
, kelvin
, NV20TCL_RC_FINAL0
, 2);
336 OUT_RING(chan
, rc
->in
);
337 OUT_RING(chan
, rc
->in
>> 32);
339 BEGIN_RING(chan
, kelvin
, NV20TCL_RC_ENABLE
, 1);
344 nv10_emit_tex_env(GLcontext
*ctx
, int emit
)
346 const int i
= emit
- NOUVEAU_STATE_TEX_ENV0
;
347 struct combiner_state rc_a
, rc_c
;
350 /* Compute the new combiner state. */
351 if (ctx
->Texture
.Unit
[i
]._ReallyEnabled
) {
352 INIT_COMBINER(RGB
, ctx
, &rc_c
, i
);
354 if (rc_c
.mode
== GL_DOT3_RGBA
)
357 INIT_COMBINER(A
, ctx
, &rc_a
, i
);
359 setup_combiner(&rc_c
);
360 setup_combiner(&rc_a
);
362 rc_const
= pack_rgba_f(MESA_FORMAT_ARGB8888
,
363 ctx
->Texture
.Unit
[i
].EnvColor
);
366 rc_a
.in
= rc_a
.out
= rc_c
.in
= rc_c
.out
= rc_const
= 0;
369 if (context_chipset(ctx
) >= 0x20)
370 nv20_load_combiner(ctx
, i
, &rc_a
, &rc_c
, rc_const
);
372 nv10_load_combiner(ctx
, i
, &rc_a
, &rc_c
, rc_const
);
374 context_dirty(ctx
, FRAG
);
378 nv10_emit_frag(GLcontext
*ctx
, int emit
)
380 struct combiner_state rc
= {};
381 int n
= log2i(ctx
->Texture
._EnabledUnits
) + 1;
384 * The final fragment value equation is something like:
385 * x_i = A_i * B_i + (1 - A_i) * C_i + D_i
387 * where D_i = E_i * F_i, i one of {red, green, blue}.
389 if (ctx
->Fog
.ColorSumEnabled
|| ctx
->Light
.Enabled
) {
390 INPUT_SRC(&rc
, D
, E_TIMES_F
, RGB
);
391 INPUT_SRC(&rc
, F
, SECONDARY_COLOR
, RGB
);
394 if (ctx
->Fog
.Enabled
) {
395 INPUT_SRC(&rc
, A
, FOG
, ALPHA
);
396 INPUT_SRC(&rc
, C
, FOG
, RGB
);
397 INPUT_SRC(&rc
, E
, FOG
, ALPHA
);
399 INPUT_ONE(&rc
, A
, 0);
400 INPUT_ONE(&rc
, C
, 0);
401 INPUT_ONE(&rc
, E
, 0);
404 if (ctx
->Texture
._EnabledUnits
) {
405 INPUT_SRC(&rc
, B
, SPARE0
, RGB
);
406 INPUT_SRC(&rc
, G
, SPARE0
, ALPHA
);
408 INPUT_SRC(&rc
, B
, PRIMARY_COLOR
, RGB
);
409 INPUT_SRC(&rc
, G
, PRIMARY_COLOR
, ALPHA
);
412 if (context_chipset(ctx
) >= 0x20)
413 nv20_load_final(ctx
, &rc
, n
);
415 nv10_load_final(ctx
, &rc
, n
);