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