2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 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.
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(GLcontext
*ctx
, GLuint n
, const GLubyte mask
[],
74 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
78 ASSERT(ctx
->Color
.BlendEquationRGB
== GL_FUNC_ADD
);
79 ASSERT(ctx
->Color
.BlendEquationA
== GL_FUNC_ADD
);
80 ASSERT(ctx
->Color
.BlendSrcRGB
== GL_ZERO
);
81 ASSERT(ctx
->Color
.BlendDstRGB
== 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 _mesa_memcpy(src
, dst
, bytes
);
97 * Special case for glBlendFunc(GL_ONE, GL_ZERO)
100 static void _BLENDAPI
101 blend_replace(GLcontext
*ctx
, GLuint n
, const GLubyte mask
[],
102 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
104 ASSERT(ctx
->Color
.BlendEquationRGB
== GL_FUNC_ADD
);
105 ASSERT(ctx
->Color
.BlendEquationA
== GL_FUNC_ADD
);
106 ASSERT(ctx
->Color
.BlendSrcRGB
== GL_ONE
);
107 ASSERT(ctx
->Color
.BlendDstRGB
== 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(GLcontext
*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
.BlendEquationRGB
== GL_FUNC_ADD
);
129 ASSERT(ctx
->Color
.BlendEquationA
== GL_FUNC_ADD
);
130 ASSERT(ctx
->Color
.BlendSrcRGB
== GL_SRC_ALPHA
);
131 ASSERT(ctx
->Color
.BlendSrcA
== GL_SRC_ALPHA
);
132 ASSERT(ctx
->Color
.BlendDstRGB
== GL_ONE_MINUS_SRC_ALPHA
);
133 ASSERT(ctx
->Color
.BlendDstA
== 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(GLcontext
*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
.BlendEquationRGB
== GL_FUNC_ADD
);
174 ASSERT(ctx
->Color
.BlendEquationA
== GL_FUNC_ADD
);
175 ASSERT(ctx
->Color
.BlendSrcRGB
== GL_SRC_ALPHA
);
176 ASSERT(ctx
->Color
.BlendSrcA
== GL_SRC_ALPHA
);
177 ASSERT(ctx
->Color
.BlendDstRGB
== GL_ONE_MINUS_SRC_ALPHA
);
178 ASSERT(ctx
->Color
.BlendDstA
== 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(GLcontext
*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
.BlendEquationRGB
== GL_FUNC_ADD
);
212 ASSERT(ctx
->Color
.BlendEquationA
== GL_FUNC_ADD
);
213 ASSERT(ctx
->Color
.BlendSrcRGB
== GL_SRC_ALPHA
);
214 ASSERT(ctx
->Color
.BlendSrcA
== GL_SRC_ALPHA
);
215 ASSERT(ctx
->Color
.BlendDstRGB
== GL_ONE_MINUS_SRC_ALPHA
);
216 ASSERT(ctx
->Color
.BlendDstA
== 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(GLcontext
*ctx
, GLuint n
, const GLubyte mask
[],
247 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
251 ASSERT(ctx
->Color
.BlendEquationRGB
== GL_FUNC_ADD
);
252 ASSERT(ctx
->Color
.BlendEquationA
== GL_FUNC_ADD
);
253 ASSERT(ctx
->Color
.BlendSrcRGB
== GL_ONE
);
254 ASSERT(ctx
->Color
.BlendDstRGB
== 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(GLcontext
*ctx
, GLuint n
, const GLubyte mask
[],
313 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
316 ASSERT(ctx
->Color
.BlendEquationRGB
== GL_MIN
);
317 ASSERT(ctx
->Color
.BlendEquationA
== 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(GLcontext
*ctx
, GLuint n
, const GLubyte mask
[],
366 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
369 ASSERT(ctx
->Color
.BlendEquationRGB
== GL_MAX
);
370 ASSERT(ctx
->Color
.BlendEquationA
== 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(GLcontext
*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(GLcontext
*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
.BlendSrcRGB
) {
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
.BlendSrcA
) {
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
.BlendDstRGB
) {
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
.BlendDstA
) {
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
.BlendEquationRGB
) {
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
.BlendEquationA
) {
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(GLcontext
*ctx
, GLuint n
, const GLubyte mask
[],
820 void *src
, const void *dst
, GLenum chanType
)
822 GLfloat rgbaF
[MAX_WIDTH
][4], destF
[MAX_WIDTH
][4];
824 if (chanType
== GL_UNSIGNED_BYTE
) {
825 GLubyte (*rgba
)[4] = (GLubyte (*)[4]) src
;
826 const GLubyte (*dest
)[4] = (const GLubyte (*)[4]) dst
;
828 /* convert ubytes to floats */
829 for (i
= 0; i
< n
; i
++) {
831 rgbaF
[i
][RCOMP
] = UBYTE_TO_FLOAT(rgba
[i
][RCOMP
]);
832 rgbaF
[i
][GCOMP
] = UBYTE_TO_FLOAT(rgba
[i
][GCOMP
]);
833 rgbaF
[i
][BCOMP
] = UBYTE_TO_FLOAT(rgba
[i
][BCOMP
]);
834 rgbaF
[i
][ACOMP
] = UBYTE_TO_FLOAT(rgba
[i
][ACOMP
]);
835 destF
[i
][RCOMP
] = UBYTE_TO_FLOAT(dest
[i
][RCOMP
]);
836 destF
[i
][GCOMP
] = UBYTE_TO_FLOAT(dest
[i
][GCOMP
]);
837 destF
[i
][BCOMP
] = UBYTE_TO_FLOAT(dest
[i
][BCOMP
]);
838 destF
[i
][ACOMP
] = UBYTE_TO_FLOAT(dest
[i
][ACOMP
]);
842 blend_general_float(ctx
, n
, mask
, rgbaF
, destF
, chanType
);
843 /* convert back to ubytes */
844 for (i
= 0; i
< n
; i
++) {
846 UNCLAMPED_FLOAT_TO_UBYTE(rgba
[i
][RCOMP
], rgbaF
[i
][RCOMP
]);
847 UNCLAMPED_FLOAT_TO_UBYTE(rgba
[i
][GCOMP
], rgbaF
[i
][GCOMP
]);
848 UNCLAMPED_FLOAT_TO_UBYTE(rgba
[i
][BCOMP
], rgbaF
[i
][BCOMP
]);
849 UNCLAMPED_FLOAT_TO_UBYTE(rgba
[i
][ACOMP
], rgbaF
[i
][ACOMP
]);
853 else if (chanType
== GL_UNSIGNED_SHORT
) {
854 GLushort (*rgba
)[4] = (GLushort (*)[4]) src
;
855 const GLushort (*dest
)[4] = (const GLushort (*)[4]) dst
;
857 /* convert ushorts to floats */
858 for (i
= 0; i
< n
; i
++) {
860 rgbaF
[i
][RCOMP
] = USHORT_TO_FLOAT(rgba
[i
][RCOMP
]);
861 rgbaF
[i
][GCOMP
] = USHORT_TO_FLOAT(rgba
[i
][GCOMP
]);
862 rgbaF
[i
][BCOMP
] = USHORT_TO_FLOAT(rgba
[i
][BCOMP
]);
863 rgbaF
[i
][ACOMP
] = USHORT_TO_FLOAT(rgba
[i
][ACOMP
]);
864 destF
[i
][RCOMP
] = USHORT_TO_FLOAT(dest
[i
][RCOMP
]);
865 destF
[i
][GCOMP
] = USHORT_TO_FLOAT(dest
[i
][GCOMP
]);
866 destF
[i
][BCOMP
] = USHORT_TO_FLOAT(dest
[i
][BCOMP
]);
867 destF
[i
][ACOMP
] = USHORT_TO_FLOAT(dest
[i
][ACOMP
]);
871 blend_general_float(ctx
, n
, mask
, rgbaF
, destF
, chanType
);
872 /* convert back to ushorts */
873 for (i
= 0; i
< n
; i
++) {
875 UNCLAMPED_FLOAT_TO_USHORT(rgba
[i
][RCOMP
], rgbaF
[i
][RCOMP
]);
876 UNCLAMPED_FLOAT_TO_USHORT(rgba
[i
][GCOMP
], rgbaF
[i
][GCOMP
]);
877 UNCLAMPED_FLOAT_TO_USHORT(rgba
[i
][BCOMP
], rgbaF
[i
][BCOMP
]);
878 UNCLAMPED_FLOAT_TO_USHORT(rgba
[i
][ACOMP
], rgbaF
[i
][ACOMP
]);
883 blend_general_float(ctx
, n
, mask
, rgbaF
, destF
, chanType
);
890 * Analyze current blending parameters to pick fastest blending function.
891 * Result: the ctx->Color.BlendFunc pointer is updated.
894 _swrast_choose_blend_func(GLcontext
*ctx
, GLenum chanType
)
896 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
897 const GLenum eq
= ctx
->Color
.BlendEquationRGB
;
898 const GLenum srcRGB
= ctx
->Color
.BlendSrcRGB
;
899 const GLenum dstRGB
= ctx
->Color
.BlendDstRGB
;
900 const GLenum srcA
= ctx
->Color
.BlendSrcA
;
901 const GLenum dstA
= ctx
->Color
.BlendDstA
;
903 if (ctx
->Color
.BlendEquationRGB
!= ctx
->Color
.BlendEquationA
) {
904 swrast
->BlendFunc
= blend_general
;
906 else if (eq
== GL_MIN
) {
907 /* Note: GL_MIN ignores the blending weight factors */
908 #if defined(USE_MMX_ASM)
909 if (cpu_has_mmx
&& chanType
== GL_UNSIGNED_BYTE
) {
910 swrast
->BlendFunc
= _mesa_mmx_blend_min
;
914 swrast
->BlendFunc
= blend_min
;
916 else if (eq
== GL_MAX
) {
917 /* Note: GL_MAX 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_max
;
924 swrast
->BlendFunc
= blend_max
;
926 else if (srcRGB
!= srcA
|| dstRGB
!= dstA
) {
927 swrast
->BlendFunc
= blend_general
;
929 else if (eq
== GL_FUNC_ADD
&& srcRGB
== GL_SRC_ALPHA
930 && dstRGB
== GL_ONE_MINUS_SRC_ALPHA
) {
931 #if defined(USE_MMX_ASM)
932 if (cpu_has_mmx
&& chanType
== GL_UNSIGNED_BYTE
) {
933 swrast
->BlendFunc
= _mesa_mmx_blend_transparency
;
938 if (chanType
== GL_UNSIGNED_BYTE
)
939 swrast
->BlendFunc
= blend_transparency_ubyte
;
940 else if (chanType
== GL_UNSIGNED_SHORT
)
941 swrast
->BlendFunc
= blend_transparency_ushort
;
943 swrast
->BlendFunc
= blend_transparency_float
;
946 else if (eq
== GL_FUNC_ADD
&& srcRGB
== GL_ONE
&& dstRGB
== GL_ONE
) {
947 #if defined(USE_MMX_ASM)
948 if (cpu_has_mmx
&& chanType
== GL_UNSIGNED_BYTE
) {
949 swrast
->BlendFunc
= _mesa_mmx_blend_add
;
953 swrast
->BlendFunc
= blend_add
;
955 else if (((eq
== GL_FUNC_ADD
|| eq
== GL_FUNC_REVERSE_SUBTRACT
)
956 && (srcRGB
== GL_ZERO
&& dstRGB
== GL_SRC_COLOR
))
958 ((eq
== GL_FUNC_ADD
|| eq
== GL_FUNC_SUBTRACT
)
959 && (srcRGB
== GL_DST_COLOR
&& dstRGB
== GL_ZERO
))) {
960 #if defined(USE_MMX_ASM)
961 if (cpu_has_mmx
&& chanType
== GL_UNSIGNED_BYTE
) {
962 swrast
->BlendFunc
= _mesa_mmx_blend_modulate
;
966 swrast
->BlendFunc
= blend_modulate
;
968 else if (eq
== GL_FUNC_ADD
&& srcRGB
== GL_ZERO
&& dstRGB
== GL_ONE
) {
969 swrast
->BlendFunc
= blend_noop
;
971 else if (eq
== GL_FUNC_ADD
&& srcRGB
== GL_ONE
&& dstRGB
== GL_ZERO
) {
972 swrast
->BlendFunc
= blend_replace
;
975 swrast
->BlendFunc
= blend_general
;
982 * Apply the blending operator to a span of pixels.
983 * We can handle horizontal runs of pixels (spans) or arrays of x/y
987 _swrast_blend_span(GLcontext
*ctx
, struct gl_renderbuffer
*rb
, SWspan
*span
)
989 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
992 ASSERT(span
->end
<= MAX_WIDTH
);
993 ASSERT(span
->arrayMask
& SPAN_RGBA
);
994 ASSERT(rb
->DataType
== span
->array
->ChanType
);
995 ASSERT(!ctx
->Color
._LogicOpEnabled
);
997 rbPixels
= _swrast_get_dest_rgba(ctx
, rb
, span
);
999 swrast
->BlendFunc(ctx
, span
->end
, span
->array
->mask
,
1000 span
->array
->rgba
, rbPixels
, span
->array
->ChanType
);