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 (at) 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 */ 48 static GLuint 49 translate_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 */ 113 static GLuint 114 translate_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 */ 158 static GLboolean 159 colormask_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 */ 174 static GLboolean 175 blend_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 189 static void 190 update_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 288 const 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