Home | History | Annotate | Download | only in nouveau
      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 "nv10_3d.xml.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)NV10_3D_RC_IN_RGB_D_INPUT_##source)
     45 #define RC_IN_USAGE(usage)					\
     46 	((uint64_t)NV10_3D_RC_IN_RGB_D_COMPONENT_USAGE_##usage)
     47 #define RC_IN_MAPPING(mapping)					\
     48 	((uint64_t)NV10_3D_RC_IN_RGB_D_MAPPING_##mapping)
     49 
     50 #define RC_OUT_BIAS	NV10_3D_RC_OUT_RGB_BIAS_BIAS_BY_NEGATIVE_ONE_HALF
     51 #define RC_OUT_SCALE_1	NV10_3D_RC_OUT_RGB_SCALE_NONE
     52 #define RC_OUT_SCALE_2	NV10_3D_RC_OUT_RGB_SCALE_SCALE_BY_TWO
     53 #define RC_OUT_SCALE_4	NV10_3D_RC_OUT_RGB_SCALE_SCALE_BY_FOUR
     54 
     55 /* Make the combiner do: spare0_i = A_i * B_i */
     56 #define RC_OUT_AB	NV10_3D_RC_OUT_RGB_AB_OUTPUT_SPARE0
     57 /* spare0_i = dot3(A, B) */
     58 #define RC_OUT_DOT_AB	(NV10_3D_RC_OUT_RGB_AB_OUTPUT_SPARE0 |	\
     59 			 NV10_3D_RC_OUT_RGB_AB_DOT_PRODUCT)
     60 /* spare0_i = A_i * B_i + C_i * D_i */
     61 #define RC_OUT_SUM	NV10_3D_RC_OUT_RGB_SUM_OUTPUT_SPARE0
     62 
     63 struct combiner_state {
     64 	struct gl_context *ctx;
     65 	int unit;
     66 	GLboolean premodulate;
     67 
     68 	/* GL state */
     69 	GLenum mode;
     70 	GLenum *source;
     71 	GLenum *operand;
     72 	GLuint logscale;
     73 
     74 	/* Derived HW state */
     75 	uint64_t in;
     76 	uint32_t out;
     77 };
     78 
     79 /* Initialize a combiner_state struct from the texture unit
     80  * context. */
     81 #define INIT_COMBINER(chan, ctx, rc, i) do {			\
     82 		struct gl_tex_env_combine_state *c =		\
     83 			ctx->Texture.Unit[i]._CurrentCombine;	\
     84 		(rc)->ctx = ctx;				\
     85 		(rc)->unit = i;					\
     86 		(rc)->premodulate = c->_NumArgs##chan == 4;	\
     87 		(rc)->mode = c->Mode##chan;			\
     88 		(rc)->source = c->Source##chan;			\
     89 		(rc)->operand = c->Operand##chan;		\
     90 		(rc)->logscale = c->ScaleShift##chan;		\
     91 		(rc)->in = (rc)->out = 0;			\
     92 	} while (0)
     93 
     94 /* Get the RC input source for the specified EXT_texture_env_combine
     95  * source. */
     96 static uint32_t
     97 get_input_source(struct combiner_state *rc, int source)
     98 {
     99 	switch (source) {
    100 	case GL_ZERO:
    101 		return RC_IN_SOURCE(ZERO);
    102 
    103 	case GL_TEXTURE:
    104 		return RC_IN_SOURCE(TEXTURE0) + rc->unit;
    105 
    106 	case GL_TEXTURE0:
    107 		return RC_IN_SOURCE(TEXTURE0);
    108 
    109 	case GL_TEXTURE1:
    110 		return RC_IN_SOURCE(TEXTURE1);
    111 
    112 	case GL_TEXTURE2:
    113 		return RC_IN_SOURCE(TEXTURE2);
    114 
    115 	case GL_TEXTURE3:
    116 		return RC_IN_SOURCE(TEXTURE3);
    117 
    118 	case GL_CONSTANT:
    119 		return context_chipset(rc->ctx) >= 0x20 ?
    120 			RC_IN_SOURCE(CONSTANT_COLOR0) :
    121 			RC_IN_SOURCE(CONSTANT_COLOR0) + rc->unit;
    122 
    123 	case GL_PRIMARY_COLOR:
    124 		return RC_IN_SOURCE(PRIMARY_COLOR);
    125 
    126 	case GL_PREVIOUS:
    127 		return rc->unit ? RC_IN_SOURCE(SPARE0)
    128 			: RC_IN_SOURCE(PRIMARY_COLOR);
    129 
    130 	default:
    131 		assert(0);
    132 	}
    133 }
    134 
    135 /* Get the RC input mapping for the specified texture_env_combine
    136  * operand, possibly inverted or biased. */
    137 #define INVERT 0x1
    138 #define HALF_BIAS 0x2
    139 
    140 static uint32_t
    141 get_input_mapping(struct combiner_state *rc, int operand, int flags)
    142 {
    143 	int map = 0;
    144 
    145 	if (is_color_operand(operand))
    146 		map |= RC_IN_USAGE(RGB);
    147 	else
    148 		map |= RC_IN_USAGE(ALPHA);
    149 
    150 	if (is_negative_operand(operand) == !(flags & INVERT))
    151 		map |= flags & HALF_BIAS ?
    152 			RC_IN_MAPPING(HALF_BIAS_NEGATE) :
    153 			RC_IN_MAPPING(UNSIGNED_INVERT);
    154 	else
    155 		map |= flags & HALF_BIAS ?
    156 			RC_IN_MAPPING(HALF_BIAS_NORMAL) :
    157 			RC_IN_MAPPING(UNSIGNED_IDENTITY);
    158 
    159 	return map;
    160 }
    161 
    162 static uint32_t
    163 get_input_arg(struct combiner_state *rc, int arg, int flags)
    164 {
    165 	int source = rc->source[arg];
    166 	int operand = rc->operand[arg];
    167 
    168 	/* Fake several unsupported texture formats. */
    169 	if (is_texture_source(source)) {
    170 		int i = (source == GL_TEXTURE ?
    171 			 rc->unit : source - GL_TEXTURE0);
    172 		struct gl_texture_object *t = rc->ctx->Texture.Unit[i]._Current;
    173 		gl_format format = t->Image[0][t->BaseLevel]->TexFormat;
    174 
    175 		if (format == MESA_FORMAT_A8) {
    176 			/* Emulated using I8. */
    177 			if (is_color_operand(operand))
    178 				return RC_IN_SOURCE(ZERO) |
    179 					get_input_mapping(rc, operand, flags);
    180 
    181 		} else if (format == MESA_FORMAT_L8) {
    182 			/* Sometimes emulated using I8. */
    183 			if (!is_color_operand(operand))
    184 				return RC_IN_SOURCE(ZERO) |
    185 					get_input_mapping(rc, operand,
    186 							  flags ^ INVERT);
    187 
    188 		} else if (format == MESA_FORMAT_XRGB8888) {
    189 			/* Sometimes emulated using ARGB8888. */
    190 			if (!is_color_operand(operand))
    191 				return RC_IN_SOURCE(ZERO) |
    192 					get_input_mapping(rc, operand,
    193 							  flags ^ INVERT);
    194 		}
    195 	}
    196 
    197 	return get_input_source(rc, source) |
    198 		get_input_mapping(rc, operand, flags);
    199 }
    200 
    201 /* Bind the RC input variable <var> to the EXT_texture_env_combine
    202  * argument <arg>, possibly inverted or biased. */
    203 #define INPUT_ARG(rc, var, arg, flags)					\
    204 	(rc)->in |= get_input_arg(rc, arg, flags) << RC_IN_SHIFT_##var
    205 
    206 /* Bind the RC input variable <var> to the RC source <src>. */
    207 #define INPUT_SRC(rc, var, src, chan)					\
    208 	(rc)->in |= (RC_IN_SOURCE(src) |				\
    209 		     RC_IN_USAGE(chan)) << RC_IN_SHIFT_##var
    210 
    211 /* Bind the RC input variable <var> to a constant +/-1 */
    212 #define INPUT_ONE(rc, var, flags)					\
    213 	(rc)->in |= (RC_IN_SOURCE(ZERO) |				\
    214 		     (flags & INVERT ? RC_IN_MAPPING(EXPAND_NORMAL) :	\
    215 		      RC_IN_MAPPING(UNSIGNED_INVERT))) << RC_IN_SHIFT_##var
    216 
    217 static void
    218 setup_combiner(struct combiner_state *rc)
    219 {
    220 	switch (rc->mode) {
    221 	case GL_REPLACE:
    222 		INPUT_ARG(rc, A, 0, 0);
    223 		INPUT_ONE(rc, B, 0);
    224 
    225 		rc->out = RC_OUT_AB;
    226 		break;
    227 
    228 	case GL_MODULATE:
    229 		INPUT_ARG(rc, A, 0, 0);
    230 		INPUT_ARG(rc, B, 1, 0);
    231 
    232 		rc->out = RC_OUT_AB;
    233 		break;
    234 
    235 	case GL_ADD:
    236 	case GL_ADD_SIGNED:
    237 		if (rc->premodulate) {
    238 			INPUT_ARG(rc, A, 0, 0);
    239 			INPUT_ARG(rc, B, 1, 0);
    240 			INPUT_ARG(rc, C, 2, 0);
    241 			INPUT_ARG(rc, D, 3, 0);
    242 		} else {
    243 			INPUT_ARG(rc, A, 0, 0);
    244 			INPUT_ONE(rc, B, 0);
    245 			INPUT_ARG(rc, C, 1, 0);
    246 			INPUT_ONE(rc, D, 0);
    247 		}
    248 
    249 		rc->out = RC_OUT_SUM |
    250 			(rc->mode == GL_ADD_SIGNED ? RC_OUT_BIAS : 0);
    251 		break;
    252 
    253 	case GL_INTERPOLATE:
    254 		INPUT_ARG(rc, A, 0, 0);
    255 		INPUT_ARG(rc, B, 2, 0);
    256 		INPUT_ARG(rc, C, 1, 0);
    257 		INPUT_ARG(rc, D, 2, INVERT);
    258 
    259 		rc->out = RC_OUT_SUM;
    260 		break;
    261 
    262 	case GL_SUBTRACT:
    263 		INPUT_ARG(rc, A, 0, 0);
    264 		INPUT_ONE(rc, B, 0);
    265 		INPUT_ARG(rc, C, 1, 0);
    266 		INPUT_ONE(rc, D, INVERT);
    267 
    268 		rc->out = RC_OUT_SUM;
    269 		break;
    270 
    271 	case GL_DOT3_RGB:
    272 	case GL_DOT3_RGBA:
    273 		INPUT_ARG(rc, A, 0, HALF_BIAS);
    274 		INPUT_ARG(rc, B, 1, HALF_BIAS);
    275 
    276 		rc->out = RC_OUT_DOT_AB | RC_OUT_SCALE_4;
    277 
    278 		assert(!rc->logscale);
    279 		break;
    280 
    281 	default:
    282 		assert(0);
    283 	}
    284 
    285 	switch (rc->logscale) {
    286 	case 0:
    287 		rc->out |= RC_OUT_SCALE_1;
    288 		break;
    289 	case 1:
    290 		rc->out |= RC_OUT_SCALE_2;
    291 		break;
    292 	case 2:
    293 		rc->out |= RC_OUT_SCALE_4;
    294 		break;
    295 	default:
    296 		assert(0);
    297 	}
    298 }
    299 
    300 void
    301 nv10_get_general_combiner(struct gl_context *ctx, int i,
    302 			  uint32_t *a_in, uint32_t *a_out,
    303 			  uint32_t *c_in, uint32_t *c_out, uint32_t *k)
    304 {
    305 	struct combiner_state rc_a, rc_c;
    306 
    307 	if (ctx->Texture.Unit[i]._ReallyEnabled) {
    308 		INIT_COMBINER(RGB, ctx, &rc_c, i);
    309 
    310 		if (rc_c.mode == GL_DOT3_RGBA)
    311 			rc_a = rc_c;
    312 		else
    313 			INIT_COMBINER(A, ctx, &rc_a, i);
    314 
    315 		setup_combiner(&rc_c);
    316 		setup_combiner(&rc_a);
    317 
    318 	} else {
    319 		rc_a.in = rc_a.out = rc_c.in = rc_c.out = 0;
    320 	}
    321 
    322 	*k = pack_rgba_f(MESA_FORMAT_ARGB8888,
    323 			 ctx->Texture.Unit[i].EnvColor);
    324 	*a_in = rc_a.in;
    325 	*a_out = rc_a.out;
    326 	*c_in = rc_c.in;
    327 	*c_out = rc_c.out;
    328 }
    329 
    330 void
    331 nv10_get_final_combiner(struct gl_context *ctx, uint64_t *in, int *n)
    332 {
    333 	struct combiner_state rc = {};
    334 
    335 	/*
    336 	 * The final fragment value equation is something like:
    337 	 *	x_i = A_i * B_i + (1 - A_i) * C_i + D_i
    338 	 *	x_alpha = G_alpha
    339 	 * where D_i = E_i * F_i, i one of {red, green, blue}.
    340 	 */
    341 	if (ctx->Fog.ColorSumEnabled || ctx->Light.Enabled) {
    342 		INPUT_SRC(&rc, D, E_TIMES_F, RGB);
    343 		INPUT_SRC(&rc, F, SECONDARY_COLOR, RGB);
    344 	}
    345 
    346 	if (ctx->Fog.Enabled) {
    347 		INPUT_SRC(&rc, A, FOG, ALPHA);
    348 		INPUT_SRC(&rc, C, FOG, RGB);
    349 		INPUT_SRC(&rc, E, FOG, ALPHA);
    350 	} else {
    351 		INPUT_ONE(&rc, A, 0);
    352 		INPUT_ONE(&rc, C, 0);
    353 		INPUT_ONE(&rc, E, 0);
    354 	}
    355 
    356 	if (ctx->Texture._EnabledUnits) {
    357 		INPUT_SRC(&rc, B, SPARE0, RGB);
    358 		INPUT_SRC(&rc, G, SPARE0, ALPHA);
    359 	} else {
    360 		INPUT_SRC(&rc, B, PRIMARY_COLOR, RGB);
    361 		INPUT_SRC(&rc, G, PRIMARY_COLOR, ALPHA);
    362 	}
    363 
    364 	*in = rc.in;
    365 	*n = log2i(ctx->Texture._EnabledUnits) + 1;
    366 }
    367 
    368 void
    369 nv10_emit_tex_env(struct gl_context *ctx, int emit)
    370 {
    371 	const int i = emit - NOUVEAU_STATE_TEX_ENV0;
    372 	struct nouveau_pushbuf *push = context_push(ctx);
    373 	uint32_t a_in, a_out, c_in, c_out, k;
    374 
    375 	nv10_get_general_combiner(ctx, i, &a_in, &a_out, &c_in, &c_out, &k);
    376 
    377 	/* Enable the combiners we're going to need. */
    378 	if (i == 1) {
    379 		if (c_out || a_out)
    380 			c_out |= 0x5 << 27;
    381 		else
    382 			c_out |= 0x3 << 27;
    383 	}
    384 
    385 	BEGIN_NV04(push, NV10_3D(RC_IN_ALPHA(i)), 1);
    386 	PUSH_DATA (push, a_in);
    387 	BEGIN_NV04(push, NV10_3D(RC_IN_RGB(i)), 1);
    388 	PUSH_DATA (push, c_in);
    389 	BEGIN_NV04(push, NV10_3D(RC_COLOR(i)), 1);
    390 	PUSH_DATA (push, k);
    391 	BEGIN_NV04(push, NV10_3D(RC_OUT_ALPHA(i)), 1);
    392 	PUSH_DATA (push, a_out);
    393 	BEGIN_NV04(push, NV10_3D(RC_OUT_RGB(i)), 1);
    394 	PUSH_DATA (push, c_out);
    395 
    396 	context_dirty(ctx, FRAG);
    397 }
    398 
    399 void
    400 nv10_emit_frag(struct gl_context *ctx, int emit)
    401 {
    402 	struct nouveau_pushbuf *push = context_push(ctx);
    403 	uint64_t in;
    404 	int n;
    405 
    406 	nv10_get_final_combiner(ctx, &in, &n);
    407 
    408 	BEGIN_NV04(push, NV10_3D(RC_FINAL0), 2);
    409 	PUSH_DATA (push, in);
    410 	PUSH_DATA (push, in >> 32);
    411 }
    412