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 */ 43 static GLuint 44 pass_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 69 static GLuint 70 emit_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 94 static inline GLuint 95 GetTexelOp(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 */ 130 GLuint 131 i830SetTexEnvCombine(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 387 static void 388 emit_texblend(struct i830_context *i830, GLuint unit, GLuint blendUnit, 389 bool last_stage) 390 { 391 struct gl_texture_unit *texUnit = &i830->intel.ctx.Texture.Unit[unit]; 392 GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz; 393 394 395 if (0) 396 fprintf(stderr, "%s unit %d\n", __func__, unit); 397 398 /* Update i830->state.TexBlend 399 */ 400 tmp_sz = i830SetTexEnvCombine(i830, texUnit->_CurrentCombine, blendUnit, 401 GetTexelOp(unit), tmp, texUnit->EnvColor); 402 403 if (last_stage) 404 tmp[0] |= TEXOP_LAST_STAGE; 405 406 if (tmp_sz != i830->state.TexBlendWordsUsed[blendUnit] || 407 memcmp(tmp, i830->state.TexBlend[blendUnit], 408 tmp_sz * sizeof(GLuint))) { 409 410 I830_STATECHANGE(i830, I830_UPLOAD_TEXBLEND(blendUnit)); 411 memcpy(i830->state.TexBlend[blendUnit], tmp, tmp_sz * sizeof(GLuint)); 412 i830->state.TexBlendWordsUsed[blendUnit] = tmp_sz; 413 } 414 415 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(blendUnit), true); 416 } 417 418 static void 419 emit_passthrough(struct i830_context *i830) 420 { 421 GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz; 422 GLuint unit = 0; 423 424 tmp_sz = pass_through(tmp, unit); 425 tmp[0] |= TEXOP_LAST_STAGE; 426 427 if (tmp_sz != i830->state.TexBlendWordsUsed[unit] || 428 memcmp(tmp, i830->state.TexBlend[unit], tmp_sz * sizeof(GLuint))) { 429 430 I830_STATECHANGE(i830, I830_UPLOAD_TEXBLEND(unit)); 431 memcpy(i830->state.TexBlend[unit], tmp, tmp_sz * sizeof(GLuint)); 432 i830->state.TexBlendWordsUsed[unit] = tmp_sz; 433 } 434 435 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(unit), true); 436 } 437 438 void 439 i830EmitTextureBlend(struct i830_context *i830) 440 { 441 struct gl_context *ctx = &i830->intel.ctx; 442 GLuint unit, blendunit = 0; 443 444 I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND_ALL, false); 445 446 if (ctx->Texture._MaxEnabledTexImageUnit != -1) { 447 for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) 448 if (ctx->Texture.Unit[unit]._Current) 449 emit_texblend(i830, unit, blendunit++, 450 unit == ctx->Texture._MaxEnabledTexImageUnit); 451 } else { 452 emit_passthrough(i830); 453 } 454 } 455