1848b8605Smrg/**
2848b8605Smrg * \file blend.c
3848b8605Smrg * Blending operations.
4848b8605Smrg */
5848b8605Smrg
6848b8605Smrg/*
7848b8605Smrg * Mesa 3-D graphics library
8848b8605Smrg *
9848b8605Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
10848b8605Smrg *
11848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
12848b8605Smrg * copy of this software and associated documentation files (the "Software"),
13848b8605Smrg * to deal in the Software without restriction, including without limitation
14848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
16848b8605Smrg * Software is furnished to do so, subject to the following conditions:
17848b8605Smrg *
18848b8605Smrg * The above copyright notice and this permission notice shall be included
19848b8605Smrg * in all copies or substantial portions of the Software.
20848b8605Smrg *
21848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
28848b8605Smrg */
29848b8605Smrg
30848b8605Smrg
31848b8605Smrg
32848b8605Smrg#include "glheader.h"
33848b8605Smrg#include "blend.h"
34848b8605Smrg#include "context.h"
35848b8605Smrg#include "enums.h"
36848b8605Smrg#include "macros.h"
37848b8605Smrg#include "mtypes.h"
38848b8605Smrg
39848b8605Smrg
40848b8605Smrg
41848b8605Smrg/**
42848b8605Smrg * Check if given blend source factor is legal.
43848b8605Smrg * \return GL_TRUE if legal, GL_FALSE otherwise.
44848b8605Smrg */
45848b8605Smrgstatic GLboolean
46848b8605Smrglegal_src_factor(const struct gl_context *ctx, GLenum factor)
47848b8605Smrg{
48848b8605Smrg   switch (factor) {
49848b8605Smrg   case GL_SRC_COLOR:
50848b8605Smrg   case GL_ONE_MINUS_SRC_COLOR:
51848b8605Smrg   case GL_ZERO:
52848b8605Smrg   case GL_ONE:
53848b8605Smrg   case GL_DST_COLOR:
54848b8605Smrg   case GL_ONE_MINUS_DST_COLOR:
55848b8605Smrg   case GL_SRC_ALPHA:
56848b8605Smrg   case GL_ONE_MINUS_SRC_ALPHA:
57848b8605Smrg   case GL_DST_ALPHA:
58848b8605Smrg   case GL_ONE_MINUS_DST_ALPHA:
59848b8605Smrg   case GL_SRC_ALPHA_SATURATE:
60848b8605Smrg      return GL_TRUE;
61848b8605Smrg   case GL_CONSTANT_COLOR:
62848b8605Smrg   case GL_ONE_MINUS_CONSTANT_COLOR:
63848b8605Smrg   case GL_CONSTANT_ALPHA:
64848b8605Smrg   case GL_ONE_MINUS_CONSTANT_ALPHA:
65848b8605Smrg      return _mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES2;
66848b8605Smrg   case GL_SRC1_COLOR:
67848b8605Smrg   case GL_SRC1_ALPHA:
68848b8605Smrg   case GL_ONE_MINUS_SRC1_COLOR:
69848b8605Smrg   case GL_ONE_MINUS_SRC1_ALPHA:
70b8e80941Smrg      return ctx->API != API_OPENGLES
71848b8605Smrg         && ctx->Extensions.ARB_blend_func_extended;
72848b8605Smrg   default:
73848b8605Smrg      return GL_FALSE;
74848b8605Smrg   }
75848b8605Smrg}
76848b8605Smrg
77848b8605Smrg
78848b8605Smrg/**
79848b8605Smrg * Check if given blend destination factor is legal.
80848b8605Smrg * \return GL_TRUE if legal, GL_FALSE otherwise.
81848b8605Smrg */
82848b8605Smrgstatic GLboolean
83848b8605Smrglegal_dst_factor(const struct gl_context *ctx, GLenum factor)
84848b8605Smrg{
85848b8605Smrg   switch (factor) {
86848b8605Smrg   case GL_DST_COLOR:
87848b8605Smrg   case GL_ONE_MINUS_DST_COLOR:
88848b8605Smrg   case GL_ZERO:
89848b8605Smrg   case GL_ONE:
90848b8605Smrg   case GL_SRC_COLOR:
91848b8605Smrg   case GL_ONE_MINUS_SRC_COLOR:
92848b8605Smrg   case GL_SRC_ALPHA:
93848b8605Smrg   case GL_ONE_MINUS_SRC_ALPHA:
94848b8605Smrg   case GL_DST_ALPHA:
95848b8605Smrg   case GL_ONE_MINUS_DST_ALPHA:
96848b8605Smrg      return GL_TRUE;
97848b8605Smrg   case GL_CONSTANT_COLOR:
98848b8605Smrg   case GL_ONE_MINUS_CONSTANT_COLOR:
99848b8605Smrg   case GL_CONSTANT_ALPHA:
100848b8605Smrg   case GL_ONE_MINUS_CONSTANT_ALPHA:
101848b8605Smrg      return _mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES2;
102848b8605Smrg   case GL_SRC_ALPHA_SATURATE:
103b8e80941Smrg      return (ctx->API != API_OPENGLES
104848b8605Smrg              && ctx->Extensions.ARB_blend_func_extended)
105848b8605Smrg         || _mesa_is_gles3(ctx);
106848b8605Smrg   case GL_SRC1_COLOR:
107848b8605Smrg   case GL_SRC1_ALPHA:
108848b8605Smrg   case GL_ONE_MINUS_SRC1_COLOR:
109848b8605Smrg   case GL_ONE_MINUS_SRC1_ALPHA:
110b8e80941Smrg      return ctx->API != API_OPENGLES
111848b8605Smrg         && ctx->Extensions.ARB_blend_func_extended;
112848b8605Smrg   default:
113848b8605Smrg      return GL_FALSE;
114848b8605Smrg   }
115848b8605Smrg}
116848b8605Smrg
117848b8605Smrg
118848b8605Smrg/**
119848b8605Smrg * Check if src/dest RGB/A blend factors are legal.  If not generate
120848b8605Smrg * a GL error.
121848b8605Smrg * \return GL_TRUE if factors are legal, GL_FALSE otherwise.
122848b8605Smrg */
123848b8605Smrgstatic GLboolean
124848b8605Smrgvalidate_blend_factors(struct gl_context *ctx, const char *func,
125848b8605Smrg                       GLenum sfactorRGB, GLenum dfactorRGB,
126848b8605Smrg                       GLenum sfactorA, GLenum dfactorA)
127848b8605Smrg{
128848b8605Smrg   if (!legal_src_factor(ctx, sfactorRGB)) {
129848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
130848b8605Smrg                  "%s(sfactorRGB = %s)", func,
131b8e80941Smrg                  _mesa_enum_to_string(sfactorRGB));
132848b8605Smrg      return GL_FALSE;
133848b8605Smrg   }
134848b8605Smrg
135848b8605Smrg   if (!legal_dst_factor(ctx, dfactorRGB)) {
136848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
137848b8605Smrg                  "%s(dfactorRGB = %s)", func,
138b8e80941Smrg                  _mesa_enum_to_string(dfactorRGB));
139848b8605Smrg      return GL_FALSE;
140848b8605Smrg   }
141848b8605Smrg
142848b8605Smrg   if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) {
143848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
144848b8605Smrg                  "%s(sfactorA = %s)", func,
145b8e80941Smrg                  _mesa_enum_to_string(sfactorA));
146848b8605Smrg      return GL_FALSE;
147848b8605Smrg   }
148848b8605Smrg
149848b8605Smrg   if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) {
150848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
151848b8605Smrg                  "%s(dfactorA = %s)", func,
152b8e80941Smrg                  _mesa_enum_to_string(dfactorA));
153848b8605Smrg      return GL_FALSE;
154848b8605Smrg   }
155848b8605Smrg
156848b8605Smrg   return GL_TRUE;
157848b8605Smrg}
158848b8605Smrg
159848b8605Smrg
160848b8605Smrgstatic GLboolean
161848b8605Smrgblend_factor_is_dual_src(GLenum factor)
162848b8605Smrg{
163848b8605Smrg   return (factor == GL_SRC1_COLOR ||
164848b8605Smrg	   factor == GL_SRC1_ALPHA ||
165848b8605Smrg	   factor == GL_ONE_MINUS_SRC1_COLOR ||
166848b8605Smrg	   factor == GL_ONE_MINUS_SRC1_ALPHA);
167848b8605Smrg}
168848b8605Smrg
169848b8605Smrgstatic void
170848b8605Smrgupdate_uses_dual_src(struct gl_context *ctx, int buf)
171848b8605Smrg{
172848b8605Smrg   ctx->Color.Blend[buf]._UsesDualSrc =
173848b8605Smrg      (blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcRGB) ||
174848b8605Smrg       blend_factor_is_dual_src(ctx->Color.Blend[buf].DstRGB) ||
175848b8605Smrg       blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcA) ||
176848b8605Smrg       blend_factor_is_dual_src(ctx->Color.Blend[buf].DstA));
177848b8605Smrg}
178848b8605Smrg
179b8e80941Smrg
180b8e80941Smrg/**
181b8e80941Smrg * Return the number of per-buffer blend states to update in
182b8e80941Smrg * glBlendFunc, glBlendFuncSeparate, glBlendEquation, etc.
183b8e80941Smrg */
184b8e80941Smrgstatic inline unsigned
185b8e80941Smrgnum_buffers(const struct gl_context *ctx)
186b8e80941Smrg{
187b8e80941Smrg   return ctx->Extensions.ARB_draw_buffers_blend
188b8e80941Smrg      ? ctx->Const.MaxDrawBuffers : 1;
189b8e80941Smrg}
190b8e80941Smrg
191b8e80941Smrg
192b8e80941Smrg/* Returns true if there was no change */
193b8e80941Smrgstatic bool
194b8e80941Smrgskip_blend_state_update(const struct gl_context *ctx,
195b8e80941Smrg                        GLenum sfactorRGB, GLenum dfactorRGB,
196b8e80941Smrg                        GLenum sfactorA, GLenum dfactorA)
197b8e80941Smrg{
198b8e80941Smrg   /* Check if we're really changing any state.  If not, return early. */
199b8e80941Smrg   if (ctx->Color._BlendFuncPerBuffer) {
200b8e80941Smrg      const unsigned numBuffers = num_buffers(ctx);
201b8e80941Smrg
202b8e80941Smrg      /* Check all per-buffer states */
203b8e80941Smrg      for (unsigned buf = 0; buf < numBuffers; buf++) {
204b8e80941Smrg         if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB ||
205b8e80941Smrg             ctx->Color.Blend[buf].DstRGB != dfactorRGB ||
206b8e80941Smrg             ctx->Color.Blend[buf].SrcA != sfactorA ||
207b8e80941Smrg             ctx->Color.Blend[buf].DstA != dfactorA) {
208b8e80941Smrg            return false;
209b8e80941Smrg         }
210b8e80941Smrg      }
211b8e80941Smrg   }
212b8e80941Smrg   else {
213b8e80941Smrg      /* only need to check 0th per-buffer state */
214b8e80941Smrg      if (ctx->Color.Blend[0].SrcRGB != sfactorRGB ||
215b8e80941Smrg          ctx->Color.Blend[0].DstRGB != dfactorRGB ||
216b8e80941Smrg          ctx->Color.Blend[0].SrcA != sfactorA ||
217b8e80941Smrg          ctx->Color.Blend[0].DstA != dfactorA) {
218b8e80941Smrg         return false;
219b8e80941Smrg      }
220b8e80941Smrg   }
221b8e80941Smrg
222b8e80941Smrg   return true;
223b8e80941Smrg}
224b8e80941Smrg
225b8e80941Smrg
226b8e80941Smrgstatic void
227b8e80941Smrgblend_func_separate(struct gl_context *ctx,
228b8e80941Smrg                    GLenum sfactorRGB, GLenum dfactorRGB,
229b8e80941Smrg                    GLenum sfactorA, GLenum dfactorA)
230b8e80941Smrg{
231b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewBlend ? 0 : _NEW_COLOR);
232b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewBlend;
233b8e80941Smrg
234b8e80941Smrg   const unsigned numBuffers = num_buffers(ctx);
235b8e80941Smrg   for (unsigned buf = 0; buf < numBuffers; buf++) {
236b8e80941Smrg      ctx->Color.Blend[buf].SrcRGB = sfactorRGB;
237b8e80941Smrg      ctx->Color.Blend[buf].DstRGB = dfactorRGB;
238b8e80941Smrg      ctx->Color.Blend[buf].SrcA = sfactorA;
239b8e80941Smrg      ctx->Color.Blend[buf].DstA = dfactorA;
240b8e80941Smrg   }
241b8e80941Smrg
242b8e80941Smrg   update_uses_dual_src(ctx, 0);
243b8e80941Smrg   for (unsigned buf = 1; buf < numBuffers; buf++) {
244b8e80941Smrg      ctx->Color.Blend[buf]._UsesDualSrc = ctx->Color.Blend[0]._UsesDualSrc;
245b8e80941Smrg   }
246b8e80941Smrg
247b8e80941Smrg   ctx->Color._BlendFuncPerBuffer = GL_FALSE;
248b8e80941Smrg
249b8e80941Smrg   if (ctx->Driver.BlendFuncSeparate) {
250b8e80941Smrg      ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB,
251b8e80941Smrg                                    sfactorA, dfactorA);
252b8e80941Smrg   }
253b8e80941Smrg}
254b8e80941Smrg
255b8e80941Smrg
256b8e80941Smrg/**
257b8e80941Smrg * Specify the blending operation.
258b8e80941Smrg *
259b8e80941Smrg * \param sfactor source factor operator.
260b8e80941Smrg * \param dfactor destination factor operator.
261b8e80941Smrg *
262b8e80941Smrg * \sa glBlendFunc, glBlendFuncSeparateEXT
263b8e80941Smrg */
264b8e80941Smrgvoid GLAPIENTRY
265b8e80941Smrg_mesa_BlendFunc( GLenum sfactor, GLenum dfactor )
266b8e80941Smrg{
267b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
268b8e80941Smrg
269b8e80941Smrg   if (skip_blend_state_update(ctx, sfactor, dfactor, sfactor, dfactor))
270b8e80941Smrg      return;
271b8e80941Smrg
272b8e80941Smrg   if (!validate_blend_factors(ctx, "glBlendFunc",
273b8e80941Smrg                               sfactor, dfactor, sfactor, dfactor)) {
274b8e80941Smrg      return;
275b8e80941Smrg   }
276b8e80941Smrg
277b8e80941Smrg   blend_func_separate(ctx, sfactor, dfactor, sfactor, dfactor);
278b8e80941Smrg}
279b8e80941Smrg
280b8e80941Smrg
281b8e80941Smrgvoid GLAPIENTRY
282b8e80941Smrg_mesa_BlendFunc_no_error(GLenum sfactor, GLenum dfactor)
283b8e80941Smrg{
284b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
285b8e80941Smrg
286b8e80941Smrg   if (skip_blend_state_update(ctx, sfactor, dfactor, sfactor, dfactor))
287b8e80941Smrg      return;
288b8e80941Smrg
289b8e80941Smrg   blend_func_separate(ctx, sfactor, dfactor, sfactor, dfactor);
290b8e80941Smrg}
291b8e80941Smrg
292b8e80941Smrg
293848b8605Smrg/**
294848b8605Smrg * Set the separate blend source/dest factors for all draw buffers.
295848b8605Smrg *
296848b8605Smrg * \param sfactorRGB RGB source factor operator.
297848b8605Smrg * \param dfactorRGB RGB destination factor operator.
298848b8605Smrg * \param sfactorA alpha source factor operator.
299848b8605Smrg * \param dfactorA alpha destination factor operator.
300848b8605Smrg */
301848b8605Smrgvoid GLAPIENTRY
302848b8605Smrg_mesa_BlendFuncSeparate( GLenum sfactorRGB, GLenum dfactorRGB,
303848b8605Smrg                            GLenum sfactorA, GLenum dfactorA )
304848b8605Smrg{
305848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
306848b8605Smrg
307848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
308848b8605Smrg      _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n",
309b8e80941Smrg                  _mesa_enum_to_string(sfactorRGB),
310b8e80941Smrg                  _mesa_enum_to_string(dfactorRGB),
311b8e80941Smrg                  _mesa_enum_to_string(sfactorA),
312b8e80941Smrg                  _mesa_enum_to_string(dfactorA));
313b8e80941Smrg
314b8e80941Smrg
315b8e80941Smrg
316b8e80941Smrg   if (skip_blend_state_update(ctx, sfactorRGB, dfactorRGB, sfactorA, dfactorA))
317b8e80941Smrg      return;
318848b8605Smrg
319848b8605Smrg   if (!validate_blend_factors(ctx, "glBlendFuncSeparate",
320848b8605Smrg                               sfactorRGB, dfactorRGB,
321848b8605Smrg                               sfactorA, dfactorA)) {
322848b8605Smrg      return;
323848b8605Smrg   }
324848b8605Smrg
325b8e80941Smrg   blend_func_separate(ctx, sfactorRGB, dfactorRGB, sfactorA, dfactorA);
326b8e80941Smrg}
327848b8605Smrg
328b8e80941Smrg
329b8e80941Smrgvoid GLAPIENTRY
330b8e80941Smrg_mesa_BlendFuncSeparate_no_error(GLenum sfactorRGB, GLenum dfactorRGB,
331b8e80941Smrg                                 GLenum sfactorA, GLenum dfactorA)
332b8e80941Smrg{
333b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
334b8e80941Smrg
335b8e80941Smrg   if (skip_blend_state_update(ctx, sfactorRGB, dfactorRGB, sfactorA, dfactorA))
336848b8605Smrg      return;
337848b8605Smrg
338b8e80941Smrg   blend_func_separate(ctx, sfactorRGB, dfactorRGB, sfactorA, dfactorA);
339b8e80941Smrg}
340848b8605Smrg
341848b8605Smrg
342b8e80941Smrgvoid GLAPIENTRY
343b8e80941Smrg_mesa_BlendFunciARB_no_error(GLuint buf, GLenum sfactor, GLenum dfactor)
344b8e80941Smrg{
345b8e80941Smrg   _mesa_BlendFuncSeparateiARB_no_error(buf, sfactor, dfactor, sfactor,
346b8e80941Smrg                                        dfactor);
347848b8605Smrg}
348848b8605Smrg
349848b8605Smrg
350848b8605Smrg/**
351848b8605Smrg * Set blend source/dest factors for one color buffer/target.
352848b8605Smrg */
353848b8605Smrgvoid GLAPIENTRY
354848b8605Smrg_mesa_BlendFunciARB(GLuint buf, GLenum sfactor, GLenum dfactor)
355848b8605Smrg{
356848b8605Smrg   _mesa_BlendFuncSeparateiARB(buf, sfactor, dfactor, sfactor, dfactor);
357848b8605Smrg}
358848b8605Smrg
359848b8605Smrg
360b8e80941Smrgstatic ALWAYS_INLINE void
361b8e80941Smrgblend_func_separatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB,
362b8e80941Smrg                     GLenum sfactorA, GLenum dfactorA, bool no_error)
363848b8605Smrg{
364848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
365848b8605Smrg
366b8e80941Smrg   if (!no_error) {
367b8e80941Smrg      if (!ctx->Extensions.ARB_draw_buffers_blend) {
368b8e80941Smrg         _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()");
369b8e80941Smrg         return;
370b8e80941Smrg      }
371848b8605Smrg
372b8e80941Smrg      if (buf >= ctx->Const.MaxDrawBuffers) {
373b8e80941Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)",
374b8e80941Smrg                     buf);
375b8e80941Smrg         return;
376b8e80941Smrg      }
377848b8605Smrg   }
378848b8605Smrg
379848b8605Smrg   if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB &&
380848b8605Smrg       ctx->Color.Blend[buf].DstRGB == dfactorRGB &&
381848b8605Smrg       ctx->Color.Blend[buf].SrcA == sfactorA &&
382848b8605Smrg       ctx->Color.Blend[buf].DstA == dfactorA)
383848b8605Smrg      return; /* no change */
384848b8605Smrg
385b8e80941Smrg   if (!no_error && !validate_blend_factors(ctx, "glBlendFuncSeparatei",
386b8e80941Smrg                                            sfactorRGB, dfactorRGB,
387b8e80941Smrg                                            sfactorA, dfactorA)) {
388b8e80941Smrg      return;
389b8e80941Smrg   }
390b8e80941Smrg
391b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewBlend ? 0 : _NEW_COLOR);
392b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewBlend;
393848b8605Smrg
394848b8605Smrg   ctx->Color.Blend[buf].SrcRGB = sfactorRGB;
395848b8605Smrg   ctx->Color.Blend[buf].DstRGB = dfactorRGB;
396848b8605Smrg   ctx->Color.Blend[buf].SrcA = sfactorA;
397848b8605Smrg   ctx->Color.Blend[buf].DstA = dfactorA;
398848b8605Smrg   update_uses_dual_src(ctx, buf);
399848b8605Smrg   ctx->Color._BlendFuncPerBuffer = GL_TRUE;
400b8e80941Smrg}
401848b8605Smrg
402b8e80941Smrg
403b8e80941Smrgvoid GLAPIENTRY
404b8e80941Smrg_mesa_BlendFuncSeparateiARB_no_error(GLuint buf, GLenum sfactorRGB,
405b8e80941Smrg                                     GLenum dfactorRGB, GLenum sfactorA,
406b8e80941Smrg                                     GLenum dfactorA)
407b8e80941Smrg{
408b8e80941Smrg   blend_func_separatei(buf, sfactorRGB, dfactorRGB, sfactorA, dfactorA,
409b8e80941Smrg                        true);
410848b8605Smrg}
411848b8605Smrg
412848b8605Smrg
413848b8605Smrg/**
414b8e80941Smrg * Set separate blend source/dest factors for one color buffer/target.
415848b8605Smrg */
416b8e80941Smrgvoid GLAPIENTRY
417b8e80941Smrg_mesa_BlendFuncSeparateiARB(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB,
418b8e80941Smrg                            GLenum sfactorA, GLenum dfactorA)
419b8e80941Smrg{
420b8e80941Smrg   blend_func_separatei(buf, sfactorRGB, dfactorRGB, sfactorA, dfactorA,
421b8e80941Smrg                        false);
422b8e80941Smrg}
423b8e80941Smrg
424b8e80941Smrg
425b8e80941Smrg/**
426b8e80941Smrg * Return true if \p mode is a legal blending equation, excluding
427b8e80941Smrg * GL_KHR_blend_equation_advanced modes.
428b8e80941Smrg */
429b8e80941Smrgstatic bool
430b8e80941Smrglegal_simple_blend_equation(const struct gl_context *ctx, GLenum mode)
431848b8605Smrg{
432848b8605Smrg   switch (mode) {
433848b8605Smrg   case GL_FUNC_ADD:
434848b8605Smrg   case GL_FUNC_SUBTRACT:
435848b8605Smrg   case GL_FUNC_REVERSE_SUBTRACT:
436848b8605Smrg      return GL_TRUE;
437848b8605Smrg   case GL_MIN:
438848b8605Smrg   case GL_MAX:
439848b8605Smrg      return ctx->Extensions.EXT_blend_minmax;
440848b8605Smrg   default:
441848b8605Smrg      return GL_FALSE;
442848b8605Smrg   }
443848b8605Smrg}
444848b8605Smrg
445b8e80941Smrgstatic enum gl_advanced_blend_mode
446b8e80941Smrgadvanced_blend_mode_from_gl_enum(GLenum mode)
447b8e80941Smrg{
448b8e80941Smrg   switch (mode) {
449b8e80941Smrg   case GL_MULTIPLY_KHR:
450b8e80941Smrg      return BLEND_MULTIPLY;
451b8e80941Smrg   case GL_SCREEN_KHR:
452b8e80941Smrg      return BLEND_SCREEN;
453b8e80941Smrg   case GL_OVERLAY_KHR:
454b8e80941Smrg      return BLEND_OVERLAY;
455b8e80941Smrg   case GL_DARKEN_KHR:
456b8e80941Smrg      return BLEND_DARKEN;
457b8e80941Smrg   case GL_LIGHTEN_KHR:
458b8e80941Smrg      return BLEND_LIGHTEN;
459b8e80941Smrg   case GL_COLORDODGE_KHR:
460b8e80941Smrg      return BLEND_COLORDODGE;
461b8e80941Smrg   case GL_COLORBURN_KHR:
462b8e80941Smrg      return BLEND_COLORBURN;
463b8e80941Smrg   case GL_HARDLIGHT_KHR:
464b8e80941Smrg      return BLEND_HARDLIGHT;
465b8e80941Smrg   case GL_SOFTLIGHT_KHR:
466b8e80941Smrg      return BLEND_SOFTLIGHT;
467b8e80941Smrg   case GL_DIFFERENCE_KHR:
468b8e80941Smrg      return BLEND_DIFFERENCE;
469b8e80941Smrg   case GL_EXCLUSION_KHR:
470b8e80941Smrg      return BLEND_EXCLUSION;
471b8e80941Smrg   case GL_HSL_HUE_KHR:
472b8e80941Smrg      return BLEND_HSL_HUE;
473b8e80941Smrg   case GL_HSL_SATURATION_KHR:
474b8e80941Smrg      return BLEND_HSL_SATURATION;
475b8e80941Smrg   case GL_HSL_COLOR_KHR:
476b8e80941Smrg      return BLEND_HSL_COLOR;
477b8e80941Smrg   case GL_HSL_LUMINOSITY_KHR:
478b8e80941Smrg      return BLEND_HSL_LUMINOSITY;
479b8e80941Smrg   default:
480b8e80941Smrg      return BLEND_NONE;
481b8e80941Smrg   }
482b8e80941Smrg}
483b8e80941Smrg
484b8e80941Smrg/**
485b8e80941Smrg * If \p mode is one of the advanced blending equations defined by
486b8e80941Smrg * GL_KHR_blend_equation_advanced (and the extension is supported),
487b8e80941Smrg * return the corresponding BLEND_* enum.  Otherwise, return BLEND_NONE
488b8e80941Smrg * (which can also be treated as false).
489b8e80941Smrg */
490b8e80941Smrgstatic enum gl_advanced_blend_mode
491b8e80941Smrgadvanced_blend_mode(const struct gl_context *ctx, GLenum mode)
492b8e80941Smrg{
493b8e80941Smrg   return _mesa_has_KHR_blend_equation_advanced(ctx) ?
494b8e80941Smrg          advanced_blend_mode_from_gl_enum(mode) : BLEND_NONE;
495b8e80941Smrg}
496848b8605Smrg
497848b8605Smrg/* This is really an extension function! */
498848b8605Smrgvoid GLAPIENTRY
499848b8605Smrg_mesa_BlendEquation( GLenum mode )
500848b8605Smrg{
501848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
502b8e80941Smrg   const unsigned numBuffers = num_buffers(ctx);
503b8e80941Smrg   unsigned buf;
504b8e80941Smrg   bool changed = false;
505b8e80941Smrg   enum gl_advanced_blend_mode advanced_mode = advanced_blend_mode(ctx, mode);
506848b8605Smrg
507848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
508848b8605Smrg      _mesa_debug(ctx, "glBlendEquation(%s)\n",
509b8e80941Smrg                  _mesa_enum_to_string(mode));
510b8e80941Smrg
511b8e80941Smrg   if (ctx->Color._BlendEquationPerBuffer) {
512b8e80941Smrg      /* Check all per-buffer states */
513b8e80941Smrg      for (buf = 0; buf < numBuffers; buf++) {
514b8e80941Smrg         if (ctx->Color.Blend[buf].EquationRGB != mode ||
515b8e80941Smrg             ctx->Color.Blend[buf].EquationA != mode) {
516b8e80941Smrg            changed = true;
517b8e80941Smrg            break;
518b8e80941Smrg         }
519b8e80941Smrg      }
520848b8605Smrg   }
521b8e80941Smrg   else {
522b8e80941Smrg      /* only need to check 0th per-buffer state */
523b8e80941Smrg      if (ctx->Color.Blend[0].EquationRGB != mode ||
524b8e80941Smrg          ctx->Color.Blend[0].EquationA != mode) {
525b8e80941Smrg         changed = true;
526848b8605Smrg      }
527848b8605Smrg   }
528b8e80941Smrg
529848b8605Smrg   if (!changed)
530848b8605Smrg      return;
531848b8605Smrg
532b8e80941Smrg
533b8e80941Smrg   if (!legal_simple_blend_equation(ctx, mode) && !advanced_mode) {
534b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
535b8e80941Smrg      return;
536b8e80941Smrg   }
537b8e80941Smrg
538b8e80941Smrg   _mesa_flush_vertices_for_blend_adv(ctx, ctx->Color.BlendEnabled,
539b8e80941Smrg                                      advanced_mode);
540b8e80941Smrg
541848b8605Smrg   for (buf = 0; buf < numBuffers; buf++) {
542848b8605Smrg      ctx->Color.Blend[buf].EquationRGB = mode;
543848b8605Smrg      ctx->Color.Blend[buf].EquationA = mode;
544848b8605Smrg   }
545848b8605Smrg   ctx->Color._BlendEquationPerBuffer = GL_FALSE;
546b8e80941Smrg   ctx->Color._AdvancedBlendMode = advanced_mode;
547848b8605Smrg
548848b8605Smrg   if (ctx->Driver.BlendEquationSeparate)
549b8e80941Smrg      ctx->Driver.BlendEquationSeparate(ctx, mode, mode);
550848b8605Smrg}
551848b8605Smrg
552848b8605Smrg
553848b8605Smrg/**
554848b8605Smrg * Set blend equation for one color buffer/target.
555848b8605Smrg */
556b8e80941Smrgstatic void
557b8e80941Smrgblend_equationi(struct gl_context *ctx, GLuint buf, GLenum mode,
558b8e80941Smrg                enum gl_advanced_blend_mode advanced_mode)
559848b8605Smrg{
560848b8605Smrg   if (ctx->Color.Blend[buf].EquationRGB == mode &&
561848b8605Smrg       ctx->Color.Blend[buf].EquationA == mode)
562848b8605Smrg      return;  /* no change */
563848b8605Smrg
564b8e80941Smrg   _mesa_flush_vertices_for_blend_adv(ctx, ctx->Color.BlendEnabled,
565b8e80941Smrg                                      advanced_mode);
566848b8605Smrg   ctx->Color.Blend[buf].EquationRGB = mode;
567848b8605Smrg   ctx->Color.Blend[buf].EquationA = mode;
568848b8605Smrg   ctx->Color._BlendEquationPerBuffer = GL_TRUE;
569848b8605Smrg
570b8e80941Smrg   if (buf == 0)
571b8e80941Smrg      ctx->Color._AdvancedBlendMode = advanced_mode;
572b8e80941Smrg}
573b8e80941Smrg
574b8e80941Smrg
575b8e80941Smrgvoid GLAPIENTRY
576b8e80941Smrg_mesa_BlendEquationiARB_no_error(GLuint buf, GLenum mode)
577b8e80941Smrg{
578b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
579b8e80941Smrg
580b8e80941Smrg   enum gl_advanced_blend_mode advanced_mode = advanced_blend_mode(ctx, mode);
581b8e80941Smrg   blend_equationi(ctx, buf, mode, advanced_mode);
582848b8605Smrg}
583848b8605Smrg
584848b8605Smrg
585848b8605Smrgvoid GLAPIENTRY
586b8e80941Smrg_mesa_BlendEquationiARB(GLuint buf, GLenum mode)
587848b8605Smrg{
588848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
589b8e80941Smrg   enum gl_advanced_blend_mode advanced_mode = advanced_blend_mode(ctx, mode);
590848b8605Smrg
591848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
592b8e80941Smrg      _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n",
593b8e80941Smrg                  buf, _mesa_enum_to_string(mode));
594848b8605Smrg
595b8e80941Smrg   if (buf >= ctx->Const.MaxDrawBuffers) {
596b8e80941Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationi(buffer=%u)",
597b8e80941Smrg                  buf);
598848b8605Smrg      return;
599848b8605Smrg   }
600848b8605Smrg
601b8e80941Smrg   if (!legal_simple_blend_equation(ctx, mode) && !advanced_mode) {
602b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi");
603848b8605Smrg      return;
604848b8605Smrg   }
605848b8605Smrg
606b8e80941Smrg   blend_equationi(ctx, buf, mode, advanced_mode);
607b8e80941Smrg}
608848b8605Smrg
609848b8605Smrg
610b8e80941Smrgstatic void
611b8e80941Smrgblend_equation_separate(struct gl_context *ctx, GLenum modeRGB, GLenum modeA,
612b8e80941Smrg                        bool no_error)
613b8e80941Smrg{
614b8e80941Smrg   const unsigned numBuffers = num_buffers(ctx);
615b8e80941Smrg   unsigned buf;
616b8e80941Smrg   bool changed = false;
617b8e80941Smrg
618b8e80941Smrg   if (ctx->Color._BlendEquationPerBuffer) {
619b8e80941Smrg      /* Check all per-buffer states */
620b8e80941Smrg      for (buf = 0; buf < numBuffers; buf++) {
621b8e80941Smrg         if (ctx->Color.Blend[buf].EquationRGB != modeRGB ||
622b8e80941Smrg             ctx->Color.Blend[buf].EquationA != modeA) {
623b8e80941Smrg            changed = true;
624b8e80941Smrg            break;
625b8e80941Smrg         }
626b8e80941Smrg      }
627b8e80941Smrg   } else {
628b8e80941Smrg      /* only need to check 0th per-buffer state */
629b8e80941Smrg      if (ctx->Color.Blend[0].EquationRGB != modeRGB ||
630b8e80941Smrg          ctx->Color.Blend[0].EquationA != modeA) {
631b8e80941Smrg         changed = true;
632848b8605Smrg      }
633848b8605Smrg   }
634b8e80941Smrg
635848b8605Smrg   if (!changed)
636848b8605Smrg      return;
637848b8605Smrg
638b8e80941Smrg   if (!no_error) {
639b8e80941Smrg      if ((modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate) {
640b8e80941Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
641b8e80941Smrg                     "glBlendEquationSeparateEXT not supported by driver");
642b8e80941Smrg         return;
643b8e80941Smrg      }
644b8e80941Smrg
645b8e80941Smrg      /* Only allow simple blending equations.
646b8e80941Smrg       * The GL_KHR_blend_equation_advanced spec says:
647b8e80941Smrg       *
648b8e80941Smrg       *    "NOTE: These enums are not accepted by the <modeRGB> or <modeAlpha>
649b8e80941Smrg       *     parameters of BlendEquationSeparate or BlendEquationSeparatei."
650b8e80941Smrg       */
651b8e80941Smrg      if (!legal_simple_blend_equation(ctx, modeRGB)) {
652b8e80941Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
653b8e80941Smrg                     "glBlendEquationSeparateEXT(modeRGB)");
654b8e80941Smrg         return;
655b8e80941Smrg      }
656b8e80941Smrg
657b8e80941Smrg      if (!legal_simple_blend_equation(ctx, modeA)) {
658b8e80941Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)");
659b8e80941Smrg         return;
660b8e80941Smrg      }
661b8e80941Smrg   }
662b8e80941Smrg
663b8e80941Smrg   _mesa_flush_vertices_for_blend_state(ctx);
664b8e80941Smrg
665848b8605Smrg   for (buf = 0; buf < numBuffers; buf++) {
666848b8605Smrg      ctx->Color.Blend[buf].EquationRGB = modeRGB;
667848b8605Smrg      ctx->Color.Blend[buf].EquationA = modeA;
668848b8605Smrg   }
669848b8605Smrg   ctx->Color._BlendEquationPerBuffer = GL_FALSE;
670b8e80941Smrg   ctx->Color._AdvancedBlendMode = BLEND_NONE;
671848b8605Smrg
672848b8605Smrg   if (ctx->Driver.BlendEquationSeparate)
673848b8605Smrg      ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA);
674848b8605Smrg}
675848b8605Smrg
676848b8605Smrg
677b8e80941Smrgvoid GLAPIENTRY
678b8e80941Smrg_mesa_BlendEquationSeparate_no_error(GLenum modeRGB, GLenum modeA)
679b8e80941Smrg{
680b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
681b8e80941Smrg   blend_equation_separate(ctx, modeRGB, modeA, true);
682b8e80941Smrg}
683b8e80941Smrg
684b8e80941Smrg
685b8e80941Smrgvoid GLAPIENTRY
686b8e80941Smrg_mesa_BlendEquationSeparate(GLenum modeRGB, GLenum modeA)
687b8e80941Smrg{
688b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
689b8e80941Smrg
690b8e80941Smrg   if (MESA_VERBOSE & VERBOSE_API)
691b8e80941Smrg      _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n",
692b8e80941Smrg                  _mesa_enum_to_string(modeRGB),
693b8e80941Smrg                  _mesa_enum_to_string(modeA));
694b8e80941Smrg
695b8e80941Smrg   blend_equation_separate(ctx, modeRGB, modeA, false);
696b8e80941Smrg}
697b8e80941Smrg
698b8e80941Smrg
699b8e80941Smrgstatic ALWAYS_INLINE void
700b8e80941Smrgblend_equation_separatei(struct gl_context *ctx, GLuint buf, GLenum modeRGB,
701b8e80941Smrg                         GLenum modeA, bool no_error)
702b8e80941Smrg{
703b8e80941Smrg   if (ctx->Color.Blend[buf].EquationRGB == modeRGB &&
704b8e80941Smrg       ctx->Color.Blend[buf].EquationA == modeA)
705b8e80941Smrg      return;  /* no change */
706b8e80941Smrg
707b8e80941Smrg   if (!no_error) {
708b8e80941Smrg      /* Only allow simple blending equations.
709b8e80941Smrg       * The GL_KHR_blend_equation_advanced spec says:
710b8e80941Smrg       *
711b8e80941Smrg       *    "NOTE: These enums are not accepted by the <modeRGB> or <modeAlpha>
712b8e80941Smrg       *     parameters of BlendEquationSeparate or BlendEquationSeparatei."
713b8e80941Smrg       */
714b8e80941Smrg      if (!legal_simple_blend_equation(ctx, modeRGB)) {
715b8e80941Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)");
716b8e80941Smrg         return;
717b8e80941Smrg      }
718b8e80941Smrg
719b8e80941Smrg      if (!legal_simple_blend_equation(ctx, modeA)) {
720b8e80941Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)");
721b8e80941Smrg         return;
722b8e80941Smrg      }
723b8e80941Smrg   }
724b8e80941Smrg
725b8e80941Smrg   _mesa_flush_vertices_for_blend_state(ctx);
726b8e80941Smrg   ctx->Color.Blend[buf].EquationRGB = modeRGB;
727b8e80941Smrg   ctx->Color.Blend[buf].EquationA = modeA;
728b8e80941Smrg   ctx->Color._BlendEquationPerBuffer = GL_TRUE;
729b8e80941Smrg   ctx->Color._AdvancedBlendMode = BLEND_NONE;
730b8e80941Smrg}
731b8e80941Smrg
732b8e80941Smrg
733b8e80941Smrgvoid GLAPIENTRY
734b8e80941Smrg_mesa_BlendEquationSeparateiARB_no_error(GLuint buf, GLenum modeRGB,
735b8e80941Smrg                                         GLenum modeA)
736b8e80941Smrg{
737b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
738b8e80941Smrg   blend_equation_separatei(ctx, buf, modeRGB, modeA, true);
739b8e80941Smrg}
740b8e80941Smrg
741b8e80941Smrg
742848b8605Smrg/**
743848b8605Smrg * Set separate blend equations for one color buffer/target.
744848b8605Smrg */
745848b8605Smrgvoid GLAPIENTRY
746848b8605Smrg_mesa_BlendEquationSeparateiARB(GLuint buf, GLenum modeRGB, GLenum modeA)
747848b8605Smrg{
748848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
749848b8605Smrg
750848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
751848b8605Smrg      _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf,
752b8e80941Smrg                  _mesa_enum_to_string(modeRGB),
753b8e80941Smrg                  _mesa_enum_to_string(modeA));
754848b8605Smrg
755848b8605Smrg   if (buf >= ctx->Const.MaxDrawBuffers) {
756848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)",
757848b8605Smrg                  buf);
758848b8605Smrg      return;
759848b8605Smrg   }
760848b8605Smrg
761b8e80941Smrg   blend_equation_separatei(ctx, buf, modeRGB, modeA, false);
762848b8605Smrg}
763848b8605Smrg
764848b8605Smrg
765848b8605Smrg/**
766848b8605Smrg * Set the blending color.
767848b8605Smrg *
768848b8605Smrg * \param red red color component.
769848b8605Smrg * \param green green color component.
770848b8605Smrg * \param blue blue color component.
771848b8605Smrg * \param alpha alpha color component.
772848b8605Smrg *
773848b8605Smrg * \sa glBlendColor().
774848b8605Smrg *
775848b8605Smrg * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor.  On a
776848b8605Smrg * change, flushes the vertices and notifies the driver via
777848b8605Smrg * dd_function_table::BlendColor callback.
778848b8605Smrg */
779848b8605Smrgvoid GLAPIENTRY
780848b8605Smrg_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
781848b8605Smrg{
782848b8605Smrg   GLfloat tmp[4];
783848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
784848b8605Smrg
785848b8605Smrg   tmp[0] = red;
786848b8605Smrg   tmp[1] = green;
787848b8605Smrg   tmp[2] = blue;
788848b8605Smrg   tmp[3] = alpha;
789848b8605Smrg
790848b8605Smrg   if (TEST_EQ_4V(tmp, ctx->Color.BlendColorUnclamped))
791848b8605Smrg      return;
792848b8605Smrg
793b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewBlendColor ? 0 : _NEW_COLOR);
794b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewBlendColor;
795848b8605Smrg   COPY_4FV( ctx->Color.BlendColorUnclamped, tmp );
796848b8605Smrg
797848b8605Smrg   ctx->Color.BlendColor[0] = CLAMP(tmp[0], 0.0F, 1.0F);
798848b8605Smrg   ctx->Color.BlendColor[1] = CLAMP(tmp[1], 0.0F, 1.0F);
799848b8605Smrg   ctx->Color.BlendColor[2] = CLAMP(tmp[2], 0.0F, 1.0F);
800848b8605Smrg   ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F);
801848b8605Smrg
802848b8605Smrg   if (ctx->Driver.BlendColor)
803b8e80941Smrg      ctx->Driver.BlendColor(ctx, ctx->Color.BlendColor);
804848b8605Smrg}
805848b8605Smrg
806848b8605Smrg
807848b8605Smrg/**
808848b8605Smrg * Specify the alpha test function.
809848b8605Smrg *
810848b8605Smrg * \param func alpha comparison function.
811848b8605Smrg * \param ref reference value.
812848b8605Smrg *
813848b8605Smrg * Verifies the parameters and updates gl_colorbuffer_attrib.
814848b8605Smrg * On a change, flushes the vertices and notifies the driver via
815848b8605Smrg * dd_function_table::AlphaFunc callback.
816848b8605Smrg */
817848b8605Smrgvoid GLAPIENTRY
818848b8605Smrg_mesa_AlphaFunc( GLenum func, GLclampf ref )
819848b8605Smrg{
820848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
821848b8605Smrg
822848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
823848b8605Smrg      _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n",
824b8e80941Smrg                  _mesa_enum_to_string(func), ref);
825b8e80941Smrg
826b8e80941Smrg   if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref)
827b8e80941Smrg      return; /* no change */
828848b8605Smrg
829848b8605Smrg   switch (func) {
830848b8605Smrg   case GL_NEVER:
831848b8605Smrg   case GL_LESS:
832848b8605Smrg   case GL_EQUAL:
833848b8605Smrg   case GL_LEQUAL:
834848b8605Smrg   case GL_GREATER:
835848b8605Smrg   case GL_NOTEQUAL:
836848b8605Smrg   case GL_GEQUAL:
837848b8605Smrg   case GL_ALWAYS:
838b8e80941Smrg      FLUSH_VERTICES(ctx, ctx->DriverFlags.NewAlphaTest ? 0 : _NEW_COLOR);
839b8e80941Smrg      ctx->NewDriverState |= ctx->DriverFlags.NewAlphaTest;
840848b8605Smrg      ctx->Color.AlphaFunc = func;
841848b8605Smrg      ctx->Color.AlphaRefUnclamped = ref;
842848b8605Smrg      ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F);
843848b8605Smrg
844848b8605Smrg      if (ctx->Driver.AlphaFunc)
845848b8605Smrg         ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef);
846848b8605Smrg      return;
847848b8605Smrg
848848b8605Smrg   default:
849848b8605Smrg      _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" );
850848b8605Smrg      return;
851848b8605Smrg   }
852848b8605Smrg}
853848b8605Smrg
854b8e80941Smrgstatic const enum gl_logicop_mode color_logicop_mapping[16] = {
855b8e80941Smrg   COLOR_LOGICOP_CLEAR,
856b8e80941Smrg   COLOR_LOGICOP_AND,
857b8e80941Smrg   COLOR_LOGICOP_AND_REVERSE,
858b8e80941Smrg   COLOR_LOGICOP_COPY,
859b8e80941Smrg   COLOR_LOGICOP_AND_INVERTED,
860b8e80941Smrg   COLOR_LOGICOP_NOOP,
861b8e80941Smrg   COLOR_LOGICOP_XOR,
862b8e80941Smrg   COLOR_LOGICOP_OR,
863b8e80941Smrg   COLOR_LOGICOP_NOR,
864b8e80941Smrg   COLOR_LOGICOP_EQUIV,
865b8e80941Smrg   COLOR_LOGICOP_INVERT,
866b8e80941Smrg   COLOR_LOGICOP_OR_REVERSE,
867b8e80941Smrg   COLOR_LOGICOP_COPY_INVERTED,
868b8e80941Smrg   COLOR_LOGICOP_OR_INVERTED,
869b8e80941Smrg   COLOR_LOGICOP_NAND,
870b8e80941Smrg   COLOR_LOGICOP_SET
871b8e80941Smrg};
872b8e80941Smrg
873b8e80941Smrgstatic ALWAYS_INLINE void
874b8e80941Smrglogic_op(struct gl_context *ctx, GLenum opcode, bool no_error)
875b8e80941Smrg{
876b8e80941Smrg   if (ctx->Color.LogicOp == opcode)
877b8e80941Smrg      return;
878b8e80941Smrg
879b8e80941Smrg   if (!no_error) {
880b8e80941Smrg      switch (opcode) {
881b8e80941Smrg         case GL_CLEAR:
882b8e80941Smrg         case GL_SET:
883b8e80941Smrg         case GL_COPY:
884b8e80941Smrg         case GL_COPY_INVERTED:
885b8e80941Smrg         case GL_NOOP:
886b8e80941Smrg         case GL_INVERT:
887b8e80941Smrg         case GL_AND:
888b8e80941Smrg         case GL_NAND:
889b8e80941Smrg         case GL_OR:
890b8e80941Smrg         case GL_NOR:
891b8e80941Smrg         case GL_XOR:
892b8e80941Smrg         case GL_EQUIV:
893b8e80941Smrg         case GL_AND_REVERSE:
894b8e80941Smrg         case GL_AND_INVERTED:
895b8e80941Smrg         case GL_OR_REVERSE:
896b8e80941Smrg         case GL_OR_INVERTED:
897b8e80941Smrg            break;
898b8e80941Smrg         default:
899b8e80941Smrg            _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" );
900b8e80941Smrg            return;
901b8e80941Smrg      }
902b8e80941Smrg   }
903b8e80941Smrg
904b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewLogicOp ? 0 : _NEW_COLOR);
905b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewLogicOp;
906b8e80941Smrg   ctx->Color.LogicOp = opcode;
907b8e80941Smrg   ctx->Color._LogicOp = color_logicop_mapping[opcode & 0x0f];
908b8e80941Smrg
909b8e80941Smrg   if (ctx->Driver.LogicOpcode)
910b8e80941Smrg      ctx->Driver.LogicOpcode(ctx, ctx->Color._LogicOp);
911b8e80941Smrg}
912b8e80941Smrg
913848b8605Smrg
914848b8605Smrg/**
915848b8605Smrg * Specify a logic pixel operation for color index rendering.
916848b8605Smrg *
917848b8605Smrg * \param opcode operation.
918848b8605Smrg *
919848b8605Smrg * Verifies that \p opcode is a valid enum and updates
920b8e80941Smrg * gl_colorbuffer_attrib::LogicOp.
921848b8605Smrg * On a change, flushes the vertices and notifies the driver via the
922848b8605Smrg * dd_function_table::LogicOpcode callback.
923848b8605Smrg */
924848b8605Smrgvoid GLAPIENTRY
925848b8605Smrg_mesa_LogicOp( GLenum opcode )
926848b8605Smrg{
927848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
928848b8605Smrg
929848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
930b8e80941Smrg      _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_enum_to_string(opcode));
931848b8605Smrg
932b8e80941Smrg   logic_op(ctx, opcode, false);
933b8e80941Smrg}
934848b8605Smrg
935848b8605Smrg
936b8e80941Smrgvoid GLAPIENTRY
937b8e80941Smrg_mesa_LogicOp_no_error(GLenum opcode)
938b8e80941Smrg{
939b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
940b8e80941Smrg   logic_op(ctx, opcode, true);
941848b8605Smrg}
942848b8605Smrg
943848b8605Smrg
944848b8605Smrgvoid GLAPIENTRY
945848b8605Smrg_mesa_IndexMask( GLuint mask )
946848b8605Smrg{
947848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
948848b8605Smrg
949848b8605Smrg   if (ctx->Color.IndexMask == mask)
950848b8605Smrg      return;
951848b8605Smrg
952b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewColorMask ? 0 : _NEW_COLOR);
953b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewColorMask;
954848b8605Smrg   ctx->Color.IndexMask = mask;
955848b8605Smrg}
956848b8605Smrg
957848b8605Smrg
958848b8605Smrg/**
959848b8605Smrg * Enable or disable writing of frame buffer color components.
960848b8605Smrg *
961848b8605Smrg * \param red whether to mask writing of the red color component.
962848b8605Smrg * \param green whether to mask writing of the green color component.
963848b8605Smrg * \param blue whether to mask writing of the blue color component.
964848b8605Smrg * \param alpha whether to mask writing of the alpha color component.
965848b8605Smrg *
966848b8605Smrg * \sa glColorMask().
967848b8605Smrg *
968848b8605Smrg * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask.  On a
969848b8605Smrg * change, flushes the vertices and notifies the driver via the
970848b8605Smrg * dd_function_table::ColorMask callback.
971848b8605Smrg */
972848b8605Smrgvoid GLAPIENTRY
973848b8605Smrg_mesa_ColorMask( GLboolean red, GLboolean green,
974848b8605Smrg                 GLboolean blue, GLboolean alpha )
975848b8605Smrg{
976848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
977848b8605Smrg
978848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
979848b8605Smrg      _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n",
980848b8605Smrg                  red, green, blue, alpha);
981848b8605Smrg
982b8e80941Smrg   GLbitfield mask = (!!red) |
983b8e80941Smrg                     ((!!green) << 1) |
984b8e80941Smrg                     ((!!blue) << 2) |
985b8e80941Smrg                     ((!!alpha) << 3);
986b8e80941Smrg   mask = _mesa_replicate_colormask(mask, ctx->Const.MaxDrawBuffers);
987b8e80941Smrg
988b8e80941Smrg   if (ctx->Color.ColorMask == mask)
989b8e80941Smrg      return;
990b8e80941Smrg
991b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewColorMask ? 0 : _NEW_COLOR);
992b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewColorMask;
993b8e80941Smrg   ctx->Color.ColorMask = mask;
994848b8605Smrg
995848b8605Smrg   if (ctx->Driver.ColorMask)
996848b8605Smrg      ctx->Driver.ColorMask( ctx, red, green, blue, alpha );
997848b8605Smrg}
998848b8605Smrg
999848b8605Smrg
1000848b8605Smrg/**
1001848b8605Smrg * For GL_EXT_draw_buffers2 and GL3
1002848b8605Smrg */
1003848b8605Smrgvoid GLAPIENTRY
1004b8e80941Smrg_mesa_ColorMaski(GLuint buf, GLboolean red, GLboolean green,
1005b8e80941Smrg                 GLboolean blue, GLboolean alpha)
1006848b8605Smrg{
1007848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
1008848b8605Smrg
1009848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
1010b8e80941Smrg      _mesa_debug(ctx, "glColorMaski %u %d %d %d %d\n",
1011848b8605Smrg                  buf, red, green, blue, alpha);
1012848b8605Smrg
1013848b8605Smrg   if (buf >= ctx->Const.MaxDrawBuffers) {
1014b8e80941Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaski(buf=%u)", buf);
1015848b8605Smrg      return;
1016848b8605Smrg   }
1017848b8605Smrg
1018b8e80941Smrg   GLbitfield mask = (!!red) |
1019b8e80941Smrg                     ((!!green) << 1) |
1020b8e80941Smrg                     ((!!blue) << 2) |
1021b8e80941Smrg                     ((!!alpha) << 3);
1022848b8605Smrg
1023b8e80941Smrg   if (GET_COLORMASK(ctx->Color.ColorMask, buf) == mask)
1024848b8605Smrg      return;
1025848b8605Smrg
1026b8e80941Smrg   FLUSH_VERTICES(ctx, ctx->DriverFlags.NewColorMask ? 0 : _NEW_COLOR);
1027b8e80941Smrg   ctx->NewDriverState |= ctx->DriverFlags.NewColorMask;
1028b8e80941Smrg   ctx->Color.ColorMask &= ~(0xf << (4 * buf));
1029b8e80941Smrg   ctx->Color.ColorMask |= mask << (4 * buf);
1030848b8605Smrg}
1031848b8605Smrg
1032848b8605Smrg
1033848b8605Smrgvoid GLAPIENTRY
1034848b8605Smrg_mesa_ClampColor(GLenum target, GLenum clamp)
1035848b8605Smrg{
1036848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
1037848b8605Smrg
1038b8e80941Smrg   /* Check for both the extension and the GL version, since the Intel driver
1039b8e80941Smrg    * does not advertise the extension in core profiles.
1040b8e80941Smrg    */
1041b8e80941Smrg   if (ctx->Version <= 30 && !ctx->Extensions.ARB_color_buffer_float) {
1042b8e80941Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glClampColor()");
1043b8e80941Smrg      return;
1044b8e80941Smrg   }
1045b8e80941Smrg
1046848b8605Smrg   if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) {
1047848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)");
1048848b8605Smrg      return;
1049848b8605Smrg   }
1050848b8605Smrg
1051848b8605Smrg   switch (target) {
1052848b8605Smrg   case GL_CLAMP_VERTEX_COLOR_ARB:
1053b8e80941Smrg      if (ctx->API == API_OPENGL_CORE)
1054848b8605Smrg         goto invalid_enum;
1055848b8605Smrg      FLUSH_VERTICES(ctx, _NEW_LIGHT);
1056848b8605Smrg      ctx->Light.ClampVertexColor = clamp;
1057b8e80941Smrg      _mesa_update_clamp_vertex_color(ctx, ctx->DrawBuffer);
1058848b8605Smrg      break;
1059848b8605Smrg   case GL_CLAMP_FRAGMENT_COLOR_ARB:
1060b8e80941Smrg      if (ctx->API == API_OPENGL_CORE)
1061848b8605Smrg         goto invalid_enum;
1062848b8605Smrg      FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP);
1063848b8605Smrg      ctx->Color.ClampFragmentColor = clamp;
1064b8e80941Smrg      _mesa_update_clamp_fragment_color(ctx, ctx->DrawBuffer);
1065848b8605Smrg      break;
1066848b8605Smrg   case GL_CLAMP_READ_COLOR_ARB:
1067848b8605Smrg      ctx->Color.ClampReadColor = clamp;
1068848b8605Smrg      break;
1069848b8605Smrg   default:
1070848b8605Smrg      goto invalid_enum;
1071848b8605Smrg   }
1072848b8605Smrg   return;
1073848b8605Smrg
1074848b8605Smrginvalid_enum:
1075848b8605Smrg   _mesa_error(ctx, GL_INVALID_ENUM, "glClampColor(%s)",
1076b8e80941Smrg               _mesa_enum_to_string(target));
1077848b8605Smrg}
1078848b8605Smrg
1079848b8605Smrgstatic GLboolean
1080848b8605Smrgget_clamp_color(const struct gl_framebuffer *fb, GLenum clamp)
1081848b8605Smrg{
1082848b8605Smrg   if (clamp == GL_TRUE || clamp == GL_FALSE)
1083848b8605Smrg      return clamp;
1084848b8605Smrg
1085b8e80941Smrg   assert(clamp == GL_FIXED_ONLY);
1086848b8605Smrg   if (!fb)
1087848b8605Smrg      return GL_TRUE;
1088848b8605Smrg
1089848b8605Smrg   return fb->_AllColorBuffersFixedPoint;
1090848b8605Smrg}
1091848b8605Smrg
1092848b8605SmrgGLboolean
1093b8e80941Smrg_mesa_get_clamp_fragment_color(const struct gl_context *ctx,
1094b8e80941Smrg                               const struct gl_framebuffer *drawFb)
1095848b8605Smrg{
1096b8e80941Smrg   return get_clamp_color(drawFb, ctx->Color.ClampFragmentColor);
1097848b8605Smrg}
1098848b8605Smrg
1099848b8605SmrgGLboolean
1100b8e80941Smrg_mesa_get_clamp_vertex_color(const struct gl_context *ctx,
1101b8e80941Smrg                             const struct gl_framebuffer *drawFb)
1102848b8605Smrg{
1103b8e80941Smrg   return get_clamp_color(drawFb, ctx->Light.ClampVertexColor);
1104848b8605Smrg}
1105848b8605Smrg
1106848b8605SmrgGLboolean
1107b8e80941Smrg_mesa_get_clamp_read_color(const struct gl_context *ctx,
1108b8e80941Smrg                           const struct gl_framebuffer *readFb)
1109848b8605Smrg{
1110b8e80941Smrg   return get_clamp_color(readFb, ctx->Color.ClampReadColor);
1111848b8605Smrg}
1112848b8605Smrg
1113848b8605Smrg/**
1114848b8605Smrg * Update the ctx->Color._ClampFragmentColor field
1115848b8605Smrg */
1116848b8605Smrgvoid
1117b8e80941Smrg_mesa_update_clamp_fragment_color(struct gl_context *ctx,
1118b8e80941Smrg                                  const struct gl_framebuffer *drawFb)
1119848b8605Smrg{
1120848b8605Smrg   /* Don't clamp if:
1121848b8605Smrg    * - there is no colorbuffer
1122848b8605Smrg    * - all colorbuffers are unsigned normalized, so clamping has no effect
1123848b8605Smrg    * - there is an integer colorbuffer
1124848b8605Smrg    */
1125b8e80941Smrg   if (!drawFb || !drawFb->_HasSNormOrFloatColorBuffer ||
1126b8e80941Smrg       drawFb->_IntegerBuffers)
1127848b8605Smrg      ctx->Color._ClampFragmentColor = GL_FALSE;
1128848b8605Smrg   else
1129b8e80941Smrg      ctx->Color._ClampFragmentColor =
1130b8e80941Smrg         _mesa_get_clamp_fragment_color(ctx, drawFb);
1131848b8605Smrg}
1132848b8605Smrg
1133848b8605Smrg/**
1134848b8605Smrg * Update the ctx->Color._ClampVertexColor field
1135848b8605Smrg */
1136848b8605Smrgvoid
1137b8e80941Smrg_mesa_update_clamp_vertex_color(struct gl_context *ctx,
1138b8e80941Smrg                                const struct gl_framebuffer *drawFb)
1139848b8605Smrg{
1140b8e80941Smrg   ctx->Light._ClampVertexColor =
1141b8e80941Smrg         _mesa_get_clamp_vertex_color(ctx, drawFb);
1142848b8605Smrg}
1143848b8605Smrg
1144848b8605Smrg/**
1145848b8605Smrg * Returns an appropriate mesa_format for color rendering based on the
1146848b8605Smrg * GL_FRAMEBUFFER_SRGB state.
1147848b8605Smrg *
1148848b8605Smrg * Some drivers implement GL_FRAMEBUFFER_SRGB using a flag on the blend state
1149848b8605Smrg * (which GL_FRAMEBUFFER_SRGB maps to reasonably), but some have to do so by
1150848b8605Smrg * overriding the format of the surface.  This is a helper for doing the
1151848b8605Smrg * surface format override variant.
1152848b8605Smrg */
1153848b8605Smrgmesa_format
1154848b8605Smrg_mesa_get_render_format(const struct gl_context *ctx, mesa_format format)
1155848b8605Smrg{
1156848b8605Smrg   if (ctx->Color.sRGBEnabled)
1157848b8605Smrg      return format;
1158848b8605Smrg   else
1159848b8605Smrg      return _mesa_get_srgb_format_linear(format);
1160848b8605Smrg}
1161848b8605Smrg
1162848b8605Smrg/**********************************************************************/
1163848b8605Smrg/** \name Initialization */
1164848b8605Smrg/*@{*/
1165848b8605Smrg
1166848b8605Smrg/**
1167848b8605Smrg * Initialization of the context's Color attribute group.
1168848b8605Smrg *
1169848b8605Smrg * \param ctx GL context.
1170848b8605Smrg *
1171848b8605Smrg * Initializes the related fields in the context color attribute group,
1172848b8605Smrg * __struct gl_contextRec::Color.
1173848b8605Smrg */
1174848b8605Smrgvoid _mesa_init_color( struct gl_context * ctx )
1175848b8605Smrg{
1176848b8605Smrg   GLuint i;
1177848b8605Smrg
1178848b8605Smrg   /* Color buffer group */
1179848b8605Smrg   ctx->Color.IndexMask = ~0u;
1180b8e80941Smrg   ctx->Color.ColorMask = 0xffffffff;
1181848b8605Smrg   ctx->Color.ClearIndex = 0;
1182848b8605Smrg   ASSIGN_4V( ctx->Color.ClearColor.f, 0, 0, 0, 0 );
1183848b8605Smrg   ctx->Color.AlphaEnabled = GL_FALSE;
1184848b8605Smrg   ctx->Color.AlphaFunc = GL_ALWAYS;
1185848b8605Smrg   ctx->Color.AlphaRef = 0;
1186848b8605Smrg   ctx->Color.BlendEnabled = 0x0;
1187b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(ctx->Color.Blend); i++) {
1188848b8605Smrg      ctx->Color.Blend[i].SrcRGB = GL_ONE;
1189848b8605Smrg      ctx->Color.Blend[i].DstRGB = GL_ZERO;
1190848b8605Smrg      ctx->Color.Blend[i].SrcA = GL_ONE;
1191848b8605Smrg      ctx->Color.Blend[i].DstA = GL_ZERO;
1192848b8605Smrg      ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD;
1193848b8605Smrg      ctx->Color.Blend[i].EquationA = GL_FUNC_ADD;
1194848b8605Smrg   }
1195848b8605Smrg   ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 );
1196848b8605Smrg   ASSIGN_4V( ctx->Color.BlendColorUnclamped, 0.0, 0.0, 0.0, 0.0 );
1197848b8605Smrg   ctx->Color.IndexLogicOpEnabled = GL_FALSE;
1198848b8605Smrg   ctx->Color.ColorLogicOpEnabled = GL_FALSE;
1199848b8605Smrg   ctx->Color.LogicOp = GL_COPY;
1200b8e80941Smrg   ctx->Color._LogicOp = COLOR_LOGICOP_COPY;
1201848b8605Smrg   ctx->Color.DitherFlag = GL_TRUE;
1202848b8605Smrg
1203848b8605Smrg   /* GL_FRONT is not possible on GLES. Instead GL_BACK will render to either
1204848b8605Smrg    * the front or the back buffer depending on the config */
1205848b8605Smrg   if (ctx->Visual.doubleBufferMode || _mesa_is_gles(ctx)) {
1206848b8605Smrg      ctx->Color.DrawBuffer[0] = GL_BACK;
1207848b8605Smrg   }
1208848b8605Smrg   else {
1209848b8605Smrg      ctx->Color.DrawBuffer[0] = GL_FRONT;
1210848b8605Smrg   }
1211848b8605Smrg
1212848b8605Smrg   ctx->Color.ClampFragmentColor = ctx->API == API_OPENGL_COMPAT ?
1213848b8605Smrg                                   GL_FIXED_ONLY_ARB : GL_FALSE;
1214848b8605Smrg   ctx->Color._ClampFragmentColor = GL_FALSE;
1215848b8605Smrg   ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB;
1216848b8605Smrg
1217b8e80941Smrg   /* GLES 1/2/3 behaves as though GL_FRAMEBUFFER_SRGB is always enabled
1218b8e80941Smrg    * if EGL_KHR_gl_colorspace has been used to request sRGB.
1219b8e80941Smrg    */
1220b8e80941Smrg   ctx->Color.sRGBEnabled = _mesa_is_gles(ctx);
1221b8e80941Smrg
1222b8e80941Smrg   ctx->Color.BlendCoherent = true;
1223848b8605Smrg}
1224848b8605Smrg
1225848b8605Smrg/*@}*/
1226