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