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 #include "main/mm.h" 33 34 #include "intel_screen.h" 35 #include "intel_tex.h" 36 37 #include "i830_context.h" 38 #include "i830_reg.h" 39 40 41 /* ================================================================ 42 * Texture combine functions 43 */ 44 static GLuint 45 pass_through(GLuint * state, GLuint blendUnit) 46 { 47 state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | 48 TEXPIPE_COLOR | 49 ENABLE_TEXOUTPUT_WRT_SEL | 50 TEXOP_OUTPUT_CURRENT | 51 DISABLE_TEX_CNTRL_STAGE | 52 TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1); 53 state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | 54 TEXPIPE_ALPHA | 55 ENABLE_TEXOUTPUT_WRT_SEL | 56 TEXOP_OUTPUT_CURRENT | 57 TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1); 58 state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | 59 TEXPIPE_COLOR | 60 TEXBLEND_ARG1 | 61 TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_CURRENT); 62 state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | 63 TEXPIPE_ALPHA | 64 TEXBLEND_ARG1 | 65 TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_CURRENT); 66 67 return 4; 68 } 69 70 static GLuint 71 emit_factor(GLuint blendUnit, GLuint * state, GLuint count, 72 const GLfloat * factor) 73 { 74 GLubyte r, g, b, a; 75 GLuint col; 76 77 if (0) 78 fprintf(stderr, "emit constant %d: %.2f %.2f %.2f %.2f\n", 79 blendUnit, factor[0], factor[1], factor[2], factor[3]); 80 81 UNCLAMPED_FLOAT_TO_UBYTE(r, factor[0]); 82 UNCLAMPED_FLOAT_TO_UBYTE(g, factor[1]); 83 UNCLAMPED_FLOAT_TO_UBYTE(b, factor[2]); 84 UNCLAMPED_FLOAT_TO_UBYTE(a, factor[3]); 85 86 col = ((a << 24) | (r << 16) | (g << 8) | b); 87 88 state[count++] = _3DSTATE_COLOR_FACTOR_N_CMD(blendUnit); 89 state[count++] = col; 90 91 return count; 92 } 93 94 95 static inline GLuint 96 GetTexelOp(GLint unit) 97 { 98 switch (unit) { 99 case 0: 100 return TEXBLENDARG_TEXEL0; 101 case 1: 102 return TEXBLENDARG_TEXEL1; 103 case 2: 104 return TEXBLENDARG_TEXEL2; 105 case 3: 106 return TEXBLENDARG_TEXEL3; 107 default: 108 return TEXBLENDARG_TEXEL0; 109 } 110 } 111 112 113 /** 114 * Calculate the hardware instuctions to setup the current texture enviromnemt 115 * settings. Since \c gl_texture_unit::_CurrentCombine is used, both 116 * "classic" texture enviroments and GL_ARB_texture_env_combine type texture 117 * environments are treated identically. 118 * 119 * \todo 120 * This function should return \c bool. When \c false is returned, 121 * it means that an environment is selected that the hardware cannot do. This 122 * is the way the Radeon and R200 drivers work. 123 * 124 * \todo 125 * Looking at i830_3d_regs.h, it seems the i830 can do part of 126 * GL_ATI_texture_env_combine3. It can handle using \c GL_ONE and 127 * \c GL_ZERO as combine inputs (which the code already supports). It can 128 * also handle the \c GL_MODULATE_ADD_ATI mode. Is it worth investigating 129 * partial support for the extension? 130 */ 131 GLuint 132 i830SetTexEnvCombine(struct i830_context * i830, 133 const struct gl_tex_env_combine_state * combine, 134 GLint blendUnit, 135 GLuint texel_op, GLuint * state, const GLfloat * factor) 136 { 137 const GLuint numColorArgs = combine->_NumArgsRGB; 138 GLuint numAlphaArgs = combine->_NumArgsA; 139 140 GLuint blendop; 141 GLuint ablendop; 142 GLuint args_RGB[3]; 143 GLuint args_A[3]; 144 GLuint rgb_shift; 145 GLuint alpha_shift; 146 bool need_factor = 0; 147 int i; 148 unsigned used; 149 static const GLuint tex_blend_rgb[3] = { 150 TEXPIPE_COLOR | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS, 151 TEXPIPE_COLOR | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS, 152 TEXPIPE_COLOR | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS, 153 }; 154 static const GLuint tex_blend_a[3] = { 155 TEXPIPE_ALPHA | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS, 156 TEXPIPE_ALPHA | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS, 157 TEXPIPE_ALPHA | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS, 158 }; 159 160 if (INTEL_DEBUG & DEBUG_TEXTURE) 161 fprintf(stderr, "%s\n", __func__); 162 163 164 /* The EXT version of the DOT3 extension does not support the 165 * scale factor, but the ARB version (and the version in OpenGL 166 * 1.3) does. 167 */ 168 switch (combine->ModeRGB) { 169 case GL_DOT3_RGB_EXT: 170 alpha_shift = combine->ScaleShiftA; 171 rgb_shift = 0; 172 break; 173 174 case GL_DOT3_RGBA_EXT: 175 alpha_shift = 0; 176 rgb_shift = 0; 177 break; 178 179 default: 180 rgb_shift = combine->ScaleShiftRGB; 181 alpha_shift = combine->ScaleShiftA; 182 break; 183 } 184 185 186 switch (combine->ModeRGB) { 187 case GL_REPLACE: 188 blendop = TEXBLENDOP_ARG1; 189 break; 190 case GL_MODULATE: 191 blendop = TEXBLENDOP_MODULATE; 192 break; 193 case GL_ADD: 194 blendop = TEXBLENDOP_ADD; 195 break; 196 case GL_ADD_SIGNED: 197 blendop = TEXBLENDOP_ADDSIGNED; 198 break; 199 case GL_INTERPOLATE: 200 blendop = TEXBLENDOP_BLEND; 201 break; 202 case GL_SUBTRACT: 203 blendop = TEXBLENDOP_SUBTRACT; 204 break; 205 case GL_DOT3_RGB_EXT: 206 case GL_DOT3_RGB: 207 blendop = TEXBLENDOP_DOT3; 208 break; 209 case GL_DOT3_RGBA_EXT: 210 case GL_DOT3_RGBA: 211 blendop = TEXBLENDOP_DOT4; 212 break; 213 default: 214 return pass_through(state, blendUnit); 215 } 216 217 blendop |= (rgb_shift << TEXOP_SCALE_SHIFT); 218 219 220 /* Handle RGB args */ 221 for (i = 0; i < 3; i++) { 222 switch (combine->SourceRGB[i]) { 223 case GL_TEXTURE: 224 args_RGB[i] = texel_op; 225 break; 226 case GL_TEXTURE0: 227 case GL_TEXTURE1: 228 case GL_TEXTURE2: 229 case GL_TEXTURE3: 230 args_RGB[i] = GetTexelOp(combine->SourceRGB[i] - GL_TEXTURE0); 231 break; 232 case GL_CONSTANT: 233 args_RGB[i] = TEXBLENDARG_FACTOR_N; 234 need_factor = 1; 235 break; 236 case GL_PRIMARY_COLOR: 237 args_RGB[i] = TEXBLENDARG_DIFFUSE; 238 break; 239 case GL_PREVIOUS: 240 args_RGB[i] = TEXBLENDARG_CURRENT; 241 break; 242 default: 243 return pass_through(state, blendUnit); 244 } 245 246 switch (combine->OperandRGB[i]) { 247 case GL_SRC_COLOR: 248 args_RGB[i] |= 0; 249 break; 250 case GL_ONE_MINUS_SRC_COLOR: 251 args_RGB[i] |= TEXBLENDARG_INV_ARG; 252 break; 253 case GL_SRC_ALPHA: 254 args_RGB[i] |= TEXBLENDARG_REPLICATE_ALPHA; 255 break; 256 case GL_ONE_MINUS_SRC_ALPHA: 257 args_RGB[i] |= (TEXBLENDARG_REPLICATE_ALPHA | TEXBLENDARG_INV_ARG); 258 break; 259 default: 260 return pass_through(state, blendUnit); 261 } 262 } 263 264 265 /* Need to knobble the alpha calculations of TEXBLENDOP_DOT4 to 266 * match the spec. Can't use DOT3 as it won't propogate values 267 * into alpha as required: 268 * 269 * Note - the global factor is set up with alpha == .5, so 270 * the alpha part of the DOT4 calculation should be zero. 271 */ 272 if (combine->ModeRGB == GL_DOT3_RGBA_EXT || 273 combine->ModeRGB == GL_DOT3_RGBA) { 274 ablendop = TEXBLENDOP_DOT4; 275 numAlphaArgs = 2; 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 388 static void 389 emit_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", __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 419 static void 420 emit_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 439 void 440 i830EmitTextureBlend(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