2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
28 * \file swrast/s_blend.c
29 * \brief software blending.
32 * Only a few blend modes have been optimized (min, max, transparency, add)
33 * more optimized cases can easily be added if needed.
34 * Celestia uses glBlendFunc(GL_SRC_ALPHA, GL_ONE), for example.
39 #include "main/glheader.h"
40 #include "main/context.h"
41 #include "main/colormac.h"
42 #include "main/macros.h"
45 #include "s_context.h"
49 #if defined(USE_MMX_ASM)
51 #include "x86/common_x86_asm.h"
52 #define _BLENDAPI _ASMAPI
59 * Integer divide by 255
60 * Declare "int divtemp" before using.
61 * This satisfies Glean and should be reasonably fast.
62 * Contributed by Nathan Hand.
64 #define DIV255(X) (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)
69 * Special case for glBlendFunc(GL_ZERO, GL_ONE).
70 * No-op means the framebuffer values remain unchanged.
74 blend_noop(struct gl_context *ctx, GLuint n, const GLubyte mask[],
75 GLvoid *src, const GLvoid *dst, GLenum chanType)
79 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
80 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
81 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ZERO);
82 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE);
86 if (chanType == GL_UNSIGNED_BYTE)
87 bytes = 4 * n * sizeof(GLubyte);
88 else if (chanType == GL_UNSIGNED_SHORT)
89 bytes = 4 * n * sizeof(GLushort);
91 bytes = 4 * n * sizeof(GLfloat);
93 memcpy(src, dst, bytes);
98 * Special case for glBlendFunc(GL_ONE, GL_ZERO)
101 static void _BLENDAPI
102 blend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[],
103 GLvoid *src, const GLvoid *dst, GLenum chanType)
105 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
106 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
107 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE);
108 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ZERO);
118 * Common transparency blending mode:
119 * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
121 static void _BLENDAPI
122 blend_transparency_ubyte(struct gl_context *ctx, GLuint n, const GLubyte mask[],
123 GLvoid *src, const GLvoid *dst, GLenum chanType)
125 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
126 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
129 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
130 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
131 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
132 ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
133 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
134 ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
135 ASSERT(chanType == GL_UNSIGNED_BYTE);
139 for (i = 0; i < n; i++) {
141 const GLint t = rgba[i][ACOMP]; /* t is in [0, 255] */
144 COPY_4UBV(rgba[i], dest[i]);
148 const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP];
149 const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP];
150 const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP];
151 const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP];
156 rgba[i][RCOMP] = (GLubyte) r;
157 rgba[i][GCOMP] = (GLubyte) g;
158 rgba[i][BCOMP] = (GLubyte) b;
159 rgba[i][ACOMP] = (GLubyte) a;
166 static void _BLENDAPI
167 blend_transparency_ushort(struct gl_context *ctx, GLuint n, const GLubyte mask[],
168 GLvoid *src, const GLvoid *dst, GLenum chanType)
170 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
171 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
174 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
175 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
176 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
177 ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
178 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
179 ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
180 ASSERT(chanType == GL_UNSIGNED_SHORT);
184 for (i = 0; i < n; i++) {
186 const GLint t = rgba[i][ACOMP];
189 COPY_4V(rgba[i], dest[i]);
191 else if (t != 65535) {
192 const GLfloat tt = (GLfloat) t / 65535.0F;
193 GLushort r = (GLushort) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
194 GLushort g = (GLushort) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
195 GLushort b = (GLushort) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
196 GLushort a = (GLushort) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
197 ASSIGN_4V(rgba[i], r, g, b, a);
204 static void _BLENDAPI
205 blend_transparency_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
206 GLvoid *src, const GLvoid *dst, GLenum chanType)
208 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
209 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
212 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
213 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
214 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
215 ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
216 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
217 ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
218 ASSERT(chanType == GL_FLOAT);
222 for (i = 0; i < n; i++) {
224 const GLfloat t = rgba[i][ACOMP]; /* t in [0, 1] */
227 COPY_4V(rgba[i], dest[i]);
229 else if (t != 1.0F) {
230 GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * t + dest[i][RCOMP];
231 GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * t + dest[i][GCOMP];
232 GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * t + dest[i][BCOMP];
233 GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * t + dest[i][ACOMP];
234 ASSIGN_4V(rgba[i], r, g, b, a);
243 * Add src and dest: glBlendFunc(GL_ONE, GL_ONE).
246 static void _BLENDAPI
247 blend_add(struct gl_context *ctx, GLuint n, const GLubyte mask[],
248 GLvoid *src, const GLvoid *dst, GLenum chanType)
252 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
253 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
254 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE);
255 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE);
258 if (chanType == GL_UNSIGNED_BYTE) {
259 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
260 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
263 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
264 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
265 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
266 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
267 rgba[i][RCOMP] = (GLubyte) MIN2( r, 255 );
268 rgba[i][GCOMP] = (GLubyte) MIN2( g, 255 );
269 rgba[i][BCOMP] = (GLubyte) MIN2( b, 255 );
270 rgba[i][ACOMP] = (GLubyte) MIN2( a, 255 );
274 else if (chanType == GL_UNSIGNED_SHORT) {
275 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
276 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
279 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
280 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
281 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
282 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
283 rgba[i][RCOMP] = (GLshort) MIN2( r, 255 );
284 rgba[i][GCOMP] = (GLshort) MIN2( g, 255 );
285 rgba[i][BCOMP] = (GLshort) MIN2( b, 255 );
286 rgba[i][ACOMP] = (GLshort) MIN2( a, 255 );
291 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
292 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
293 ASSERT(chanType == GL_FLOAT);
296 /* don't RGB clamp to max */
297 rgba[i][RCOMP] += dest[i][RCOMP];
298 rgba[i][GCOMP] += dest[i][GCOMP];
299 rgba[i][BCOMP] += dest[i][BCOMP];
300 rgba[i][ACOMP] += dest[i][ACOMP];
309 * Blend min function.
312 static void _BLENDAPI
313 blend_min(struct gl_context *ctx, GLuint n, const GLubyte mask[],
314 GLvoid *src, const GLvoid *dst, GLenum chanType)
317 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_MIN);
318 ASSERT(ctx->Color.Blend[0].EquationA == GL_MIN);
321 if (chanType == GL_UNSIGNED_BYTE) {
322 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
323 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
326 rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
327 rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
328 rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
329 rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
333 else if (chanType == GL_UNSIGNED_SHORT) {
334 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
335 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
338 rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
339 rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
340 rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
341 rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
346 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
347 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
348 ASSERT(chanType == GL_FLOAT);
351 rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
352 rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
353 rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
354 rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
362 * Blend max function.
365 static void _BLENDAPI
366 blend_max(struct gl_context *ctx, GLuint n, const GLubyte mask[],
367 GLvoid *src, const GLvoid *dst, GLenum chanType)
370 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_MAX);
371 ASSERT(ctx->Color.Blend[0].EquationA == GL_MAX);
374 if (chanType == GL_UNSIGNED_BYTE) {
375 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
376 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
379 rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
380 rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
381 rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
382 rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
386 else if (chanType == GL_UNSIGNED_SHORT) {
387 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
388 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
391 rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
392 rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
393 rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
394 rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
399 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
400 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
401 ASSERT(chanType == GL_FLOAT);
404 rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
405 rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
406 rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
407 rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
416 * Modulate: result = src * dest
419 static void _BLENDAPI
420 blend_modulate(struct gl_context *ctx, GLuint n, const GLubyte mask[],
421 GLvoid *src, const GLvoid *dst, GLenum chanType)
426 if (chanType == GL_UNSIGNED_BYTE) {
427 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
428 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
432 rgba[i][RCOMP] = DIV255(rgba[i][RCOMP] * dest[i][RCOMP]);
433 rgba[i][GCOMP] = DIV255(rgba[i][GCOMP] * dest[i][GCOMP]);
434 rgba[i][BCOMP] = DIV255(rgba[i][BCOMP] * dest[i][BCOMP]);
435 rgba[i][ACOMP] = DIV255(rgba[i][ACOMP] * dest[i][ACOMP]);
439 else if (chanType == GL_UNSIGNED_SHORT) {
440 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
441 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
444 rgba[i][RCOMP] = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
445 rgba[i][GCOMP] = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
446 rgba[i][BCOMP] = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
447 rgba[i][ACOMP] = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
452 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
453 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
454 ASSERT(chanType == GL_FLOAT);
457 rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
458 rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
459 rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
460 rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
468 * Do any blending operation, using floating point.
469 * \param n number of pixels
470 * \param mask fragment writemask array
471 * \param rgba array of incoming (and modified) pixels
472 * \param dest array of pixels from the dest color buffer
475 blend_general_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
476 GLfloat rgba[][4], GLfloat dest[][4],
481 for (i = 0; i < n; i++) {
483 /* Incoming/source Color */
484 const GLfloat Rs = rgba[i][RCOMP];
485 const GLfloat Gs = rgba[i][GCOMP];
486 const GLfloat Bs = rgba[i][BCOMP];
487 const GLfloat As = rgba[i][ACOMP];
489 /* Frame buffer/dest color */
490 const GLfloat Rd = dest[i][RCOMP];
491 const GLfloat Gd = dest[i][GCOMP];
492 const GLfloat Bd = dest[i][BCOMP];
493 const GLfloat Ad = dest[i][ACOMP];
495 GLfloat sR, sG, sB, sA; /* Source factor */
496 GLfloat dR, dG, dB, dA; /* Dest factor */
497 GLfloat r, g, b, a; /* result color */
499 /* XXX for the case of constant blend terms we could init
500 * the sX and dX variables just once before the loop.
503 /* Source RGB factor */
504 switch (ctx->Color.Blend[0].SrcRGB) {
516 case GL_ONE_MINUS_DST_COLOR:
524 case GL_ONE_MINUS_SRC_ALPHA:
525 sR = sG = sB = 1.0F - As;
530 case GL_ONE_MINUS_DST_ALPHA:
531 sR = sG = sB = 1.0F - Ad;
533 case GL_SRC_ALPHA_SATURATE:
534 if (As < 1.0F - Ad) {
538 sR = sG = sB = 1.0F - Ad;
541 case GL_CONSTANT_COLOR:
542 sR = ctx->Color.BlendColor[0];
543 sG = ctx->Color.BlendColor[1];
544 sB = ctx->Color.BlendColor[2];
546 case GL_ONE_MINUS_CONSTANT_COLOR:
547 sR = 1.0F - ctx->Color.BlendColor[0];
548 sG = 1.0F - ctx->Color.BlendColor[1];
549 sB = 1.0F - ctx->Color.BlendColor[2];
551 case GL_CONSTANT_ALPHA:
552 sR = sG = sB = ctx->Color.BlendColor[3];
554 case GL_ONE_MINUS_CONSTANT_ALPHA:
555 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
562 case GL_ONE_MINUS_SRC_COLOR:
568 /* this should never happen */
569 _mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float");
573 /* Source Alpha factor */
574 switch (ctx->Color.Blend[0].SrcA) {
584 case GL_ONE_MINUS_DST_COLOR:
590 case GL_ONE_MINUS_SRC_ALPHA:
596 case GL_ONE_MINUS_DST_ALPHA:
599 case GL_SRC_ALPHA_SATURATE:
602 case GL_CONSTANT_COLOR:
603 sA = ctx->Color.BlendColor[3];
605 case GL_ONE_MINUS_CONSTANT_COLOR:
606 sA = 1.0F - ctx->Color.BlendColor[3];
608 case GL_CONSTANT_ALPHA:
609 sA = ctx->Color.BlendColor[3];
611 case GL_ONE_MINUS_CONSTANT_ALPHA:
612 sA = 1.0F - ctx->Color.BlendColor[3];
617 case GL_ONE_MINUS_SRC_COLOR:
621 /* this should never happen */
623 _mesa_problem(ctx, "Bad blend source A factor in blend_general_float");
627 /* Dest RGB factor */
628 switch (ctx->Color.Blend[0].DstRGB) {
640 case GL_ONE_MINUS_SRC_COLOR:
648 case GL_ONE_MINUS_SRC_ALPHA:
649 dR = dG = dB = 1.0F - As;
654 case GL_ONE_MINUS_DST_ALPHA:
655 dR = dG = dB = 1.0F - Ad;
657 case GL_CONSTANT_COLOR:
658 dR = ctx->Color.BlendColor[0];
659 dG = ctx->Color.BlendColor[1];
660 dB = ctx->Color.BlendColor[2];
662 case GL_ONE_MINUS_CONSTANT_COLOR:
663 dR = 1.0F - ctx->Color.BlendColor[0];
664 dG = 1.0F - ctx->Color.BlendColor[1];
665 dB = 1.0F - ctx->Color.BlendColor[2];
667 case GL_CONSTANT_ALPHA:
668 dR = dG = dB = ctx->Color.BlendColor[3];
670 case GL_ONE_MINUS_CONSTANT_ALPHA:
671 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
678 case GL_ONE_MINUS_DST_COLOR:
684 /* this should never happen */
686 _mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float");
690 /* Dest Alpha factor */
691 switch (ctx->Color.Blend[0].DstA) {
701 case GL_ONE_MINUS_SRC_COLOR:
707 case GL_ONE_MINUS_SRC_ALPHA:
713 case GL_ONE_MINUS_DST_ALPHA:
716 case GL_CONSTANT_COLOR:
717 dA = ctx->Color.BlendColor[3];
719 case GL_ONE_MINUS_CONSTANT_COLOR:
720 dA = 1.0F - ctx->Color.BlendColor[3];
722 case GL_CONSTANT_ALPHA:
723 dA = ctx->Color.BlendColor[3];
725 case GL_ONE_MINUS_CONSTANT_ALPHA:
726 dA = 1.0F - ctx->Color.BlendColor[3];
731 case GL_ONE_MINUS_DST_COLOR:
735 /* this should never happen */
737 _mesa_problem(ctx, "Bad blend dest A factor in blend_general_float");
741 /* compute the blended RGB */
742 switch (ctx->Color.Blend[0].EquationRGB) {
744 r = Rs * sR + Rd * dR;
745 g = Gs * sG + Gd * dG;
746 b = Bs * sB + Bd * dB;
747 a = As * sA + Ad * dA;
749 case GL_FUNC_SUBTRACT:
750 r = Rs * sR - Rd * dR;
751 g = Gs * sG - Gd * dG;
752 b = Bs * sB - Bd * dB;
753 a = As * sA - Ad * dA;
755 case GL_FUNC_REVERSE_SUBTRACT:
756 r = Rd * dR - Rs * sR;
757 g = Gd * dG - Gs * sG;
758 b = Bd * dB - Bs * sB;
759 a = Ad * dA - As * sA;
772 /* should never get here */
773 r = g = b = 0.0F; /* silence uninitialized var warning */
774 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
778 /* compute the blended alpha */
779 switch (ctx->Color.Blend[0].EquationA) {
781 a = As * sA + Ad * dA;
783 case GL_FUNC_SUBTRACT:
784 a = As * sA - Ad * dA;
786 case GL_FUNC_REVERSE_SUBTRACT:
787 a = Ad * dA - As * sA;
796 /* should never get here */
797 a = 0.0F; /* silence uninitialized var warning */
798 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
804 rgba[i][RCOMP] = MAX2( r, 0.0F );
805 rgba[i][GCOMP] = MAX2( g, 0.0F );
806 rgba[i][BCOMP] = MAX2( b, 0.0F );
807 rgba[i][ACOMP] = CLAMP( a, 0.0F, 1.0F );
809 ASSIGN_4V(rgba[i], r, g, b, a);
817 * Do any blending operation, any chanType.
820 blend_general(struct gl_context *ctx, GLuint n, const GLubyte mask[],
821 void *src, const void *dst, GLenum chanType)
823 GLfloat (*rgbaF)[4], (*destF)[4];
825 rgbaF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
826 destF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
827 if (!rgbaF || !destF) {
830 _mesa_error(ctx, GL_OUT_OF_MEMORY, "blending");
834 if (chanType == GL_UNSIGNED_BYTE) {
835 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
836 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
838 /* convert ubytes to floats */
839 for (i = 0; i < n; i++) {
841 rgbaF[i][RCOMP] = UBYTE_TO_FLOAT(rgba[i][RCOMP]);
842 rgbaF[i][GCOMP] = UBYTE_TO_FLOAT(rgba[i][GCOMP]);
843 rgbaF[i][BCOMP] = UBYTE_TO_FLOAT(rgba[i][BCOMP]);
844 rgbaF[i][ACOMP] = UBYTE_TO_FLOAT(rgba[i][ACOMP]);
845 destF[i][RCOMP] = UBYTE_TO_FLOAT(dest[i][RCOMP]);
846 destF[i][GCOMP] = UBYTE_TO_FLOAT(dest[i][GCOMP]);
847 destF[i][BCOMP] = UBYTE_TO_FLOAT(dest[i][BCOMP]);
848 destF[i][ACOMP] = UBYTE_TO_FLOAT(dest[i][ACOMP]);
852 blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
853 /* convert back to ubytes */
854 for (i = 0; i < n; i++) {
856 _mesa_unclamped_float_rgba_to_ubyte(rgba[i], rgbaF[i]);
859 else if (chanType == GL_UNSIGNED_SHORT) {
860 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
861 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
863 /* convert ushorts to floats */
864 for (i = 0; i < n; i++) {
866 rgbaF[i][RCOMP] = USHORT_TO_FLOAT(rgba[i][RCOMP]);
867 rgbaF[i][GCOMP] = USHORT_TO_FLOAT(rgba[i][GCOMP]);
868 rgbaF[i][BCOMP] = USHORT_TO_FLOAT(rgba[i][BCOMP]);
869 rgbaF[i][ACOMP] = USHORT_TO_FLOAT(rgba[i][ACOMP]);
870 destF[i][RCOMP] = USHORT_TO_FLOAT(dest[i][RCOMP]);
871 destF[i][GCOMP] = USHORT_TO_FLOAT(dest[i][GCOMP]);
872 destF[i][BCOMP] = USHORT_TO_FLOAT(dest[i][BCOMP]);
873 destF[i][ACOMP] = USHORT_TO_FLOAT(dest[i][ACOMP]);
877 blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
878 /* convert back to ushorts */
879 for (i = 0; i < n; i++) {
881 UNCLAMPED_FLOAT_TO_USHORT(rgba[i][RCOMP], rgbaF[i][RCOMP]);
882 UNCLAMPED_FLOAT_TO_USHORT(rgba[i][GCOMP], rgbaF[i][GCOMP]);
883 UNCLAMPED_FLOAT_TO_USHORT(rgba[i][BCOMP], rgbaF[i][BCOMP]);
884 UNCLAMPED_FLOAT_TO_USHORT(rgba[i][ACOMP], rgbaF[i][ACOMP]);
889 blend_general_float(ctx, n, mask, (GLfloat (*)[4]) src,
890 (GLfloat (*)[4]) dst, chanType);
900 * Analyze current blending parameters to pick fastest blending function.
901 * Result: the ctx->Color.BlendFunc pointer is updated.
904 _swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType)
906 SWcontext *swrast = SWRAST_CONTEXT(ctx);
907 const GLenum eq = ctx->Color.Blend[0].EquationRGB;
908 const GLenum srcRGB = ctx->Color.Blend[0].SrcRGB;
909 const GLenum dstRGB = ctx->Color.Blend[0].DstRGB;
910 const GLenum srcA = ctx->Color.Blend[0].SrcA;
911 const GLenum dstA = ctx->Color.Blend[0].DstA;
913 if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) {
914 swrast->BlendFunc = blend_general;
916 else if (eq == GL_MIN) {
917 /* Note: GL_MIN ignores the blending weight factors */
918 #if defined(USE_MMX_ASM)
919 if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
920 swrast->BlendFunc = _mesa_mmx_blend_min;
924 swrast->BlendFunc = blend_min;
926 else if (eq == GL_MAX) {
927 /* Note: GL_MAX ignores the blending weight factors */
928 #if defined(USE_MMX_ASM)
929 if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
930 swrast->BlendFunc = _mesa_mmx_blend_max;
934 swrast->BlendFunc = blend_max;
936 else if (srcRGB != srcA || dstRGB != dstA) {
937 swrast->BlendFunc = blend_general;
939 else if (eq == GL_FUNC_ADD && srcRGB == GL_SRC_ALPHA
940 && dstRGB == GL_ONE_MINUS_SRC_ALPHA) {
941 #if defined(USE_MMX_ASM)
942 if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
943 swrast->BlendFunc = _mesa_mmx_blend_transparency;
948 if (chanType == GL_UNSIGNED_BYTE)
949 swrast->BlendFunc = blend_transparency_ubyte;
950 else if (chanType == GL_UNSIGNED_SHORT)
951 swrast->BlendFunc = blend_transparency_ushort;
953 swrast->BlendFunc = blend_transparency_float;
956 else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ONE) {
957 #if defined(USE_MMX_ASM)
958 if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
959 swrast->BlendFunc = _mesa_mmx_blend_add;
963 swrast->BlendFunc = blend_add;
965 else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT)
966 && (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR))
968 ((eq == GL_FUNC_ADD || eq == GL_FUNC_SUBTRACT)
969 && (srcRGB == GL_DST_COLOR && dstRGB == GL_ZERO))) {
970 #if defined(USE_MMX_ASM)
971 if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
972 swrast->BlendFunc = _mesa_mmx_blend_modulate;
976 swrast->BlendFunc = blend_modulate;
978 else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
979 swrast->BlendFunc = blend_noop;
981 else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
982 swrast->BlendFunc = blend_replace;
985 swrast->BlendFunc = blend_general;
992 * Apply the blending operator to a span of pixels.
993 * We can handle horizontal runs of pixels (spans) or arrays of x/y
997 _swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span)
999 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1002 ASSERT(span->end <= SWRAST_MAX_WIDTH);
1003 ASSERT(span->arrayMask & SPAN_RGBA);
1004 ASSERT(!ctx->Color.ColorLogicOpEnabled);
1006 rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
1008 swrast->BlendFunc(ctx, span->end, span->array->mask,
1009 span->array->rgba, rbPixels, span->array->ChanType);