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 
39 
40 
41 /**
42  * Check if given blend source factor is legal.
43  * \return GL_TRUE if legal, GL_FALSE otherwise.
44  */
45 static GLboolean
legal_src_factor(const struct gl_context * ctx,GLenum factor)46 legal_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       return ctx->Extensions.NV_blend_square;
52    case GL_ZERO:
53    case GL_ONE:
54    case GL_DST_COLOR:
55    case GL_ONE_MINUS_DST_COLOR:
56    case GL_SRC_ALPHA:
57    case GL_ONE_MINUS_SRC_ALPHA:
58    case GL_DST_ALPHA:
59    case GL_ONE_MINUS_DST_ALPHA:
60    case GL_SRC_ALPHA_SATURATE:
61       return GL_TRUE;
62    case GL_CONSTANT_COLOR:
63    case GL_ONE_MINUS_CONSTANT_COLOR:
64    case GL_CONSTANT_ALPHA:
65    case GL_ONE_MINUS_CONSTANT_ALPHA:
66       return _mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES2;
67    case GL_SRC1_COLOR:
68    case GL_SRC1_ALPHA:
69    case GL_ONE_MINUS_SRC1_COLOR:
70    case GL_ONE_MINUS_SRC1_ALPHA:
71       return _mesa_is_desktop_gl(ctx)
72          && ctx->Extensions.ARB_blend_func_extended;
73    default:
74       return GL_FALSE;
75    }
76 }
77 
78 
79 /**
80  * Check if given blend destination factor is legal.
81  * \return GL_TRUE if legal, GL_FALSE otherwise.
82  */
83 static GLboolean
legal_dst_factor(const struct gl_context * ctx,GLenum factor)84 legal_dst_factor(const struct gl_context *ctx, GLenum factor)
85 {
86    switch (factor) {
87    case GL_DST_COLOR:
88    case GL_ONE_MINUS_DST_COLOR:
89       return ctx->Extensions.NV_blend_square;
90    case GL_ZERO:
91    case GL_ONE:
92    case GL_SRC_COLOR:
93    case GL_ONE_MINUS_SRC_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       return GL_TRUE;
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       return _mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES2;
104    case GL_SRC_ALPHA_SATURATE:
105       return (_mesa_is_desktop_gl(ctx)
106               && ctx->Extensions.ARB_blend_func_extended)
107          || _mesa_is_gles3(ctx);
108    case GL_SRC1_COLOR:
109    case GL_SRC1_ALPHA:
110    case GL_ONE_MINUS_SRC1_COLOR:
111    case GL_ONE_MINUS_SRC1_ALPHA:
112       return _mesa_is_desktop_gl(ctx)
113          && ctx->Extensions.ARB_blend_func_extended;
114    default:
115       return GL_FALSE;
116    }
117 }
118 
119 
120 /**
121  * Check if src/dest RGB/A blend factors are legal.  If not generate
122  * a GL error.
123  * \return GL_TRUE if factors are legal, GL_FALSE otherwise.
124  */
125 static GLboolean
validate_blend_factors(struct gl_context * ctx,const char * func,GLenum sfactorRGB,GLenum dfactorRGB,GLenum sfactorA,GLenum dfactorA)126 validate_blend_factors(struct gl_context *ctx, const char *func,
127                        GLenum sfactorRGB, GLenum dfactorRGB,
128                        GLenum sfactorA, GLenum dfactorA)
129 {
130    if (!legal_src_factor(ctx, sfactorRGB)) {
131       _mesa_error(ctx, GL_INVALID_ENUM,
132                   "%s(sfactorRGB = %s)", func,
133                   _mesa_lookup_enum_by_nr(sfactorRGB));
134       return GL_FALSE;
135    }
136 
137    if (!legal_dst_factor(ctx, dfactorRGB)) {
138       _mesa_error(ctx, GL_INVALID_ENUM,
139                   "%s(dfactorRGB = %s)", func,
140                   _mesa_lookup_enum_by_nr(dfactorRGB));
141       return GL_FALSE;
142    }
143 
144    if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) {
145       _mesa_error(ctx, GL_INVALID_ENUM,
146                   "%s(sfactorA = %s)", func,
147                   _mesa_lookup_enum_by_nr(sfactorA));
148       return GL_FALSE;
149    }
150 
151    if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) {
152       _mesa_error(ctx, GL_INVALID_ENUM,
153                   "%s(dfactorA = %s)", func,
154                   _mesa_lookup_enum_by_nr(dfactorA));
155       return GL_FALSE;
156    }
157 
158    return GL_TRUE;
159 }
160 
161 
162 /**
163  * Specify the blending operation.
164  *
165  * \param sfactor source factor operator.
166  * \param dfactor destination factor operator.
167  *
168  * \sa glBlendFunc, glBlendFuncSeparateEXT
169  */
170 void GLAPIENTRY
_mesa_BlendFunc(GLenum sfactor,GLenum dfactor)171 _mesa_BlendFunc( GLenum sfactor, GLenum dfactor )
172 {
173    _mesa_BlendFuncSeparateEXT(sfactor, dfactor, sfactor, dfactor);
174 }
175 
176 static GLboolean
blend_factor_is_dual_src(GLenum factor)177 blend_factor_is_dual_src(GLenum factor)
178 {
179    return (factor == GL_SRC1_COLOR ||
180 	   factor == GL_SRC1_ALPHA ||
181 	   factor == GL_ONE_MINUS_SRC1_COLOR ||
182 	   factor == GL_ONE_MINUS_SRC1_ALPHA);
183 }
184 
185 static void
update_uses_dual_src(struct gl_context * ctx,int buf)186 update_uses_dual_src(struct gl_context *ctx, int buf)
187 {
188    ctx->Color.Blend[buf]._UsesDualSrc =
189       (blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcRGB) ||
190        blend_factor_is_dual_src(ctx->Color.Blend[buf].DstRGB) ||
191        blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcA) ||
192        blend_factor_is_dual_src(ctx->Color.Blend[buf].DstA));
193 }
194 
195 /**
196  * Set the separate blend source/dest factors for all draw buffers.
197  *
198  * \param sfactorRGB RGB source factor operator.
199  * \param dfactorRGB RGB destination factor operator.
200  * \param sfactorA alpha source factor operator.
201  * \param dfactorA alpha destination factor operator.
202  */
203 void GLAPIENTRY
_mesa_BlendFuncSeparateEXT(GLenum sfactorRGB,GLenum dfactorRGB,GLenum sfactorA,GLenum dfactorA)204 _mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB,
205                             GLenum sfactorA, GLenum dfactorA )
206 {
207    GLuint buf, numBuffers;
208    GLboolean changed;
209    GET_CURRENT_CONTEXT(ctx);
210    ASSERT_OUTSIDE_BEGIN_END(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 #if _HAVE_FULL_GL
260 
261 
262 /**
263  * Set blend source/dest factors for one color buffer/target.
264  */
265 void GLAPIENTRY
_mesa_BlendFunci(GLuint buf,GLenum sfactor,GLenum dfactor)266 _mesa_BlendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
267 {
268    _mesa_BlendFuncSeparatei(buf, sfactor, dfactor, sfactor, dfactor);
269 }
270 
271 
272 /**
273  * Set separate blend source/dest factors for one color buffer/target.
274  */
275 void GLAPIENTRY
_mesa_BlendFuncSeparatei(GLuint buf,GLenum sfactorRGB,GLenum dfactorRGB,GLenum sfactorA,GLenum dfactorA)276 _mesa_BlendFuncSeparatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB,
277                          GLenum sfactorA, GLenum dfactorA)
278 {
279    GET_CURRENT_CONTEXT(ctx);
280    ASSERT_OUTSIDE_BEGIN_END(ctx);
281 
282    if (!ctx->Extensions.ARB_draw_buffers_blend) {
283       _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()");
284       return;
285    }
286 
287    if (buf >= ctx->Const.MaxDrawBuffers) {
288       _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)",
289                   buf);
290       return;
291    }
292 
293    if (!validate_blend_factors(ctx, "glBlendFuncSeparatei",
294                                sfactorRGB, dfactorRGB,
295                                sfactorA, dfactorA)) {
296       return;
297    }
298 
299    if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB &&
300        ctx->Color.Blend[buf].DstRGB == dfactorRGB &&
301        ctx->Color.Blend[buf].SrcA == sfactorA &&
302        ctx->Color.Blend[buf].DstA == dfactorA)
303       return; /* no change */
304 
305    FLUSH_VERTICES(ctx, _NEW_COLOR);
306 
307    ctx->Color.Blend[buf].SrcRGB = sfactorRGB;
308    ctx->Color.Blend[buf].DstRGB = dfactorRGB;
309    ctx->Color.Blend[buf].SrcA = sfactorA;
310    ctx->Color.Blend[buf].DstA = dfactorA;
311    update_uses_dual_src(ctx, buf);
312    ctx->Color._BlendFuncPerBuffer = GL_TRUE;
313 
314    if (ctx->Driver.BlendFuncSeparatei) {
315       ctx->Driver.BlendFuncSeparatei(ctx, buf, sfactorRGB, dfactorRGB,
316                                      sfactorA, dfactorA);
317    }
318 }
319 
320 
321 /**
322  * Check if given blend equation is legal.
323  * \return GL_TRUE if legal, GL_FALSE otherwise.
324  */
325 static GLboolean
legal_blend_equation(const struct gl_context * ctx,GLenum mode)326 legal_blend_equation(const struct gl_context *ctx, GLenum mode)
327 {
328    switch (mode) {
329    case GL_FUNC_ADD:
330    case GL_FUNC_SUBTRACT:
331    case GL_FUNC_REVERSE_SUBTRACT:
332       return GL_TRUE;
333    case GL_MIN:
334    case GL_MAX:
335       return ctx->Extensions.EXT_blend_minmax;
336    default:
337       return GL_FALSE;
338    }
339 }
340 
341 
342 /* This is really an extension function! */
343 void GLAPIENTRY
_mesa_BlendEquation(GLenum mode)344 _mesa_BlendEquation( GLenum mode )
345 {
346    GLuint buf, numBuffers;
347    GLboolean changed;
348    GET_CURRENT_CONTEXT(ctx);
349    ASSERT_OUTSIDE_BEGIN_END(ctx);
350 
351    if (MESA_VERBOSE & VERBOSE_API)
352       _mesa_debug(ctx, "glBlendEquation(%s)\n",
353                   _mesa_lookup_enum_by_nr(mode));
354 
355    if (!legal_blend_equation(ctx, mode)) {
356       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
357       return;
358    }
359 
360    numBuffers = ctx->Extensions.ARB_draw_buffers_blend
361       ? ctx->Const.MaxDrawBuffers : 1;
362 
363    changed = GL_FALSE;
364    for (buf = 0; buf < numBuffers; buf++) {
365       if (ctx->Color.Blend[buf].EquationRGB != mode ||
366           ctx->Color.Blend[buf].EquationA != mode) {
367          changed = GL_TRUE;
368          break;
369       }
370    }
371    if (!changed)
372       return;
373 
374    FLUSH_VERTICES(ctx, _NEW_COLOR);
375    for (buf = 0; buf < numBuffers; buf++) {
376       ctx->Color.Blend[buf].EquationRGB = mode;
377       ctx->Color.Blend[buf].EquationA = mode;
378    }
379    ctx->Color._BlendEquationPerBuffer = GL_FALSE;
380 
381    if (ctx->Driver.BlendEquationSeparate)
382       (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode );
383 }
384 
385 
386 /**
387  * Set blend equation for one color buffer/target.
388  */
389 void GLAPIENTRY
_mesa_BlendEquationi(GLuint buf,GLenum mode)390 _mesa_BlendEquationi(GLuint buf, GLenum mode)
391 {
392    GET_CURRENT_CONTEXT(ctx);
393    ASSERT_OUTSIDE_BEGIN_END(ctx);
394 
395    if (MESA_VERBOSE & VERBOSE_API)
396       _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n",
397                   buf, _mesa_lookup_enum_by_nr(mode));
398 
399    if (buf >= ctx->Const.MaxDrawBuffers) {
400       _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)",
401                   buf);
402       return;
403    }
404 
405    if (!legal_blend_equation(ctx, mode)) {
406       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi");
407       return;
408    }
409 
410    if (ctx->Color.Blend[buf].EquationRGB == mode &&
411        ctx->Color.Blend[buf].EquationA == mode)
412       return;  /* no change */
413 
414    FLUSH_VERTICES(ctx, _NEW_COLOR);
415    ctx->Color.Blend[buf].EquationRGB = mode;
416    ctx->Color.Blend[buf].EquationA = mode;
417    ctx->Color._BlendEquationPerBuffer = GL_TRUE;
418 
419    if (ctx->Driver.BlendEquationSeparatei)
420       ctx->Driver.BlendEquationSeparatei(ctx, buf, mode, mode);
421 }
422 
423 
424 void GLAPIENTRY
_mesa_BlendEquationSeparateEXT(GLenum modeRGB,GLenum modeA)425 _mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA )
426 {
427    GLuint buf, numBuffers;
428    GLboolean changed;
429    GET_CURRENT_CONTEXT(ctx);
430    ASSERT_OUTSIDE_BEGIN_END(ctx);
431 
432    if (MESA_VERBOSE & VERBOSE_API)
433       _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n",
434                   _mesa_lookup_enum_by_nr(modeRGB),
435                   _mesa_lookup_enum_by_nr(modeA));
436 
437    if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) {
438       _mesa_error(ctx, GL_INVALID_OPERATION,
439 		  "glBlendEquationSeparateEXT not supported by driver");
440       return;
441    }
442 
443    if (!legal_blend_equation(ctx, modeRGB)) {
444       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)");
445       return;
446    }
447 
448    if (!legal_blend_equation(ctx, modeA)) {
449       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)");
450       return;
451    }
452 
453    numBuffers = ctx->Extensions.ARB_draw_buffers_blend
454       ? ctx->Const.MaxDrawBuffers : 1;
455 
456    changed = GL_FALSE;
457    for (buf = 0; buf < numBuffers; buf++) {
458       if (ctx->Color.Blend[buf].EquationRGB != modeRGB ||
459           ctx->Color.Blend[buf].EquationA != modeA) {
460          changed = GL_TRUE;
461          break;
462       }
463    }
464    if (!changed)
465       return;
466 
467    FLUSH_VERTICES(ctx, _NEW_COLOR);
468    for (buf = 0; buf < numBuffers; buf++) {
469       ctx->Color.Blend[buf].EquationRGB = modeRGB;
470       ctx->Color.Blend[buf].EquationA = modeA;
471    }
472    ctx->Color._BlendEquationPerBuffer = GL_FALSE;
473 
474    if (ctx->Driver.BlendEquationSeparate)
475       ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA);
476 }
477 
478 
479 /**
480  * Set separate blend equations for one color buffer/target.
481  */
482 void GLAPIENTRY
_mesa_BlendEquationSeparatei(GLuint buf,GLenum modeRGB,GLenum modeA)483 _mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA)
484 {
485    GET_CURRENT_CONTEXT(ctx);
486    ASSERT_OUTSIDE_BEGIN_END(ctx);
487 
488    if (MESA_VERBOSE & VERBOSE_API)
489       _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf,
490                   _mesa_lookup_enum_by_nr(modeRGB),
491                   _mesa_lookup_enum_by_nr(modeA));
492 
493    if (buf >= ctx->Const.MaxDrawBuffers) {
494       _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)",
495                   buf);
496       return;
497    }
498 
499    if (!legal_blend_equation(ctx, modeRGB)) {
500       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)");
501       return;
502    }
503 
504    if (!legal_blend_equation(ctx, modeA)) {
505       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)");
506       return;
507    }
508 
509    if (ctx->Color.Blend[buf].EquationRGB == modeRGB &&
510        ctx->Color.Blend[buf].EquationA == modeA)
511       return;  /* no change */
512 
513    FLUSH_VERTICES(ctx, _NEW_COLOR);
514    ctx->Color.Blend[buf].EquationRGB = modeRGB;
515    ctx->Color.Blend[buf].EquationA = modeA;
516    ctx->Color._BlendEquationPerBuffer = GL_TRUE;
517 
518    if (ctx->Driver.BlendEquationSeparatei)
519       ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA);
520 }
521 
522 
523 
524 #endif /* _HAVE_FULL_GL */
525 
526 
527 /**
528  * Set the blending color.
529  *
530  * \param red red color component.
531  * \param green green color component.
532  * \param blue blue color component.
533  * \param alpha alpha color component.
534  *
535  * \sa glBlendColor().
536  *
537  * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor.  On a
538  * change, flushes the vertices and notifies the driver via
539  * dd_function_table::BlendColor callback.
540  */
541 void GLAPIENTRY
_mesa_BlendColor(GLclampf red,GLclampf green,GLclampf blue,GLclampf alpha)542 _mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
543 {
544    GLfloat tmp[4];
545    GET_CURRENT_CONTEXT(ctx);
546    ASSERT_OUTSIDE_BEGIN_END(ctx);
547 
548    tmp[0] = red;
549    tmp[1] = green;
550    tmp[2] = blue;
551    tmp[3] = alpha;
552 
553    if (TEST_EQ_4V(tmp, ctx->Color.BlendColorUnclamped))
554       return;
555 
556    FLUSH_VERTICES(ctx, _NEW_COLOR);
557    COPY_4FV( ctx->Color.BlendColorUnclamped, tmp );
558 
559    ctx->Color.BlendColor[0] = CLAMP(tmp[0], 0.0F, 1.0F);
560    ctx->Color.BlendColor[1] = CLAMP(tmp[1], 0.0F, 1.0F);
561    ctx->Color.BlendColor[2] = CLAMP(tmp[2], 0.0F, 1.0F);
562    ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F);
563 
564    if (ctx->Driver.BlendColor)
565       (*ctx->Driver.BlendColor)(ctx, ctx->Color.BlendColor);
566 }
567 
568 
569 /**
570  * Specify the alpha test function.
571  *
572  * \param func alpha comparison function.
573  * \param ref reference value.
574  *
575  * Verifies the parameters and updates gl_colorbuffer_attrib.
576  * On a change, flushes the vertices and notifies the driver via
577  * dd_function_table::AlphaFunc callback.
578  */
579 void GLAPIENTRY
_mesa_AlphaFunc(GLenum func,GLclampf ref)580 _mesa_AlphaFunc( GLenum func, GLclampf ref )
581 {
582    GET_CURRENT_CONTEXT(ctx);
583    ASSERT_OUTSIDE_BEGIN_END(ctx);
584 
585    if (MESA_VERBOSE & VERBOSE_API)
586       _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n",
587                   _mesa_lookup_enum_by_nr(func), ref);
588 
589    switch (func) {
590    case GL_NEVER:
591    case GL_LESS:
592    case GL_EQUAL:
593    case GL_LEQUAL:
594    case GL_GREATER:
595    case GL_NOTEQUAL:
596    case GL_GEQUAL:
597    case GL_ALWAYS:
598       if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref)
599          return; /* no change */
600 
601       FLUSH_VERTICES(ctx, _NEW_COLOR);
602       ctx->Color.AlphaFunc = func;
603       ctx->Color.AlphaRefUnclamped = ref;
604       ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F);
605 
606       if (ctx->Driver.AlphaFunc)
607          ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef);
608       return;
609 
610    default:
611       _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" );
612       return;
613    }
614 }
615 
616 
617 /**
618  * Specify a logic pixel operation for color index rendering.
619  *
620  * \param opcode operation.
621  *
622  * Verifies that \p opcode is a valid enum and updates
623 gl_colorbuffer_attrib::LogicOp.
624  * On a change, flushes the vertices and notifies the driver via the
625  * dd_function_table::LogicOpcode callback.
626  */
627 void GLAPIENTRY
_mesa_LogicOp(GLenum opcode)628 _mesa_LogicOp( GLenum opcode )
629 {
630    GET_CURRENT_CONTEXT(ctx);
631    ASSERT_OUTSIDE_BEGIN_END(ctx);
632 
633    if (MESA_VERBOSE & VERBOSE_API)
634       _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_lookup_enum_by_nr(opcode));
635 
636    switch (opcode) {
637       case GL_CLEAR:
638       case GL_SET:
639       case GL_COPY:
640       case GL_COPY_INVERTED:
641       case GL_NOOP:
642       case GL_INVERT:
643       case GL_AND:
644       case GL_NAND:
645       case GL_OR:
646       case GL_NOR:
647       case GL_XOR:
648       case GL_EQUIV:
649       case GL_AND_REVERSE:
650       case GL_AND_INVERTED:
651       case GL_OR_REVERSE:
652       case GL_OR_INVERTED:
653 	 break;
654       default:
655          _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" );
656 	 return;
657    }
658 
659    if (ctx->Color.LogicOp == opcode)
660       return;
661 
662    FLUSH_VERTICES(ctx, _NEW_COLOR);
663    ctx->Color.LogicOp = opcode;
664 
665    if (ctx->Driver.LogicOpcode)
666       ctx->Driver.LogicOpcode( ctx, opcode );
667 }
668 
669 #if _HAVE_FULL_GL
670 void GLAPIENTRY
_mesa_IndexMask(GLuint mask)671 _mesa_IndexMask( GLuint mask )
672 {
673    GET_CURRENT_CONTEXT(ctx);
674    ASSERT_OUTSIDE_BEGIN_END(ctx);
675 
676    if (ctx->Color.IndexMask == mask)
677       return;
678 
679    FLUSH_VERTICES(ctx, _NEW_COLOR);
680    ctx->Color.IndexMask = mask;
681 }
682 #endif
683 
684 
685 /**
686  * Enable or disable writing of frame buffer color components.
687  *
688  * \param red whether to mask writing of the red color component.
689  * \param green whether to mask writing of the green color component.
690  * \param blue whether to mask writing of the blue color component.
691  * \param alpha whether to mask writing of the alpha color component.
692  *
693  * \sa glColorMask().
694  *
695  * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask.  On a
696  * change, flushes the vertices and notifies the driver via the
697  * dd_function_table::ColorMask callback.
698  */
699 void GLAPIENTRY
_mesa_ColorMask(GLboolean red,GLboolean green,GLboolean blue,GLboolean alpha)700 _mesa_ColorMask( GLboolean red, GLboolean green,
701                  GLboolean blue, GLboolean alpha )
702 {
703    GET_CURRENT_CONTEXT(ctx);
704    GLubyte tmp[4];
705    GLuint i;
706    GLboolean flushed;
707    ASSERT_OUTSIDE_BEGIN_END(ctx);
708 
709    if (MESA_VERBOSE & VERBOSE_API)
710       _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n",
711                   red, green, blue, alpha);
712 
713    /* Shouldn't have any information about channel depth in core mesa
714     * -- should probably store these as the native booleans:
715     */
716    tmp[RCOMP] = red    ? 0xff : 0x0;
717    tmp[GCOMP] = green  ? 0xff : 0x0;
718    tmp[BCOMP] = blue   ? 0xff : 0x0;
719    tmp[ACOMP] = alpha  ? 0xff : 0x0;
720 
721    flushed = GL_FALSE;
722    for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
723       if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) {
724          if (!flushed) {
725             FLUSH_VERTICES(ctx, _NEW_COLOR);
726          }
727          flushed = GL_TRUE;
728          COPY_4UBV(ctx->Color.ColorMask[i], tmp);
729       }
730    }
731 
732    if (ctx->Driver.ColorMask)
733       ctx->Driver.ColorMask( ctx, red, green, blue, alpha );
734 }
735 
736 
737 /**
738  * For GL_EXT_draw_buffers2 and GL3
739  */
740 void GLAPIENTRY
_mesa_ColorMaskIndexed(GLuint buf,GLboolean red,GLboolean green,GLboolean blue,GLboolean alpha)741 _mesa_ColorMaskIndexed( GLuint buf, GLboolean red, GLboolean green,
742                         GLboolean blue, GLboolean alpha )
743 {
744    GLubyte tmp[4];
745    GET_CURRENT_CONTEXT(ctx);
746    ASSERT_OUTSIDE_BEGIN_END(ctx);
747 
748    if (MESA_VERBOSE & VERBOSE_API)
749       _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n",
750                   buf, red, green, blue, alpha);
751 
752    if (buf >= ctx->Const.MaxDrawBuffers) {
753       _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf);
754       return;
755    }
756 
757    /* Shouldn't have any information about channel depth in core mesa
758     * -- should probably store these as the native booleans:
759     */
760    tmp[RCOMP] = red    ? 0xff : 0x0;
761    tmp[GCOMP] = green  ? 0xff : 0x0;
762    tmp[BCOMP] = blue   ? 0xff : 0x0;
763    tmp[ACOMP] = alpha  ? 0xff : 0x0;
764 
765    if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf]))
766       return;
767 
768    FLUSH_VERTICES(ctx, _NEW_COLOR);
769    COPY_4UBV(ctx->Color.ColorMask[buf], tmp);
770 
771    if (ctx->Driver.ColorMaskIndexed)
772       ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha);
773 }
774 
775 
776 void GLAPIENTRY
_mesa_ClampColorARB(GLenum target,GLenum clamp)777 _mesa_ClampColorARB(GLenum target, GLenum clamp)
778 {
779    GET_CURRENT_CONTEXT(ctx);
780 
781    ASSERT_OUTSIDE_BEGIN_END(ctx);
782 
783    if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) {
784       _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)");
785       return;
786    }
787 
788    switch (target) {
789    case GL_CLAMP_VERTEX_COLOR_ARB:
790       FLUSH_VERTICES(ctx, _NEW_LIGHT);
791       ctx->Light.ClampVertexColor = clamp;
792       break;
793    case GL_CLAMP_FRAGMENT_COLOR_ARB:
794       FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP);
795       ctx->Color.ClampFragmentColor = clamp;
796       break;
797    case GL_CLAMP_READ_COLOR_ARB:
798       FLUSH_VERTICES(ctx, _NEW_COLOR);
799       ctx->Color.ClampReadColor = clamp;
800       break;
801    default:
802       _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)");
803       return;
804    }
805 }
806 
807 
808 
809 
810 /**********************************************************************/
811 /** \name Initialization */
812 /*@{*/
813 
814 /**
815  * Initialization of the context's Color attribute group.
816  *
817  * \param ctx GL context.
818  *
819  * Initializes the related fields in the context color attribute group,
820  * __struct gl_contextRec::Color.
821  */
_mesa_init_color(struct gl_context * ctx)822 void _mesa_init_color( struct gl_context * ctx )
823 {
824    GLuint i;
825 
826    /* Color buffer group */
827    ctx->Color.IndexMask = ~0u;
828    memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask));
829    ctx->Color.ClearIndex = 0;
830    ASSIGN_4V( ctx->Color.ClearColor.f, 0, 0, 0, 0 );
831    ctx->Color.AlphaEnabled = GL_FALSE;
832    ctx->Color.AlphaFunc = GL_ALWAYS;
833    ctx->Color.AlphaRef = 0;
834    ctx->Color.BlendEnabled = 0x0;
835    for (i = 0; i < Elements(ctx->Color.Blend); i++) {
836       ctx->Color.Blend[i].SrcRGB = GL_ONE;
837       ctx->Color.Blend[i].DstRGB = GL_ZERO;
838       ctx->Color.Blend[i].SrcA = GL_ONE;
839       ctx->Color.Blend[i].DstA = GL_ZERO;
840       ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD;
841       ctx->Color.Blend[i].EquationA = GL_FUNC_ADD;
842    }
843    ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 );
844    ASSIGN_4V( ctx->Color.BlendColorUnclamped, 0.0, 0.0, 0.0, 0.0 );
845    ctx->Color.IndexLogicOpEnabled = GL_FALSE;
846    ctx->Color.ColorLogicOpEnabled = GL_FALSE;
847    ctx->Color.LogicOp = GL_COPY;
848    ctx->Color.DitherFlag = GL_TRUE;
849 
850    if (ctx->Visual.doubleBufferMode) {
851       ctx->Color.DrawBuffer[0] = GL_BACK;
852    }
853    else {
854       ctx->Color.DrawBuffer[0] = GL_FRONT;
855    }
856 
857    ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB;
858    ctx->Color._ClampFragmentColor = GL_TRUE;
859    ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB;
860    ctx->Color._ClampReadColor = GL_TRUE;
861 }
862 
863 /*@}*/
864