blend.c revision 7117f1b4
1/** 2 * \file blend.c 3 * Blending operations. 4 */ 5 6/* 7 * Mesa 3-D graphics library 8 * Version: 6.5.1 9 * 10 * Copyright (C) 1999-2006 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 if (ctx->Driver.BlendEquationSeparate) 279 (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); 280} 281 282 283void GLAPIENTRY 284_mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA ) 285{ 286 GET_CURRENT_CONTEXT(ctx); 287 ASSERT_OUTSIDE_BEGIN_END(ctx); 288 289 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 290 _mesa_debug(ctx, "glBlendEquationSeparateEXT %s %s\n", 291 _mesa_lookup_enum_by_nr(modeRGB), 292 _mesa_lookup_enum_by_nr(modeA)); 293 294 if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { 295 _mesa_error(ctx, GL_INVALID_OPERATION, 296 "glBlendEquationSeparateEXT not supported by driver"); 297 return; 298 } 299 300 if ( ! _mesa_validate_blend_equation( ctx, modeRGB, GL_TRUE ) ) { 301 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); 302 return; 303 } 304 305 if ( ! _mesa_validate_blend_equation( ctx, modeA, GL_TRUE ) ) { 306 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); 307 return; 308 } 309 310 311 if ( (ctx->Color.BlendEquationRGB == modeRGB) && 312 (ctx->Color.BlendEquationA == modeA) ) 313 return; 314 315 FLUSH_VERTICES(ctx, _NEW_COLOR); 316 ctx->Color.BlendEquationRGB = modeRGB; 317 ctx->Color.BlendEquationA = modeA; 318 319 if (ctx->Driver.BlendEquationSeparate) 320 (*ctx->Driver.BlendEquationSeparate)( ctx, modeRGB, modeA ); 321} 322#endif 323 324 325/** 326 * Set the blending color. 327 * 328 * \param red red color component. 329 * \param green green color component. 330 * \param blue blue color component. 331 * \param alpha alpha color component. 332 * 333 * \sa glBlendColor(). 334 * 335 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a 336 * change, flushes the vertices and notifies the driver via 337 * dd_function_table::BlendColor callback. 338 */ 339void GLAPIENTRY 340_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 341{ 342 GLfloat tmp[4]; 343 GET_CURRENT_CONTEXT(ctx); 344 ASSERT_OUTSIDE_BEGIN_END(ctx); 345 346 tmp[0] = CLAMP( red, 0.0F, 1.0F ); 347 tmp[1] = CLAMP( green, 0.0F, 1.0F ); 348 tmp[2] = CLAMP( blue, 0.0F, 1.0F ); 349 tmp[3] = CLAMP( alpha, 0.0F, 1.0F ); 350 351 if (TEST_EQ_4V(tmp, ctx->Color.BlendColor)) 352 return; 353 354 FLUSH_VERTICES(ctx, _NEW_COLOR); 355 COPY_4FV( ctx->Color.BlendColor, tmp ); 356 357 if (ctx->Driver.BlendColor) 358 (*ctx->Driver.BlendColor)(ctx, tmp); 359} 360 361 362/** 363 * Specify the alpha test function. 364 * 365 * \param func alpha comparison function. 366 * \param ref reference value. 367 * 368 * Verifies the parameters and updates gl_colorbuffer_attrib. 369 * On a change, flushes the vertices and notifies the driver via 370 * dd_function_table::AlphaFunc callback. 371 */ 372void GLAPIENTRY 373_mesa_AlphaFunc( GLenum func, GLclampf ref ) 374{ 375 GET_CURRENT_CONTEXT(ctx); 376 ASSERT_OUTSIDE_BEGIN_END(ctx); 377 378 switch (func) { 379 case GL_NEVER: 380 case GL_LESS: 381 case GL_EQUAL: 382 case GL_LEQUAL: 383 case GL_GREATER: 384 case GL_NOTEQUAL: 385 case GL_GEQUAL: 386 case GL_ALWAYS: 387 ref = CLAMP(ref, 0.0F, 1.0F); 388 389 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRef == ref) 390 return; /* no change */ 391 392 FLUSH_VERTICES(ctx, _NEW_COLOR); 393 ctx->Color.AlphaFunc = func; 394 ctx->Color.AlphaRef = ref; 395 396 if (ctx->Driver.AlphaFunc) 397 ctx->Driver.AlphaFunc(ctx, func, ref); 398 return; 399 400 default: 401 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); 402 return; 403 } 404} 405 406 407/** 408 * Specify a logic pixel operation for color index rendering. 409 * 410 * \param opcode operation. 411 * 412 * Verifies that \p opcode is a valid enum and updates 413gl_colorbuffer_attrib::LogicOp. 414 * On a change, flushes the vertices and notifies the driver via the 415 * dd_function_table::LogicOpcode callback. 416 */ 417void GLAPIENTRY 418_mesa_LogicOp( GLenum opcode ) 419{ 420 GET_CURRENT_CONTEXT(ctx); 421 ASSERT_OUTSIDE_BEGIN_END(ctx); 422 423 switch (opcode) { 424 case GL_CLEAR: 425 case GL_SET: 426 case GL_COPY: 427 case GL_COPY_INVERTED: 428 case GL_NOOP: 429 case GL_INVERT: 430 case GL_AND: 431 case GL_NAND: 432 case GL_OR: 433 case GL_NOR: 434 case GL_XOR: 435 case GL_EQUIV: 436 case GL_AND_REVERSE: 437 case GL_AND_INVERTED: 438 case GL_OR_REVERSE: 439 case GL_OR_INVERTED: 440 break; 441 default: 442 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); 443 return; 444 } 445 446 if (ctx->Color.LogicOp == opcode) 447 return; 448 449 FLUSH_VERTICES(ctx, _NEW_COLOR); 450 ctx->Color.LogicOp = opcode; 451 452 if (ctx->Driver.LogicOpcode) 453 ctx->Driver.LogicOpcode( ctx, opcode ); 454} 455 456#if _HAVE_FULL_GL 457void GLAPIENTRY 458_mesa_IndexMask( GLuint mask ) 459{ 460 GET_CURRENT_CONTEXT(ctx); 461 ASSERT_OUTSIDE_BEGIN_END(ctx); 462 463 if (ctx->Color.IndexMask == mask) 464 return; 465 466 FLUSH_VERTICES(ctx, _NEW_COLOR); 467 ctx->Color.IndexMask = mask; 468 469 if (ctx->Driver.IndexMask) 470 ctx->Driver.IndexMask( ctx, mask ); 471} 472#endif 473 474 475/** 476 * Enable or disable writing of frame buffer color components. 477 * 478 * \param red whether to mask writing of the red color component. 479 * \param green whether to mask writing of the green color component. 480 * \param blue whether to mask writing of the blue color component. 481 * \param alpha whether to mask writing of the alpha color component. 482 * 483 * \sa glColorMask(). 484 * 485 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a 486 * change, flushes the vertices and notifies the driver via the 487 * dd_function_table::ColorMask callback. 488 */ 489void GLAPIENTRY 490_mesa_ColorMask( GLboolean red, GLboolean green, 491 GLboolean blue, GLboolean alpha ) 492{ 493 GET_CURRENT_CONTEXT(ctx); 494 GLubyte tmp[4]; 495 ASSERT_OUTSIDE_BEGIN_END(ctx); 496 497 if (MESA_VERBOSE & VERBOSE_API) 498 _mesa_debug(ctx, "glColorMask %d %d %d %d\n", red, green, blue, alpha); 499 500 /* Shouldn't have any information about channel depth in core mesa 501 * -- should probably store these as the native booleans: 502 */ 503 tmp[RCOMP] = red ? 0xff : 0x0; 504 tmp[GCOMP] = green ? 0xff : 0x0; 505 tmp[BCOMP] = blue ? 0xff : 0x0; 506 tmp[ACOMP] = alpha ? 0xff : 0x0; 507 508 if (TEST_EQ_4UBV(tmp, ctx->Color.ColorMask)) 509 return; 510 511 FLUSH_VERTICES(ctx, _NEW_COLOR); 512 COPY_4UBV(ctx->Color.ColorMask, tmp); 513 514 if (ctx->Driver.ColorMask) 515 ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); 516} 517 518 519extern void GLAPIENTRY 520_mesa_ClampColorARB(GLenum target, GLenum clamp) 521{ 522 GET_CURRENT_CONTEXT(ctx); 523 524 ASSERT_OUTSIDE_BEGIN_END(ctx); 525 526 if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { 527 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); 528 return; 529 } 530 531 switch (target) { 532 case GL_CLAMP_VERTEX_COLOR_ARB: 533 ctx->Light.ClampVertexColor = clamp; 534 break; 535 case GL_CLAMP_FRAGMENT_COLOR_ARB: 536 ctx->Color.ClampFragmentColor = clamp; 537 break; 538 case GL_CLAMP_READ_COLOR_ARB: 539 ctx->Color.ClampReadColor = clamp; 540 break; 541 default: 542 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)"); 543 return; 544 } 545} 546 547 548 549 550/**********************************************************************/ 551/** \name Initialization */ 552/*@{*/ 553 554/** 555 * Initialization of the context's Color attribute group. 556 * 557 * \param ctx GL context. 558 * 559 * Initializes the related fields in the context color attribute group, 560 * __GLcontextRec::Color. 561 */ 562void _mesa_init_color( GLcontext * ctx ) 563{ 564 /* Color buffer group */ 565 ctx->Color.IndexMask = ~0u; 566 ctx->Color.ColorMask[0] = 0xff; 567 ctx->Color.ColorMask[1] = 0xff; 568 ctx->Color.ColorMask[2] = 0xff; 569 ctx->Color.ColorMask[3] = 0xff; 570 ctx->Color.ClearIndex = 0; 571 ASSIGN_4V( ctx->Color.ClearColor, 0, 0, 0, 0 ); 572 ctx->Color.AlphaEnabled = GL_FALSE; 573 ctx->Color.AlphaFunc = GL_ALWAYS; 574 ctx->Color.AlphaRef = 0; 575 ctx->Color.BlendEnabled = GL_FALSE; 576 ctx->Color.BlendSrcRGB = GL_ONE; 577 ctx->Color.BlendDstRGB = GL_ZERO; 578 ctx->Color.BlendSrcA = GL_ONE; 579 ctx->Color.BlendDstA = GL_ZERO; 580 ctx->Color.BlendEquationRGB = GL_FUNC_ADD; 581 ctx->Color.BlendEquationA = GL_FUNC_ADD; 582 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); 583 ctx->Color.IndexLogicOpEnabled = GL_FALSE; 584 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 585 ctx->Color._LogicOpEnabled = GL_FALSE; 586 ctx->Color.LogicOp = GL_COPY; 587 ctx->Color.DitherFlag = GL_TRUE; 588 589 if (ctx->Visual.doubleBufferMode) { 590 ctx->Color.DrawBuffer[0] = GL_BACK; 591 } 592 else { 593 ctx->Color.DrawBuffer[0] = GL_FRONT; 594 } 595 596 ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; 597 ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; 598} 599 600/*@}*/ 601