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