blend.c revision 2f11e92cef51c88a09bc778e2ceca4ab50cf0017
1/** 2 * \file blend.c 3 * Blending operations. 4 */ 5 6/* 7 * Mesa 3-D graphics library 8 * 9 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 10 * 11 * Permission is hereby granted, free of charge, to any person obtaining a 12 * copy of this software and associated documentation files (the "Software"), 13 * to deal in the Software without restriction, including without limitation 14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15 * and/or sell copies of the Software, and to permit persons to whom the 16 * Software is furnished to do so, subject to the following conditions: 17 * 18 * The above copyright notice and this permission notice shall be included 19 * in all copies or substantial portions of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 * 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 39 40 41/** 42 * Check if given blend source factor is legal. 43 * \return GL_TRUE if legal, GL_FALSE otherwise. 44 */ 45static GLboolean 46legal_src_factor(const struct gl_context *ctx, GLenum factor) 47{ 48 switch (factor) { 49 case GL_SRC_COLOR: 50 case GL_ONE_MINUS_SRC_COLOR: 51 case GL_ZERO: 52 case GL_ONE: 53 case GL_DST_COLOR: 54 case GL_ONE_MINUS_DST_COLOR: 55 case GL_SRC_ALPHA: 56 case GL_ONE_MINUS_SRC_ALPHA: 57 case GL_DST_ALPHA: 58 case GL_ONE_MINUS_DST_ALPHA: 59 case GL_SRC_ALPHA_SATURATE: 60 return GL_TRUE; 61 case GL_CONSTANT_COLOR: 62 case GL_ONE_MINUS_CONSTANT_COLOR: 63 case GL_CONSTANT_ALPHA: 64 case GL_ONE_MINUS_CONSTANT_ALPHA: 65 return _mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES2; 66 case GL_SRC1_COLOR: 67 case GL_SRC1_ALPHA: 68 case GL_ONE_MINUS_SRC1_COLOR: 69 case GL_ONE_MINUS_SRC1_ALPHA: 70 return _mesa_is_desktop_gl(ctx) 71 && ctx->Extensions.ARB_blend_func_extended; 72 default: 73 return GL_FALSE; 74 } 75} 76 77 78/** 79 * Check if given blend destination factor is legal. 80 * \return GL_TRUE if legal, GL_FALSE otherwise. 81 */ 82static GLboolean 83legal_dst_factor(const struct gl_context *ctx, GLenum factor) 84{ 85 switch (factor) { 86 case GL_DST_COLOR: 87 case GL_ONE_MINUS_DST_COLOR: 88 case GL_ZERO: 89 case GL_ONE: 90 case GL_SRC_COLOR: 91 case GL_ONE_MINUS_SRC_COLOR: 92 case GL_SRC_ALPHA: 93 case GL_ONE_MINUS_SRC_ALPHA: 94 case GL_DST_ALPHA: 95 case GL_ONE_MINUS_DST_ALPHA: 96 return GL_TRUE; 97 case GL_CONSTANT_COLOR: 98 case GL_ONE_MINUS_CONSTANT_COLOR: 99 case GL_CONSTANT_ALPHA: 100 case GL_ONE_MINUS_CONSTANT_ALPHA: 101 return _mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES2; 102 case GL_SRC_ALPHA_SATURATE: 103 return (_mesa_is_desktop_gl(ctx) 104 && ctx->Extensions.ARB_blend_func_extended) 105 || _mesa_is_gles3(ctx); 106 case GL_SRC1_COLOR: 107 case GL_SRC1_ALPHA: 108 case GL_ONE_MINUS_SRC1_COLOR: 109 case GL_ONE_MINUS_SRC1_ALPHA: 110 return _mesa_is_desktop_gl(ctx) 111 && ctx->Extensions.ARB_blend_func_extended; 112 default: 113 return GL_FALSE; 114 } 115} 116 117 118/** 119 * Check if src/dest RGB/A blend factors are legal. If not generate 120 * a GL error. 121 * \return GL_TRUE if factors are legal, GL_FALSE otherwise. 122 */ 123static GLboolean 124validate_blend_factors(struct gl_context *ctx, const char *func, 125 GLenum sfactorRGB, GLenum dfactorRGB, 126 GLenum sfactorA, GLenum dfactorA) 127{ 128 if (!legal_src_factor(ctx, sfactorRGB)) { 129 _mesa_error(ctx, GL_INVALID_ENUM, 130 "%s(sfactorRGB = %s)", func, 131 _mesa_enum_to_string(sfactorRGB)); 132 return GL_FALSE; 133 } 134 135 if (!legal_dst_factor(ctx, dfactorRGB)) { 136 _mesa_error(ctx, GL_INVALID_ENUM, 137 "%s(dfactorRGB = %s)", func, 138 _mesa_enum_to_string(dfactorRGB)); 139 return GL_FALSE; 140 } 141 142 if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) { 143 _mesa_error(ctx, GL_INVALID_ENUM, 144 "%s(sfactorA = %s)", func, 145 _mesa_enum_to_string(sfactorA)); 146 return GL_FALSE; 147 } 148 149 if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) { 150 _mesa_error(ctx, GL_INVALID_ENUM, 151 "%s(dfactorA = %s)", func, 152 _mesa_enum_to_string(dfactorA)); 153 return GL_FALSE; 154 } 155 156 return GL_TRUE; 157} 158 159 160/** 161 * Specify the blending operation. 162 * 163 * \param sfactor source factor operator. 164 * \param dfactor destination factor operator. 165 * 166 * \sa glBlendFunc, glBlendFuncSeparateEXT 167 */ 168void GLAPIENTRY 169_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) 170{ 171 _mesa_BlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); 172} 173 174static GLboolean 175blend_factor_is_dual_src(GLenum factor) 176{ 177 return (factor == GL_SRC1_COLOR || 178 factor == GL_SRC1_ALPHA || 179 factor == GL_ONE_MINUS_SRC1_COLOR || 180 factor == GL_ONE_MINUS_SRC1_ALPHA); 181} 182 183static void 184update_uses_dual_src(struct gl_context *ctx, int buf) 185{ 186 ctx->Color.Blend[buf]._UsesDualSrc = 187 (blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcRGB) || 188 blend_factor_is_dual_src(ctx->Color.Blend[buf].DstRGB) || 189 blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcA) || 190 blend_factor_is_dual_src(ctx->Color.Blend[buf].DstA)); 191} 192 193/** 194 * Set the separate blend source/dest factors for all draw buffers. 195 * 196 * \param sfactorRGB RGB source factor operator. 197 * \param dfactorRGB RGB destination factor operator. 198 * \param sfactorA alpha source factor operator. 199 * \param dfactorA alpha destination factor operator. 200 */ 201void GLAPIENTRY 202_mesa_BlendFuncSeparate( GLenum sfactorRGB, GLenum dfactorRGB, 203 GLenum sfactorA, GLenum dfactorA ) 204{ 205 GLuint buf, numBuffers; 206 GLboolean changed; 207 GET_CURRENT_CONTEXT(ctx); 208 209 if (MESA_VERBOSE & VERBOSE_API) 210 _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", 211 _mesa_enum_to_string(sfactorRGB), 212 _mesa_enum_to_string(dfactorRGB), 213 _mesa_enum_to_string(sfactorA), 214 _mesa_enum_to_string(dfactorA)); 215 216 if (!validate_blend_factors(ctx, "glBlendFuncSeparate", 217 sfactorRGB, dfactorRGB, 218 sfactorA, dfactorA)) { 219 return; 220 } 221 222 numBuffers = ctx->Extensions.ARB_draw_buffers_blend 223 ? ctx->Const.MaxDrawBuffers : 1; 224 225 changed = GL_FALSE; 226 for (buf = 0; buf < numBuffers; buf++) { 227 if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB || 228 ctx->Color.Blend[buf].DstRGB != dfactorRGB || 229 ctx->Color.Blend[buf].SrcA != sfactorA || 230 ctx->Color.Blend[buf].DstA != dfactorA) { 231 changed = GL_TRUE; 232 break; 233 } 234 } 235 if (!changed) 236 return; 237 238 FLUSH_VERTICES(ctx, _NEW_COLOR); 239 240 for (buf = 0; buf < numBuffers; buf++) { 241 ctx->Color.Blend[buf].SrcRGB = sfactorRGB; 242 ctx->Color.Blend[buf].DstRGB = dfactorRGB; 243 ctx->Color.Blend[buf].SrcA = sfactorA; 244 ctx->Color.Blend[buf].DstA = dfactorA; 245 update_uses_dual_src(ctx, buf); 246 } 247 ctx->Color._BlendFuncPerBuffer = GL_FALSE; 248 249 if (ctx->Driver.BlendFuncSeparate) { 250 ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB, 251 sfactorA, dfactorA); 252 } 253} 254 255 256/** 257 * Set blend source/dest factors for one color buffer/target. 258 */ 259void GLAPIENTRY 260_mesa_BlendFunciARB(GLuint buf, GLenum sfactor, GLenum dfactor) 261{ 262 _mesa_BlendFuncSeparateiARB(buf, sfactor, dfactor, sfactor, dfactor); 263} 264 265 266/** 267 * Set separate blend source/dest factors for one color buffer/target. 268 */ 269void GLAPIENTRY 270_mesa_BlendFuncSeparateiARB(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB, 271 GLenum sfactorA, GLenum dfactorA) 272{ 273 GET_CURRENT_CONTEXT(ctx); 274 275 if (!ctx->Extensions.ARB_draw_buffers_blend) { 276 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()"); 277 return; 278 } 279 280 if (buf >= ctx->Const.MaxDrawBuffers) { 281 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", 282 buf); 283 return; 284 } 285 286 if (!validate_blend_factors(ctx, "glBlendFuncSeparatei", 287 sfactorRGB, dfactorRGB, 288 sfactorA, dfactorA)) { 289 return; 290 } 291 292 if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB && 293 ctx->Color.Blend[buf].DstRGB == dfactorRGB && 294 ctx->Color.Blend[buf].SrcA == sfactorA && 295 ctx->Color.Blend[buf].DstA == dfactorA) 296 return; /* no change */ 297 298 FLUSH_VERTICES(ctx, _NEW_COLOR); 299 300 ctx->Color.Blend[buf].SrcRGB = sfactorRGB; 301 ctx->Color.Blend[buf].DstRGB = dfactorRGB; 302 ctx->Color.Blend[buf].SrcA = sfactorA; 303 ctx->Color.Blend[buf].DstA = dfactorA; 304 update_uses_dual_src(ctx, buf); 305 ctx->Color._BlendFuncPerBuffer = GL_TRUE; 306 307 if (ctx->Driver.BlendFuncSeparatei) { 308 ctx->Driver.BlendFuncSeparatei(ctx, buf, sfactorRGB, dfactorRGB, 309 sfactorA, dfactorA); 310 } 311} 312 313 314/** 315 * Check if given blend equation is legal. 316 * \return GL_TRUE if legal, GL_FALSE otherwise. 317 */ 318static GLboolean 319legal_blend_equation(const struct gl_context *ctx, GLenum mode) 320{ 321 switch (mode) { 322 case GL_FUNC_ADD: 323 case GL_FUNC_SUBTRACT: 324 case GL_FUNC_REVERSE_SUBTRACT: 325 return GL_TRUE; 326 case GL_MIN: 327 case GL_MAX: 328 return ctx->Extensions.EXT_blend_minmax; 329 default: 330 return GL_FALSE; 331 } 332} 333 334 335/* This is really an extension function! */ 336void GLAPIENTRY 337_mesa_BlendEquation( GLenum mode ) 338{ 339 GLuint buf, numBuffers; 340 GLboolean changed; 341 GET_CURRENT_CONTEXT(ctx); 342 343 if (MESA_VERBOSE & VERBOSE_API) 344 _mesa_debug(ctx, "glBlendEquation(%s)\n", 345 _mesa_enum_to_string(mode)); 346 347 if (!legal_blend_equation(ctx, mode)) { 348 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); 349 return; 350 } 351 352 numBuffers = ctx->Extensions.ARB_draw_buffers_blend 353 ? ctx->Const.MaxDrawBuffers : 1; 354 355 changed = GL_FALSE; 356 for (buf = 0; buf < numBuffers; buf++) { 357 if (ctx->Color.Blend[buf].EquationRGB != mode || 358 ctx->Color.Blend[buf].EquationA != mode) { 359 changed = GL_TRUE; 360 break; 361 } 362 } 363 if (!changed) 364 return; 365 366 FLUSH_VERTICES(ctx, _NEW_COLOR); 367 for (buf = 0; buf < numBuffers; buf++) { 368 ctx->Color.Blend[buf].EquationRGB = mode; 369 ctx->Color.Blend[buf].EquationA = mode; 370 } 371 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 372 373 if (ctx->Driver.BlendEquationSeparate) 374 (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); 375} 376 377 378/** 379 * Set blend equation for one color buffer/target. 380 */ 381void GLAPIENTRY 382_mesa_BlendEquationiARB(GLuint buf, GLenum mode) 383{ 384 GET_CURRENT_CONTEXT(ctx); 385 386 if (MESA_VERBOSE & VERBOSE_API) 387 _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", 388 buf, _mesa_enum_to_string(mode)); 389 390 if (buf >= ctx->Const.MaxDrawBuffers) { 391 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", 392 buf); 393 return; 394 } 395 396 if (!legal_blend_equation(ctx, mode)) { 397 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); 398 return; 399 } 400 401 if (ctx->Color.Blend[buf].EquationRGB == mode && 402 ctx->Color.Blend[buf].EquationA == mode) 403 return; /* no change */ 404 405 FLUSH_VERTICES(ctx, _NEW_COLOR); 406 ctx->Color.Blend[buf].EquationRGB = mode; 407 ctx->Color.Blend[buf].EquationA = mode; 408 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 409 410 if (ctx->Driver.BlendEquationSeparatei) 411 ctx->Driver.BlendEquationSeparatei(ctx, buf, mode, mode); 412} 413 414 415void GLAPIENTRY 416_mesa_BlendEquationSeparate( GLenum modeRGB, GLenum modeA ) 417{ 418 GLuint buf, numBuffers; 419 GLboolean changed; 420 GET_CURRENT_CONTEXT(ctx); 421 422 if (MESA_VERBOSE & VERBOSE_API) 423 _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", 424 _mesa_enum_to_string(modeRGB), 425 _mesa_enum_to_string(modeA)); 426 427 if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { 428 _mesa_error(ctx, GL_INVALID_OPERATION, 429 "glBlendEquationSeparateEXT not supported by driver"); 430 return; 431 } 432 433 if (!legal_blend_equation(ctx, modeRGB)) { 434 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); 435 return; 436 } 437 438 if (!legal_blend_equation(ctx, modeA)) { 439 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); 440 return; 441 } 442 443 numBuffers = ctx->Extensions.ARB_draw_buffers_blend 444 ? ctx->Const.MaxDrawBuffers : 1; 445 446 changed = GL_FALSE; 447 for (buf = 0; buf < numBuffers; buf++) { 448 if (ctx->Color.Blend[buf].EquationRGB != modeRGB || 449 ctx->Color.Blend[buf].EquationA != modeA) { 450 changed = GL_TRUE; 451 break; 452 } 453 } 454 if (!changed) 455 return; 456 457 FLUSH_VERTICES(ctx, _NEW_COLOR); 458 for (buf = 0; buf < numBuffers; buf++) { 459 ctx->Color.Blend[buf].EquationRGB = modeRGB; 460 ctx->Color.Blend[buf].EquationA = modeA; 461 } 462 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 463 464 if (ctx->Driver.BlendEquationSeparate) 465 ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); 466} 467 468 469/** 470 * Set separate blend equations for one color buffer/target. 471 */ 472void GLAPIENTRY 473_mesa_BlendEquationSeparateiARB(GLuint buf, GLenum modeRGB, GLenum modeA) 474{ 475 GET_CURRENT_CONTEXT(ctx); 476 477 if (MESA_VERBOSE & VERBOSE_API) 478 _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, 479 _mesa_enum_to_string(modeRGB), 480 _mesa_enum_to_string(modeA)); 481 482 if (buf >= ctx->Const.MaxDrawBuffers) { 483 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", 484 buf); 485 return; 486 } 487 488 if (!legal_blend_equation(ctx, modeRGB)) { 489 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); 490 return; 491 } 492 493 if (!legal_blend_equation(ctx, modeA)) { 494 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); 495 return; 496 } 497 498 if (ctx->Color.Blend[buf].EquationRGB == modeRGB && 499 ctx->Color.Blend[buf].EquationA == modeA) 500 return; /* no change */ 501 502 FLUSH_VERTICES(ctx, _NEW_COLOR); 503 ctx->Color.Blend[buf].EquationRGB = modeRGB; 504 ctx->Color.Blend[buf].EquationA = modeA; 505 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 506 507 if (ctx->Driver.BlendEquationSeparatei) 508 ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA); 509} 510 511 512/** 513 * Set the blending color. 514 * 515 * \param red red color component. 516 * \param green green color component. 517 * \param blue blue color component. 518 * \param alpha alpha color component. 519 * 520 * \sa glBlendColor(). 521 * 522 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a 523 * change, flushes the vertices and notifies the driver via 524 * dd_function_table::BlendColor callback. 525 */ 526void GLAPIENTRY 527_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 528{ 529 GLfloat tmp[4]; 530 GET_CURRENT_CONTEXT(ctx); 531 532 tmp[0] = red; 533 tmp[1] = green; 534 tmp[2] = blue; 535 tmp[3] = alpha; 536 537 if (TEST_EQ_4V(tmp, ctx->Color.BlendColorUnclamped)) 538 return; 539 540 FLUSH_VERTICES(ctx, _NEW_COLOR); 541 COPY_4FV( ctx->Color.BlendColorUnclamped, tmp ); 542 543 ctx->Color.BlendColor[0] = CLAMP(tmp[0], 0.0F, 1.0F); 544 ctx->Color.BlendColor[1] = CLAMP(tmp[1], 0.0F, 1.0F); 545 ctx->Color.BlendColor[2] = CLAMP(tmp[2], 0.0F, 1.0F); 546 ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F); 547 548 if (ctx->Driver.BlendColor) 549 (*ctx->Driver.BlendColor)(ctx, ctx->Color.BlendColor); 550} 551 552 553/** 554 * Specify the alpha test function. 555 * 556 * \param func alpha comparison function. 557 * \param ref reference value. 558 * 559 * Verifies the parameters and updates gl_colorbuffer_attrib. 560 * On a change, flushes the vertices and notifies the driver via 561 * dd_function_table::AlphaFunc callback. 562 */ 563void GLAPIENTRY 564_mesa_AlphaFunc( GLenum func, GLclampf ref ) 565{ 566 GET_CURRENT_CONTEXT(ctx); 567 568 if (MESA_VERBOSE & VERBOSE_API) 569 _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", 570 _mesa_enum_to_string(func), ref); 571 572 switch (func) { 573 case GL_NEVER: 574 case GL_LESS: 575 case GL_EQUAL: 576 case GL_LEQUAL: 577 case GL_GREATER: 578 case GL_NOTEQUAL: 579 case GL_GEQUAL: 580 case GL_ALWAYS: 581 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref) 582 return; /* no change */ 583 584 FLUSH_VERTICES(ctx, _NEW_COLOR); 585 ctx->Color.AlphaFunc = func; 586 ctx->Color.AlphaRefUnclamped = ref; 587 ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F); 588 589 if (ctx->Driver.AlphaFunc) 590 ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef); 591 return; 592 593 default: 594 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); 595 return; 596 } 597} 598 599 600/** 601 * Specify a logic pixel operation for color index rendering. 602 * 603 * \param opcode operation. 604 * 605 * Verifies that \p opcode is a valid enum and updates 606gl_colorbuffer_attrib::LogicOp. 607 * On a change, flushes the vertices and notifies the driver via the 608 * dd_function_table::LogicOpcode callback. 609 */ 610void GLAPIENTRY 611_mesa_LogicOp( GLenum opcode ) 612{ 613 GET_CURRENT_CONTEXT(ctx); 614 615 if (MESA_VERBOSE & VERBOSE_API) 616 _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_enum_to_string(opcode)); 617 618 switch (opcode) { 619 case GL_CLEAR: 620 case GL_SET: 621 case GL_COPY: 622 case GL_COPY_INVERTED: 623 case GL_NOOP: 624 case GL_INVERT: 625 case GL_AND: 626 case GL_NAND: 627 case GL_OR: 628 case GL_NOR: 629 case GL_XOR: 630 case GL_EQUIV: 631 case GL_AND_REVERSE: 632 case GL_AND_INVERTED: 633 case GL_OR_REVERSE: 634 case GL_OR_INVERTED: 635 break; 636 default: 637 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); 638 return; 639 } 640 641 if (ctx->Color.LogicOp == opcode) 642 return; 643 644 FLUSH_VERTICES(ctx, _NEW_COLOR); 645 ctx->Color.LogicOp = opcode; 646 647 if (ctx->Driver.LogicOpcode) 648 ctx->Driver.LogicOpcode( ctx, opcode ); 649} 650 651 652void GLAPIENTRY 653_mesa_IndexMask( GLuint mask ) 654{ 655 GET_CURRENT_CONTEXT(ctx); 656 657 if (ctx->Color.IndexMask == mask) 658 return; 659 660 FLUSH_VERTICES(ctx, _NEW_COLOR); 661 ctx->Color.IndexMask = mask; 662} 663 664 665/** 666 * Enable or disable writing of frame buffer color components. 667 * 668 * \param red whether to mask writing of the red color component. 669 * \param green whether to mask writing of the green color component. 670 * \param blue whether to mask writing of the blue color component. 671 * \param alpha whether to mask writing of the alpha color component. 672 * 673 * \sa glColorMask(). 674 * 675 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a 676 * change, flushes the vertices and notifies the driver via the 677 * dd_function_table::ColorMask callback. 678 */ 679void GLAPIENTRY 680_mesa_ColorMask( GLboolean red, GLboolean green, 681 GLboolean blue, GLboolean alpha ) 682{ 683 GET_CURRENT_CONTEXT(ctx); 684 GLubyte tmp[4]; 685 GLuint i; 686 GLboolean flushed; 687 688 if (MESA_VERBOSE & VERBOSE_API) 689 _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n", 690 red, green, blue, alpha); 691 692 /* Shouldn't have any information about channel depth in core mesa 693 * -- should probably store these as the native booleans: 694 */ 695 tmp[RCOMP] = red ? 0xff : 0x0; 696 tmp[GCOMP] = green ? 0xff : 0x0; 697 tmp[BCOMP] = blue ? 0xff : 0x0; 698 tmp[ACOMP] = alpha ? 0xff : 0x0; 699 700 flushed = GL_FALSE; 701 for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { 702 if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { 703 if (!flushed) { 704 FLUSH_VERTICES(ctx, _NEW_COLOR); 705 } 706 flushed = GL_TRUE; 707 COPY_4UBV(ctx->Color.ColorMask[i], tmp); 708 } 709 } 710 711 if (ctx->Driver.ColorMask) 712 ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); 713} 714 715 716/** 717 * For GL_EXT_draw_buffers2 and GL3 718 */ 719void GLAPIENTRY 720_mesa_ColorMaski( GLuint buf, GLboolean red, GLboolean green, 721 GLboolean blue, GLboolean alpha ) 722{ 723 GLubyte tmp[4]; 724 GET_CURRENT_CONTEXT(ctx); 725 726 if (MESA_VERBOSE & VERBOSE_API) 727 _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n", 728 buf, red, green, blue, alpha); 729 730 if (buf >= ctx->Const.MaxDrawBuffers) { 731 _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf); 732 return; 733 } 734 735 /* Shouldn't have any information about channel depth in core mesa 736 * -- should probably store these as the native booleans: 737 */ 738 tmp[RCOMP] = red ? 0xff : 0x0; 739 tmp[GCOMP] = green ? 0xff : 0x0; 740 tmp[BCOMP] = blue ? 0xff : 0x0; 741 tmp[ACOMP] = alpha ? 0xff : 0x0; 742 743 if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) 744 return; 745 746 FLUSH_VERTICES(ctx, _NEW_COLOR); 747 COPY_4UBV(ctx->Color.ColorMask[buf], tmp); 748 749 if (ctx->Driver.ColorMaskIndexed) 750 ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha); 751} 752 753 754void GLAPIENTRY 755_mesa_ClampColor(GLenum target, GLenum clamp) 756{ 757 GET_CURRENT_CONTEXT(ctx); 758 759 if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { 760 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); 761 return; 762 } 763 764 switch (target) { 765 case GL_CLAMP_VERTEX_COLOR_ARB: 766 if (ctx->API == API_OPENGL_CORE && 767 !ctx->Extensions.ARB_color_buffer_float) { 768 goto invalid_enum; 769 } 770 FLUSH_VERTICES(ctx, _NEW_LIGHT); 771 ctx->Light.ClampVertexColor = clamp; 772 _mesa_update_clamp_vertex_color(ctx, ctx->DrawBuffer); 773 break; 774 case GL_CLAMP_FRAGMENT_COLOR_ARB: 775 if (ctx->API == API_OPENGL_CORE && 776 !ctx->Extensions.ARB_color_buffer_float) { 777 goto invalid_enum; 778 } 779 FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP); 780 ctx->Color.ClampFragmentColor = clamp; 781 _mesa_update_clamp_fragment_color(ctx, ctx->DrawBuffer); 782 break; 783 case GL_CLAMP_READ_COLOR_ARB: 784 ctx->Color.ClampReadColor = clamp; 785 break; 786 default: 787 goto invalid_enum; 788 } 789 return; 790 791invalid_enum: 792 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColor(%s)", 793 _mesa_enum_to_string(target)); 794} 795 796static GLboolean 797get_clamp_color(const struct gl_framebuffer *fb, GLenum clamp) 798{ 799 if (clamp == GL_TRUE || clamp == GL_FALSE) 800 return clamp; 801 802 assert(clamp == GL_FIXED_ONLY); 803 if (!fb) 804 return GL_TRUE; 805 806 return fb->_AllColorBuffersFixedPoint; 807} 808 809GLboolean 810_mesa_get_clamp_fragment_color(const struct gl_context *ctx, 811 const struct gl_framebuffer *drawFb) 812{ 813 return get_clamp_color(drawFb, ctx->Color.ClampFragmentColor); 814} 815 816GLboolean 817_mesa_get_clamp_vertex_color(const struct gl_context *ctx, 818 const struct gl_framebuffer *drawFb) 819{ 820 return get_clamp_color(drawFb, ctx->Light.ClampVertexColor); 821} 822 823GLboolean 824_mesa_get_clamp_read_color(const struct gl_context *ctx, 825 const struct gl_framebuffer *readFb) 826{ 827 return get_clamp_color(readFb, ctx->Color.ClampReadColor); 828} 829 830/** 831 * Update the ctx->Color._ClampFragmentColor field 832 */ 833void 834_mesa_update_clamp_fragment_color(struct gl_context *ctx, 835 const struct gl_framebuffer *drawFb) 836{ 837 /* Don't clamp if: 838 * - there is no colorbuffer 839 * - all colorbuffers are unsigned normalized, so clamping has no effect 840 * - there is an integer colorbuffer 841 */ 842 if (!drawFb || !drawFb->_HasSNormOrFloatColorBuffer || 843 drawFb->_IntegerColor) 844 ctx->Color._ClampFragmentColor = GL_FALSE; 845 else 846 ctx->Color._ClampFragmentColor = 847 _mesa_get_clamp_fragment_color(ctx, drawFb); 848} 849 850/** 851 * Update the ctx->Color._ClampVertexColor field 852 */ 853void 854_mesa_update_clamp_vertex_color(struct gl_context *ctx, 855 const struct gl_framebuffer *drawFb) 856{ 857 ctx->Light._ClampVertexColor = 858 _mesa_get_clamp_vertex_color(ctx, drawFb); 859} 860 861/** 862 * Returns an appropriate mesa_format for color rendering based on the 863 * GL_FRAMEBUFFER_SRGB state. 864 * 865 * Some drivers implement GL_FRAMEBUFFER_SRGB using a flag on the blend state 866 * (which GL_FRAMEBUFFER_SRGB maps to reasonably), but some have to do so by 867 * overriding the format of the surface. This is a helper for doing the 868 * surface format override variant. 869 */ 870mesa_format 871_mesa_get_render_format(const struct gl_context *ctx, mesa_format format) 872{ 873 if (ctx->Color.sRGBEnabled) 874 return format; 875 else 876 return _mesa_get_srgb_format_linear(format); 877} 878 879/**********************************************************************/ 880/** \name Initialization */ 881/*@{*/ 882 883/** 884 * Initialization of the context's Color attribute group. 885 * 886 * \param ctx GL context. 887 * 888 * Initializes the related fields in the context color attribute group, 889 * __struct gl_contextRec::Color. 890 */ 891void _mesa_init_color( struct gl_context * ctx ) 892{ 893 GLuint i; 894 895 /* Color buffer group */ 896 ctx->Color.IndexMask = ~0u; 897 memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); 898 ctx->Color.ClearIndex = 0; 899 ASSIGN_4V( ctx->Color.ClearColor.f, 0, 0, 0, 0 ); 900 ctx->Color.AlphaEnabled = GL_FALSE; 901 ctx->Color.AlphaFunc = GL_ALWAYS; 902 ctx->Color.AlphaRef = 0; 903 ctx->Color.BlendEnabled = 0x0; 904 for (i = 0; i < ARRAY_SIZE(ctx->Color.Blend); i++) { 905 ctx->Color.Blend[i].SrcRGB = GL_ONE; 906 ctx->Color.Blend[i].DstRGB = GL_ZERO; 907 ctx->Color.Blend[i].SrcA = GL_ONE; 908 ctx->Color.Blend[i].DstA = GL_ZERO; 909 ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; 910 ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; 911 } 912 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); 913 ASSIGN_4V( ctx->Color.BlendColorUnclamped, 0.0, 0.0, 0.0, 0.0 ); 914 ctx->Color.IndexLogicOpEnabled = GL_FALSE; 915 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 916 ctx->Color.LogicOp = GL_COPY; 917 ctx->Color.DitherFlag = GL_TRUE; 918 919 /* GL_FRONT is not possible on GLES. Instead GL_BACK will render to either 920 * the front or the back buffer depending on the config */ 921 if (ctx->Visual.doubleBufferMode || _mesa_is_gles(ctx)) { 922 ctx->Color.DrawBuffer[0] = GL_BACK; 923 } 924 else { 925 ctx->Color.DrawBuffer[0] = GL_FRONT; 926 } 927 928 ctx->Color.ClampFragmentColor = ctx->API == API_OPENGL_COMPAT ? 929 GL_FIXED_ONLY_ARB : GL_FALSE; 930 ctx->Color._ClampFragmentColor = GL_FALSE; 931 ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; 932 933 /* GLES 1/2/3 behaves as though GL_FRAMEBUFFER_SRGB is always enabled 934 * if EGL_KHR_gl_colorspace has been used to request sRGB. 935 */ 936 ctx->Color.sRGBEnabled = _mesa_is_gles(ctx); 937} 938 939/*@}*/ 940