move mesa32 over to new dir
[reactos.git] / reactos / lib / mesa32 / src / swrast / s_blend.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.3
4 *
5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 */
24
25 /*
26 * Regarding GL_NV_blend_square:
27 *
28 * Portions of this software may use or implement intellectual
29 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
30 * any and all warranties with respect to such intellectual property,
31 * including any use thereof or modifications thereto.
32 */
33
34
35 #include "glheader.h"
36 #include "context.h"
37 #include "colormac.h"
38 #include "macros.h"
39
40 #include "s_blend.h"
41 #include "s_context.h"
42 #include "s_span.h"
43
44
45 #if defined(USE_MMX_ASM)
46 #include "x86/mmx.h"
47 #include "x86/common_x86_asm.h"
48 #define _BLENDAPI _ASMAPI
49 #else
50 #define _BLENDAPI
51 #endif
52
53
54 /*
55 * Special case for glBlendFunc(GL_ZERO, GL_ONE)
56 */
57 static void _BLENDAPI
58 blend_noop( GLcontext *ctx, GLuint n, const GLubyte mask[],
59 GLchan rgba[][4], CONST GLchan dest[][4] )
60 {
61 GLuint i;
62 ASSERT(ctx->Color.BlendEquationRGB==GL_FUNC_ADD);
63 ASSERT(ctx->Color.BlendEquationA==GL_FUNC_ADD);
64 ASSERT(ctx->Color.BlendSrcRGB==GL_ZERO);
65 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
66 (void) ctx;
67
68 for (i = 0; i < n; i++) {
69 if (mask[i]) {
70 COPY_CHAN4( rgba[i], dest[i] );
71 }
72 }
73 }
74
75
76 /*
77 * Special case for glBlendFunc(GL_ONE, GL_ZERO)
78 */
79 static void _BLENDAPI
80 blend_replace( GLcontext *ctx, GLuint n, const GLubyte mask[],
81 GLchan rgba[][4], CONST GLchan dest[][4] )
82 {
83 ASSERT(ctx->Color.BlendEquationRGB==GL_FUNC_ADD);
84 ASSERT(ctx->Color.BlendEquationA==GL_FUNC_ADD);
85 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
86 ASSERT(ctx->Color.BlendDstRGB==GL_ZERO);
87 (void) ctx;
88 (void) n;
89 (void) mask;
90 (void) rgba;
91 (void) dest;
92 }
93
94
95 /*
96 * Common transparency blending mode.
97 */
98 static void _BLENDAPI
99 blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[],
100 GLchan rgba[][4], CONST GLchan dest[][4] )
101 {
102 GLuint i;
103 ASSERT(ctx->Color.BlendEquationRGB==GL_FUNC_ADD);
104 ASSERT(ctx->Color.BlendEquationA==GL_FUNC_ADD);
105 ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA);
106 ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA);
107 (void) ctx;
108
109 for (i=0;i<n;i++) {
110 if (mask[i]) {
111 const GLchan t = rgba[i][ACOMP]; /* t in [0, CHAN_MAX] */
112 if (t == 0) {
113 /* 0% alpha */
114 rgba[i][RCOMP] = dest[i][RCOMP];
115 rgba[i][GCOMP] = dest[i][GCOMP];
116 rgba[i][BCOMP] = dest[i][BCOMP];
117 rgba[i][ACOMP] = dest[i][ACOMP];
118 }
119 else if (t == CHAN_MAX) {
120 /* 100% alpha, no-op */
121 }
122 else {
123 #if 0
124 /* This is pretty close, but Glean complains */
125 const GLint s = CHAN_MAX - t;
126 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s + 1) >> 8;
127 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s + 1) >> 8;
128 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s + 1) >> 8;
129 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s + 1) >> 8;
130 #elif 0
131 /* This is slower but satisfies Glean */
132 const GLint s = CHAN_MAX - t;
133 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / 255;
134 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / 255;
135 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / 255;
136 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / 255;
137 #else
138 #if CHAN_BITS == 8
139 /* This satisfies Glean and should be reasonably fast */
140 /* Contributed by Nathan Hand */
141 #if 0
142 #define DIV255(X) (((X) << 8) + (X) + 256) >> 16
143 #else
144 GLint temp;
145 #define DIV255(X) (temp = (X), ((temp << 8) + temp + 256) >> 16)
146 #endif
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];
151
152 #undef DIV255
153 #elif CHAN_BITS == 16
154 const GLfloat tt = (GLfloat) t / CHAN_MAXF;
155 const GLint r = (GLint) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
156 const GLint g = (GLint) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
157 const GLint b = (GLint) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
158 const GLint a = (GLint) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
159 #else /* CHAN_BITS == 32 */
160 const GLfloat tt = (GLfloat) t / CHAN_MAXF;
161 const GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP];
162 const GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP];
163 const GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP];
164 const GLfloat a = CLAMP( rgba[i][ACOMP], 0.0F, CHAN_MAXF ) * t +
165 CLAMP( dest[i][ACOMP], 0.0F, CHAN_MAXF ) * (1.0F - t);
166 #endif
167 #endif
168 ASSERT(r <= CHAN_MAX);
169 ASSERT(g <= CHAN_MAX);
170 ASSERT(b <= CHAN_MAX);
171 ASSERT(a <= CHAN_MAX);
172 rgba[i][RCOMP] = (GLchan) r;
173 rgba[i][GCOMP] = (GLchan) g;
174 rgba[i][BCOMP] = (GLchan) b;
175 rgba[i][ACOMP] = (GLchan) a;
176 }
177 }
178 }
179 }
180
181
182
183 /*
184 * Add src and dest.
185 */
186 static void _BLENDAPI
187 blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[],
188 GLchan rgba[][4], CONST GLchan dest[][4] )
189 {
190 GLuint i;
191 ASSERT(ctx->Color.BlendEquationRGB==GL_FUNC_ADD);
192 ASSERT(ctx->Color.BlendEquationA==GL_FUNC_ADD);
193 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
194 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
195 (void) ctx;
196
197 for (i=0;i<n;i++) {
198 if (mask[i]) {
199 #if CHAN_TYPE == GL_FLOAT
200 /* don't RGB clamp to max */
201 GLfloat a = CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF) + dest[i][ACOMP];
202 rgba[i][RCOMP] += dest[i][RCOMP];
203 rgba[i][GCOMP] += dest[i][GCOMP];
204 rgba[i][BCOMP] += dest[i][BCOMP];
205 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAXF );
206 #else
207 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
208 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
209 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
210 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
211 rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAX );
212 rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAX );
213 rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAX );
214 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAX );
215 #endif
216 }
217 }
218 }
219
220
221
222 /*
223 * Blend min function (for GL_EXT_blend_minmax)
224 */
225 static void _BLENDAPI
226 blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
227 GLchan rgba[][4], CONST GLchan dest[][4] )
228 {
229 GLuint i;
230 ASSERT(ctx->Color.BlendEquationRGB==GL_MIN);
231 ASSERT(ctx->Color.BlendEquationA==GL_MIN);
232 (void) ctx;
233
234 for (i=0;i<n;i++) {
235 if (mask[i]) {
236 rgba[i][RCOMP] = (GLchan) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
237 rgba[i][GCOMP] = (GLchan) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
238 rgba[i][BCOMP] = (GLchan) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
239 #if CHAN_TYPE == GL_FLOAT
240 rgba[i][ACOMP] = (GLchan) MIN2(CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF),
241 dest[i][ACOMP]);
242 #else
243 rgba[i][ACOMP] = (GLchan) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
244 #endif
245 }
246 }
247 }
248
249
250
251 /*
252 * Blend max function (for GL_EXT_blend_minmax)
253 */
254 static void _BLENDAPI
255 blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
256 GLchan rgba[][4], CONST GLchan dest[][4] )
257 {
258 GLuint i;
259 ASSERT(ctx->Color.BlendEquationRGB==GL_MAX);
260 ASSERT(ctx->Color.BlendEquationA==GL_MAX);
261 (void) ctx;
262
263 for (i=0;i<n;i++) {
264 if (mask[i]) {
265 rgba[i][RCOMP] = (GLchan) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
266 rgba[i][GCOMP] = (GLchan) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
267 rgba[i][BCOMP] = (GLchan) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
268 #if CHAN_TYPE == GL_FLOAT
269 rgba[i][ACOMP] = (GLchan) MAX2(CLAMP(rgba[i][ACOMP], 0.0F, CHAN_MAXF),
270 dest[i][ACOMP]);
271 #else
272 rgba[i][ACOMP] = (GLchan) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
273 #endif
274 }
275 }
276 }
277
278
279
280 /*
281 * Modulate: result = src * dest
282 */
283 static void _BLENDAPI
284 blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
285 GLchan rgba[][4], CONST GLchan dest[][4] )
286 {
287 GLuint i;
288 (void) ctx;
289
290 for (i=0;i<n;i++) {
291 if (mask[i]) {
292 #if CHAN_TYPE == GL_FLOAT
293 rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
294 rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
295 rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
296 rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
297 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
298 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
299 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
300 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
301 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
302 rgba[i][RCOMP] = (GLchan) r;
303 rgba[i][GCOMP] = (GLchan) g;
304 rgba[i][BCOMP] = (GLchan) b;
305 rgba[i][ACOMP] = (GLchan) a;
306 #else
307 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP] + 255) >> 8;
308 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP] + 255) >> 8;
309 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP] + 255) >> 8;
310 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP] + 255) >> 8;
311 rgba[i][RCOMP] = (GLchan) r;
312 rgba[i][GCOMP] = (GLchan) g;
313 rgba[i][BCOMP] = (GLchan) b;
314 rgba[i][ACOMP] = (GLchan) a;
315 #endif
316 }
317 }
318 }
319
320
321
322 /*
323 * General case blend pixels.
324 * Input: n - number of pixels
325 * mask - the usual write mask
326 * In/Out: rgba - the incoming and modified pixels
327 * Input: dest - the pixels from the dest color buffer
328 */
329 static void _BLENDAPI
330 blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
331 GLchan rgba[][4], CONST GLchan dest[][4] )
332 {
333 const GLfloat rscale = 1.0F / CHAN_MAXF;
334 const GLfloat gscale = 1.0F / CHAN_MAXF;
335 const GLfloat bscale = 1.0F / CHAN_MAXF;
336 const GLfloat ascale = 1.0F / CHAN_MAXF;
337 GLuint i;
338
339 for (i=0;i<n;i++) {
340 if (mask[i]) {
341 #if CHAN_TYPE == GL_FLOAT
342 GLfloat Rs, Gs, Bs, As; /* Source colors */
343 GLfloat Rd, Gd, Bd, Ad; /* Dest colors */
344 #else
345 GLint Rs, Gs, Bs, As; /* Source colors */
346 GLint Rd, Gd, Bd, Ad; /* Dest colors */
347 #endif
348 GLfloat sR, sG, sB, sA; /* Source scaling */
349 GLfloat dR, dG, dB, dA; /* Dest scaling */
350 GLfloat r, g, b, a; /* result color */
351
352 /* Incoming/source Color */
353 Rs = rgba[i][RCOMP];
354 Gs = rgba[i][GCOMP];
355 Bs = rgba[i][BCOMP];
356 As = rgba[i][ACOMP];
357 #if CHAN_TYPE == GL_FLOAT
358 /* clamp */
359 Rs = MIN2(Rs, CHAN_MAXF);
360 Gs = MIN2(Gs, CHAN_MAXF);
361 Bs = MIN2(Bs, CHAN_MAXF);
362 As = MIN2(As, CHAN_MAXF);
363 #endif
364
365 /* Frame buffer/dest color */
366 Rd = dest[i][RCOMP];
367 Gd = dest[i][GCOMP];
368 Bd = dest[i][BCOMP];
369 Ad = dest[i][ACOMP];
370 #if CHAN_TYPE == GL_FLOAT
371 /* clamp */
372 Rd = MIN2(Rd, CHAN_MAXF);
373 Gd = MIN2(Gd, CHAN_MAXF);
374 Bd = MIN2(Bd, CHAN_MAXF);
375 Ad = MIN2(Ad, CHAN_MAXF);
376 #endif
377
378 /* Source RGB factor */
379 switch (ctx->Color.BlendSrcRGB) {
380 case GL_ZERO:
381 sR = sG = sB = 0.0F;
382 break;
383 case GL_ONE:
384 sR = sG = sB = 1.0F;
385 break;
386 case GL_DST_COLOR:
387 sR = (GLfloat) Rd * rscale;
388 sG = (GLfloat) Gd * gscale;
389 sB = (GLfloat) Bd * bscale;
390 break;
391 case GL_ONE_MINUS_DST_COLOR:
392 sR = 1.0F - (GLfloat) Rd * rscale;
393 sG = 1.0F - (GLfloat) Gd * gscale;
394 sB = 1.0F - (GLfloat) Bd * bscale;
395 break;
396 case GL_SRC_ALPHA:
397 sR = sG = sB = (GLfloat) As * ascale;
398 break;
399 case GL_ONE_MINUS_SRC_ALPHA:
400 sR = sG = sB = 1.0F - (GLfloat) As * ascale;
401 break;
402 case GL_DST_ALPHA:
403 sR = sG = sB = (GLfloat) Ad * ascale;
404 break;
405 case GL_ONE_MINUS_DST_ALPHA:
406 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
407 break;
408 case GL_SRC_ALPHA_SATURATE:
409 if (As < CHAN_MAX - Ad) {
410 sR = sG = sB = (GLfloat) As * ascale;
411 }
412 else {
413 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
414 }
415 break;
416 case GL_CONSTANT_COLOR:
417 sR = ctx->Color.BlendColor[0];
418 sG = ctx->Color.BlendColor[1];
419 sB = ctx->Color.BlendColor[2];
420 break;
421 case GL_ONE_MINUS_CONSTANT_COLOR:
422 sR = 1.0F - ctx->Color.BlendColor[0];
423 sG = 1.0F - ctx->Color.BlendColor[1];
424 sB = 1.0F - ctx->Color.BlendColor[2];
425 break;
426 case GL_CONSTANT_ALPHA:
427 sR = sG = sB = ctx->Color.BlendColor[3];
428 break;
429 case GL_ONE_MINUS_CONSTANT_ALPHA:
430 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
431 break;
432 case GL_SRC_COLOR: /* GL_NV_blend_square */
433 sR = (GLfloat) Rs * rscale;
434 sG = (GLfloat) Gs * gscale;
435 sB = (GLfloat) Bs * bscale;
436 break;
437 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
438 sR = 1.0F - (GLfloat) Rs * rscale;
439 sG = 1.0F - (GLfloat) Gs * gscale;
440 sB = 1.0F - (GLfloat) Bs * bscale;
441 break;
442 default:
443 /* this should never happen */
444 _mesa_problem(ctx, "Bad blend source RGB factor in do_blend");
445 return;
446 }
447
448 /* Source Alpha factor */
449 switch (ctx->Color.BlendSrcA) {
450 case GL_ZERO:
451 sA = 0.0F;
452 break;
453 case GL_ONE:
454 sA = 1.0F;
455 break;
456 case GL_DST_COLOR:
457 sA = (GLfloat) Ad * ascale;
458 break;
459 case GL_ONE_MINUS_DST_COLOR:
460 sA = 1.0F - (GLfloat) Ad * ascale;
461 break;
462 case GL_SRC_ALPHA:
463 sA = (GLfloat) As * ascale;
464 break;
465 case GL_ONE_MINUS_SRC_ALPHA:
466 sA = 1.0F - (GLfloat) As * ascale;
467 break;
468 case GL_DST_ALPHA:
469 sA =(GLfloat) Ad * ascale;
470 break;
471 case GL_ONE_MINUS_DST_ALPHA:
472 sA = 1.0F - (GLfloat) Ad * ascale;
473 break;
474 case GL_SRC_ALPHA_SATURATE:
475 sA = 1.0;
476 break;
477 case GL_CONSTANT_COLOR:
478 sA = ctx->Color.BlendColor[3];
479 break;
480 case GL_ONE_MINUS_CONSTANT_COLOR:
481 sA = 1.0F - ctx->Color.BlendColor[3];
482 break;
483 case GL_CONSTANT_ALPHA:
484 sA = ctx->Color.BlendColor[3];
485 break;
486 case GL_ONE_MINUS_CONSTANT_ALPHA:
487 sA = 1.0F - ctx->Color.BlendColor[3];
488 break;
489 case GL_SRC_COLOR: /* GL_NV_blend_square */
490 sA = (GLfloat) As * ascale;
491 break;
492 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
493 sA = 1.0F - (GLfloat) As * ascale;
494 break;
495 default:
496 /* this should never happen */
497 sA = 0.0F;
498 _mesa_problem(ctx, "Bad blend source A factor in do_blend");
499 }
500
501 /* Dest RGB factor */
502 switch (ctx->Color.BlendDstRGB) {
503 case GL_ZERO:
504 dR = dG = dB = 0.0F;
505 break;
506 case GL_ONE:
507 dR = dG = dB = 1.0F;
508 break;
509 case GL_SRC_COLOR:
510 dR = (GLfloat) Rs * rscale;
511 dG = (GLfloat) Gs * gscale;
512 dB = (GLfloat) Bs * bscale;
513 break;
514 case GL_ONE_MINUS_SRC_COLOR:
515 dR = 1.0F - (GLfloat) Rs * rscale;
516 dG = 1.0F - (GLfloat) Gs * gscale;
517 dB = 1.0F - (GLfloat) Bs * bscale;
518 break;
519 case GL_SRC_ALPHA:
520 dR = dG = dB = (GLfloat) As * ascale;
521 break;
522 case GL_ONE_MINUS_SRC_ALPHA:
523 dR = dG = dB = 1.0F - (GLfloat) As * ascale;
524 break;
525 case GL_DST_ALPHA:
526 dR = dG = dB = (GLfloat) Ad * ascale;
527 break;
528 case GL_ONE_MINUS_DST_ALPHA:
529 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
530 break;
531 case GL_CONSTANT_COLOR:
532 dR = ctx->Color.BlendColor[0];
533 dG = ctx->Color.BlendColor[1];
534 dB = ctx->Color.BlendColor[2];
535 break;
536 case GL_ONE_MINUS_CONSTANT_COLOR:
537 dR = 1.0F - ctx->Color.BlendColor[0];
538 dG = 1.0F - ctx->Color.BlendColor[1];
539 dB = 1.0F - ctx->Color.BlendColor[2];
540 break;
541 case GL_CONSTANT_ALPHA:
542 dR = dG = dB = ctx->Color.BlendColor[3];
543 break;
544 case GL_ONE_MINUS_CONSTANT_ALPHA:
545 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
546 break;
547 case GL_DST_COLOR: /* GL_NV_blend_square */
548 dR = (GLfloat) Rd * rscale;
549 dG = (GLfloat) Gd * gscale;
550 dB = (GLfloat) Bd * bscale;
551 break;
552 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
553 dR = 1.0F - (GLfloat) Rd * rscale;
554 dG = 1.0F - (GLfloat) Gd * gscale;
555 dB = 1.0F - (GLfloat) Bd * bscale;
556 break;
557 default:
558 /* this should never happen */
559 dR = dG = dB = 0.0F;
560 _mesa_problem(ctx, "Bad blend dest RGB factor in do_blend");
561 }
562
563 /* Dest Alpha factor */
564 switch (ctx->Color.BlendDstA) {
565 case GL_ZERO:
566 dA = 0.0F;
567 break;
568 case GL_ONE:
569 dA = 1.0F;
570 break;
571 case GL_SRC_COLOR:
572 dA = (GLfloat) As * ascale;
573 break;
574 case GL_ONE_MINUS_SRC_COLOR:
575 dA = 1.0F - (GLfloat) As * ascale;
576 break;
577 case GL_SRC_ALPHA:
578 dA = (GLfloat) As * ascale;
579 break;
580 case GL_ONE_MINUS_SRC_ALPHA:
581 dA = 1.0F - (GLfloat) As * ascale;
582 break;
583 case GL_DST_ALPHA:
584 dA = (GLfloat) Ad * ascale;
585 break;
586 case GL_ONE_MINUS_DST_ALPHA:
587 dA = 1.0F - (GLfloat) Ad * ascale;
588 break;
589 case GL_CONSTANT_COLOR:
590 dA = ctx->Color.BlendColor[3];
591 break;
592 case GL_ONE_MINUS_CONSTANT_COLOR:
593 dA = 1.0F - ctx->Color.BlendColor[3];
594 break;
595 case GL_CONSTANT_ALPHA:
596 dA = ctx->Color.BlendColor[3];
597 break;
598 case GL_ONE_MINUS_CONSTANT_ALPHA:
599 dA = 1.0F - ctx->Color.BlendColor[3];
600 break;
601 case GL_DST_COLOR: /* GL_NV_blend_square */
602 dA = (GLfloat) Ad * ascale;
603 break;
604 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
605 dA = 1.0F - (GLfloat) Ad * ascale;
606 break;
607 default:
608 /* this should never happen */
609 dA = 0.0F;
610 _mesa_problem(ctx, "Bad blend dest A factor in do_blend");
611 return;
612 }
613
614 /* Due to round-off problems we have to clamp against zero. */
615 /* Optimization: we don't have to do this for all src & dst factors */
616 if (dA < 0.0F) dA = 0.0F;
617 if (dR < 0.0F) dR = 0.0F;
618 if (dG < 0.0F) dG = 0.0F;
619 if (dB < 0.0F) dB = 0.0F;
620 if (sA < 0.0F) sA = 0.0F;
621 if (sR < 0.0F) sR = 0.0F;
622 if (sG < 0.0F) sG = 0.0F;
623 if (sB < 0.0F) sB = 0.0F;
624
625 ASSERT( sR <= 1.0 );
626 ASSERT( sG <= 1.0 );
627 ASSERT( sB <= 1.0 );
628 ASSERT( sA <= 1.0 );
629 ASSERT( dR <= 1.0 );
630 ASSERT( dG <= 1.0 );
631 ASSERT( dB <= 1.0 );
632 ASSERT( dA <= 1.0 );
633
634 /* compute blended color */
635 #if CHAN_TYPE == GL_FLOAT
636 if (ctx->Color.BlendEquationRGB==GL_FUNC_ADD) {
637 r = Rs * sR + Rd * dR;
638 g = Gs * sG + Gd * dG;
639 b = Bs * sB + Bd * dB;
640 a = As * sA + Ad * dA;
641 }
642 else if (ctx->Color.BlendEquationRGB==GL_FUNC_SUBTRACT) {
643 r = Rs * sR - Rd * dR;
644 g = Gs * sG - Gd * dG;
645 b = Bs * sB - Bd * dB;
646 a = As * sA - Ad * dA;
647 }
648 else if (ctx->Color.BlendEquationRGB==GL_FUNC_REVERSE_SUBTRACT) {
649 r = Rd * dR - Rs * sR;
650 g = Gd * dG - Gs * sG;
651 b = Bd * dB - Bs * sB;
652 a = Ad * dA - As * sA;
653 }
654 else if (ctx->Color.BlendEquationRGB==GL_MIN) {
655 r = MIN2( Rd, Rs );
656 g = MIN2( Gd, Gs );
657 b = MIN2( Bd, Bs );
658 }
659 else if (ctx->Color.BlendEquationRGB==GL_MAX) {
660 r = MAX2( Rd, Rs );
661 g = MAX2( Gd, Gs );
662 b = MAX2( Bd, Bs );
663 }
664 else {
665 /* should never get here */
666 r = g = b = 0.0F; /* silence uninitialized var warning */
667 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
668 }
669
670 if (ctx->Color.BlendEquationA==GL_FUNC_ADD) {
671 a = As * sA + Ad * dA;
672 }
673 else if (ctx->Color.BlendEquationA==GL_FUNC_SUBTRACT) {
674 a = As * sA - Ad * dA;
675 }
676 else if (ctx->Color.BlendEquationA==GL_FUNC_REVERSE_SUBTRACT) {
677 a = Ad * dA - As * sA;
678 }
679 else if (ctx->Color.BlendEquationA==GL_MIN) {
680 a = MIN2( Ad, As );
681 }
682 else if (ctx->Color.BlendEquationA==GL_MAX) {
683 a = MAX2( Ad, As );
684 }
685 else {
686 /* should never get here */
687 a = 0.0F; /* silence uninitialized var warning */
688 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
689 }
690
691 /* final clamping */
692 rgba[i][RCOMP] = MAX2( r, 0.0F );
693 rgba[i][GCOMP] = MAX2( g, 0.0F );
694 rgba[i][BCOMP] = MAX2( b, 0.0F );
695 rgba[i][ACOMP] = CLAMP( a, 0.0F, CHAN_MAXF );
696 #else
697 if (ctx->Color.BlendEquationRGB==GL_FUNC_ADD) {
698 r = Rs * sR + Rd * dR + 0.5F;
699 g = Gs * sG + Gd * dG + 0.5F;
700 b = Bs * sB + Bd * dB + 0.5F;
701 }
702 else if (ctx->Color.BlendEquationRGB==GL_FUNC_SUBTRACT) {
703 r = Rs * sR - Rd * dR + 0.5F;
704 g = Gs * sG - Gd * dG + 0.5F;
705 b = Bs * sB - Bd * dB + 0.5F;
706 }
707 else if (ctx->Color.BlendEquationRGB==GL_FUNC_REVERSE_SUBTRACT) {
708 r = Rd * dR - Rs * sR + 0.5F;
709 g = Gd * dG - Gs * sG + 0.5F;
710 b = Bd * dB - Bs * sB + 0.5F;
711 }
712 else if (ctx->Color.BlendEquationRGB==GL_MIN) {
713 r = MIN2( Rd, Rs );
714 g = MIN2( Gd, Gs );
715 b = MIN2( Bd, Bs );
716 }
717 else if (ctx->Color.BlendEquationRGB==GL_MAX) {
718 r = MAX2( Rd, Rs );
719 g = MAX2( Gd, Gs );
720 b = MAX2( Bd, Bs );
721 }
722 else {
723 /* should never get here */
724 r = g = b = 0.0F; /* silence uninitialized var warning */
725 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
726 }
727
728 if (ctx->Color.BlendEquationA==GL_FUNC_ADD) {
729 a = As * sA + Ad * dA + 0.5F;
730 }
731 else if (ctx->Color.BlendEquationA==GL_FUNC_SUBTRACT) {
732 a = As * sA - Ad * dA + 0.5F;
733 }
734 else if (ctx->Color.BlendEquationA==GL_FUNC_REVERSE_SUBTRACT) {
735 a = Ad * dA - As * sA + 0.5F;
736 }
737 else if (ctx->Color.BlendEquationA==GL_MIN) {
738 a = MIN2( Ad, As );
739 }
740 else if (ctx->Color.BlendEquationA==GL_MAX) {
741 a = MAX2( Ad, As );
742 }
743 else {
744 /* should never get here */
745 a = 0.0F; /* silence uninitialized var warning */
746 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
747 }
748
749 /* final clamping */
750 rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
751 rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
752 rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
753 rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
754 #endif
755 }
756 }
757 }
758
759
760 /*
761 * Analyze current blending parameters to pick fastest blending function.
762 * Result: the ctx->Color.BlendFunc pointer is updated.
763 */
764 void _swrast_choose_blend_func( GLcontext *ctx )
765 {
766 const GLenum eq = ctx->Color.BlendEquationRGB;
767 const GLenum srcRGB = ctx->Color.BlendSrcRGB;
768 const GLenum dstRGB = ctx->Color.BlendDstRGB;
769 const GLenum srcA = ctx->Color.BlendSrcA;
770 const GLenum dstA = ctx->Color.BlendDstA;
771
772 if (ctx->Color.BlendEquationRGB != ctx->Color.BlendEquationA) {
773 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
774 }
775 else if (eq==GL_MIN) {
776 /* Note: GL_MIN ignores the blending weight factors */
777 #if defined(USE_MMX_ASM)
778 if ( cpu_has_mmx ) {
779 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_min;
780 }
781 else
782 #endif
783 SWRAST_CONTEXT(ctx)->BlendFunc = blend_min;
784 }
785 else if (eq==GL_MAX) {
786 /* Note: GL_MAX ignores the blending weight factors */
787 #if defined(USE_MMX_ASM)
788 if ( cpu_has_mmx ) {
789 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_max;
790 }
791 else
792 #endif
793 SWRAST_CONTEXT(ctx)->BlendFunc = blend_max;
794 }
795 else if (srcRGB != srcA || dstRGB != dstA) {
796 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
797 }
798 else if (eq==GL_FUNC_ADD && srcRGB==GL_SRC_ALPHA
799 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
800 #if defined(USE_MMX_ASM)
801 if ( cpu_has_mmx ) {
802 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_transparency;
803 }
804 else
805 #endif
806 SWRAST_CONTEXT(ctx)->BlendFunc = blend_transparency;
807 }
808 else if (eq==GL_FUNC_ADD && srcRGB==GL_ONE && dstRGB==GL_ONE) {
809 #if defined(USE_MMX_ASM)
810 if ( cpu_has_mmx ) {
811 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_add;
812 }
813 else
814 #endif
815 SWRAST_CONTEXT(ctx)->BlendFunc = blend_add;
816 }
817 else if (((eq==GL_FUNC_ADD || eq==GL_FUNC_REVERSE_SUBTRACT)
818 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
819 ||
820 ((eq==GL_FUNC_ADD || eq==GL_FUNC_SUBTRACT)
821 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
822 #if defined(USE_MMX_ASM)
823 if ( cpu_has_mmx ) {
824 SWRAST_CONTEXT(ctx)->BlendFunc = _mesa_mmx_blend_modulate;
825 }
826 else
827 #endif
828 SWRAST_CONTEXT(ctx)->BlendFunc = blend_modulate;
829 }
830 else if (eq==GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
831 SWRAST_CONTEXT(ctx)->BlendFunc = blend_noop;
832 }
833 else if (eq==GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
834 SWRAST_CONTEXT(ctx)->BlendFunc = blend_replace;
835 }
836 else {
837 SWRAST_CONTEXT(ctx)->BlendFunc = blend_general;
838 }
839 }
840
841
842
843 /*
844 * Apply the blending operator to a span of pixels.
845 * We can handle horizontal runs of pixels (spans) or arrays of x/y
846 * pixel coordinates.
847 */
848 void
849 _swrast_blend_span(GLcontext *ctx, struct gl_renderbuffer *rb,
850 const struct sw_span *span, GLchan rgba[][4])
851 {
852 GLchan framebuffer[MAX_WIDTH][4];
853
854 ASSERT(span->end <= MAX_WIDTH);
855 ASSERT(span->arrayMask & SPAN_RGBA);
856 ASSERT(!ctx->Color._LogicOpEnabled);
857
858 /* Read span of current frame buffer pixels */
859 if (span->arrayMask & SPAN_XY) {
860 /* array of x/y pixel coords */
861 _swrast_get_values(ctx, rb, span->end, span->array->x, span->array->y,
862 framebuffer, 4 * sizeof(GLchan));
863 }
864 else {
865 /* horizontal run of pixels */
866 _swrast_read_rgba_span(ctx, rb, span->end, span->x, span->y,
867 framebuffer);
868 }
869
870 SWRAST_CONTEXT(ctx)->BlendFunc( ctx, span->end, span->array->mask, rgba,
871 (const GLchan (*)[4]) framebuffer );
872 }