i830_texblend.c revision 35fd72756a05463568d94862f4fcd234903e1204
1/************************************************************************** 2 * 3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28#include "glheader.h" 29#include "macros.h" 30#include "mtypes.h" 31#include "simple_list.h" 32#include "enums.h" 33#include "texformat.h" 34#include "texstore.h" 35 36#include "mm.h" 37 38#include "intel_screen.h" 39#include "intel_tex.h" 40 41#include "i830_context.h" 42#include "i830_reg.h" 43 44 45/* ================================================================ 46 * Texture combine functions 47 */ 48static GLuint 49pass_through(GLuint * state, GLuint blendUnit) 50{ 51 state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | 52 TEXPIPE_COLOR | 53 ENABLE_TEXOUTPUT_WRT_SEL | 54 TEXOP_OUTPUT_CURRENT | 55 DISABLE_TEX_CNTRL_STAGE | 56 TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1); 57 state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | 58 TEXPIPE_ALPHA | 59 ENABLE_TEXOUTPUT_WRT_SEL | 60 TEXOP_OUTPUT_CURRENT | 61 TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1); 62 state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | 63 TEXPIPE_COLOR | 64 TEXBLEND_ARG1 | 65 TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_CURRENT); 66 state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | 67 TEXPIPE_ALPHA | 68 TEXBLEND_ARG1 | 69 TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_CURRENT); 70 71 return 4; 72} 73 74static GLuint 75emit_factor(GLuint blendUnit, GLuint * state, GLuint count, 76 const GLfloat * factor) 77{ 78 GLubyte r, g, b, a; 79 GLuint col; 80 81 if (0) 82 fprintf(stderr, "emit constant %d: %.2f %.2f %.2f %.2f\n", 83 blendUnit, factor[0], factor[1], factor[2], factor[3]); 84 85 UNCLAMPED_FLOAT_TO_UBYTE(r, factor[0]); 86 UNCLAMPED_FLOAT_TO_UBYTE(g, factor[1]); 87 UNCLAMPED_FLOAT_TO_UBYTE(b, factor[2]); 88 UNCLAMPED_FLOAT_TO_UBYTE(a, factor[3]); 89 90 col = ((a << 24) | (r << 16) | (g << 8) | b); 91 92 state[count++] = _3DSTATE_COLOR_FACTOR_N_CMD(blendUnit); 93 state[count++] = col; 94 95 return count; 96} 97 98 99static INLINE GLuint 100GetTexelOp(GLint unit) 101{ 102 switch (unit) { 103 case 0: 104 return TEXBLENDARG_TEXEL0; 105 case 1: 106 return TEXBLENDARG_TEXEL1; 107 case 2: 108 return TEXBLENDARG_TEXEL2; 109 case 3: 110 return TEXBLENDARG_TEXEL3; 111 default: 112 return TEXBLENDARG_TEXEL0; 113 } 114} 115 116 117/** 118 * Calculate the hardware instuctions to setup the current texture enviromnemt 119 * settings. Since \c gl_texture_unit::_CurrentCombine is used, both 120 * "classic" texture enviroments and GL_ARB_texture_env_combine type texture 121 * environments are treated identically. 122 * 123 * \todo 124 * This function should return \c GLboolean. When \c GL_FALSE is returned, 125 * it means that an environment is selected that the hardware cannot do. This 126 * is the way the Radeon and R200 drivers work. 127 * 128 * \todo 129 * Looking at i830_3d_regs.h, it seems the i830 can do part of 130 * GL_ATI_texture_env_combine3. It can handle using \c GL_ONE and 131 * \c GL_ZERO as combine inputs (which the code already supports). It can 132 * also handle the \c GL_MODULATE_ADD_ATI mode. Is it worth investigating 133 * partial support for the extension? 134 */ 135GLuint 136i830SetTexEnvCombine(struct i830_context * i830, 137 const struct gl_tex_env_combine_state * combine, 138 GLint blendUnit, 139 GLuint texel_op, GLuint * state, const GLfloat * factor) 140{ 141 const GLuint numColorArgs = combine->_NumArgsRGB; 142 const GLuint numAlphaArgs = combine->_NumArgsA; 143 144 GLuint blendop; 145 GLuint ablendop; 146 GLuint args_RGB[3]; 147 GLuint args_A[3]; 148 GLuint rgb_shift; 149 GLuint alpha_shift; 150 GLboolean need_factor = 0; 151 int i; 152 unsigned used; 153 static const GLuint tex_blend_rgb[3] = { 154 TEXPIPE_COLOR | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS, 155 TEXPIPE_COLOR | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS, 156 TEXPIPE_COLOR | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS, 157 }; 158 static const GLuint tex_blend_a[3] = { 159 TEXPIPE_ALPHA | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS, 160 TEXPIPE_ALPHA | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS, 161 TEXPIPE_ALPHA | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS, 162 }; 163 164 if (INTEL_DEBUG & DEBUG_TEXTURE) 165 fprintf(stderr, "%s\n", __FUNCTION__); 166 167 168 /* The EXT version of the DOT3 extension does not support the 169 * scale factor, but the ARB version (and the version in OpenGL 170 * 1.3) does. 171 */ 172 switch (combine->ModeRGB) { 173 case GL_DOT3_RGB_EXT: 174 alpha_shift = combine->ScaleShiftA; 175 rgb_shift = 0; 176 break; 177 178 case GL_DOT3_RGBA_EXT: 179 alpha_shift = 0; 180 rgb_shift = 0; 181 break; 182 183 default: 184 rgb_shift = combine->ScaleShiftRGB; 185 alpha_shift = combine->ScaleShiftA; 186 break; 187 } 188 189 190 switch (combine->ModeRGB) { 191 case GL_REPLACE: 192 blendop = TEXBLENDOP_ARG1; 193 break; 194 case GL_MODULATE: 195 blendop = TEXBLENDOP_MODULATE; 196 break; 197 case GL_ADD: 198 blendop = TEXBLENDOP_ADD; 199 break; 200 case GL_ADD_SIGNED: 201 blendop = TEXBLENDOP_ADDSIGNED; 202 break; 203 case GL_INTERPOLATE: 204 blendop = TEXBLENDOP_BLEND; 205 break; 206 case GL_SUBTRACT: 207 blendop = TEXBLENDOP_SUBTRACT; 208 break; 209 case GL_DOT3_RGB_EXT: 210 case GL_DOT3_RGB: 211 blendop = TEXBLENDOP_DOT3; 212 break; 213 case GL_DOT3_RGBA_EXT: 214 case GL_DOT3_RGBA: 215 blendop = TEXBLENDOP_DOT3; 216 break; 217 default: 218 return pass_through(state, blendUnit); 219 } 220 221 blendop |= (rgb_shift << TEXOP_SCALE_SHIFT); 222 223 224 /* Handle RGB args */ 225 for (i = 0; i < 3; i++) { 226 switch (combine->SourceRGB[i]) { 227 case GL_TEXTURE: 228 args_RGB[i] = texel_op; 229 break; 230 case GL_TEXTURE0: 231 case GL_TEXTURE1: 232 case GL_TEXTURE2: 233 case GL_TEXTURE3: 234 args_RGB[i] = GetTexelOp(combine->SourceRGB[i] - GL_TEXTURE0); 235 break; 236 case GL_CONSTANT: 237 args_RGB[i] = TEXBLENDARG_FACTOR_N; 238 need_factor = 1; 239 break; 240 case GL_PRIMARY_COLOR: 241 args_RGB[i] = TEXBLENDARG_DIFFUSE; 242 break; 243 case GL_PREVIOUS: 244 args_RGB[i] = TEXBLENDARG_CURRENT; 245 break; 246 default: 247 return pass_through(state, blendUnit); 248 } 249 250 switch (combine->OperandRGB[i]) { 251 case GL_SRC_COLOR: 252 args_RGB[i] |= 0; 253 break; 254 case GL_ONE_MINUS_SRC_COLOR: 255 args_RGB[i] |= TEXBLENDARG_INV_ARG; 256 break; 257 case GL_SRC_ALPHA: 258 args_RGB[i] |= TEXBLENDARG_REPLICATE_ALPHA; 259 break; 260 case GL_ONE_MINUS_SRC_ALPHA: 261 args_RGB[i] |= (TEXBLENDARG_REPLICATE_ALPHA | TEXBLENDARG_INV_ARG); 262 break; 263 default: 264 return pass_through(state, blendUnit); 265 } 266 } 267 268 269 /* Need to knobble the alpha calculations of TEXBLENDOP_DOT4 to 270 * match the spec. Can't use DOT3 as it won't propogate values 271 * into alpha as required: 272 * 273 * Note - the global factor is set up with alpha == .5, so 274 * the alpha part of the DOT4 calculation should be zero. 275 */ 276 if (combine->ModeRGB == GL_DOT3_RGBA_EXT || 277 combine->ModeRGB == GL_DOT3_RGBA) { 278 ablendop = TEXBLENDOP_DOT4; 279 args_A[0] = TEXBLENDARG_FACTOR; /* the global factor */ 280 args_A[1] = TEXBLENDARG_FACTOR; 281 args_A[2] = TEXBLENDARG_FACTOR; 282 } 283 else { 284 switch (combine->ModeA) { 285 case GL_REPLACE: 286 ablendop = TEXBLENDOP_ARG1; 287 break; 288 case GL_MODULATE: 289 ablendop = TEXBLENDOP_MODULATE; 290 break; 291 case GL_ADD: 292 ablendop = TEXBLENDOP_ADD; 293 break; 294 case GL_ADD_SIGNED: 295 ablendop = TEXBLENDOP_ADDSIGNED; 296 break; 297 case GL_INTERPOLATE: 298 ablendop = TEXBLENDOP_BLEND; 299 break; 300 case GL_SUBTRACT: 301 ablendop = TEXBLENDOP_SUBTRACT; 302 break; 303 default: 304 return pass_through(state, blendUnit); 305 } 306 307 308 ablendop |= (alpha_shift << TEXOP_SCALE_SHIFT); 309 310 /* Handle A args */ 311 for (i = 0; i < 3; i++) { 312 switch (combine->SourceA[i]) { 313 case GL_TEXTURE: 314 args_A[i] = texel_op; 315 break; 316 case GL_TEXTURE0: 317 case GL_TEXTURE1: 318 case GL_TEXTURE2: 319 case GL_TEXTURE3: 320 args_A[i] = GetTexelOp(combine->SourceA[i] - GL_TEXTURE0); 321 break; 322 case GL_CONSTANT: 323 args_A[i] = TEXBLENDARG_FACTOR_N; 324 need_factor = 1; 325 break; 326 case GL_PRIMARY_COLOR: 327 args_A[i] = TEXBLENDARG_DIFFUSE; 328 break; 329 case GL_PREVIOUS: 330 args_A[i] = TEXBLENDARG_CURRENT; 331 break; 332 default: 333 return pass_through(state, blendUnit); 334 } 335 336 switch (combine->OperandA[i]) { 337 case GL_SRC_ALPHA: 338 args_A[i] |= 0; 339 break; 340 case GL_ONE_MINUS_SRC_ALPHA: 341 args_A[i] |= TEXBLENDARG_INV_ARG; 342 break; 343 default: 344 return pass_through(state, blendUnit); 345 } 346 } 347 } 348 349 350 351 /* Native Arg1 == Arg0 in GL_EXT_texture_env_combine spec */ 352 /* Native Arg2 == Arg1 in GL_EXT_texture_env_combine spec */ 353 /* Native Arg0 == Arg2 in GL_EXT_texture_env_combine spec */ 354 355 /* When we render we need to figure out which is the last really enabled 356 * tex unit, and put last stage on it 357 */ 358 359 360 /* Build color & alpha pipelines */ 361 362 used = 0; 363 state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | 364 TEXPIPE_COLOR | 365 ENABLE_TEXOUTPUT_WRT_SEL | 366 TEXOP_OUTPUT_CURRENT | 367 DISABLE_TEX_CNTRL_STAGE | TEXOP_MODIFY_PARMS | blendop); 368 state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | 369 TEXPIPE_ALPHA | 370 ENABLE_TEXOUTPUT_WRT_SEL | 371 TEXOP_OUTPUT_CURRENT | TEXOP_MODIFY_PARMS | ablendop); 372 373 for (i = 0; i < numColorArgs; i++) { 374 state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | 375 tex_blend_rgb[i] | args_RGB[i]); 376 } 377 378 for (i = 0; i < numAlphaArgs; i++) { 379 state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | 380 tex_blend_a[i] | args_A[i]); 381 } 382 383 384 if (need_factor) 385 return emit_factor(blendUnit, state, used, factor); 386 else 387 return used; 388} 389 390 391static void 392emit_texblend(struct i830_context *i830, GLuint unit, GLuint blendUnit, 393 GLboolean last_stage) 394{ 395 struct gl_texture_unit *texUnit = &i830->intel.ctx.Texture.Unit[unit]; 396 GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz; 397 398 399 if (0) 400 fprintf(stderr, "%s unit %d\n", __FUNCTION__, unit); 401 402 /* Update i830->state.TexBlend 403 */ 404 tmp_sz = i830SetTexEnvCombine(i830, texUnit->_CurrentCombine, blendUnit, 405 GetTexelOp(unit), tmp, texUnit->EnvColor); 406 407 if (last_stage) 408 tmp[0] |= TEXOP_LAST_STAGE; 409 410 if (tmp_sz != i830->state.TexBlendWordsUsed[blendUnit] || 411 memcmp(tmp, i830->state.TexBlend[blendUnit], 412 tmp_sz * sizeof(GLuint))) { 413 414 I830_STATECHANGE(i830, I830_UPLOAD_TEXBLEND(blendUnit)); 415 memcpy(i830->state.TexBlend[blendUnit], tmp, tmp_sz * sizeof(GLuint)); 416 i830->state.TexBlendWordsUsed[blendUnit] = tmp_sz; 417 } 418 419 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(blendUnit), GL_TRUE); 420} 421 422static void 423emit_passthrough(struct i830_context *i830) 424{ 425 GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz; 426 GLuint unit = 0; 427 428 tmp_sz = pass_through(tmp, unit); 429 tmp[0] |= TEXOP_LAST_STAGE; 430 431 if (tmp_sz != i830->state.TexBlendWordsUsed[unit] || 432 memcmp(tmp, i830->state.TexBlend[unit], tmp_sz * sizeof(GLuint))) { 433 434 I830_STATECHANGE(i830, I830_UPLOAD_TEXBLEND(unit)); 435 memcpy(i830->state.TexBlend[unit], tmp, tmp_sz * sizeof(GLuint)); 436 i830->state.TexBlendWordsUsed[unit] = tmp_sz; 437 } 438 439 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(unit), GL_TRUE); 440} 441 442void 443i830EmitTextureBlend(struct i830_context *i830) 444{ 445 GLcontext *ctx = &i830->intel.ctx; 446 GLuint unit, last_stage = 0, blendunit = 0; 447 448 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND_ALL, GL_FALSE); 449 450 if (ctx->Texture._EnabledUnits) { 451 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) 452 if (ctx->Texture.Unit[unit]._ReallyEnabled) 453 last_stage = unit; 454 455 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) 456 if (ctx->Texture.Unit[unit]._ReallyEnabled) 457 emit_texblend(i830, unit, blendunit++, last_stage == unit); 458 } 459 else { 460 emit_passthrough(i830); 461 } 462} 463