blend.c revision 379255298f8fa9d9d8d53bf8898345fdd4fd0222
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 308 309/** 310 * Check if given blend equation is legal. 311 * \return GL_TRUE if legal, GL_FALSE otherwise. 312 */ 313static GLboolean 314legal_blend_equation(const struct gl_context *ctx, GLenum mode) 315{ 316 switch (mode) { 317 case GL_FUNC_ADD: 318 case GL_FUNC_SUBTRACT: 319 case GL_FUNC_REVERSE_SUBTRACT: 320 return GL_TRUE; 321 case GL_MIN: 322 case GL_MAX: 323 return ctx->Extensions.EXT_blend_minmax; 324 default: 325 return GL_FALSE; 326 } 327} 328 329 330/* This is really an extension function! */ 331void GLAPIENTRY 332_mesa_BlendEquation( GLenum mode ) 333{ 334 GLuint buf, numBuffers; 335 GLboolean changed; 336 GET_CURRENT_CONTEXT(ctx); 337 338 if (MESA_VERBOSE & VERBOSE_API) 339 _mesa_debug(ctx, "glBlendEquation(%s)\n", 340 _mesa_enum_to_string(mode)); 341 342 if (!legal_blend_equation(ctx, mode)) { 343 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); 344 return; 345 } 346 347 numBuffers = ctx->Extensions.ARB_draw_buffers_blend 348 ? ctx->Const.MaxDrawBuffers : 1; 349 350 changed = GL_FALSE; 351 for (buf = 0; buf < numBuffers; buf++) { 352 if (ctx->Color.Blend[buf].EquationRGB != mode || 353 ctx->Color.Blend[buf].EquationA != mode) { 354 changed = GL_TRUE; 355 break; 356 } 357 } 358 if (!changed) 359 return; 360 361 FLUSH_VERTICES(ctx, _NEW_COLOR); 362 for (buf = 0; buf < numBuffers; buf++) { 363 ctx->Color.Blend[buf].EquationRGB = mode; 364 ctx->Color.Blend[buf].EquationA = mode; 365 } 366 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 367 368 if (ctx->Driver.BlendEquationSeparate) 369 (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); 370} 371 372 373/** 374 * Set blend equation for one color buffer/target. 375 */ 376void GLAPIENTRY 377_mesa_BlendEquationiARB(GLuint buf, GLenum mode) 378{ 379 GET_CURRENT_CONTEXT(ctx); 380 381 if (MESA_VERBOSE & VERBOSE_API) 382 _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", 383 buf, _mesa_enum_to_string(mode)); 384 385 if (buf >= ctx->Const.MaxDrawBuffers) { 386 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", 387 buf); 388 return; 389 } 390 391 if (!legal_blend_equation(ctx, mode)) { 392 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); 393 return; 394 } 395 396 if (ctx->Color.Blend[buf].EquationRGB == mode && 397 ctx->Color.Blend[buf].EquationA == mode) 398 return; /* no change */ 399 400 FLUSH_VERTICES(ctx, _NEW_COLOR); 401 ctx->Color.Blend[buf].EquationRGB = mode; 402 ctx->Color.Blend[buf].EquationA = mode; 403 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 404} 405 406 407void GLAPIENTRY 408_mesa_BlendEquationSeparate( GLenum modeRGB, GLenum modeA ) 409{ 410 GLuint buf, numBuffers; 411 GLboolean changed; 412 GET_CURRENT_CONTEXT(ctx); 413 414 if (MESA_VERBOSE & VERBOSE_API) 415 _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", 416 _mesa_enum_to_string(modeRGB), 417 _mesa_enum_to_string(modeA)); 418 419 if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { 420 _mesa_error(ctx, GL_INVALID_OPERATION, 421 "glBlendEquationSeparateEXT not supported by driver"); 422 return; 423 } 424 425 if (!legal_blend_equation(ctx, modeRGB)) { 426 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); 427 return; 428 } 429 430 if (!legal_blend_equation(ctx, modeA)) { 431 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); 432 return; 433 } 434 435 numBuffers = ctx->Extensions.ARB_draw_buffers_blend 436 ? ctx->Const.MaxDrawBuffers : 1; 437 438 changed = GL_FALSE; 439 for (buf = 0; buf < numBuffers; buf++) { 440 if (ctx->Color.Blend[buf].EquationRGB != modeRGB || 441 ctx->Color.Blend[buf].EquationA != modeA) { 442 changed = GL_TRUE; 443 break; 444 } 445 } 446 if (!changed) 447 return; 448 449 FLUSH_VERTICES(ctx, _NEW_COLOR); 450 for (buf = 0; buf < numBuffers; buf++) { 451 ctx->Color.Blend[buf].EquationRGB = modeRGB; 452 ctx->Color.Blend[buf].EquationA = modeA; 453 } 454 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 455 456 if (ctx->Driver.BlendEquationSeparate) 457 ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); 458} 459 460 461/** 462 * Set separate blend equations for one color buffer/target. 463 */ 464void GLAPIENTRY 465_mesa_BlendEquationSeparateiARB(GLuint buf, GLenum modeRGB, GLenum modeA) 466{ 467 GET_CURRENT_CONTEXT(ctx); 468 469 if (MESA_VERBOSE & VERBOSE_API) 470 _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, 471 _mesa_enum_to_string(modeRGB), 472 _mesa_enum_to_string(modeA)); 473 474 if (buf >= ctx->Const.MaxDrawBuffers) { 475 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", 476 buf); 477 return; 478 } 479 480 if (!legal_blend_equation(ctx, modeRGB)) { 481 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); 482 return; 483 } 484 485 if (!legal_blend_equation(ctx, modeA)) { 486 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); 487 return; 488 } 489 490 if (ctx->Color.Blend[buf].EquationRGB == modeRGB && 491 ctx->Color.Blend[buf].EquationA == modeA) 492 return; /* no change */ 493 494 FLUSH_VERTICES(ctx, _NEW_COLOR); 495 ctx->Color.Blend[buf].EquationRGB = modeRGB; 496 ctx->Color.Blend[buf].EquationA = modeA; 497 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 498} 499 500 501/** 502 * Set the blending color. 503 * 504 * \param red red color component. 505 * \param green green color component. 506 * \param blue blue color component. 507 * \param alpha alpha color component. 508 * 509 * \sa glBlendColor(). 510 * 511 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a 512 * change, flushes the vertices and notifies the driver via 513 * dd_function_table::BlendColor callback. 514 */ 515void GLAPIENTRY 516_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 517{ 518 GLfloat tmp[4]; 519 GET_CURRENT_CONTEXT(ctx); 520 521 tmp[0] = red; 522 tmp[1] = green; 523 tmp[2] = blue; 524 tmp[3] = alpha; 525 526 if (TEST_EQ_4V(tmp, ctx->Color.BlendColorUnclamped)) 527 return; 528 529 FLUSH_VERTICES(ctx, _NEW_COLOR); 530 COPY_4FV( ctx->Color.BlendColorUnclamped, tmp ); 531 532 ctx->Color.BlendColor[0] = CLAMP(tmp[0], 0.0F, 1.0F); 533 ctx->Color.BlendColor[1] = CLAMP(tmp[1], 0.0F, 1.0F); 534 ctx->Color.BlendColor[2] = CLAMP(tmp[2], 0.0F, 1.0F); 535 ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F); 536 537 if (ctx->Driver.BlendColor) 538 (*ctx->Driver.BlendColor)(ctx, ctx->Color.BlendColor); 539} 540 541 542/** 543 * Specify the alpha test function. 544 * 545 * \param func alpha comparison function. 546 * \param ref reference value. 547 * 548 * Verifies the parameters and updates gl_colorbuffer_attrib. 549 * On a change, flushes the vertices and notifies the driver via 550 * dd_function_table::AlphaFunc callback. 551 */ 552void GLAPIENTRY 553_mesa_AlphaFunc( GLenum func, GLclampf ref ) 554{ 555 GET_CURRENT_CONTEXT(ctx); 556 557 if (MESA_VERBOSE & VERBOSE_API) 558 _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", 559 _mesa_enum_to_string(func), ref); 560 561 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref) 562 return; /* no change */ 563 564 switch (func) { 565 case GL_NEVER: 566 case GL_LESS: 567 case GL_EQUAL: 568 case GL_LEQUAL: 569 case GL_GREATER: 570 case GL_NOTEQUAL: 571 case GL_GEQUAL: 572 case GL_ALWAYS: 573 FLUSH_VERTICES(ctx, _NEW_COLOR); 574 ctx->Color.AlphaFunc = func; 575 ctx->Color.AlphaRefUnclamped = ref; 576 ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F); 577 578 if (ctx->Driver.AlphaFunc) 579 ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef); 580 return; 581 582 default: 583 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); 584 return; 585 } 586} 587 588 589/** 590 * Specify a logic pixel operation for color index rendering. 591 * 592 * \param opcode operation. 593 * 594 * Verifies that \p opcode is a valid enum and updates 595gl_colorbuffer_attrib::LogicOp. 596 * On a change, flushes the vertices and notifies the driver via the 597 * dd_function_table::LogicOpcode callback. 598 */ 599void GLAPIENTRY 600_mesa_LogicOp( GLenum opcode ) 601{ 602 GET_CURRENT_CONTEXT(ctx); 603 604 if (MESA_VERBOSE & VERBOSE_API) 605 _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_enum_to_string(opcode)); 606 607 switch (opcode) { 608 case GL_CLEAR: 609 case GL_SET: 610 case GL_COPY: 611 case GL_COPY_INVERTED: 612 case GL_NOOP: 613 case GL_INVERT: 614 case GL_AND: 615 case GL_NAND: 616 case GL_OR: 617 case GL_NOR: 618 case GL_XOR: 619 case GL_EQUIV: 620 case GL_AND_REVERSE: 621 case GL_AND_INVERTED: 622 case GL_OR_REVERSE: 623 case GL_OR_INVERTED: 624 break; 625 default: 626 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); 627 return; 628 } 629 630 if (ctx->Color.LogicOp == opcode) 631 return; 632 633 FLUSH_VERTICES(ctx, _NEW_COLOR); 634 ctx->Color.LogicOp = opcode; 635 636 if (ctx->Driver.LogicOpcode) 637 ctx->Driver.LogicOpcode( ctx, opcode ); 638} 639 640 641void GLAPIENTRY 642_mesa_IndexMask( GLuint mask ) 643{ 644 GET_CURRENT_CONTEXT(ctx); 645 646 if (ctx->Color.IndexMask == mask) 647 return; 648 649 FLUSH_VERTICES(ctx, _NEW_COLOR); 650 ctx->Color.IndexMask = mask; 651} 652 653 654/** 655 * Enable or disable writing of frame buffer color components. 656 * 657 * \param red whether to mask writing of the red color component. 658 * \param green whether to mask writing of the green color component. 659 * \param blue whether to mask writing of the blue color component. 660 * \param alpha whether to mask writing of the alpha color component. 661 * 662 * \sa glColorMask(). 663 * 664 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a 665 * change, flushes the vertices and notifies the driver via the 666 * dd_function_table::ColorMask callback. 667 */ 668void GLAPIENTRY 669_mesa_ColorMask( GLboolean red, GLboolean green, 670 GLboolean blue, GLboolean alpha ) 671{ 672 GET_CURRENT_CONTEXT(ctx); 673 GLubyte tmp[4]; 674 GLuint i; 675 GLboolean flushed; 676 677 if (MESA_VERBOSE & VERBOSE_API) 678 _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n", 679 red, green, blue, alpha); 680 681 /* Shouldn't have any information about channel depth in core mesa 682 * -- should probably store these as the native booleans: 683 */ 684 tmp[RCOMP] = red ? 0xff : 0x0; 685 tmp[GCOMP] = green ? 0xff : 0x0; 686 tmp[BCOMP] = blue ? 0xff : 0x0; 687 tmp[ACOMP] = alpha ? 0xff : 0x0; 688 689 flushed = GL_FALSE; 690 for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { 691 if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { 692 if (!flushed) { 693 FLUSH_VERTICES(ctx, _NEW_COLOR); 694 } 695 flushed = GL_TRUE; 696 COPY_4UBV(ctx->Color.ColorMask[i], tmp); 697 } 698 } 699 700 if (ctx->Driver.ColorMask) 701 ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); 702} 703 704 705/** 706 * For GL_EXT_draw_buffers2 and GL3 707 */ 708void GLAPIENTRY 709_mesa_ColorMaski( GLuint buf, GLboolean red, GLboolean green, 710 GLboolean blue, GLboolean alpha ) 711{ 712 GLubyte tmp[4]; 713 GET_CURRENT_CONTEXT(ctx); 714 715 if (MESA_VERBOSE & VERBOSE_API) 716 _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n", 717 buf, red, green, blue, alpha); 718 719 if (buf >= ctx->Const.MaxDrawBuffers) { 720 _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf); 721 return; 722 } 723 724 /* Shouldn't have any information about channel depth in core mesa 725 * -- should probably store these as the native booleans: 726 */ 727 tmp[RCOMP] = red ? 0xff : 0x0; 728 tmp[GCOMP] = green ? 0xff : 0x0; 729 tmp[BCOMP] = blue ? 0xff : 0x0; 730 tmp[ACOMP] = alpha ? 0xff : 0x0; 731 732 if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) 733 return; 734 735 FLUSH_VERTICES(ctx, _NEW_COLOR); 736 COPY_4UBV(ctx->Color.ColorMask[buf], tmp); 737 738 if (ctx->Driver.ColorMaskIndexed) 739 ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha); 740} 741 742 743void GLAPIENTRY 744_mesa_ClampColor(GLenum target, GLenum clamp) 745{ 746 GET_CURRENT_CONTEXT(ctx); 747 748 if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { 749 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); 750 return; 751 } 752 753 switch (target) { 754 case GL_CLAMP_VERTEX_COLOR_ARB: 755 if (ctx->API == API_OPENGL_CORE && 756 !ctx->Extensions.ARB_color_buffer_float) { 757 goto invalid_enum; 758 } 759 FLUSH_VERTICES(ctx, _NEW_LIGHT); 760 ctx->Light.ClampVertexColor = clamp; 761 _mesa_update_clamp_vertex_color(ctx, ctx->DrawBuffer); 762 break; 763 case GL_CLAMP_FRAGMENT_COLOR_ARB: 764 if (ctx->API == API_OPENGL_CORE && 765 !ctx->Extensions.ARB_color_buffer_float) { 766 goto invalid_enum; 767 } 768 FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP); 769 ctx->Color.ClampFragmentColor = clamp; 770 _mesa_update_clamp_fragment_color(ctx, ctx->DrawBuffer); 771 break; 772 case GL_CLAMP_READ_COLOR_ARB: 773 ctx->Color.ClampReadColor = clamp; 774 break; 775 default: 776 goto invalid_enum; 777 } 778 return; 779 780invalid_enum: 781 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColor(%s)", 782 _mesa_enum_to_string(target)); 783} 784 785static GLboolean 786get_clamp_color(const struct gl_framebuffer *fb, GLenum clamp) 787{ 788 if (clamp == GL_TRUE || clamp == GL_FALSE) 789 return clamp; 790 791 assert(clamp == GL_FIXED_ONLY); 792 if (!fb) 793 return GL_TRUE; 794 795 return fb->_AllColorBuffersFixedPoint; 796} 797 798GLboolean 799_mesa_get_clamp_fragment_color(const struct gl_context *ctx, 800 const struct gl_framebuffer *drawFb) 801{ 802 return get_clamp_color(drawFb, ctx->Color.ClampFragmentColor); 803} 804 805GLboolean 806_mesa_get_clamp_vertex_color(const struct gl_context *ctx, 807 const struct gl_framebuffer *drawFb) 808{ 809 return get_clamp_color(drawFb, ctx->Light.ClampVertexColor); 810} 811 812GLboolean 813_mesa_get_clamp_read_color(const struct gl_context *ctx, 814 const struct gl_framebuffer *readFb) 815{ 816 return get_clamp_color(readFb, ctx->Color.ClampReadColor); 817} 818 819/** 820 * Update the ctx->Color._ClampFragmentColor field 821 */ 822void 823_mesa_update_clamp_fragment_color(struct gl_context *ctx, 824 const struct gl_framebuffer *drawFb) 825{ 826 /* Don't clamp if: 827 * - there is no colorbuffer 828 * - all colorbuffers are unsigned normalized, so clamping has no effect 829 * - there is an integer colorbuffer 830 */ 831 if (!drawFb || !drawFb->_HasSNormOrFloatColorBuffer || 832 drawFb->_IntegerColor) 833 ctx->Color._ClampFragmentColor = GL_FALSE; 834 else 835 ctx->Color._ClampFragmentColor = 836 _mesa_get_clamp_fragment_color(ctx, drawFb); 837} 838 839/** 840 * Update the ctx->Color._ClampVertexColor field 841 */ 842void 843_mesa_update_clamp_vertex_color(struct gl_context *ctx, 844 const struct gl_framebuffer *drawFb) 845{ 846 ctx->Light._ClampVertexColor = 847 _mesa_get_clamp_vertex_color(ctx, drawFb); 848} 849 850/** 851 * Returns an appropriate mesa_format for color rendering based on the 852 * GL_FRAMEBUFFER_SRGB state. 853 * 854 * Some drivers implement GL_FRAMEBUFFER_SRGB using a flag on the blend state 855 * (which GL_FRAMEBUFFER_SRGB maps to reasonably), but some have to do so by 856 * overriding the format of the surface. This is a helper for doing the 857 * surface format override variant. 858 */ 859mesa_format 860_mesa_get_render_format(const struct gl_context *ctx, mesa_format format) 861{ 862 if (ctx->Color.sRGBEnabled) 863 return format; 864 else 865 return _mesa_get_srgb_format_linear(format); 866} 867 868/**********************************************************************/ 869/** \name Initialization */ 870/*@{*/ 871 872/** 873 * Initialization of the context's Color attribute group. 874 * 875 * \param ctx GL context. 876 * 877 * Initializes the related fields in the context color attribute group, 878 * __struct gl_contextRec::Color. 879 */ 880void _mesa_init_color( struct gl_context * ctx ) 881{ 882 GLuint i; 883 884 /* Color buffer group */ 885 ctx->Color.IndexMask = ~0u; 886 memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); 887 ctx->Color.ClearIndex = 0; 888 ASSIGN_4V( ctx->Color.ClearColor.f, 0, 0, 0, 0 ); 889 ctx->Color.AlphaEnabled = GL_FALSE; 890 ctx->Color.AlphaFunc = GL_ALWAYS; 891 ctx->Color.AlphaRef = 0; 892 ctx->Color.BlendEnabled = 0x0; 893 for (i = 0; i < ARRAY_SIZE(ctx->Color.Blend); i++) { 894 ctx->Color.Blend[i].SrcRGB = GL_ONE; 895 ctx->Color.Blend[i].DstRGB = GL_ZERO; 896 ctx->Color.Blend[i].SrcA = GL_ONE; 897 ctx->Color.Blend[i].DstA = GL_ZERO; 898 ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; 899 ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; 900 } 901 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); 902 ASSIGN_4V( ctx->Color.BlendColorUnclamped, 0.0, 0.0, 0.0, 0.0 ); 903 ctx->Color.IndexLogicOpEnabled = GL_FALSE; 904 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 905 ctx->Color.LogicOp = GL_COPY; 906 ctx->Color.DitherFlag = GL_TRUE; 907 908 /* GL_FRONT is not possible on GLES. Instead GL_BACK will render to either 909 * the front or the back buffer depending on the config */ 910 if (ctx->Visual.doubleBufferMode || _mesa_is_gles(ctx)) { 911 ctx->Color.DrawBuffer[0] = GL_BACK; 912 } 913 else { 914 ctx->Color.DrawBuffer[0] = GL_FRONT; 915 } 916 917 ctx->Color.ClampFragmentColor = ctx->API == API_OPENGL_COMPAT ? 918 GL_FIXED_ONLY_ARB : GL_FALSE; 919 ctx->Color._ClampFragmentColor = GL_FALSE; 920 ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; 921 922 /* GLES 1/2/3 behaves as though GL_FRAMEBUFFER_SRGB is always enabled 923 * if EGL_KHR_gl_colorspace has been used to request sRGB. 924 */ 925 ctx->Color.sRGBEnabled = _mesa_is_gles(ctx); 926} 927 928/*@}*/ 929