Home | History | Annotate | Download | only in nouveau
      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 "nv_object.xml.h"
     31 #include "nv04_3d.xml.h"
     32 #include "nv04_driver.h"
     33 
     34 #define COMBINER_SHIFT(in)						\
     35 	(NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_ARGUMENT##in##__SHIFT	\
     36 	 - NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_ARGUMENT0__SHIFT)
     37 #define COMBINER_SOURCE(reg)					\
     38 	NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_ARGUMENT0_##reg
     39 #define COMBINER_INVERT					\
     40 	NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_INVERSE0
     41 #define COMBINER_ALPHA					\
     42 	NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_ALPHA0
     43 
     44 struct combiner_state {
     45 	struct gl_context *ctx;
     46 	int unit;
     47 	GLboolean alpha;
     48 	GLboolean premodulate;
     49 
     50 	/* GL state */
     51 	GLenum mode;
     52 	GLenum *source;
     53 	GLenum *operand;
     54 	GLuint logscale;
     55 
     56 	/* Derived HW state */
     57 	uint32_t hw;
     58 };
     59 
     60 #define __INIT_COMBINER_ALPHA_A GL_TRUE
     61 #define __INIT_COMBINER_ALPHA_RGB GL_FALSE
     62 
     63 /* Initialize a combiner_state struct from the texture unit
     64  * context. */
     65 #define INIT_COMBINER(chan, ctx, rc, i) do {			\
     66 		struct gl_tex_env_combine_state *c =		\
     67 			ctx->Texture.Unit[i]._CurrentCombine;	\
     68 		(rc)->ctx = ctx;				\
     69 		(rc)->unit = i;					\
     70 		(rc)->alpha = __INIT_COMBINER_ALPHA_##chan;	\
     71 		(rc)->premodulate = c->_NumArgs##chan == 4;	\
     72 		(rc)->mode = c->Mode##chan;			\
     73 		(rc)->source = c->Source##chan;			\
     74 		(rc)->operand = c->Operand##chan;		\
     75 		(rc)->logscale = c->ScaleShift##chan;		\
     76 		(rc)->hw = 0;					\
     77 	} while (0)
     78 
     79 /* Get the combiner source for the specified EXT_texture_env_combine
     80  * source. */
     81 static uint32_t
     82 get_input_source(struct combiner_state *rc, int source)
     83 {
     84 	switch (source) {
     85 	case GL_ZERO:
     86 		return COMBINER_SOURCE(ZERO);
     87 
     88 	case GL_TEXTURE:
     89 		return rc->unit ? COMBINER_SOURCE(TEXTURE1) :
     90 			COMBINER_SOURCE(TEXTURE0);
     91 
     92 	case GL_TEXTURE0:
     93 		return COMBINER_SOURCE(TEXTURE0);
     94 
     95 	case GL_TEXTURE1:
     96 		return COMBINER_SOURCE(TEXTURE1);
     97 
     98 	case GL_CONSTANT:
     99 		return COMBINER_SOURCE(CONSTANT);
    100 
    101 	case GL_PRIMARY_COLOR:
    102 		return COMBINER_SOURCE(PRIMARY_COLOR);
    103 
    104 	case GL_PREVIOUS:
    105 		return rc->unit ? COMBINER_SOURCE(PREVIOUS) :
    106 			COMBINER_SOURCE(PRIMARY_COLOR);
    107 
    108 	default:
    109 		assert(0);
    110 	}
    111 }
    112 
    113 /* Get the (possibly inverted) combiner input mapping for the
    114  * specified EXT_texture_env_combine operand. */
    115 #define INVERT 0x1
    116 
    117 static uint32_t
    118 get_input_mapping(struct combiner_state *rc, int operand, int flags)
    119 {
    120 	int map = 0;
    121 
    122 	if (!is_color_operand(operand) && !rc->alpha)
    123 		map |= COMBINER_ALPHA;
    124 
    125 	if (is_negative_operand(operand) == !(flags & INVERT))
    126 		map |= COMBINER_INVERT;
    127 
    128 	return map;
    129 }
    130 
    131 static uint32_t
    132 get_input_arg(struct combiner_state *rc, int arg, int flags)
    133 {
    134 	int source = rc->source[arg];
    135 	int operand = rc->operand[arg];
    136 
    137 	/* Fake several unsupported texture formats. */
    138 	if (is_texture_source(source)) {
    139 		int i = (source == GL_TEXTURE ?
    140 			 rc->unit : source - GL_TEXTURE0);
    141 		struct gl_texture_object *t = rc->ctx->Texture.Unit[i]._Current;
    142 		gl_format format = t->Image[0][t->BaseLevel]->TexFormat;
    143 
    144 		if (format == MESA_FORMAT_A8) {
    145 			/* Emulated using I8. */
    146 			if (is_color_operand(operand))
    147 				return COMBINER_SOURCE(ZERO) |
    148 					get_input_mapping(rc, operand, flags);
    149 
    150 		} else if (format == MESA_FORMAT_L8) {
    151 			/* Emulated using I8. */
    152 			if (!is_color_operand(operand))
    153 				return COMBINER_SOURCE(ZERO) |
    154 					get_input_mapping(rc, operand,
    155 							  flags ^ INVERT);
    156 		}
    157 	}
    158 
    159 	return get_input_source(rc, source) |
    160 		get_input_mapping(rc, operand, flags);
    161 }
    162 
    163 /* Bind the combiner input <in> to the combiner source <src>,
    164  * possibly inverted. */
    165 #define INPUT_SRC(rc, in, src, flags)					\
    166 	(rc)->hw |= ((flags & INVERT ? COMBINER_INVERT : 0) |		\
    167 		   COMBINER_SOURCE(src)) << COMBINER_SHIFT(in)
    168 
    169 /* Bind the combiner input <in> to the EXT_texture_env_combine
    170  * argument <arg>, possibly inverted. */
    171 #define INPUT_ARG(rc, in, arg, flags)					\
    172 	(rc)->hw |= get_input_arg(rc, arg, flags) << COMBINER_SHIFT(in)
    173 
    174 #define UNSIGNED_OP(rc)							\
    175 	(rc)->hw |= ((rc)->logscale ?					\
    176 		     NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_MAP_SCALE2 :	\
    177 		     NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_MAP_IDENTITY)
    178 #define SIGNED_OP(rc)							\
    179 	(rc)->hw |= ((rc)->logscale ?					\
    180 		     NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_MAP_BIAS_SCALE2 : \
    181 		     NV04_MULTITEX_TRIANGLE_COMBINE_COLOR_MAP_BIAS)
    182 
    183 static void
    184 setup_combiner(struct combiner_state *rc)
    185 {
    186 	switch (rc->mode) {
    187 	case GL_REPLACE:
    188 		INPUT_ARG(rc, 0, 0, 0);
    189 		INPUT_SRC(rc, 1, ZERO, INVERT);
    190 		INPUT_SRC(rc, 2, ZERO, 0);
    191 		INPUT_SRC(rc, 3, ZERO, 0);
    192 		UNSIGNED_OP(rc);
    193 		break;
    194 
    195 	case GL_MODULATE:
    196 		INPUT_ARG(rc, 0, 0, 0);
    197 		INPUT_ARG(rc, 1, 1, 0);
    198 		INPUT_SRC(rc, 2, ZERO, 0);
    199 		INPUT_SRC(rc, 3, ZERO, 0);
    200 		UNSIGNED_OP(rc);
    201 		break;
    202 
    203 	case GL_ADD:
    204 	case GL_ADD_SIGNED:
    205 		if (rc->premodulate) {
    206 			INPUT_ARG(rc, 0, 0, 0);
    207 			INPUT_ARG(rc, 1, 1, 0);
    208 			INPUT_ARG(rc, 2, 2, 0);
    209 			INPUT_ARG(rc, 3, 3, 0);
    210 		} else {
    211 			INPUT_ARG(rc, 0, 0, 0);
    212 			INPUT_SRC(rc, 1, ZERO, INVERT);
    213 			INPUT_ARG(rc, 2, 1, 0);
    214 			INPUT_SRC(rc, 3, ZERO, INVERT);
    215 		}
    216 
    217 		if (rc->mode == GL_ADD_SIGNED)
    218 			SIGNED_OP(rc);
    219 		else
    220 			UNSIGNED_OP(rc);
    221 
    222 		break;
    223 
    224 	case GL_INTERPOLATE:
    225 		INPUT_ARG(rc, 0, 0, 0);
    226 		INPUT_ARG(rc, 1, 2, 0);
    227 		INPUT_ARG(rc, 2, 1, 0);
    228 		INPUT_ARG(rc, 3, 2, INVERT);
    229 		UNSIGNED_OP(rc);
    230 		break;
    231 
    232 	default:
    233 		assert(0);
    234 	}
    235 }
    236 
    237 static unsigned
    238 get_texenv_mode(unsigned mode)
    239 {
    240 	switch (mode) {
    241 	case GL_REPLACE:
    242 		return 0x1;
    243 	case GL_DECAL:
    244 		return 0x3;
    245 	case GL_MODULATE:
    246 		return 0x4;
    247 	default:
    248 		assert(0);
    249 	}
    250 }
    251 
    252 void
    253 nv04_emit_tex_env(struct gl_context *ctx, int emit)
    254 {
    255 	struct nv04_context *nv04 = to_nv04_context(ctx);
    256 	const int i = emit - NOUVEAU_STATE_TEX_ENV0;
    257 	struct combiner_state rc_a = {}, rc_c = {};
    258 
    259 	/* Compute the new combiner state. */
    260 	if (ctx->Texture.Unit[i]._ReallyEnabled) {
    261 		INIT_COMBINER(A, ctx, &rc_a, i);
    262 		setup_combiner(&rc_a);
    263 
    264 		INIT_COMBINER(RGB, ctx, &rc_c, i);
    265 		setup_combiner(&rc_c);
    266 
    267 	} else {
    268 		if (i == 0) {
    269 			INPUT_SRC(&rc_a, 0, PRIMARY_COLOR, 0);
    270 			INPUT_SRC(&rc_c, 0, PRIMARY_COLOR, 0);
    271 		} else {
    272 			INPUT_SRC(&rc_a, 0, PREVIOUS, 0);
    273 			INPUT_SRC(&rc_c, 0, PREVIOUS, 0);
    274 		}
    275 
    276 		INPUT_SRC(&rc_a, 1, ZERO, INVERT);
    277 		INPUT_SRC(&rc_c, 1, ZERO, INVERT);
    278 		INPUT_SRC(&rc_a, 2, ZERO, 0);
    279 		INPUT_SRC(&rc_c, 2, ZERO, 0);
    280 		INPUT_SRC(&rc_a, 3, ZERO, 0);
    281 		INPUT_SRC(&rc_c, 3, ZERO, 0);
    282 
    283 		UNSIGNED_OP(&rc_a);
    284 		UNSIGNED_OP(&rc_c);
    285 	}
    286 
    287 	/* calculate non-multitex state */
    288 	nv04->blend &= ~NV04_TEXTURED_TRIANGLE_BLEND_TEXTURE_MAP__MASK;
    289 	if (ctx->Texture._EnabledUnits)
    290 		nv04->blend |= get_texenv_mode(ctx->Texture.Unit[0].EnvMode);
    291 	else
    292 		nv04->blend |= get_texenv_mode(GL_MODULATE);
    293 
    294 	/* update calculated multitex state */
    295 	nv04->alpha[i] = rc_a.hw;
    296 	nv04->color[i] = rc_c.hw;
    297 	nv04->factor   = pack_rgba_f(MESA_FORMAT_ARGB8888,
    298 				     ctx->Texture.Unit[0].EnvColor);
    299 }
    300