1/**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /*
29  * Authors:
30  *   Keith Whitwell <keith@tungstengraphics.com>
31  *   Brian Paul
32  */
33
34
35#include "st_context.h"
36#include "st_atom.h"
37
38#include "pipe/p_context.h"
39#include "pipe/p_defines.h"
40#include "cso_cache/cso_context.h"
41
42#include "main/macros.h"
43
44/**
45 * Convert GLenum blend tokens to pipe tokens.
46 * Both blend factors and blend funcs are accepted.
47 */
48static GLuint
49translate_blend(GLenum blend)
50{
51   switch (blend) {
52   /* blend functions */
53   case GL_FUNC_ADD:
54      return PIPE_BLEND_ADD;
55   case GL_FUNC_SUBTRACT:
56      return PIPE_BLEND_SUBTRACT;
57   case GL_FUNC_REVERSE_SUBTRACT:
58      return PIPE_BLEND_REVERSE_SUBTRACT;
59   case GL_MIN:
60      return PIPE_BLEND_MIN;
61   case GL_MAX:
62      return PIPE_BLEND_MAX;
63
64   /* blend factors */
65   case GL_ONE:
66      return PIPE_BLENDFACTOR_ONE;
67   case GL_SRC_COLOR:
68      return PIPE_BLENDFACTOR_SRC_COLOR;
69   case GL_SRC_ALPHA:
70      return PIPE_BLENDFACTOR_SRC_ALPHA;
71   case GL_DST_ALPHA:
72      return PIPE_BLENDFACTOR_DST_ALPHA;
73   case GL_DST_COLOR:
74      return PIPE_BLENDFACTOR_DST_COLOR;
75   case GL_SRC_ALPHA_SATURATE:
76      return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
77   case GL_CONSTANT_COLOR:
78      return PIPE_BLENDFACTOR_CONST_COLOR;
79   case GL_CONSTANT_ALPHA:
80      return PIPE_BLENDFACTOR_CONST_ALPHA;
81   case GL_SRC1_COLOR:
82      return PIPE_BLENDFACTOR_SRC1_COLOR;
83   case GL_SRC1_ALPHA:
84      return PIPE_BLENDFACTOR_SRC1_ALPHA;
85   case GL_ZERO:
86      return PIPE_BLENDFACTOR_ZERO;
87   case GL_ONE_MINUS_SRC_COLOR:
88      return PIPE_BLENDFACTOR_INV_SRC_COLOR;
89   case GL_ONE_MINUS_SRC_ALPHA:
90      return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
91   case GL_ONE_MINUS_DST_COLOR:
92      return PIPE_BLENDFACTOR_INV_DST_COLOR;
93   case GL_ONE_MINUS_DST_ALPHA:
94      return PIPE_BLENDFACTOR_INV_DST_ALPHA;
95   case GL_ONE_MINUS_CONSTANT_COLOR:
96      return PIPE_BLENDFACTOR_INV_CONST_COLOR;
97   case GL_ONE_MINUS_CONSTANT_ALPHA:
98      return PIPE_BLENDFACTOR_INV_CONST_ALPHA;
99   case GL_ONE_MINUS_SRC1_COLOR:
100      return PIPE_BLENDFACTOR_INV_SRC1_COLOR;
101   case GL_ONE_MINUS_SRC1_ALPHA:
102      return PIPE_BLENDFACTOR_INV_SRC1_ALPHA;
103   default:
104      assert("invalid GL token in translate_blend()" == NULL);
105      return 0;
106   }
107}
108
109
110/**
111 * Convert GLenum logicop tokens to pipe tokens.
112 */
113static GLuint
114translate_logicop(GLenum logicop)
115{
116   switch (logicop) {
117   case GL_CLEAR:
118      return PIPE_LOGICOP_CLEAR;
119   case GL_NOR:
120      return PIPE_LOGICOP_NOR;
121   case GL_AND_INVERTED:
122      return PIPE_LOGICOP_AND_INVERTED;
123   case GL_COPY_INVERTED:
124      return PIPE_LOGICOP_COPY_INVERTED;
125   case GL_AND_REVERSE:
126      return PIPE_LOGICOP_AND_REVERSE;
127   case GL_INVERT:
128      return PIPE_LOGICOP_INVERT;
129   case GL_XOR:
130      return PIPE_LOGICOP_XOR;
131   case GL_NAND:
132      return PIPE_LOGICOP_NAND;
133   case GL_AND:
134      return PIPE_LOGICOP_AND;
135   case GL_EQUIV:
136      return PIPE_LOGICOP_EQUIV;
137   case GL_NOOP:
138      return PIPE_LOGICOP_NOOP;
139   case GL_OR_INVERTED:
140      return PIPE_LOGICOP_OR_INVERTED;
141   case GL_COPY:
142      return PIPE_LOGICOP_COPY;
143   case GL_OR_REVERSE:
144      return PIPE_LOGICOP_OR_REVERSE;
145   case GL_OR:
146      return PIPE_LOGICOP_OR;
147   case GL_SET:
148      return PIPE_LOGICOP_SET;
149   default:
150      assert("invalid GL token in translate_logicop()" == NULL);
151      return 0;
152   }
153}
154
155/**
156 * Figure out if colormasks are different per rt.
157 */
158static GLboolean
159colormask_per_rt(const struct gl_context *ctx)
160{
161   /* a bit suboptimal have to compare lots of values */
162   unsigned i;
163   for (i = 1; i < ctx->Const.MaxDrawBuffers; i++) {
164      if (memcmp(ctx->Color.ColorMask[0], ctx->Color.ColorMask[i], 4)) {
165         return GL_TRUE;
166      }
167   }
168   return GL_FALSE;
169}
170
171/**
172 * Figure out if blend enables/state are different per rt.
173 */
174static GLboolean
175blend_per_rt(const struct gl_context *ctx)
176{
177   if (ctx->Color.BlendEnabled &&
178      (ctx->Color.BlendEnabled != ((1 << ctx->Const.MaxDrawBuffers) - 1))) {
179      /* This can only happen if GL_EXT_draw_buffers2 is enabled */
180      return GL_TRUE;
181   }
182   if (ctx->Color._BlendFuncPerBuffer || ctx->Color._BlendEquationPerBuffer) {
183      /* this can only happen if GL_ARB_draw_buffers_blend is enabled */
184      return GL_TRUE;
185   }
186   return GL_FALSE;
187}
188
189static void
190update_blend( struct st_context *st )
191{
192   struct pipe_blend_state *blend = &st->state.blend;
193   const struct gl_context *ctx = st->ctx;
194   unsigned num_state = 1;
195   unsigned i, j;
196
197   memset(blend, 0, sizeof(*blend));
198
199   if (blend_per_rt(ctx) || colormask_per_rt(ctx)) {
200      num_state = ctx->Const.MaxDrawBuffers;
201      blend->independent_blend_enable = 1;
202   }
203   if (ctx->Color.ColorLogicOpEnabled) {
204      /* logicop enabled */
205      blend->logicop_enable = 1;
206      blend->logicop_func = translate_logicop(ctx->Color.LogicOp);
207   }
208   else if (ctx->Color.BlendEnabled) {
209      /* blending enabled */
210      for (i = 0, j = 0; i < num_state; i++) {
211
212         blend->rt[i].blend_enable = (ctx->Color.BlendEnabled >> i) & 0x1;
213
214         if (ctx->Extensions.ARB_draw_buffers_blend)
215            j = i;
216
217         blend->rt[i].rgb_func =
218            translate_blend(ctx->Color.Blend[j].EquationRGB);
219
220         if (ctx->Color.Blend[i].EquationRGB == GL_MIN ||
221             ctx->Color.Blend[i].EquationRGB == GL_MAX) {
222            /* Min/max are special */
223            blend->rt[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
224            blend->rt[i].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
225         }
226         else {
227            blend->rt[i].rgb_src_factor =
228               translate_blend(ctx->Color.Blend[j].SrcRGB);
229            blend->rt[i].rgb_dst_factor =
230               translate_blend(ctx->Color.Blend[j].DstRGB);
231         }
232
233         blend->rt[i].alpha_func =
234            translate_blend(ctx->Color.Blend[j].EquationA);
235
236         if (ctx->Color.Blend[i].EquationA == GL_MIN ||
237             ctx->Color.Blend[i].EquationA == GL_MAX) {
238            /* Min/max are special */
239            blend->rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
240            blend->rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
241         }
242         else {
243            blend->rt[i].alpha_src_factor =
244               translate_blend(ctx->Color.Blend[j].SrcA);
245            blend->rt[i].alpha_dst_factor =
246               translate_blend(ctx->Color.Blend[j].DstA);
247         }
248      }
249   }
250   else {
251      /* no blending / logicop */
252   }
253
254   /* Colormask - maybe reverse these bits? */
255   for (i = 0; i < num_state; i++) {
256      if (ctx->Color.ColorMask[i][0])
257         blend->rt[i].colormask |= PIPE_MASK_R;
258      if (ctx->Color.ColorMask[i][1])
259         blend->rt[i].colormask |= PIPE_MASK_G;
260      if (ctx->Color.ColorMask[i][2])
261         blend->rt[i].colormask |= PIPE_MASK_B;
262      if (ctx->Color.ColorMask[i][3])
263         blend->rt[i].colormask |= PIPE_MASK_A;
264   }
265
266   if (ctx->Color.DitherFlag)
267      blend->dither = 1;
268
269   if (ctx->Multisample.Enabled) {
270      /* unlike in gallium/d3d10 these operations are only performed
271         if msaa is enabled */
272      if (ctx->Multisample.SampleAlphaToCoverage)
273         blend->alpha_to_coverage = 1;
274      if (ctx->Multisample.SampleAlphaToOne)
275         blend->alpha_to_one = 1;
276   }
277
278   cso_set_blend(st->cso_context, blend);
279
280   {
281      struct pipe_blend_color bc;
282      COPY_4FV(bc.color, ctx->Color.BlendColorUnclamped);
283      cso_set_blend_color(st->cso_context, &bc);
284   }
285}
286
287
288const struct st_tracked_state st_update_blend = {
289   "st_update_blend",					/* name */
290   {							/* dirty */
291      (_NEW_COLOR | _NEW_MULTISAMPLE),  /* XXX _NEW_BLEND someday? */	/* mesa */
292      0,						/* st */
293   },
294   update_blend,					/* update */
295};
296