blend.c revision c1f859d4
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 "context.h" 35#include "enums.h" 36#include "macros.h" 37#include "mtypes.h" 38#include "glapi/glapitable.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 */ 49void GLAPIENTRY 50_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) 51{ 52 _mesa_BlendFuncSeparateEXT(sfactor, dfactor, sfactor, dfactor); 53} 54 55 56/** 57 * Process GL_EXT_blend_func_separate(). 58 * 59 * \param sfactorRGB RGB source factor operator. 60 * \param dfactorRGB RGB destination factor operator. 61 * \param sfactorA alpha source factor operator. 62 * \param dfactorA alpha destination factor operator. 63 * 64 * Verifies the parameters and updates gl_colorbuffer_attrib. 65 * On a change, flush the vertices and notify the driver via 66 * dd_function_table::BlendFuncSeparate. 67 */ 68void GLAPIENTRY 69_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, 70 GLenum sfactorA, GLenum dfactorA ) 71{ 72 GET_CURRENT_CONTEXT(ctx); 73 ASSERT_OUTSIDE_BEGIN_END(ctx); 74 75 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 76 _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", 77 _mesa_lookup_enum_by_nr(sfactorRGB), 78 _mesa_lookup_enum_by_nr(dfactorRGB), 79 _mesa_lookup_enum_by_nr(sfactorA), 80 _mesa_lookup_enum_by_nr(dfactorA)); 81 82 switch (sfactorRGB) { 83 case GL_SRC_COLOR: 84 case GL_ONE_MINUS_SRC_COLOR: 85 if (!ctx->Extensions.NV_blend_square) { 86 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorRGB)"); 87 return; 88 } 89 /* fall-through */ 90 case GL_ZERO: 91 case GL_ONE: 92 case GL_DST_COLOR: 93 case GL_ONE_MINUS_DST_COLOR: 94 case GL_SRC_ALPHA: 95 case GL_ONE_MINUS_SRC_ALPHA: 96 case GL_DST_ALPHA: 97 case GL_ONE_MINUS_DST_ALPHA: 98 case GL_SRC_ALPHA_SATURATE: 99 case GL_CONSTANT_COLOR: 100 case GL_ONE_MINUS_CONSTANT_COLOR: 101 case GL_CONSTANT_ALPHA: 102 case GL_ONE_MINUS_CONSTANT_ALPHA: 103 break; 104 default: 105 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorRGB)"); 106 return; 107 } 108 109 switch (dfactorRGB) { 110 case GL_DST_COLOR: 111 case GL_ONE_MINUS_DST_COLOR: 112 if (!ctx->Extensions.NV_blend_square) { 113 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorRGB)"); 114 return; 115 } 116 /* fall-through */ 117 case GL_ZERO: 118 case GL_ONE: 119 case GL_SRC_COLOR: 120 case GL_ONE_MINUS_SRC_COLOR: 121 case GL_SRC_ALPHA: 122 case GL_ONE_MINUS_SRC_ALPHA: 123 case GL_DST_ALPHA: 124 case GL_ONE_MINUS_DST_ALPHA: 125 case GL_CONSTANT_COLOR: 126 case GL_ONE_MINUS_CONSTANT_COLOR: 127 case GL_CONSTANT_ALPHA: 128 case GL_ONE_MINUS_CONSTANT_ALPHA: 129 break; 130 default: 131 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorRGB)"); 132 return; 133 } 134 135 switch (sfactorA) { 136 case GL_SRC_COLOR: 137 case GL_ONE_MINUS_SRC_COLOR: 138 if (!ctx->Extensions.NV_blend_square) { 139 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorA)"); 140 return; 141 } 142 /* fall-through */ 143 case GL_ZERO: 144 case GL_ONE: 145 case GL_DST_COLOR: 146 case GL_ONE_MINUS_DST_COLOR: 147 case GL_SRC_ALPHA: 148 case GL_ONE_MINUS_SRC_ALPHA: 149 case GL_DST_ALPHA: 150 case GL_ONE_MINUS_DST_ALPHA: 151 case GL_SRC_ALPHA_SATURATE: 152 case GL_CONSTANT_COLOR: 153 case GL_ONE_MINUS_CONSTANT_COLOR: 154 case GL_CONSTANT_ALPHA: 155 case GL_ONE_MINUS_CONSTANT_ALPHA: 156 break; 157 default: 158 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorA)"); 159 return; 160 } 161 162 switch (dfactorA) { 163 case GL_DST_COLOR: 164 case GL_ONE_MINUS_DST_COLOR: 165 if (!ctx->Extensions.NV_blend_square) { 166 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorA)"); 167 return; 168 } 169 /* fall-through */ 170 case GL_ZERO: 171 case GL_ONE: 172 case GL_SRC_COLOR: 173 case GL_ONE_MINUS_SRC_COLOR: 174 case GL_SRC_ALPHA: 175 case GL_ONE_MINUS_SRC_ALPHA: 176 case GL_DST_ALPHA: 177 case GL_ONE_MINUS_DST_ALPHA: 178 case GL_CONSTANT_COLOR: 179 case GL_ONE_MINUS_CONSTANT_COLOR: 180 case GL_CONSTANT_ALPHA: 181 case GL_ONE_MINUS_CONSTANT_ALPHA: 182 break; 183 default: 184 _mesa_error( ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorA)" ); 185 return; 186 } 187 188 if (ctx->Color.BlendSrcRGB == sfactorRGB && 189 ctx->Color.BlendDstRGB == dfactorRGB && 190 ctx->Color.BlendSrcA == sfactorA && 191 ctx->Color.BlendDstA == dfactorA) 192 return; 193 194 FLUSH_VERTICES(ctx, _NEW_COLOR); 195 196 ctx->Color.BlendSrcRGB = sfactorRGB; 197 ctx->Color.BlendDstRGB = dfactorRGB; 198 ctx->Color.BlendSrcA = sfactorA; 199 ctx->Color.BlendDstA = dfactorA; 200 201 if (ctx->Driver.BlendFuncSeparate) { 202 (*ctx->Driver.BlendFuncSeparate)( ctx, sfactorRGB, dfactorRGB, 203 sfactorA, dfactorA ); 204 } 205} 206 207 208#if _HAVE_FULL_GL 209 210static GLboolean 211_mesa_validate_blend_equation( GLcontext *ctx, 212 GLenum mode, GLboolean is_separate ) 213{ 214 switch (mode) { 215 case GL_FUNC_ADD: 216 break; 217 case GL_MIN: 218 case GL_MAX: 219 if (!ctx->Extensions.EXT_blend_minmax && 220 !ctx->Extensions.ARB_imaging) { 221 return GL_FALSE; 222 } 223 break; 224 /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter. 225 */ 226 case GL_LOGIC_OP: 227 if (!ctx->Extensions.EXT_blend_logic_op || is_separate) { 228 return GL_FALSE; 229 } 230 break; 231 case GL_FUNC_SUBTRACT: 232 case GL_FUNC_REVERSE_SUBTRACT: 233 if (!ctx->Extensions.EXT_blend_subtract && 234 !ctx->Extensions.ARB_imaging) { 235 return GL_FALSE; 236 } 237 break; 238 default: 239 return GL_FALSE; 240 } 241 242 return GL_TRUE; 243} 244 245 246/* This is really an extension function! */ 247void GLAPIENTRY 248_mesa_BlendEquation( GLenum mode ) 249{ 250 GET_CURRENT_CONTEXT(ctx); 251 ASSERT_OUTSIDE_BEGIN_END(ctx); 252 253 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 254 _mesa_debug(ctx, "glBlendEquation %s\n", 255 _mesa_lookup_enum_by_nr(mode)); 256 257 if ( ! _mesa_validate_blend_equation( ctx, mode, GL_FALSE ) ) { 258 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); 259 return; 260 } 261 262 if ( (ctx->Color.BlendEquationRGB == mode) && 263 (ctx->Color.BlendEquationA == mode) ) 264 return; 265 266 FLUSH_VERTICES(ctx, _NEW_COLOR); 267 ctx->Color.BlendEquationRGB = mode; 268 ctx->Color.BlendEquationA = mode; 269 270 if (ctx->Driver.BlendEquationSeparate) 271 (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); 272} 273 274 275void GLAPIENTRY 276_mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA ) 277{ 278 GET_CURRENT_CONTEXT(ctx); 279 ASSERT_OUTSIDE_BEGIN_END(ctx); 280 281 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 282 _mesa_debug(ctx, "glBlendEquationSeparateEXT %s %s\n", 283 _mesa_lookup_enum_by_nr(modeRGB), 284 _mesa_lookup_enum_by_nr(modeA)); 285 286 if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { 287 _mesa_error(ctx, GL_INVALID_OPERATION, 288 "glBlendEquationSeparateEXT not supported by driver"); 289 return; 290 } 291 292 if ( ! _mesa_validate_blend_equation( ctx, modeRGB, GL_TRUE ) ) { 293 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); 294 return; 295 } 296 297 if ( ! _mesa_validate_blend_equation( ctx, modeA, GL_TRUE ) ) { 298 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); 299 return; 300 } 301 302 303 if ( (ctx->Color.BlendEquationRGB == modeRGB) && 304 (ctx->Color.BlendEquationA == modeA) ) 305 return; 306 307 FLUSH_VERTICES(ctx, _NEW_COLOR); 308 ctx->Color.BlendEquationRGB = modeRGB; 309 ctx->Color.BlendEquationA = modeA; 310 311 if (ctx->Driver.BlendEquationSeparate) 312 (*ctx->Driver.BlendEquationSeparate)( ctx, modeRGB, modeA ); 313} 314#endif 315 316 317/** 318 * Set the blending color. 319 * 320 * \param red red color component. 321 * \param green green color component. 322 * \param blue blue color component. 323 * \param alpha alpha color component. 324 * 325 * \sa glBlendColor(). 326 * 327 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a 328 * change, flushes the vertices and notifies the driver via 329 * dd_function_table::BlendColor callback. 330 */ 331void GLAPIENTRY 332_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 333{ 334 GLfloat tmp[4]; 335 GET_CURRENT_CONTEXT(ctx); 336 ASSERT_OUTSIDE_BEGIN_END(ctx); 337 338 tmp[0] = CLAMP( red, 0.0F, 1.0F ); 339 tmp[1] = CLAMP( green, 0.0F, 1.0F ); 340 tmp[2] = CLAMP( blue, 0.0F, 1.0F ); 341 tmp[3] = CLAMP( alpha, 0.0F, 1.0F ); 342 343 if (TEST_EQ_4V(tmp, ctx->Color.BlendColor)) 344 return; 345 346 FLUSH_VERTICES(ctx, _NEW_COLOR); 347 COPY_4FV( ctx->Color.BlendColor, tmp ); 348 349 if (ctx->Driver.BlendColor) 350 (*ctx->Driver.BlendColor)(ctx, tmp); 351} 352 353 354/** 355 * Specify the alpha test function. 356 * 357 * \param func alpha comparison function. 358 * \param ref reference value. 359 * 360 * Verifies the parameters and updates gl_colorbuffer_attrib. 361 * On a change, flushes the vertices and notifies the driver via 362 * dd_function_table::AlphaFunc callback. 363 */ 364void GLAPIENTRY 365_mesa_AlphaFunc( GLenum func, GLclampf ref ) 366{ 367 GET_CURRENT_CONTEXT(ctx); 368 ASSERT_OUTSIDE_BEGIN_END(ctx); 369 370 switch (func) { 371 case GL_NEVER: 372 case GL_LESS: 373 case GL_EQUAL: 374 case GL_LEQUAL: 375 case GL_GREATER: 376 case GL_NOTEQUAL: 377 case GL_GEQUAL: 378 case GL_ALWAYS: 379 ref = CLAMP(ref, 0.0F, 1.0F); 380 381 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRef == ref) 382 return; /* no change */ 383 384 FLUSH_VERTICES(ctx, _NEW_COLOR); 385 ctx->Color.AlphaFunc = func; 386 ctx->Color.AlphaRef = ref; 387 388 if (ctx->Driver.AlphaFunc) 389 ctx->Driver.AlphaFunc(ctx, func, ref); 390 return; 391 392 default: 393 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); 394 return; 395 } 396} 397 398 399/** 400 * Specify a logic pixel operation for color index rendering. 401 * 402 * \param opcode operation. 403 * 404 * Verifies that \p opcode is a valid enum and updates 405gl_colorbuffer_attrib::LogicOp. 406 * On a change, flushes the vertices and notifies the driver via the 407 * dd_function_table::LogicOpcode callback. 408 */ 409void GLAPIENTRY 410_mesa_LogicOp( GLenum opcode ) 411{ 412 GET_CURRENT_CONTEXT(ctx); 413 ASSERT_OUTSIDE_BEGIN_END(ctx); 414 415 switch (opcode) { 416 case GL_CLEAR: 417 case GL_SET: 418 case GL_COPY: 419 case GL_COPY_INVERTED: 420 case GL_NOOP: 421 case GL_INVERT: 422 case GL_AND: 423 case GL_NAND: 424 case GL_OR: 425 case GL_NOR: 426 case GL_XOR: 427 case GL_EQUIV: 428 case GL_AND_REVERSE: 429 case GL_AND_INVERTED: 430 case GL_OR_REVERSE: 431 case GL_OR_INVERTED: 432 break; 433 default: 434 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); 435 return; 436 } 437 438 if (ctx->Color.LogicOp == opcode) 439 return; 440 441 FLUSH_VERTICES(ctx, _NEW_COLOR); 442 ctx->Color.LogicOp = opcode; 443 444 if (ctx->Driver.LogicOpcode) 445 ctx->Driver.LogicOpcode( ctx, opcode ); 446} 447 448#if _HAVE_FULL_GL 449void GLAPIENTRY 450_mesa_IndexMask( GLuint mask ) 451{ 452 GET_CURRENT_CONTEXT(ctx); 453 ASSERT_OUTSIDE_BEGIN_END(ctx); 454 455 if (ctx->Color.IndexMask == mask) 456 return; 457 458 FLUSH_VERTICES(ctx, _NEW_COLOR); 459 ctx->Color.IndexMask = mask; 460 461 if (ctx->Driver.IndexMask) 462 ctx->Driver.IndexMask( ctx, mask ); 463} 464#endif 465 466 467/** 468 * Enable or disable writing of frame buffer color components. 469 * 470 * \param red whether to mask writing of the red color component. 471 * \param green whether to mask writing of the green color component. 472 * \param blue whether to mask writing of the blue color component. 473 * \param alpha whether to mask writing of the alpha color component. 474 * 475 * \sa glColorMask(). 476 * 477 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a 478 * change, flushes the vertices and notifies the driver via the 479 * dd_function_table::ColorMask callback. 480 */ 481void GLAPIENTRY 482_mesa_ColorMask( GLboolean red, GLboolean green, 483 GLboolean blue, GLboolean alpha ) 484{ 485 GET_CURRENT_CONTEXT(ctx); 486 GLubyte tmp[4]; 487 ASSERT_OUTSIDE_BEGIN_END(ctx); 488 489 if (MESA_VERBOSE & VERBOSE_API) 490 _mesa_debug(ctx, "glColorMask %d %d %d %d\n", red, green, blue, alpha); 491 492 /* Shouldn't have any information about channel depth in core mesa 493 * -- should probably store these as the native booleans: 494 */ 495 tmp[RCOMP] = red ? 0xff : 0x0; 496 tmp[GCOMP] = green ? 0xff : 0x0; 497 tmp[BCOMP] = blue ? 0xff : 0x0; 498 tmp[ACOMP] = alpha ? 0xff : 0x0; 499 500 if (TEST_EQ_4UBV(tmp, ctx->Color.ColorMask)) 501 return; 502 503 FLUSH_VERTICES(ctx, _NEW_COLOR); 504 COPY_4UBV(ctx->Color.ColorMask, tmp); 505 506 if (ctx->Driver.ColorMask) 507 ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); 508} 509 510 511extern void GLAPIENTRY 512_mesa_ClampColorARB(GLenum target, GLenum clamp) 513{ 514 GET_CURRENT_CONTEXT(ctx); 515 516 ASSERT_OUTSIDE_BEGIN_END(ctx); 517 518 if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { 519 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); 520 return; 521 } 522 523 switch (target) { 524 case GL_CLAMP_VERTEX_COLOR_ARB: 525 ctx->Light.ClampVertexColor = clamp; 526 break; 527 case GL_CLAMP_FRAGMENT_COLOR_ARB: 528 ctx->Color.ClampFragmentColor = clamp; 529 break; 530 case GL_CLAMP_READ_COLOR_ARB: 531 ctx->Color.ClampReadColor = clamp; 532 break; 533 default: 534 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)"); 535 return; 536 } 537} 538 539 540 541 542/**********************************************************************/ 543/** \name Initialization */ 544/*@{*/ 545 546/** 547 * Initialization of the context's Color attribute group. 548 * 549 * \param ctx GL context. 550 * 551 * Initializes the related fields in the context color attribute group, 552 * __GLcontextRec::Color. 553 */ 554void _mesa_init_color( GLcontext * ctx ) 555{ 556 /* Color buffer group */ 557 ctx->Color.IndexMask = ~0u; 558 ctx->Color.ColorMask[0] = 0xff; 559 ctx->Color.ColorMask[1] = 0xff; 560 ctx->Color.ColorMask[2] = 0xff; 561 ctx->Color.ColorMask[3] = 0xff; 562 ctx->Color.ClearIndex = 0; 563 ASSIGN_4V( ctx->Color.ClearColor, 0, 0, 0, 0 ); 564 ctx->Color.AlphaEnabled = GL_FALSE; 565 ctx->Color.AlphaFunc = GL_ALWAYS; 566 ctx->Color.AlphaRef = 0; 567 ctx->Color.BlendEnabled = GL_FALSE; 568 ctx->Color.BlendSrcRGB = GL_ONE; 569 ctx->Color.BlendDstRGB = GL_ZERO; 570 ctx->Color.BlendSrcA = GL_ONE; 571 ctx->Color.BlendDstA = GL_ZERO; 572 ctx->Color.BlendEquationRGB = GL_FUNC_ADD; 573 ctx->Color.BlendEquationA = GL_FUNC_ADD; 574 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); 575 ctx->Color.IndexLogicOpEnabled = GL_FALSE; 576 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 577 ctx->Color._LogicOpEnabled = GL_FALSE; 578 ctx->Color.LogicOp = GL_COPY; 579 ctx->Color.DitherFlag = GL_TRUE; 580 581 if (ctx->Visual.doubleBufferMode) { 582 ctx->Color.DrawBuffer[0] = GL_BACK; 583 } 584 else { 585 ctx->Color.DrawBuffer[0] = GL_FRONT; 586 } 587 588 ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; 589 ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; 590} 591 592/*@}*/ 593