2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * 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"
55 * Integer divide by 255
56 * Declare "int divtemp" before using.
57 * This satisfies Glean and should be reasonably fast.
58 * Contributed by Nathan Hand.
60 #define DIV255(X) (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)
65 * Special case for glBlendFunc(GL_ZERO, GL_ONE).
66 * No-op means the framebuffer values remain unchanged.
70 blend_noop(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
71 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
75 assert(ctx
->Color
.Blend
[0].EquationRGB
== GL_FUNC_ADD
);
76 assert(ctx
->Color
.Blend
[0].EquationA
== GL_FUNC_ADD
);
77 assert(ctx
->Color
.Blend
[0].SrcRGB
== GL_ZERO
);
78 assert(ctx
->Color
.Blend
[0].DstRGB
== GL_ONE
);
82 if (chanType
== GL_UNSIGNED_BYTE
)
83 bytes
= 4 * n
* sizeof(GLubyte
);
84 else if (chanType
== GL_UNSIGNED_SHORT
)
85 bytes
= 4 * n
* sizeof(GLushort
);
87 bytes
= 4 * n
* sizeof(GLfloat
);
89 memcpy(src
, dst
, bytes
);
94 * Special case for glBlendFunc(GL_ONE, GL_ZERO)
98 blend_replace(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
99 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
101 assert(ctx
->Color
.Blend
[0].EquationRGB
== GL_FUNC_ADD
);
102 assert(ctx
->Color
.Blend
[0].EquationA
== GL_FUNC_ADD
);
103 assert(ctx
->Color
.Blend
[0].SrcRGB
== GL_ONE
);
104 assert(ctx
->Color
.Blend
[0].DstRGB
== GL_ZERO
);
114 * Common transparency blending mode:
115 * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
118 blend_transparency_ubyte(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
119 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
121 GLubyte (*rgba
)[4] = (GLubyte (*)[4]) src
;
122 const GLubyte (*dest
)[4] = (const GLubyte (*)[4]) dst
;
125 assert(ctx
->Color
.Blend
[0].EquationRGB
== GL_FUNC_ADD
);
126 assert(ctx
->Color
.Blend
[0].EquationA
== GL_FUNC_ADD
);
127 assert(ctx
->Color
.Blend
[0].SrcRGB
== GL_SRC_ALPHA
);
128 assert(ctx
->Color
.Blend
[0].SrcA
== GL_SRC_ALPHA
);
129 assert(ctx
->Color
.Blend
[0].DstRGB
== GL_ONE_MINUS_SRC_ALPHA
);
130 assert(ctx
->Color
.Blend
[0].DstA
== GL_ONE_MINUS_SRC_ALPHA
);
131 assert(chanType
== GL_UNSIGNED_BYTE
);
135 for (i
= 0; i
< n
; i
++) {
137 const GLint t
= rgba
[i
][ACOMP
]; /* t is in [0, 255] */
140 COPY_4UBV(rgba
[i
], dest
[i
]);
144 const GLint r
= DIV255((rgba
[i
][RCOMP
] - dest
[i
][RCOMP
]) * t
) + dest
[i
][RCOMP
];
145 const GLint g
= DIV255((rgba
[i
][GCOMP
] - dest
[i
][GCOMP
]) * t
) + dest
[i
][GCOMP
];
146 const GLint b
= DIV255((rgba
[i
][BCOMP
] - dest
[i
][BCOMP
]) * t
) + dest
[i
][BCOMP
];
147 const GLint a
= DIV255((rgba
[i
][ACOMP
] - dest
[i
][ACOMP
]) * t
) + dest
[i
][ACOMP
];
152 rgba
[i
][RCOMP
] = (GLubyte
) r
;
153 rgba
[i
][GCOMP
] = (GLubyte
) g
;
154 rgba
[i
][BCOMP
] = (GLubyte
) b
;
155 rgba
[i
][ACOMP
] = (GLubyte
) a
;
163 blend_transparency_ushort(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
164 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
166 GLushort (*rgba
)[4] = (GLushort (*)[4]) src
;
167 const GLushort (*dest
)[4] = (const GLushort (*)[4]) dst
;
170 assert(ctx
->Color
.Blend
[0].EquationRGB
== GL_FUNC_ADD
);
171 assert(ctx
->Color
.Blend
[0].EquationA
== GL_FUNC_ADD
);
172 assert(ctx
->Color
.Blend
[0].SrcRGB
== GL_SRC_ALPHA
);
173 assert(ctx
->Color
.Blend
[0].SrcA
== GL_SRC_ALPHA
);
174 assert(ctx
->Color
.Blend
[0].DstRGB
== GL_ONE_MINUS_SRC_ALPHA
);
175 assert(ctx
->Color
.Blend
[0].DstA
== GL_ONE_MINUS_SRC_ALPHA
);
176 assert(chanType
== GL_UNSIGNED_SHORT
);
180 for (i
= 0; i
< n
; i
++) {
182 const GLint t
= rgba
[i
][ACOMP
];
185 COPY_4V(rgba
[i
], dest
[i
]);
187 else if (t
!= 65535) {
188 const GLfloat tt
= (GLfloat
) t
/ 65535.0F
;
189 GLushort r
= (GLushort
) ((rgba
[i
][RCOMP
] - dest
[i
][RCOMP
]) * tt
+ dest
[i
][RCOMP
]);
190 GLushort g
= (GLushort
) ((rgba
[i
][GCOMP
] - dest
[i
][GCOMP
]) * tt
+ dest
[i
][GCOMP
]);
191 GLushort b
= (GLushort
) ((rgba
[i
][BCOMP
] - dest
[i
][BCOMP
]) * tt
+ dest
[i
][BCOMP
]);
192 GLushort a
= (GLushort
) ((rgba
[i
][ACOMP
] - dest
[i
][ACOMP
]) * tt
+ dest
[i
][ACOMP
]);
193 ASSIGN_4V(rgba
[i
], r
, g
, b
, a
);
201 blend_transparency_float(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
202 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
204 GLfloat (*rgba
)[4] = (GLfloat (*)[4]) src
;
205 const GLfloat (*dest
)[4] = (const GLfloat (*)[4]) dst
;
208 assert(ctx
->Color
.Blend
[0].EquationRGB
== GL_FUNC_ADD
);
209 assert(ctx
->Color
.Blend
[0].EquationA
== GL_FUNC_ADD
);
210 assert(ctx
->Color
.Blend
[0].SrcRGB
== GL_SRC_ALPHA
);
211 assert(ctx
->Color
.Blend
[0].SrcA
== GL_SRC_ALPHA
);
212 assert(ctx
->Color
.Blend
[0].DstRGB
== GL_ONE_MINUS_SRC_ALPHA
);
213 assert(ctx
->Color
.Blend
[0].DstA
== GL_ONE_MINUS_SRC_ALPHA
);
214 assert(chanType
== GL_FLOAT
);
218 for (i
= 0; i
< n
; i
++) {
220 const GLfloat t
= rgba
[i
][ACOMP
]; /* t in [0, 1] */
223 COPY_4V(rgba
[i
], dest
[i
]);
225 else if (t
!= 1.0F
) {
226 GLfloat r
= (rgba
[i
][RCOMP
] - dest
[i
][RCOMP
]) * t
+ dest
[i
][RCOMP
];
227 GLfloat g
= (rgba
[i
][GCOMP
] - dest
[i
][GCOMP
]) * t
+ dest
[i
][GCOMP
];
228 GLfloat b
= (rgba
[i
][BCOMP
] - dest
[i
][BCOMP
]) * t
+ dest
[i
][BCOMP
];
229 GLfloat a
= (rgba
[i
][ACOMP
] - dest
[i
][ACOMP
]) * t
+ dest
[i
][ACOMP
];
230 ASSIGN_4V(rgba
[i
], r
, g
, b
, a
);
239 * Add src and dest: glBlendFunc(GL_ONE, GL_ONE).
243 blend_add(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
244 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
248 assert(ctx
->Color
.Blend
[0].EquationRGB
== GL_FUNC_ADD
);
249 assert(ctx
->Color
.Blend
[0].EquationA
== GL_FUNC_ADD
);
250 assert(ctx
->Color
.Blend
[0].SrcRGB
== GL_ONE
);
251 assert(ctx
->Color
.Blend
[0].DstRGB
== GL_ONE
);
254 if (chanType
== GL_UNSIGNED_BYTE
) {
255 GLubyte (*rgba
)[4] = (GLubyte (*)[4]) src
;
256 const GLubyte (*dest
)[4] = (const GLubyte (*)[4]) dst
;
259 GLint r
= rgba
[i
][RCOMP
] + dest
[i
][RCOMP
];
260 GLint g
= rgba
[i
][GCOMP
] + dest
[i
][GCOMP
];
261 GLint b
= rgba
[i
][BCOMP
] + dest
[i
][BCOMP
];
262 GLint a
= rgba
[i
][ACOMP
] + dest
[i
][ACOMP
];
263 rgba
[i
][RCOMP
] = (GLubyte
) MIN2( r
, 255 );
264 rgba
[i
][GCOMP
] = (GLubyte
) MIN2( g
, 255 );
265 rgba
[i
][BCOMP
] = (GLubyte
) MIN2( b
, 255 );
266 rgba
[i
][ACOMP
] = (GLubyte
) MIN2( a
, 255 );
270 else if (chanType
== GL_UNSIGNED_SHORT
) {
271 GLushort (*rgba
)[4] = (GLushort (*)[4]) src
;
272 const GLushort (*dest
)[4] = (const GLushort (*)[4]) dst
;
275 GLint r
= rgba
[i
][RCOMP
] + dest
[i
][RCOMP
];
276 GLint g
= rgba
[i
][GCOMP
] + dest
[i
][GCOMP
];
277 GLint b
= rgba
[i
][BCOMP
] + dest
[i
][BCOMP
];
278 GLint a
= rgba
[i
][ACOMP
] + dest
[i
][ACOMP
];
279 rgba
[i
][RCOMP
] = (GLshort
) MIN2( r
, 255 );
280 rgba
[i
][GCOMP
] = (GLshort
) MIN2( g
, 255 );
281 rgba
[i
][BCOMP
] = (GLshort
) MIN2( b
, 255 );
282 rgba
[i
][ACOMP
] = (GLshort
) MIN2( a
, 255 );
287 GLfloat (*rgba
)[4] = (GLfloat (*)[4]) src
;
288 const GLfloat (*dest
)[4] = (const GLfloat (*)[4]) dst
;
289 assert(chanType
== GL_FLOAT
);
292 /* don't RGB clamp to max */
293 rgba
[i
][RCOMP
] += dest
[i
][RCOMP
];
294 rgba
[i
][GCOMP
] += dest
[i
][GCOMP
];
295 rgba
[i
][BCOMP
] += dest
[i
][BCOMP
];
296 rgba
[i
][ACOMP
] += dest
[i
][ACOMP
];
305 * Blend min function.
309 blend_min(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
310 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
313 assert(ctx
->Color
.Blend
[0].EquationRGB
== GL_MIN
);
314 assert(ctx
->Color
.Blend
[0].EquationA
== GL_MIN
);
317 if (chanType
== GL_UNSIGNED_BYTE
) {
318 GLubyte (*rgba
)[4] = (GLubyte (*)[4]) src
;
319 const GLubyte (*dest
)[4] = (const GLubyte (*)[4]) dst
;
322 rgba
[i
][RCOMP
] = MIN2( rgba
[i
][RCOMP
], dest
[i
][RCOMP
] );
323 rgba
[i
][GCOMP
] = MIN2( rgba
[i
][GCOMP
], dest
[i
][GCOMP
] );
324 rgba
[i
][BCOMP
] = MIN2( rgba
[i
][BCOMP
], dest
[i
][BCOMP
] );
325 rgba
[i
][ACOMP
] = MIN2( rgba
[i
][ACOMP
], dest
[i
][ACOMP
] );
329 else if (chanType
== GL_UNSIGNED_SHORT
) {
330 GLushort (*rgba
)[4] = (GLushort (*)[4]) src
;
331 const GLushort (*dest
)[4] = (const GLushort (*)[4]) dst
;
334 rgba
[i
][RCOMP
] = MIN2( rgba
[i
][RCOMP
], dest
[i
][RCOMP
] );
335 rgba
[i
][GCOMP
] = MIN2( rgba
[i
][GCOMP
], dest
[i
][GCOMP
] );
336 rgba
[i
][BCOMP
] = MIN2( rgba
[i
][BCOMP
], dest
[i
][BCOMP
] );
337 rgba
[i
][ACOMP
] = MIN2( rgba
[i
][ACOMP
], dest
[i
][ACOMP
] );
342 GLfloat (*rgba
)[4] = (GLfloat (*)[4]) src
;
343 const GLfloat (*dest
)[4] = (const GLfloat (*)[4]) dst
;
344 assert(chanType
== GL_FLOAT
);
347 rgba
[i
][RCOMP
] = MIN2( rgba
[i
][RCOMP
], dest
[i
][RCOMP
] );
348 rgba
[i
][GCOMP
] = MIN2( rgba
[i
][GCOMP
], dest
[i
][GCOMP
] );
349 rgba
[i
][BCOMP
] = MIN2( rgba
[i
][BCOMP
], dest
[i
][BCOMP
] );
350 rgba
[i
][ACOMP
] = MIN2( rgba
[i
][ACOMP
], dest
[i
][ACOMP
] );
358 * Blend max function.
362 blend_max(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
363 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
366 assert(ctx
->Color
.Blend
[0].EquationRGB
== GL_MAX
);
367 assert(ctx
->Color
.Blend
[0].EquationA
== GL_MAX
);
370 if (chanType
== GL_UNSIGNED_BYTE
) {
371 GLubyte (*rgba
)[4] = (GLubyte (*)[4]) src
;
372 const GLubyte (*dest
)[4] = (const GLubyte (*)[4]) dst
;
375 rgba
[i
][RCOMP
] = MAX2( rgba
[i
][RCOMP
], dest
[i
][RCOMP
] );
376 rgba
[i
][GCOMP
] = MAX2( rgba
[i
][GCOMP
], dest
[i
][GCOMP
] );
377 rgba
[i
][BCOMP
] = MAX2( rgba
[i
][BCOMP
], dest
[i
][BCOMP
] );
378 rgba
[i
][ACOMP
] = MAX2( rgba
[i
][ACOMP
], dest
[i
][ACOMP
] );
382 else if (chanType
== GL_UNSIGNED_SHORT
) {
383 GLushort (*rgba
)[4] = (GLushort (*)[4]) src
;
384 const GLushort (*dest
)[4] = (const GLushort (*)[4]) dst
;
387 rgba
[i
][RCOMP
] = MAX2( rgba
[i
][RCOMP
], dest
[i
][RCOMP
] );
388 rgba
[i
][GCOMP
] = MAX2( rgba
[i
][GCOMP
], dest
[i
][GCOMP
] );
389 rgba
[i
][BCOMP
] = MAX2( rgba
[i
][BCOMP
], dest
[i
][BCOMP
] );
390 rgba
[i
][ACOMP
] = MAX2( rgba
[i
][ACOMP
], dest
[i
][ACOMP
] );
395 GLfloat (*rgba
)[4] = (GLfloat (*)[4]) src
;
396 const GLfloat (*dest
)[4] = (const GLfloat (*)[4]) dst
;
397 assert(chanType
== GL_FLOAT
);
400 rgba
[i
][RCOMP
] = MAX2( rgba
[i
][RCOMP
], dest
[i
][RCOMP
] );
401 rgba
[i
][GCOMP
] = MAX2( rgba
[i
][GCOMP
], dest
[i
][GCOMP
] );
402 rgba
[i
][BCOMP
] = MAX2( rgba
[i
][BCOMP
], dest
[i
][BCOMP
] );
403 rgba
[i
][ACOMP
] = MAX2( rgba
[i
][ACOMP
], dest
[i
][ACOMP
] );
412 * Modulate: result = src * dest
416 blend_modulate(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
417 GLvoid
*src
, const GLvoid
*dst
, GLenum chanType
)
422 if (chanType
== GL_UNSIGNED_BYTE
) {
423 GLubyte (*rgba
)[4] = (GLubyte (*)[4]) src
;
424 const GLubyte (*dest
)[4] = (const GLubyte (*)[4]) dst
;
428 rgba
[i
][RCOMP
] = DIV255(rgba
[i
][RCOMP
] * dest
[i
][RCOMP
]);
429 rgba
[i
][GCOMP
] = DIV255(rgba
[i
][GCOMP
] * dest
[i
][GCOMP
]);
430 rgba
[i
][BCOMP
] = DIV255(rgba
[i
][BCOMP
] * dest
[i
][BCOMP
]);
431 rgba
[i
][ACOMP
] = DIV255(rgba
[i
][ACOMP
] * dest
[i
][ACOMP
]);
435 else if (chanType
== GL_UNSIGNED_SHORT
) {
436 GLushort (*rgba
)[4] = (GLushort (*)[4]) src
;
437 const GLushort (*dest
)[4] = (const GLushort (*)[4]) dst
;
440 rgba
[i
][RCOMP
] = (rgba
[i
][RCOMP
] * dest
[i
][RCOMP
] + 65535) >> 16;
441 rgba
[i
][GCOMP
] = (rgba
[i
][GCOMP
] * dest
[i
][GCOMP
] + 65535) >> 16;
442 rgba
[i
][BCOMP
] = (rgba
[i
][BCOMP
] * dest
[i
][BCOMP
] + 65535) >> 16;
443 rgba
[i
][ACOMP
] = (rgba
[i
][ACOMP
] * dest
[i
][ACOMP
] + 65535) >> 16;
448 GLfloat (*rgba
)[4] = (GLfloat (*)[4]) src
;
449 const GLfloat (*dest
)[4] = (const GLfloat (*)[4]) dst
;
450 assert(chanType
== GL_FLOAT
);
453 rgba
[i
][RCOMP
] = rgba
[i
][RCOMP
] * dest
[i
][RCOMP
];
454 rgba
[i
][GCOMP
] = rgba
[i
][GCOMP
] * dest
[i
][GCOMP
];
455 rgba
[i
][BCOMP
] = rgba
[i
][BCOMP
] * dest
[i
][BCOMP
];
456 rgba
[i
][ACOMP
] = rgba
[i
][ACOMP
] * dest
[i
][ACOMP
];
464 * Do any blending operation, using floating point.
465 * \param n number of pixels
466 * \param mask fragment writemask array
467 * \param rgba array of incoming (and modified) pixels
468 * \param dest array of pixels from the dest color buffer
471 blend_general_float(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
472 GLfloat rgba
[][4], GLfloat dest
[][4],
477 for (i
= 0; i
< n
; i
++) {
479 /* Incoming/source Color */
480 const GLfloat Rs
= rgba
[i
][RCOMP
];
481 const GLfloat Gs
= rgba
[i
][GCOMP
];
482 const GLfloat Bs
= rgba
[i
][BCOMP
];
483 const GLfloat As
= rgba
[i
][ACOMP
];
485 /* Frame buffer/dest color */
486 const GLfloat Rd
= dest
[i
][RCOMP
];
487 const GLfloat Gd
= dest
[i
][GCOMP
];
488 const GLfloat Bd
= dest
[i
][BCOMP
];
489 const GLfloat Ad
= dest
[i
][ACOMP
];
491 GLfloat sR
, sG
, sB
, sA
; /* Source factor */
492 GLfloat dR
, dG
, dB
, dA
; /* Dest factor */
493 GLfloat r
, g
, b
, a
; /* result color */
495 /* XXX for the case of constant blend terms we could init
496 * the sX and dX variables just once before the loop.
499 /* Source RGB factor */
500 switch (ctx
->Color
.Blend
[0].SrcRGB
) {
512 case GL_ONE_MINUS_DST_COLOR
:
520 case GL_ONE_MINUS_SRC_ALPHA
:
521 sR
= sG
= sB
= 1.0F
- As
;
526 case GL_ONE_MINUS_DST_ALPHA
:
527 sR
= sG
= sB
= 1.0F
- Ad
;
529 case GL_SRC_ALPHA_SATURATE
:
530 if (As
< 1.0F
- Ad
) {
534 sR
= sG
= sB
= 1.0F
- Ad
;
537 case GL_CONSTANT_COLOR
:
538 sR
= ctx
->Color
.BlendColor
[0];
539 sG
= ctx
->Color
.BlendColor
[1];
540 sB
= ctx
->Color
.BlendColor
[2];
542 case GL_ONE_MINUS_CONSTANT_COLOR
:
543 sR
= 1.0F
- ctx
->Color
.BlendColor
[0];
544 sG
= 1.0F
- ctx
->Color
.BlendColor
[1];
545 sB
= 1.0F
- ctx
->Color
.BlendColor
[2];
547 case GL_CONSTANT_ALPHA
:
548 sR
= sG
= sB
= ctx
->Color
.BlendColor
[3];
550 case GL_ONE_MINUS_CONSTANT_ALPHA
:
551 sR
= sG
= sB
= 1.0F
- ctx
->Color
.BlendColor
[3];
558 case GL_ONE_MINUS_SRC_COLOR
:
564 /* this should never happen */
565 _mesa_problem(ctx
, "Bad blend source RGB factor in blend_general_float");
569 /* Source Alpha factor */
570 switch (ctx
->Color
.Blend
[0].SrcA
) {
580 case GL_ONE_MINUS_DST_COLOR
:
586 case GL_ONE_MINUS_SRC_ALPHA
:
592 case GL_ONE_MINUS_DST_ALPHA
:
595 case GL_SRC_ALPHA_SATURATE
:
598 case GL_CONSTANT_COLOR
:
599 sA
= ctx
->Color
.BlendColor
[3];
601 case GL_ONE_MINUS_CONSTANT_COLOR
:
602 sA
= 1.0F
- ctx
->Color
.BlendColor
[3];
604 case GL_CONSTANT_ALPHA
:
605 sA
= ctx
->Color
.BlendColor
[3];
607 case GL_ONE_MINUS_CONSTANT_ALPHA
:
608 sA
= 1.0F
- ctx
->Color
.BlendColor
[3];
613 case GL_ONE_MINUS_SRC_COLOR
:
617 /* this should never happen */
619 _mesa_problem(ctx
, "Bad blend source A factor in blend_general_float");
623 /* Dest RGB factor */
624 switch (ctx
->Color
.Blend
[0].DstRGB
) {
636 case GL_ONE_MINUS_SRC_COLOR
:
644 case GL_ONE_MINUS_SRC_ALPHA
:
645 dR
= dG
= dB
= 1.0F
- As
;
650 case GL_ONE_MINUS_DST_ALPHA
:
651 dR
= dG
= dB
= 1.0F
- Ad
;
653 case GL_CONSTANT_COLOR
:
654 dR
= ctx
->Color
.BlendColor
[0];
655 dG
= ctx
->Color
.BlendColor
[1];
656 dB
= ctx
->Color
.BlendColor
[2];
658 case GL_ONE_MINUS_CONSTANT_COLOR
:
659 dR
= 1.0F
- ctx
->Color
.BlendColor
[0];
660 dG
= 1.0F
- ctx
->Color
.BlendColor
[1];
661 dB
= 1.0F
- ctx
->Color
.BlendColor
[2];
663 case GL_CONSTANT_ALPHA
:
664 dR
= dG
= dB
= ctx
->Color
.BlendColor
[3];
666 case GL_ONE_MINUS_CONSTANT_ALPHA
:
667 dR
= dG
= dB
= 1.0F
- ctx
->Color
.BlendColor
[3];
674 case GL_ONE_MINUS_DST_COLOR
:
680 /* this should never happen */
682 _mesa_problem(ctx
, "Bad blend dest RGB factor in blend_general_float");
686 /* Dest Alpha factor */
687 switch (ctx
->Color
.Blend
[0].DstA
) {
697 case GL_ONE_MINUS_SRC_COLOR
:
703 case GL_ONE_MINUS_SRC_ALPHA
:
709 case GL_ONE_MINUS_DST_ALPHA
:
712 case GL_CONSTANT_COLOR
:
713 dA
= ctx
->Color
.BlendColor
[3];
715 case GL_ONE_MINUS_CONSTANT_COLOR
:
716 dA
= 1.0F
- ctx
->Color
.BlendColor
[3];
718 case GL_CONSTANT_ALPHA
:
719 dA
= ctx
->Color
.BlendColor
[3];
721 case GL_ONE_MINUS_CONSTANT_ALPHA
:
722 dA
= 1.0F
- ctx
->Color
.BlendColor
[3];
727 case GL_ONE_MINUS_DST_COLOR
:
731 /* this should never happen */
733 _mesa_problem(ctx
, "Bad blend dest A factor in blend_general_float");
737 /* compute the blended RGB */
738 switch (ctx
->Color
.Blend
[0].EquationRGB
) {
740 r
= Rs
* sR
+ Rd
* dR
;
741 g
= Gs
* sG
+ Gd
* dG
;
742 b
= Bs
* sB
+ Bd
* dB
;
743 a
= As
* sA
+ Ad
* dA
;
745 case GL_FUNC_SUBTRACT
:
746 r
= Rs
* sR
- Rd
* dR
;
747 g
= Gs
* sG
- Gd
* dG
;
748 b
= Bs
* sB
- Bd
* dB
;
749 a
= As
* sA
- Ad
* dA
;
751 case GL_FUNC_REVERSE_SUBTRACT
:
752 r
= Rd
* dR
- Rs
* sR
;
753 g
= Gd
* dG
- Gs
* sG
;
754 b
= Bd
* dB
- Bs
* sB
;
755 a
= Ad
* dA
- As
* sA
;
768 /* should never get here */
769 r
= g
= b
= 0.0F
; /* silence uninitialized var warning */
770 _mesa_problem(ctx
, "unexpected BlendEquation in blend_general()");
774 /* compute the blended alpha */
775 switch (ctx
->Color
.Blend
[0].EquationA
) {
777 a
= As
* sA
+ Ad
* dA
;
779 case GL_FUNC_SUBTRACT
:
780 a
= As
* sA
- Ad
* dA
;
782 case GL_FUNC_REVERSE_SUBTRACT
:
783 a
= Ad
* dA
- As
* sA
;
792 /* should never get here */
793 a
= 0.0F
; /* silence uninitialized var warning */
794 _mesa_problem(ctx
, "unexpected BlendEquation in blend_general()");
800 rgba
[i
][RCOMP
] = MAX2( r
, 0.0F
);
801 rgba
[i
][GCOMP
] = MAX2( g
, 0.0F
);
802 rgba
[i
][BCOMP
] = MAX2( b
, 0.0F
);
803 rgba
[i
][ACOMP
] = CLAMP( a
, 0.0F
, 1.0F
);
805 ASSIGN_4V(rgba
[i
], r
, g
, b
, a
);
813 * Do any blending operation, any chanType.
816 blend_general(struct gl_context
*ctx
, GLuint n
, const GLubyte mask
[],
817 void *src
, const void *dst
, GLenum chanType
)
819 GLfloat (*rgbaF
)[4], (*destF
)[4];
821 rgbaF
= (GLfloat (*)[4]) malloc(4 * n
* sizeof(GLfloat
));
822 destF
= (GLfloat (*)[4]) malloc(4 * n
* sizeof(GLfloat
));
823 if (!rgbaF
|| !destF
) {
826 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "blending");
830 if (chanType
== GL_UNSIGNED_BYTE
) {
831 GLubyte (*rgba
)[4] = (GLubyte (*)[4]) src
;
832 const GLubyte (*dest
)[4] = (const GLubyte (*)[4]) dst
;
834 /* convert ubytes to floats */
835 for (i
= 0; i
< n
; i
++) {
837 rgbaF
[i
][RCOMP
] = UBYTE_TO_FLOAT(rgba
[i
][RCOMP
]);
838 rgbaF
[i
][GCOMP
] = UBYTE_TO_FLOAT(rgba
[i
][GCOMP
]);
839 rgbaF
[i
][BCOMP
] = UBYTE_TO_FLOAT(rgba
[i
][BCOMP
]);
840 rgbaF
[i
][ACOMP
] = UBYTE_TO_FLOAT(rgba
[i
][ACOMP
]);
841 destF
[i
][RCOMP
] = UBYTE_TO_FLOAT(dest
[i
][RCOMP
]);
842 destF
[i
][GCOMP
] = UBYTE_TO_FLOAT(dest
[i
][GCOMP
]);
843 destF
[i
][BCOMP
] = UBYTE_TO_FLOAT(dest
[i
][BCOMP
]);
844 destF
[i
][ACOMP
] = UBYTE_TO_FLOAT(dest
[i
][ACOMP
]);
848 blend_general_float(ctx
, n
, mask
, rgbaF
, destF
, chanType
);
849 /* convert back to ubytes */
850 for (i
= 0; i
< n
; i
++) {
852 _mesa_unclamped_float_rgba_to_ubyte(rgba
[i
], rgbaF
[i
]);
855 else if (chanType
== GL_UNSIGNED_SHORT
) {
856 GLushort (*rgba
)[4] = (GLushort (*)[4]) src
;
857 const GLushort (*dest
)[4] = (const GLushort (*)[4]) dst
;
859 /* convert ushorts to floats */
860 for (i
= 0; i
< n
; i
++) {
862 rgbaF
[i
][RCOMP
] = USHORT_TO_FLOAT(rgba
[i
][RCOMP
]);
863 rgbaF
[i
][GCOMP
] = USHORT_TO_FLOAT(rgba
[i
][GCOMP
]);
864 rgbaF
[i
][BCOMP
] = USHORT_TO_FLOAT(rgba
[i
][BCOMP
]);
865 rgbaF
[i
][ACOMP
] = USHORT_TO_FLOAT(rgba
[i
][ACOMP
]);
866 destF
[i
][RCOMP
] = USHORT_TO_FLOAT(dest
[i
][RCOMP
]);
867 destF
[i
][GCOMP
] = USHORT_TO_FLOAT(dest
[i
][GCOMP
]);
868 destF
[i
][BCOMP
] = USHORT_TO_FLOAT(dest
[i
][BCOMP
]);
869 destF
[i
][ACOMP
] = USHORT_TO_FLOAT(dest
[i
][ACOMP
]);
873 blend_general_float(ctx
, n
, mask
, rgbaF
, destF
, chanType
);
874 /* convert back to ushorts */
875 for (i
= 0; i
< n
; i
++) {
877 UNCLAMPED_FLOAT_TO_USHORT(rgba
[i
][RCOMP
], rgbaF
[i
][RCOMP
]);
878 UNCLAMPED_FLOAT_TO_USHORT(rgba
[i
][GCOMP
], rgbaF
[i
][GCOMP
]);
879 UNCLAMPED_FLOAT_TO_USHORT(rgba
[i
][BCOMP
], rgbaF
[i
][BCOMP
]);
880 UNCLAMPED_FLOAT_TO_USHORT(rgba
[i
][ACOMP
], rgbaF
[i
][ACOMP
]);
885 blend_general_float(ctx
, n
, mask
, (GLfloat (*)[4]) src
,
886 (GLfloat (*)[4]) dst
, chanType
);
896 * Analyze current blending parameters to pick fastest blending function.
897 * Result: the ctx->Color.BlendFunc pointer is updated.
900 _swrast_choose_blend_func(struct gl_context
*ctx
, GLenum chanType
)
902 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
903 const GLenum eq
= ctx
->Color
.Blend
[0].EquationRGB
;
904 const GLenum srcRGB
= ctx
->Color
.Blend
[0].SrcRGB
;
905 const GLenum dstRGB
= ctx
->Color
.Blend
[0].DstRGB
;
906 const GLenum srcA
= ctx
->Color
.Blend
[0].SrcA
;
907 const GLenum dstA
= ctx
->Color
.Blend
[0].DstA
;
909 if (ctx
->Color
.Blend
[0].EquationRGB
!= ctx
->Color
.Blend
[0].EquationA
) {
910 swrast
->BlendFunc
= blend_general
;
912 else if (eq
== GL_MIN
) {
913 /* Note: GL_MIN ignores the blending weight factors */
914 #if defined(USE_MMX_ASM)
915 if (cpu_has_mmx
&& chanType
== GL_UNSIGNED_BYTE
) {
916 swrast
->BlendFunc
= _mesa_mmx_blend_min
;
920 swrast
->BlendFunc
= blend_min
;
922 else if (eq
== GL_MAX
) {
923 /* Note: GL_MAX ignores the blending weight factors */
924 #if defined(USE_MMX_ASM)
925 if (cpu_has_mmx
&& chanType
== GL_UNSIGNED_BYTE
) {
926 swrast
->BlendFunc
= _mesa_mmx_blend_max
;
930 swrast
->BlendFunc
= blend_max
;
932 else if (srcRGB
!= srcA
|| dstRGB
!= dstA
) {
933 swrast
->BlendFunc
= blend_general
;
935 else if (eq
== GL_FUNC_ADD
&& srcRGB
== GL_SRC_ALPHA
936 && dstRGB
== GL_ONE_MINUS_SRC_ALPHA
) {
937 #if defined(USE_MMX_ASM)
938 if (cpu_has_mmx
&& chanType
== GL_UNSIGNED_BYTE
) {
939 swrast
->BlendFunc
= _mesa_mmx_blend_transparency
;
944 if (chanType
== GL_UNSIGNED_BYTE
)
945 swrast
->BlendFunc
= blend_transparency_ubyte
;
946 else if (chanType
== GL_UNSIGNED_SHORT
)
947 swrast
->BlendFunc
= blend_transparency_ushort
;
949 swrast
->BlendFunc
= blend_transparency_float
;
952 else if (eq
== GL_FUNC_ADD
&& srcRGB
== GL_ONE
&& dstRGB
== GL_ONE
) {
953 #if defined(USE_MMX_ASM)
954 if (cpu_has_mmx
&& chanType
== GL_UNSIGNED_BYTE
) {
955 swrast
->BlendFunc
= _mesa_mmx_blend_add
;
959 swrast
->BlendFunc
= blend_add
;
961 else if (((eq
== GL_FUNC_ADD
|| eq
== GL_FUNC_REVERSE_SUBTRACT
)
962 && (srcRGB
== GL_ZERO
&& dstRGB
== GL_SRC_COLOR
))
964 ((eq
== GL_FUNC_ADD
|| eq
== GL_FUNC_SUBTRACT
)
965 && (srcRGB
== GL_DST_COLOR
&& dstRGB
== GL_ZERO
))) {
966 #if defined(USE_MMX_ASM)
967 if (cpu_has_mmx
&& chanType
== GL_UNSIGNED_BYTE
) {
968 swrast
->BlendFunc
= _mesa_mmx_blend_modulate
;
972 swrast
->BlendFunc
= blend_modulate
;
974 else if (eq
== GL_FUNC_ADD
&& srcRGB
== GL_ZERO
&& dstRGB
== GL_ONE
) {
975 swrast
->BlendFunc
= blend_noop
;
977 else if (eq
== GL_FUNC_ADD
&& srcRGB
== GL_ONE
&& dstRGB
== GL_ZERO
) {
978 swrast
->BlendFunc
= blend_replace
;
981 swrast
->BlendFunc
= blend_general
;
988 * Apply the blending operator to a span of pixels.
989 * We can handle horizontal runs of pixels (spans) or arrays of x/y
993 _swrast_blend_span(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
, SWspan
*span
)
995 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
998 assert(span
->end
<= SWRAST_MAX_WIDTH
);
999 assert(span
->arrayMask
& SPAN_RGBA
);
1000 assert(!ctx
->Color
.ColorLogicOpEnabled
);
1002 rbPixels
= _swrast_get_dest_rgba(ctx
, rb
, span
);
1004 swrast
->BlendFunc(ctx
, span
->end
, span
->array
->mask
,
1005 span
->array
->rgba
, rbPixels
, span
->array
->ChanType
);