st_atom_blend.c revision f9995b30756140724f41daf963fa06167912be7f
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      /*
82      return PIPE_BLENDFACTOR_SRC1_COLOR;
83      return PIPE_BLENDFACTOR_SRC1_ALPHA;
84      */
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      /*
100      return PIPE_BLENDFACTOR_INV_SRC1_COLOR;
101      return PIPE_BLENDFACTOR_INV_SRC1_ALPHA;
102      */
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(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 are different per rt.
173 */
174static GLboolean
175blend_per_rt(struct gl_context *ctx)
176{
177   if (ctx->Color.BlendEnabled &&
178      (ctx->Color.BlendEnabled != ((1 << ctx->Const.MaxDrawBuffers) - 1))) {
179      return GL_TRUE;
180   }
181   return GL_FALSE;
182}
183
184static void
185update_blend( struct st_context *st )
186{
187   struct pipe_blend_state *blend = &st->state.blend;
188   unsigned num_state = 1;
189   unsigned i;
190
191   memset(blend, 0, sizeof(*blend));
192
193   if (blend_per_rt(st->ctx) || colormask_per_rt(st->ctx)) {
194      num_state = st->ctx->Const.MaxDrawBuffers;
195      blend->independent_blend_enable = 1;
196   }
197   /* Note it is impossible to correctly deal with EXT_blend_logic_op and
198      EXT_draw_buffers2/EXT_blend_equation_separate at the same time.
199      These combinations would require support for per-rt logicop enables
200      and separate alpha/rgb logicop/blend support respectively. Neither
201      possible in gallium nor most hardware. Assume these combinations
202      don't happen. */
203   if (st->ctx->Color.ColorLogicOpEnabled ||
204       (st->ctx->Color.BlendEnabled &&
205        st->ctx->Color.BlendEquationRGB == GL_LOGIC_OP)) {
206      /* logicop enabled */
207      blend->logicop_enable = 1;
208      blend->logicop_func = translate_logicop(st->ctx->Color.LogicOp);
209   }
210   else if (st->ctx->Color.BlendEnabled) {
211      /* blending enabled */
212      for (i = 0; i < num_state; i++) {
213
214         blend->rt[i].blend_enable = (st->ctx->Color.BlendEnabled >> i) & 0x1;
215
216         blend->rt[i].rgb_func = translate_blend(st->ctx->Color.BlendEquationRGB);
217         if (st->ctx->Color.BlendEquationRGB == GL_MIN ||
218             st->ctx->Color.BlendEquationRGB == GL_MAX) {
219            /* Min/max are special */
220            blend->rt[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
221            blend->rt[i].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
222         }
223         else {
224            blend->rt[i].rgb_src_factor = translate_blend(st->ctx->Color.BlendSrcRGB);
225            blend->rt[i].rgb_dst_factor = translate_blend(st->ctx->Color.BlendDstRGB);
226         }
227
228         blend->rt[i].alpha_func = translate_blend(st->ctx->Color.BlendEquationA);
229         if (st->ctx->Color.BlendEquationA == GL_MIN ||
230             st->ctx->Color.BlendEquationA == GL_MAX) {
231            /* Min/max are special */
232            blend->rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
233            blend->rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
234         }
235         else {
236            blend->rt[i].alpha_src_factor = translate_blend(st->ctx->Color.BlendSrcA);
237            blend->rt[i].alpha_dst_factor = translate_blend(st->ctx->Color.BlendDstA);
238         }
239      }
240   }
241   else {
242      /* no blending / logicop */
243   }
244
245   /* Colormask - maybe reverse these bits? */
246   for (i = 0; i < num_state; i++) {
247      if (st->ctx->Color.ColorMask[i][0])
248         blend->rt[i].colormask |= PIPE_MASK_R;
249      if (st->ctx->Color.ColorMask[i][1])
250         blend->rt[i].colormask |= PIPE_MASK_G;
251      if (st->ctx->Color.ColorMask[i][2])
252         blend->rt[i].colormask |= PIPE_MASK_B;
253      if (st->ctx->Color.ColorMask[i][3])
254         blend->rt[i].colormask |= PIPE_MASK_A;
255   }
256
257   if (st->ctx->Color.DitherFlag)
258      blend->dither = 1;
259
260   if (st->ctx->Multisample.Enabled) {
261      /* unlike in gallium/d3d10 these operations are only performed
262         if msaa is enabled */
263      if (st->ctx->Multisample.SampleAlphaToCoverage)
264         blend->alpha_to_coverage = 1;
265      if (st->ctx->Multisample.SampleAlphaToOne)
266         blend->alpha_to_one = 1;
267   }
268
269   cso_set_blend(st->cso_context, blend);
270
271   {
272      struct pipe_blend_color bc;
273      COPY_4FV(bc.color, st->ctx->Color.BlendColor);
274      cso_set_blend_color(st->cso_context, &bc);
275   }
276}
277
278
279const struct st_tracked_state st_update_blend = {
280   "st_update_blend",					/* name */
281   {							/* dirty */
282      (_NEW_COLOR | _NEW_MULTISAMPLE),  /* XXX _NEW_BLEND someday? */	/* mesa */
283      0,						/* st */
284   },
285   update_blend,					/* update */
286};
287