blend.c revision 53f82c5aadbb15585754bfacf3237093eccdb2ce
1/** 2 * \file blend.c 3 * Blending operations. 4 */ 5 6/* 7 * Mesa 3-D graphics library 8 * Version: 6.1 9 * 10 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining a 13 * copy of this software and associated documentation files (the "Software"), 14 * to deal in the Software without restriction, including without limitation 15 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 16 * and/or sell copies of the Software, and to permit persons to whom the 17 * Software is furnished to do so, subject to the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be included 20 * in all copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 25 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 30 31 32#include "glheader.h" 33#include "blend.h" 34#include "colormac.h" 35#include "context.h" 36#include "enums.h" 37#include "macros.h" 38#include "mtypes.h" 39 40 41/** 42 * Specify the blending operation. 43 * 44 * \param sfactor source factor operator. 45 * \param dfactor destination factor operator. 46 * 47 * \sa glBlendFunc, glBlendFuncSeparateEXT 48 * 49 * Swizzles the inputs and calls \c glBlendFuncSeparateEXT. This is done 50 * using the \c CurrentDispatch table in the context, so this same function 51 * can be used while compiling display lists. Therefore, there is no need 52 * for the display list code to save and restore this function. 53 */ 54void GLAPIENTRY 55_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) 56{ 57 GET_CURRENT_CONTEXT(ctx); 58 59 (*ctx->CurrentDispatch->BlendFuncSeparateEXT)( sfactor, dfactor, 60 sfactor, dfactor ); 61} 62 63 64/** 65 * Process GL_EXT_blend_func_separate(). 66 * 67 * \param sfactorRGB RGB source factor operator. 68 * \param dfactorRGB RGB destination factor operator. 69 * \param sfactorA alpha source factor operator. 70 * \param dfactorA alpha destination factor operator. 71 * 72 * Verifies the parameters and updates gl_colorbuffer_attrib. 73 * On a change, flush the vertices and notify the driver via 74 * dd_function_table::BlendFuncSeparate. 75 */ 76void GLAPIENTRY 77_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, 78 GLenum sfactorA, GLenum dfactorA ) 79{ 80 GET_CURRENT_CONTEXT(ctx); 81 ASSERT_OUTSIDE_BEGIN_END(ctx); 82 83 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 84 _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", 85 _mesa_lookup_enum_by_nr(sfactorRGB), 86 _mesa_lookup_enum_by_nr(dfactorRGB), 87 _mesa_lookup_enum_by_nr(sfactorA), 88 _mesa_lookup_enum_by_nr(dfactorA)); 89 90 switch (sfactorRGB) { 91 case GL_SRC_COLOR: 92 case GL_ONE_MINUS_SRC_COLOR: 93 if (!ctx->Extensions.NV_blend_square) { 94 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorRGB)"); 95 return; 96 } 97 /* fall-through */ 98 case GL_ZERO: 99 case GL_ONE: 100 case GL_DST_COLOR: 101 case GL_ONE_MINUS_DST_COLOR: 102 case GL_SRC_ALPHA: 103 case GL_ONE_MINUS_SRC_ALPHA: 104 case GL_DST_ALPHA: 105 case GL_ONE_MINUS_DST_ALPHA: 106 case GL_SRC_ALPHA_SATURATE: 107 case GL_CONSTANT_COLOR: 108 case GL_ONE_MINUS_CONSTANT_COLOR: 109 case GL_CONSTANT_ALPHA: 110 case GL_ONE_MINUS_CONSTANT_ALPHA: 111 break; 112 default: 113 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorRGB)"); 114 return; 115 } 116 117 switch (dfactorRGB) { 118 case GL_DST_COLOR: 119 case GL_ONE_MINUS_DST_COLOR: 120 if (!ctx->Extensions.NV_blend_square) { 121 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorRGB)"); 122 return; 123 } 124 /* fall-through */ 125 case GL_ZERO: 126 case GL_ONE: 127 case GL_SRC_COLOR: 128 case GL_ONE_MINUS_SRC_COLOR: 129 case GL_SRC_ALPHA: 130 case GL_ONE_MINUS_SRC_ALPHA: 131 case GL_DST_ALPHA: 132 case GL_ONE_MINUS_DST_ALPHA: 133 case GL_CONSTANT_COLOR: 134 case GL_ONE_MINUS_CONSTANT_COLOR: 135 case GL_CONSTANT_ALPHA: 136 case GL_ONE_MINUS_CONSTANT_ALPHA: 137 break; 138 default: 139 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorRGB)"); 140 return; 141 } 142 143 switch (sfactorA) { 144 case GL_SRC_COLOR: 145 case GL_ONE_MINUS_SRC_COLOR: 146 if (!ctx->Extensions.NV_blend_square) { 147 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorA)"); 148 return; 149 } 150 /* fall-through */ 151 case GL_ZERO: 152 case GL_ONE: 153 case GL_DST_COLOR: 154 case GL_ONE_MINUS_DST_COLOR: 155 case GL_SRC_ALPHA: 156 case GL_ONE_MINUS_SRC_ALPHA: 157 case GL_DST_ALPHA: 158 case GL_ONE_MINUS_DST_ALPHA: 159 case GL_SRC_ALPHA_SATURATE: 160 case GL_CONSTANT_COLOR: 161 case GL_ONE_MINUS_CONSTANT_COLOR: 162 case GL_CONSTANT_ALPHA: 163 case GL_ONE_MINUS_CONSTANT_ALPHA: 164 break; 165 default: 166 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorA)"); 167 return; 168 } 169 170 switch (dfactorA) { 171 case GL_DST_COLOR: 172 case GL_ONE_MINUS_DST_COLOR: 173 if (!ctx->Extensions.NV_blend_square) { 174 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorA)"); 175 return; 176 } 177 /* fall-through */ 178 case GL_ZERO: 179 case GL_ONE: 180 case GL_SRC_COLOR: 181 case GL_ONE_MINUS_SRC_COLOR: 182 case GL_SRC_ALPHA: 183 case GL_ONE_MINUS_SRC_ALPHA: 184 case GL_DST_ALPHA: 185 case GL_ONE_MINUS_DST_ALPHA: 186 case GL_CONSTANT_COLOR: 187 case GL_ONE_MINUS_CONSTANT_COLOR: 188 case GL_CONSTANT_ALPHA: 189 case GL_ONE_MINUS_CONSTANT_ALPHA: 190 break; 191 default: 192 _mesa_error( ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorA)" ); 193 return; 194 } 195 196 if (ctx->Color.BlendSrcRGB == sfactorRGB && 197 ctx->Color.BlendDstRGB == dfactorRGB && 198 ctx->Color.BlendSrcA == sfactorA && 199 ctx->Color.BlendDstA == dfactorA) 200 return; 201 202 FLUSH_VERTICES(ctx, _NEW_COLOR); 203 204 ctx->Color.BlendSrcRGB = sfactorRGB; 205 ctx->Color.BlendDstRGB = dfactorRGB; 206 ctx->Color.BlendSrcA = sfactorA; 207 ctx->Color.BlendDstA = dfactorA; 208 209 if (ctx->Driver.BlendFuncSeparate) { 210 (*ctx->Driver.BlendFuncSeparate)( ctx, sfactorRGB, dfactorRGB, 211 sfactorA, dfactorA ); 212 } 213} 214 215 216#if _HAVE_FULL_GL 217 218static GLboolean 219_mesa_validate_blend_equation( GLcontext *ctx, 220 GLenum mode, GLboolean is_separate ) 221{ 222 switch (mode) { 223 case GL_FUNC_ADD: 224 break; 225 case GL_MIN: 226 case GL_MAX: 227 if (!ctx->Extensions.EXT_blend_minmax && 228 !ctx->Extensions.ARB_imaging) { 229 return GL_FALSE; 230 } 231 break; 232 /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter. 233 */ 234 case GL_LOGIC_OP: 235 if (!ctx->Extensions.EXT_blend_logic_op || is_separate) { 236 return GL_FALSE; 237 } 238 break; 239 case GL_FUNC_SUBTRACT: 240 case GL_FUNC_REVERSE_SUBTRACT: 241 if (!ctx->Extensions.EXT_blend_subtract && 242 !ctx->Extensions.ARB_imaging) { 243 return GL_FALSE; 244 } 245 break; 246 default: 247 return GL_FALSE; 248 } 249 250 return GL_TRUE; 251} 252 253 254/* This is really an extension function! */ 255void GLAPIENTRY 256_mesa_BlendEquation( GLenum mode ) 257{ 258 GET_CURRENT_CONTEXT(ctx); 259 ASSERT_OUTSIDE_BEGIN_END(ctx); 260 261 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 262 _mesa_debug(ctx, "glBlendEquation %s\n", 263 _mesa_lookup_enum_by_nr(mode)); 264 265 if ( ! _mesa_validate_blend_equation( ctx, mode, GL_FALSE ) ) { 266 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); 267 return; 268 } 269 270 if ( (ctx->Color.BlendEquationRGB == mode) && 271 (ctx->Color.BlendEquationA == mode) ) 272 return; 273 274 FLUSH_VERTICES(ctx, _NEW_COLOR); 275 ctx->Color.BlendEquationRGB = mode; 276 ctx->Color.BlendEquationA = mode; 277 278 /* This is needed to support 1.1's RGB logic ops AND 279 * 1.0's blending logicops. 280 */ 281 ctx->Color._LogicOpEnabled = (ctx->Color.ColorLogicOpEnabled || 282 (ctx->Color.BlendEnabled && 283 mode == GL_LOGIC_OP)); 284 285 if (ctx->Driver.BlendEquationSeparate) 286 (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); 287} 288 289void GLAPIENTRY 290_mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA ) 291{ 292 GET_CURRENT_CONTEXT(ctx); 293 ASSERT_OUTSIDE_BEGIN_END(ctx); 294 295 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 296 _mesa_debug(ctx, "glBlendEquationSeparateEXT %s %s\n", 297 _mesa_lookup_enum_by_nr(modeRGB), 298 _mesa_lookup_enum_by_nr(modeA)); 299 300 if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { 301 _mesa_error(ctx, GL_INVALID_OPERATION, 302 "glBlendEquationSeparateEXT not supported by driver"); 303 return; 304 } 305 306 if ( ! _mesa_validate_blend_equation( ctx, modeRGB, GL_TRUE ) ) { 307 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); 308 return; 309 } 310 311 if ( ! _mesa_validate_blend_equation( ctx, modeA, GL_TRUE ) ) { 312 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); 313 return; 314 } 315 316 317 if ( (ctx->Color.BlendEquationRGB == modeRGB) && 318 (ctx->Color.BlendEquationA == modeA) ) 319 return; 320 321 FLUSH_VERTICES(ctx, _NEW_COLOR); 322 ctx->Color.BlendEquationRGB = modeRGB; 323 ctx->Color.BlendEquationA = modeA; 324 325 /* This is needed to support 1.1's RGB logic ops AND 326 * 1.0's blending logicops. This test is simplified over glBlendEquation 327 * because modeRGB cannot be GL_LOGIC_OP. 328 */ 329 ctx->Color._LogicOpEnabled = (ctx->Color.ColorLogicOpEnabled); 330 331 if (ctx->Driver.BlendEquationSeparate) 332 (*ctx->Driver.BlendEquationSeparate)( ctx, modeRGB, modeA ); 333} 334#endif 335 336 337/** 338 * Set the blending color. 339 * 340 * \param red red color component. 341 * \param green green color component. 342 * \param blue blue color component. 343 * \param alpha alpha color component. 344 * 345 * \sa glBlendColor(). 346 * 347 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a 348 * change, flushes the vertices and notifies the driver via 349 * dd_function_table::BlendColor callback. 350 */ 351void GLAPIENTRY 352_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 353{ 354 GLfloat tmp[4]; 355 GET_CURRENT_CONTEXT(ctx); 356 ASSERT_OUTSIDE_BEGIN_END(ctx); 357 358 tmp[0] = CLAMP( red, 0.0F, 1.0F ); 359 tmp[1] = CLAMP( green, 0.0F, 1.0F ); 360 tmp[2] = CLAMP( blue, 0.0F, 1.0F ); 361 tmp[3] = CLAMP( alpha, 0.0F, 1.0F ); 362 363 if (TEST_EQ_4V(tmp, ctx->Color.BlendColor)) 364 return; 365 366 FLUSH_VERTICES(ctx, _NEW_COLOR); 367 COPY_4FV( ctx->Color.BlendColor, tmp ); 368 369 if (ctx->Driver.BlendColor) 370 (*ctx->Driver.BlendColor)(ctx, tmp); 371} 372 373 374/** 375 * Specify the alpha test function. 376 * 377 * \param func alpha comparison function. 378 * \param ref reference value. 379 * 380 * Verifies the parameters and updates gl_colorbuffer_attrib. 381 * On a change, flushes the vertices and notifies the driver via 382 * dd_function_table::AlphaFunc callback. 383 */ 384void GLAPIENTRY 385_mesa_AlphaFunc( GLenum func, GLclampf ref ) 386{ 387 GET_CURRENT_CONTEXT(ctx); 388 ASSERT_OUTSIDE_BEGIN_END(ctx); 389 390 switch (func) { 391 case GL_NEVER: 392 case GL_LESS: 393 case GL_EQUAL: 394 case GL_LEQUAL: 395 case GL_GREATER: 396 case GL_NOTEQUAL: 397 case GL_GEQUAL: 398 case GL_ALWAYS: 399 ref = CLAMP(ref, 0.0F, 1.0F); 400 401 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRef == ref) 402 return; /* no change */ 403 404 FLUSH_VERTICES(ctx, _NEW_COLOR); 405 ctx->Color.AlphaFunc = func; 406 ctx->Color.AlphaRef = ref; 407 408 if (ctx->Driver.AlphaFunc) 409 ctx->Driver.AlphaFunc(ctx, func, ref); 410 return; 411 412 default: 413 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); 414 return; 415 } 416} 417 418 419/** 420 * Specify a logic pixel operation for color index rendering. 421 * 422 * \param opcode operation. 423 * 424 * Verifies that \p opcode is a valid enum and updates 425gl_colorbuffer_attrib::LogicOp. 426 * On a change, flushes the vertices and notifies the driver via the 427 * dd_function_table::LogicOpcode callback. 428 */ 429void GLAPIENTRY 430_mesa_LogicOp( GLenum opcode ) 431{ 432 GET_CURRENT_CONTEXT(ctx); 433 ASSERT_OUTSIDE_BEGIN_END(ctx); 434 435 switch (opcode) { 436 case GL_CLEAR: 437 case GL_SET: 438 case GL_COPY: 439 case GL_COPY_INVERTED: 440 case GL_NOOP: 441 case GL_INVERT: 442 case GL_AND: 443 case GL_NAND: 444 case GL_OR: 445 case GL_NOR: 446 case GL_XOR: 447 case GL_EQUIV: 448 case GL_AND_REVERSE: 449 case GL_AND_INVERTED: 450 case GL_OR_REVERSE: 451 case GL_OR_INVERTED: 452 break; 453 default: 454 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); 455 return; 456 } 457 458 if (ctx->Color.LogicOp == opcode) 459 return; 460 461 FLUSH_VERTICES(ctx, _NEW_COLOR); 462 ctx->Color.LogicOp = opcode; 463 464 if (ctx->Driver.LogicOpcode) 465 ctx->Driver.LogicOpcode( ctx, opcode ); 466} 467 468#if _HAVE_FULL_GL 469void GLAPIENTRY 470_mesa_IndexMask( GLuint mask ) 471{ 472 GET_CURRENT_CONTEXT(ctx); 473 ASSERT_OUTSIDE_BEGIN_END(ctx); 474 475 if (ctx->Color.IndexMask == mask) 476 return; 477 478 FLUSH_VERTICES(ctx, _NEW_COLOR); 479 ctx->Color.IndexMask = mask; 480 481 if (ctx->Driver.IndexMask) 482 ctx->Driver.IndexMask( ctx, mask ); 483} 484#endif 485 486 487/** 488 * Enable or disable writing of frame buffer color components. 489 * 490 * \param red whether to mask writing of the red color component. 491 * \param green whether to mask writing of the green color component. 492 * \param blue whether to mask writing of the blue color component. 493 * \param alpha whether to mask writing of the alpha color component. 494 * 495 * \sa glColorMask(). 496 * 497 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a 498 * change, flushes the vertices and notifies the driver via the 499 * dd_function_table::ColorMask callback. 500 */ 501void GLAPIENTRY 502_mesa_ColorMask( GLboolean red, GLboolean green, 503 GLboolean blue, GLboolean alpha ) 504{ 505 GET_CURRENT_CONTEXT(ctx); 506 GLubyte tmp[4]; 507 ASSERT_OUTSIDE_BEGIN_END(ctx); 508 509 if (MESA_VERBOSE & VERBOSE_API) 510 _mesa_debug(ctx, "glColorMask %d %d %d %d\n", red, green, blue, alpha); 511 512 /* Shouldn't have any information about channel depth in core mesa 513 * -- should probably store these as the native booleans: 514 */ 515 tmp[RCOMP] = red ? 0xff : 0x0; 516 tmp[GCOMP] = green ? 0xff : 0x0; 517 tmp[BCOMP] = blue ? 0xff : 0x0; 518 tmp[ACOMP] = alpha ? 0xff : 0x0; 519 520 if (TEST_EQ_4UBV(tmp, ctx->Color.ColorMask)) 521 return; 522 523 FLUSH_VERTICES(ctx, _NEW_COLOR); 524 COPY_4UBV(ctx->Color.ColorMask, tmp); 525 526 if (ctx->Driver.ColorMask) 527 ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); 528} 529 530/**********************************************************************/ 531/** \name Initialization */ 532/*@{*/ 533 534/** 535 * Initialization of the context's Color attribute group. 536 * 537 * \param ctx GL context. 538 * 539 * Initializes the related fields in the context color attribute group, 540 * __GLcontextRec::Color. 541 */ 542void _mesa_init_color( GLcontext * ctx ) 543{ 544 /* Color buffer group */ 545 ctx->Color.IndexMask = 0xffffffff; 546 ctx->Color.ColorMask[0] = 0xff; 547 ctx->Color.ColorMask[1] = 0xff; 548 ctx->Color.ColorMask[2] = 0xff; 549 ctx->Color.ColorMask[3] = 0xff; 550 ctx->Color.ClearIndex = 0; 551 ASSIGN_4V( ctx->Color.ClearColor, 0, 0, 0, 0 ); 552 ctx->Color.AlphaEnabled = GL_FALSE; 553 ctx->Color.AlphaFunc = GL_ALWAYS; 554 ctx->Color.AlphaRef = 0; 555 ctx->Color.BlendEnabled = GL_FALSE; 556 ctx->Color.BlendSrcRGB = GL_ONE; 557 ctx->Color.BlendDstRGB = GL_ZERO; 558 ctx->Color.BlendSrcA = GL_ONE; 559 ctx->Color.BlendDstA = GL_ZERO; 560 ctx->Color.BlendEquationRGB = GL_FUNC_ADD; 561 ctx->Color.BlendEquationA = GL_FUNC_ADD; 562 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); 563 ctx->Color.IndexLogicOpEnabled = GL_FALSE; 564 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 565 ctx->Color._LogicOpEnabled = GL_FALSE; 566 ctx->Color.LogicOp = GL_COPY; 567 ctx->Color.DitherFlag = GL_TRUE; 568 569 if (ctx->Visual.doubleBufferMode) { 570 ctx->Color.DrawBuffer[0] = GL_BACK; 571 ctx->Color._DrawDestMask[0] = DD_BACK_LEFT_BIT; 572 } 573 else { 574 ctx->Color.DrawBuffer[0] = GL_FRONT; 575 ctx->Color._DrawDestMask[0] = DD_FRONT_LEFT_BIT; 576 } 577} 578 579/*@}*/ 580