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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * \file swrast/s_blend.c
28 * \brief software blending.
31 * Only a few blend modes have been optimized (min, max, transparency, add)
32 * more optimized cases can easily be added if needed.
33 * Celestia uses glBlendFunc(GL_SRC_ALPHA, GL_ONE), for example.
38 #include "main/glheader.h"
39 #include "main/context.h"
40 #include "main/colormac.h"
41 #include "main/macros.h"
44 #include "s_context.h"
48 #if defined(USE_MMX_ASM)
50 #include "x86/common_x86_asm.h"
51 #define _BLENDAPI _ASMAPI
58 * Integer divide by 255
59 * Declare "int divtemp" before using.
60 * This satisfies Glean and should be reasonably fast.
61 * Contributed by Nathan Hand.
63 #define DIV255(X) (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)
68 * Special case for glBlendFunc(GL_ZERO, GL_ONE).
69 * No-op means the framebuffer values remain unchanged.
73 blend_noop(struct gl_context *ctx, GLuint n, const GLubyte mask[],
74 GLvoid *src, const GLvoid *dst, GLenum chanType)
78 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
79 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
80 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ZERO);
81 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE);
85 if (chanType == GL_UNSIGNED_BYTE)
86 bytes = 4 * n * sizeof(GLubyte);
87 else if (chanType == GL_UNSIGNED_SHORT)
88 bytes = 4 * n * sizeof(GLushort);
90 bytes = 4 * n * sizeof(GLfloat);
92 memcpy(src, dst, bytes);
97 * Special case for glBlendFunc(GL_ONE, GL_ZERO)
100 static void _BLENDAPI
101 blend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[],
102 GLvoid *src, const GLvoid *dst, GLenum chanType)
104 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
105 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
106 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE);
107 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ZERO);
117 * Common transparency blending mode:
118 * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
120 static void _BLENDAPI
121 blend_transparency_ubyte(struct gl_context *ctx, GLuint n, const GLubyte mask[],
122 GLvoid *src, const GLvoid *dst, GLenum chanType)
124 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
125 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
128 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
129 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
130 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
131 ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
132 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
133 ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
134 ASSERT(chanType == GL_UNSIGNED_BYTE);
138 for (i = 0; i < n; i++) {
140 const GLint t = rgba[i][ACOMP]; /* t is in [0, 255] */
143 COPY_4UBV(rgba[i], dest[i]);
147 const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP];
148 const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP];
149 const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP];
150 const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP];
155 rgba[i][RCOMP] = (GLubyte) r;
156 rgba[i][GCOMP] = (GLubyte) g;
157 rgba[i][BCOMP] = (GLubyte) b;
158 rgba[i][ACOMP] = (GLubyte) a;
165 static void _BLENDAPI
166 blend_transparency_ushort(struct gl_context *ctx, GLuint n, const GLubyte mask[],
167 GLvoid *src, const GLvoid *dst, GLenum chanType)
169 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
170 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
173 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
174 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
175 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
176 ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
177 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
178 ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
179 ASSERT(chanType == GL_UNSIGNED_SHORT);
183 for (i = 0; i < n; i++) {
185 const GLint t = rgba[i][ACOMP];
188 COPY_4V(rgba[i], dest[i]);
190 else if (t != 65535) {
191 const GLfloat tt = (GLfloat) t / 65535.0F;
192 GLushort r = (GLushort) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
193 GLushort g = (GLushort) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
194 GLushort b = (GLushort) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
195 GLushort a = (GLushort) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
196 ASSIGN_4V(rgba[i], r, g, b, a);
203 static void _BLENDAPI
204 blend_transparency_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
205 GLvoid *src, const GLvoid *dst, GLenum chanType)
207 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
208 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
211 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
212 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
213 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
214 ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
215 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
216 ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
217 ASSERT(chanType == GL_FLOAT);
221 for (i = 0; i < n; i++) {
223 const GLfloat t = rgba[i][ACOMP]; /* t in [0, 1] */
226 COPY_4V(rgba[i], dest[i]);
228 else if (t != 1.0F) {
229 GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * t + dest[i][RCOMP];
230 GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * t + dest[i][GCOMP];
231 GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * t + dest[i][BCOMP];
232 GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * t + dest[i][ACOMP];
233 ASSIGN_4V(rgba[i], r, g, b, a);
242 * Add src and dest: glBlendFunc(GL_ONE, GL_ONE).
245 static void _BLENDAPI
246 blend_add(struct gl_context *ctx, GLuint n, const GLubyte mask[],
247 GLvoid *src, const GLvoid *dst, GLenum chanType)
251 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
252 ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
253 ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE);
254 ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE);
257 if (chanType == GL_UNSIGNED_BYTE) {
258 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
259 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
262 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
263 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
264 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
265 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
266 rgba[i][RCOMP] = (GLubyte) MIN2( r, 255 );
267 rgba[i][GCOMP] = (GLubyte) MIN2( g, 255 );
268 rgba[i][BCOMP] = (GLubyte) MIN2( b, 255 );
269 rgba[i][ACOMP] = (GLubyte) MIN2( a, 255 );
273 else if (chanType == GL_UNSIGNED_SHORT) {
274 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
275 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
278 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
279 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
280 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
281 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
282 rgba[i][RCOMP] = (GLshort) MIN2( r, 255 );
283 rgba[i][GCOMP] = (GLshort) MIN2( g, 255 );
284 rgba[i][BCOMP] = (GLshort) MIN2( b, 255 );
285 rgba[i][ACOMP] = (GLshort) MIN2( a, 255 );
290 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
291 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
292 ASSERT(chanType == GL_FLOAT);
295 /* don't RGB clamp to max */
296 rgba[i][RCOMP] += dest[i][RCOMP];
297 rgba[i][GCOMP] += dest[i][GCOMP];
298 rgba[i][BCOMP] += dest[i][BCOMP];
299 rgba[i][ACOMP] += dest[i][ACOMP];
308 * Blend min function.
311 static void _BLENDAPI
312 blend_min(struct gl_context *ctx, GLuint n, const GLubyte mask[],
313 GLvoid *src, const GLvoid *dst, GLenum chanType)
316 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_MIN);
317 ASSERT(ctx->Color.Blend[0].EquationA == GL_MIN);
320 if (chanType == GL_UNSIGNED_BYTE) {
321 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
322 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
325 rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
326 rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
327 rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
328 rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
332 else if (chanType == GL_UNSIGNED_SHORT) {
333 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
334 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
337 rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
338 rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
339 rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
340 rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
345 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
346 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
347 ASSERT(chanType == GL_FLOAT);
350 rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
351 rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
352 rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
353 rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
361 * Blend max function.
364 static void _BLENDAPI
365 blend_max(struct gl_context *ctx, GLuint n, const GLubyte mask[],
366 GLvoid *src, const GLvoid *dst, GLenum chanType)
369 ASSERT(ctx->Color.Blend[0].EquationRGB == GL_MAX);
370 ASSERT(ctx->Color.Blend[0].EquationA == GL_MAX);
373 if (chanType == GL_UNSIGNED_BYTE) {
374 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
375 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
378 rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
379 rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
380 rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
381 rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
385 else if (chanType == GL_UNSIGNED_SHORT) {
386 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
387 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
390 rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
391 rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
392 rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
393 rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
398 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
399 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
400 ASSERT(chanType == GL_FLOAT);
403 rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
404 rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
405 rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
406 rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
415 * Modulate: result = src * dest
418 static void _BLENDAPI
419 blend_modulate(struct gl_context *ctx, GLuint n, const GLubyte mask[],
420 GLvoid *src, const GLvoid *dst, GLenum chanType)
425 if (chanType == GL_UNSIGNED_BYTE) {
426 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
427 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
431 rgba[i][RCOMP] = DIV255(rgba[i][RCOMP] * dest[i][RCOMP]);
432 rgba[i][GCOMP] = DIV255(rgba[i][GCOMP] * dest[i][GCOMP]);
433 rgba[i][BCOMP] = DIV255(rgba[i][BCOMP] * dest[i][BCOMP]);
434 rgba[i][ACOMP] = DIV255(rgba[i][ACOMP] * dest[i][ACOMP]);
438 else if (chanType == GL_UNSIGNED_SHORT) {
439 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
440 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
443 rgba[i][RCOMP] = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
444 rgba[i][GCOMP] = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
445 rgba[i][BCOMP] = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
446 rgba[i][ACOMP] = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
451 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
452 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
453 ASSERT(chanType == GL_FLOAT);
456 rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
457 rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
458 rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
459 rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
467 * Do any blending operation, using floating point.
468 * \param n number of pixels
469 * \param mask fragment writemask array
470 * \param rgba array of incoming (and modified) pixels
471 * \param dest array of pixels from the dest color buffer
474 blend_general_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
475 GLfloat rgba[][4], GLfloat dest[][4],
480 for (i = 0; i < n; i++) {
482 /* Incoming/source Color */
483 const GLfloat Rs = rgba[i][RCOMP];
484 const GLfloat Gs = rgba[i][GCOMP];
485 const GLfloat Bs = rgba[i][BCOMP];
486 const GLfloat As = rgba[i][ACOMP];
488 /* Frame buffer/dest color */
489 const GLfloat Rd = dest[i][RCOMP];
490 const GLfloat Gd = dest[i][GCOMP];
491 const GLfloat Bd = dest[i][BCOMP];
492 const GLfloat Ad = dest[i][ACOMP];
494 GLfloat sR, sG, sB, sA; /* Source factor */
495 GLfloat dR, dG, dB, dA; /* Dest factor */
496 GLfloat r, g, b, a; /* result color */
498 /* XXX for the case of constant blend terms we could init
499 * the sX and dX variables just once before the loop.
502 /* Source RGB factor */
503 switch (ctx->Color.Blend[0].SrcRGB) {
515 case GL_ONE_MINUS_DST_COLOR:
523 case GL_ONE_MINUS_SRC_ALPHA:
524 sR = sG = sB = 1.0F - As;
529 case GL_ONE_MINUS_DST_ALPHA:
530 sR = sG = sB = 1.0F - Ad;
532 case GL_SRC_ALPHA_SATURATE:
533 if (As < 1.0F - Ad) {
537 sR = sG = sB = 1.0F - Ad;
540 case GL_CONSTANT_COLOR:
541 sR = ctx->Color.BlendColor[0];
542 sG = ctx->Color.BlendColor[1];
543 sB = ctx->Color.BlendColor[2];
545 case GL_ONE_MINUS_CONSTANT_COLOR:
546 sR = 1.0F - ctx->Color.BlendColor[0];
547 sG = 1.0F - ctx->Color.BlendColor[1];
548 sB = 1.0F - ctx->Color.BlendColor[2];
550 case GL_CONSTANT_ALPHA:
551 sR = sG = sB = ctx->Color.BlendColor[3];
553 case GL_ONE_MINUS_CONSTANT_ALPHA:
554 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
561 case GL_ONE_MINUS_SRC_COLOR:
567 /* this should never happen */
568 _mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float");
572 /* Source Alpha factor */
573 switch (ctx->Color.Blend[0].SrcA) {
583 case GL_ONE_MINUS_DST_COLOR:
589 case GL_ONE_MINUS_SRC_ALPHA:
595 case GL_ONE_MINUS_DST_ALPHA:
598 case GL_SRC_ALPHA_SATURATE:
601 case GL_CONSTANT_COLOR:
602 sA = ctx->Color.BlendColor[3];
604 case GL_ONE_MINUS_CONSTANT_COLOR:
605 sA = 1.0F - ctx->Color.BlendColor[3];
607 case GL_CONSTANT_ALPHA:
608 sA = ctx->Color.BlendColor[3];
610 case GL_ONE_MINUS_CONSTANT_ALPHA:
611 sA = 1.0F - ctx->Color.BlendColor[3];
616 case GL_ONE_MINUS_SRC_COLOR:
620 /* this should never happen */
622 _mesa_problem(ctx, "Bad blend source A factor in blend_general_float");
626 /* Dest RGB factor */
627 switch (ctx->Color.Blend[0].DstRGB) {
639 case GL_ONE_MINUS_SRC_COLOR:
647 case GL_ONE_MINUS_SRC_ALPHA:
648 dR = dG = dB = 1.0F - As;
653 case GL_ONE_MINUS_DST_ALPHA:
654 dR = dG = dB = 1.0F - Ad;
656 case GL_CONSTANT_COLOR:
657 dR = ctx->Color.BlendColor[0];
658 dG = ctx->Color.BlendColor[1];
659 dB = ctx->Color.BlendColor[2];
661 case GL_ONE_MINUS_CONSTANT_COLOR:
662 dR = 1.0F - ctx->Color.BlendColor[0];
663 dG = 1.0F - ctx->Color.BlendColor[1];
664 dB = 1.0F - ctx->Color.BlendColor[2];
666 case GL_CONSTANT_ALPHA:
667 dR = dG = dB = ctx->Color.BlendColor[3];
669 case GL_ONE_MINUS_CONSTANT_ALPHA:
670 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
677 case GL_ONE_MINUS_DST_COLOR:
683 /* this should never happen */
685 _mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float");
689 /* Dest Alpha factor */
690 switch (ctx->Color.Blend[0].DstA) {
700 case GL_ONE_MINUS_SRC_COLOR:
706 case GL_ONE_MINUS_SRC_ALPHA:
712 case GL_ONE_MINUS_DST_ALPHA:
715 case GL_CONSTANT_COLOR:
716 dA = ctx->Color.BlendColor[3];
718 case GL_ONE_MINUS_CONSTANT_COLOR:
719 dA = 1.0F - ctx->Color.BlendColor[3];
721 case GL_CONSTANT_ALPHA:
722 dA = ctx->Color.BlendColor[3];
724 case GL_ONE_MINUS_CONSTANT_ALPHA:
725 dA = 1.0F - ctx->Color.BlendColor[3];
730 case GL_ONE_MINUS_DST_COLOR:
734 /* this should never happen */
736 _mesa_problem(ctx, "Bad blend dest A factor in blend_general_float");
740 /* compute the blended RGB */
741 switch (ctx->Color.Blend[0].EquationRGB) {
743 r = Rs * sR + Rd * dR;
744 g = Gs * sG + Gd * dG;
745 b = Bs * sB + Bd * dB;
746 a = As * sA + Ad * dA;
748 case GL_FUNC_SUBTRACT:
749 r = Rs * sR - Rd * dR;
750 g = Gs * sG - Gd * dG;
751 b = Bs * sB - Bd * dB;
752 a = As * sA - Ad * dA;
754 case GL_FUNC_REVERSE_SUBTRACT:
755 r = Rd * dR - Rs * sR;
756 g = Gd * dG - Gs * sG;
757 b = Bd * dB - Bs * sB;
758 a = Ad * dA - As * sA;
771 /* should never get here */
772 r = g = b = 0.0F; /* silence uninitialized var warning */
773 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
777 /* compute the blended alpha */
778 switch (ctx->Color.Blend[0].EquationA) {
780 a = As * sA + Ad * dA;
782 case GL_FUNC_SUBTRACT:
783 a = As * sA - Ad * dA;
785 case GL_FUNC_REVERSE_SUBTRACT:
786 a = Ad * dA - As * sA;
795 /* should never get here */
796 a = 0.0F; /* silence uninitialized var warning */
797 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
803 rgba[i][RCOMP] = MAX2( r, 0.0F );
804 rgba[i][GCOMP] = MAX2( g, 0.0F );
805 rgba[i][BCOMP] = MAX2( b, 0.0F );
806 rgba[i][ACOMP] = CLAMP( a, 0.0F, 1.0F );
808 ASSIGN_4V(rgba[i], r, g, b, a);
816 * Do any blending operation, any chanType.
819 blend_general(struct gl_context *ctx, GLuint n, const GLubyte mask[],
820 void *src, const void *dst, GLenum chanType)
822 GLfloat (*rgbaF)[4], (*destF)[4];
824 rgbaF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
825 destF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
826 if (!rgbaF || !destF) {
829 _mesa_error(ctx, GL_OUT_OF_MEMORY, "blending");
833 if (chanType == GL_UNSIGNED_BYTE) {
834 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
835 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
837 /* convert ubytes to floats */
838 for (i = 0; i < n; i++) {
840 rgbaF[i][RCOMP] = UBYTE_TO_FLOAT(rgba[i][RCOMP]);
841 rgbaF[i][GCOMP] = UBYTE_TO_FLOAT(rgba[i][GCOMP]);
842 rgbaF[i][BCOMP] = UBYTE_TO_FLOAT(rgba[i][BCOMP]);
843 rgbaF[i][ACOMP] = UBYTE_TO_FLOAT(rgba[i][ACOMP]);
844 destF[i][RCOMP] = UBYTE_TO_FLOAT(dest[i][RCOMP]);
845 destF[i][GCOMP] = UBYTE_TO_FLOAT(dest[i][GCOMP]);
846 destF[i][BCOMP] = UBYTE_TO_FLOAT(dest[i][BCOMP]);
847 destF[i][ACOMP] = UBYTE_TO_FLOAT(dest[i][ACOMP]);
851 blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
852 /* convert back to ubytes */
853 for (i = 0; i < n; i++) {
855 UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][RCOMP], rgbaF[i][RCOMP]);
856 UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][GCOMP], rgbaF[i][GCOMP]);
857 UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][BCOMP], rgbaF[i][BCOMP]);
858 UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][ACOMP], rgbaF[i][ACOMP]);
862 else if (chanType == GL_UNSIGNED_SHORT) {
863 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
864 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
866 /* convert ushorts to floats */
867 for (i = 0; i < n; i++) {
869 rgbaF[i][RCOMP] = USHORT_TO_FLOAT(rgba[i][RCOMP]);
870 rgbaF[i][GCOMP] = USHORT_TO_FLOAT(rgba[i][GCOMP]);
871 rgbaF[i][BCOMP] = USHORT_TO_FLOAT(rgba[i][BCOMP]);
872 rgbaF[i][ACOMP] = USHORT_TO_FLOAT(rgba[i][ACOMP]);
873 destF[i][RCOMP] = USHORT_TO_FLOAT(dest[i][RCOMP]);
874 destF[i][GCOMP] = USHORT_TO_FLOAT(dest[i][GCOMP]);
875 destF[i][BCOMP] = USHORT_TO_FLOAT(dest[i][BCOMP]);
876 destF[i][ACOMP] = USHORT_TO_FLOAT(dest[i][ACOMP]);
880 blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
881 /* convert back to ushorts */
882 for (i = 0; i < n; i++) {
884 UNCLAMPED_FLOAT_TO_USHORT(rgba[i][RCOMP], rgbaF[i][RCOMP]);
885 UNCLAMPED_FLOAT_TO_USHORT(rgba[i][GCOMP], rgbaF[i][GCOMP]);
886 UNCLAMPED_FLOAT_TO_USHORT(rgba[i][BCOMP], rgbaF[i][BCOMP]);
887 UNCLAMPED_FLOAT_TO_USHORT(rgba[i][ACOMP], rgbaF[i][ACOMP]);
892 blend_general_float(ctx, n, mask, (GLfloat (*)[4]) src,
893 (GLfloat (*)[4]) dst, chanType);
903 * Analyze current blending parameters to pick fastest blending function.
904 * Result: the ctx->Color.BlendFunc pointer is updated.
907 _swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType)
909 SWcontext *swrast = SWRAST_CONTEXT(ctx);
910 const GLenum eq = ctx->Color.Blend[0].EquationRGB;
911 const GLenum srcRGB = ctx->Color.Blend[0].SrcRGB;
912 const GLenum dstRGB = ctx->Color.Blend[0].DstRGB;
913 const GLenum srcA = ctx->Color.Blend[0].SrcA;
914 const GLenum dstA = ctx->Color.Blend[0].DstA;
916 if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) {
917 swrast->BlendFunc = blend_general;
919 else if (eq == GL_MIN) {
920 /* Note: GL_MIN ignores the blending weight factors */
921 #if defined(USE_MMX_ASM)
922 if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
923 swrast->BlendFunc = _mesa_mmx_blend_min;
927 swrast->BlendFunc = blend_min;
929 else if (eq == GL_MAX) {
930 /* Note: GL_MAX ignores the blending weight factors */
931 #if defined(USE_MMX_ASM)
932 if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
933 swrast->BlendFunc = _mesa_mmx_blend_max;
937 swrast->BlendFunc = blend_max;
939 else if (srcRGB != srcA || dstRGB != dstA) {
940 swrast->BlendFunc = blend_general;
942 else if (eq == GL_FUNC_ADD && srcRGB == GL_SRC_ALPHA
943 && dstRGB == GL_ONE_MINUS_SRC_ALPHA) {
944 #if defined(USE_MMX_ASM)
945 if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
946 swrast->BlendFunc = _mesa_mmx_blend_transparency;
951 if (chanType == GL_UNSIGNED_BYTE)
952 swrast->BlendFunc = blend_transparency_ubyte;
953 else if (chanType == GL_UNSIGNED_SHORT)
954 swrast->BlendFunc = blend_transparency_ushort;
956 swrast->BlendFunc = blend_transparency_float;
959 else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ONE) {
960 #if defined(USE_MMX_ASM)
961 if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
962 swrast->BlendFunc = _mesa_mmx_blend_add;
966 swrast->BlendFunc = blend_add;
968 else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT)
969 && (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR))
971 ((eq == GL_FUNC_ADD || eq == GL_FUNC_SUBTRACT)
972 && (srcRGB == GL_DST_COLOR && dstRGB == GL_ZERO))) {
973 #if defined(USE_MMX_ASM)
974 if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
975 swrast->BlendFunc = _mesa_mmx_blend_modulate;
979 swrast->BlendFunc = blend_modulate;
981 else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
982 swrast->BlendFunc = blend_noop;
984 else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
985 swrast->BlendFunc = blend_replace;
988 swrast->BlendFunc = blend_general;
995 * Apply the blending operator to a span of pixels.
996 * We can handle horizontal runs of pixels (spans) or arrays of x/y
1000 _swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span)
1002 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1005 ASSERT(span->end <= MAX_WIDTH);
1006 ASSERT(span->arrayMask & SPAN_RGBA);
1007 ASSERT(rb->DataType == span->array->ChanType);
1008 ASSERT(!ctx->Color._LogicOpEnabled);
1010 rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
1012 swrast->BlendFunc(ctx, span->end, span->array->mask,
1013 span->array->rgba, rbPixels, span->array->ChanType);