1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
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.
23 */
24
25
26 /**
27 * \file swrast/s_blend.c
28 * \brief software blending.
29 * \author Brian Paul
30 *
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.
34 */
35
36
37
38 #include "main/glheader.h"
39 #include "main/context.h"
40 #include "main/colormac.h"
41 #include "main/macros.h"
42
43 #include "s_blend.h"
44 #include "s_context.h"
45 #include "s_span.h"
46
47
48 #if defined(USE_MMX_ASM)
49 #include "x86/mmx.h"
50 #include "x86/common_x86_asm.h"
51 #endif
52
53
54 /**
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.
59 */
60 #define DIV255(X) (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)
61
62
63
64 /**
65 * Special case for glBlendFunc(GL_ZERO, GL_ONE).
66 * No-op means the framebuffer values remain unchanged.
67 * Any chanType ok.
68 */
69 static void
blend_noop(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)70 blend_noop(struct gl_context *ctx, GLuint n, const GLubyte mask[],
71 GLvoid *src, const GLvoid *dst, GLenum chanType)
72 {
73 GLint bytes;
74
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);
79 (void) ctx;
80
81 /* just memcpy */
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);
86 else
87 bytes = 4 * n * sizeof(GLfloat);
88
89 memcpy(src, dst, bytes);
90 }
91
92
93 /**
94 * Special case for glBlendFunc(GL_ONE, GL_ZERO)
95 * Any chanType ok.
96 */
97 static void
blend_replace(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)98 blend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[],
99 GLvoid *src, const GLvoid *dst, GLenum chanType)
100 {
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);
105 (void) ctx;
106 (void) n;
107 (void) mask;
108 (void) src;
109 (void) dst;
110 }
111
112
113 /**
114 * Common transparency blending mode:
115 * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
116 */
117 static void
blend_transparency_ubyte(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)118 blend_transparency_ubyte(struct gl_context *ctx, GLuint n, const GLubyte mask[],
119 GLvoid *src, const GLvoid *dst, GLenum chanType)
120 {
121 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
122 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
123 GLuint i;
124
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);
132
133 (void) ctx;
134
135 for (i = 0; i < n; i++) {
136 if (mask[i]) {
137 const GLint t = rgba[i][ACOMP]; /* t is in [0, 255] */
138 if (t == 0) {
139 /* 0% alpha */
140 COPY_4UBV(rgba[i], dest[i]);
141 }
142 else if (t != 255) {
143 GLint divtemp;
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];
148 assert(r <= 255);
149 assert(g <= 255);
150 assert(b <= 255);
151 assert(a <= 255);
152 rgba[i][RCOMP] = (GLubyte) r;
153 rgba[i][GCOMP] = (GLubyte) g;
154 rgba[i][BCOMP] = (GLubyte) b;
155 rgba[i][ACOMP] = (GLubyte) a;
156 }
157 }
158 }
159 }
160
161
162 static void
blend_transparency_ushort(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)163 blend_transparency_ushort(struct gl_context *ctx, GLuint n, const GLubyte mask[],
164 GLvoid *src, const GLvoid *dst, GLenum chanType)
165 {
166 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
167 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
168 GLuint i;
169
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);
177
178 (void) ctx;
179
180 for (i = 0; i < n; i++) {
181 if (mask[i]) {
182 const GLint t = rgba[i][ACOMP];
183 if (t == 0) {
184 /* 0% alpha */
185 COPY_4V(rgba[i], dest[i]);
186 }
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);
194 }
195 }
196 }
197 }
198
199
200 static void
blend_transparency_float(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)201 blend_transparency_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
202 GLvoid *src, const GLvoid *dst, GLenum chanType)
203 {
204 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
205 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
206 GLuint i;
207
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);
215
216 (void) ctx;
217
218 for (i = 0; i < n; i++) {
219 if (mask[i]) {
220 const GLfloat t = rgba[i][ACOMP]; /* t in [0, 1] */
221 if (t == 0.0F) {
222 /* 0% alpha */
223 COPY_4V(rgba[i], dest[i]);
224 }
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);
231 }
232 }
233 }
234 }
235
236
237
238 /**
239 * Add src and dest: glBlendFunc(GL_ONE, GL_ONE).
240 * Any chanType ok.
241 */
242 static void
blend_add(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)243 blend_add(struct gl_context *ctx, GLuint n, const GLubyte mask[],
244 GLvoid *src, const GLvoid *dst, GLenum chanType)
245 {
246 GLuint i;
247
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);
252 (void) ctx;
253
254 if (chanType == GL_UNSIGNED_BYTE) {
255 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
256 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
257 for (i=0;i<n;i++) {
258 if (mask[i]) {
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 );
267 }
268 }
269 }
270 else if (chanType == GL_UNSIGNED_SHORT) {
271 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
272 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
273 for (i=0;i<n;i++) {
274 if (mask[i]) {
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 );
283 }
284 }
285 }
286 else {
287 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
288 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
289 assert(chanType == GL_FLOAT);
290 for (i=0;i<n;i++) {
291 if (mask[i]) {
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];
297 }
298 }
299 }
300 }
301
302
303
304 /**
305 * Blend min function.
306 * Any chanType ok.
307 */
308 static void
blend_min(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)309 blend_min(struct gl_context *ctx, GLuint n, const GLubyte mask[],
310 GLvoid *src, const GLvoid *dst, GLenum chanType)
311 {
312 GLuint i;
313 assert(ctx->Color.Blend[0].EquationRGB == GL_MIN);
314 assert(ctx->Color.Blend[0].EquationA == GL_MIN);
315 (void) ctx;
316
317 if (chanType == GL_UNSIGNED_BYTE) {
318 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
319 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
320 for (i=0;i<n;i++) {
321 if (mask[i]) {
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] );
326 }
327 }
328 }
329 else if (chanType == GL_UNSIGNED_SHORT) {
330 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
331 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
332 for (i=0;i<n;i++) {
333 if (mask[i]) {
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] );
338 }
339 }
340 }
341 else {
342 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
343 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
344 assert(chanType == GL_FLOAT);
345 for (i=0;i<n;i++) {
346 if (mask[i]) {
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] );
351 }
352 }
353 }
354 }
355
356
357 /**
358 * Blend max function.
359 * Any chanType ok.
360 */
361 static void
blend_max(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)362 blend_max(struct gl_context *ctx, GLuint n, const GLubyte mask[],
363 GLvoid *src, const GLvoid *dst, GLenum chanType)
364 {
365 GLuint i;
366 assert(ctx->Color.Blend[0].EquationRGB == GL_MAX);
367 assert(ctx->Color.Blend[0].EquationA == GL_MAX);
368 (void) ctx;
369
370 if (chanType == GL_UNSIGNED_BYTE) {
371 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
372 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
373 for (i=0;i<n;i++) {
374 if (mask[i]) {
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] );
379 }
380 }
381 }
382 else if (chanType == GL_UNSIGNED_SHORT) {
383 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
384 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
385 for (i=0;i<n;i++) {
386 if (mask[i]) {
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] );
391 }
392 }
393 }
394 else {
395 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
396 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
397 assert(chanType == GL_FLOAT);
398 for (i=0;i<n;i++) {
399 if (mask[i]) {
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] );
404 }
405 }
406 }
407 }
408
409
410
411 /**
412 * Modulate: result = src * dest
413 * Any chanType ok.
414 */
415 static void
blend_modulate(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)416 blend_modulate(struct gl_context *ctx, GLuint n, const GLubyte mask[],
417 GLvoid *src, const GLvoid *dst, GLenum chanType)
418 {
419 GLuint i;
420 (void) ctx;
421
422 if (chanType == GL_UNSIGNED_BYTE) {
423 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
424 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
425 for (i=0;i<n;i++) {
426 if (mask[i]) {
427 GLint divtemp;
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]);
432 }
433 }
434 }
435 else if (chanType == GL_UNSIGNED_SHORT) {
436 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
437 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
438 for (i=0;i<n;i++) {
439 if (mask[i]) {
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;
444 }
445 }
446 }
447 else {
448 GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
449 const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
450 assert(chanType == GL_FLOAT);
451 for (i=0;i<n;i++) {
452 if (mask[i]) {
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];
457 }
458 }
459 }
460 }
461
462
463 /**
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
469 */
470 static void
blend_general_float(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLfloat rgba[][4],GLfloat dest[][4],GLenum chanType)471 blend_general_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
472 GLfloat rgba[][4], GLfloat dest[][4],
473 GLenum chanType)
474 {
475 GLuint i;
476
477 for (i = 0; i < n; i++) {
478 if (mask[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];
484
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];
490
491 GLfloat sR, sG, sB, sA; /* Source factor */
492 GLfloat dR, dG, dB, dA; /* Dest factor */
493 GLfloat r, g, b, a; /* result color */
494
495 /* XXX for the case of constant blend terms we could init
496 * the sX and dX variables just once before the loop.
497 */
498
499 /* Source RGB factor */
500 switch (ctx->Color.Blend[0].SrcRGB) {
501 case GL_ZERO:
502 sR = sG = sB = 0.0F;
503 break;
504 case GL_ONE:
505 sR = sG = sB = 1.0F;
506 break;
507 case GL_DST_COLOR:
508 sR = Rd;
509 sG = Gd;
510 sB = Bd;
511 break;
512 case GL_ONE_MINUS_DST_COLOR:
513 sR = 1.0F - Rd;
514 sG = 1.0F - Gd;
515 sB = 1.0F - Bd;
516 break;
517 case GL_SRC_ALPHA:
518 sR = sG = sB = As;
519 break;
520 case GL_ONE_MINUS_SRC_ALPHA:
521 sR = sG = sB = 1.0F - As;
522 break;
523 case GL_DST_ALPHA:
524 sR = sG = sB = Ad;
525 break;
526 case GL_ONE_MINUS_DST_ALPHA:
527 sR = sG = sB = 1.0F - Ad;
528 break;
529 case GL_SRC_ALPHA_SATURATE:
530 if (As < 1.0F - Ad) {
531 sR = sG = sB = As;
532 }
533 else {
534 sR = sG = sB = 1.0F - Ad;
535 }
536 break;
537 case GL_CONSTANT_COLOR:
538 sR = ctx->Color.BlendColor[0];
539 sG = ctx->Color.BlendColor[1];
540 sB = ctx->Color.BlendColor[2];
541 break;
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];
546 break;
547 case GL_CONSTANT_ALPHA:
548 sR = sG = sB = ctx->Color.BlendColor[3];
549 break;
550 case GL_ONE_MINUS_CONSTANT_ALPHA:
551 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
552 break;
553 case GL_SRC_COLOR:
554 sR = Rs;
555 sG = Gs;
556 sB = Bs;
557 break;
558 case GL_ONE_MINUS_SRC_COLOR:
559 sR = 1.0F - Rs;
560 sG = 1.0F - Gs;
561 sB = 1.0F - Bs;
562 break;
563 default:
564 /* this should never happen */
565 _mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float");
566 return;
567 }
568
569 /* Source Alpha factor */
570 switch (ctx->Color.Blend[0].SrcA) {
571 case GL_ZERO:
572 sA = 0.0F;
573 break;
574 case GL_ONE:
575 sA = 1.0F;
576 break;
577 case GL_DST_COLOR:
578 sA = Ad;
579 break;
580 case GL_ONE_MINUS_DST_COLOR:
581 sA = 1.0F - Ad;
582 break;
583 case GL_SRC_ALPHA:
584 sA = As;
585 break;
586 case GL_ONE_MINUS_SRC_ALPHA:
587 sA = 1.0F - As;
588 break;
589 case GL_DST_ALPHA:
590 sA = Ad;
591 break;
592 case GL_ONE_MINUS_DST_ALPHA:
593 sA = 1.0F - Ad;
594 break;
595 case GL_SRC_ALPHA_SATURATE:
596 sA = 1.0;
597 break;
598 case GL_CONSTANT_COLOR:
599 sA = ctx->Color.BlendColor[3];
600 break;
601 case GL_ONE_MINUS_CONSTANT_COLOR:
602 sA = 1.0F - ctx->Color.BlendColor[3];
603 break;
604 case GL_CONSTANT_ALPHA:
605 sA = ctx->Color.BlendColor[3];
606 break;
607 case GL_ONE_MINUS_CONSTANT_ALPHA:
608 sA = 1.0F - ctx->Color.BlendColor[3];
609 break;
610 case GL_SRC_COLOR:
611 sA = As;
612 break;
613 case GL_ONE_MINUS_SRC_COLOR:
614 sA = 1.0F - As;
615 break;
616 default:
617 /* this should never happen */
618 sA = 0.0F;
619 _mesa_problem(ctx, "Bad blend source A factor in blend_general_float");
620 return;
621 }
622
623 /* Dest RGB factor */
624 switch (ctx->Color.Blend[0].DstRGB) {
625 case GL_ZERO:
626 dR = dG = dB = 0.0F;
627 break;
628 case GL_ONE:
629 dR = dG = dB = 1.0F;
630 break;
631 case GL_SRC_COLOR:
632 dR = Rs;
633 dG = Gs;
634 dB = Bs;
635 break;
636 case GL_ONE_MINUS_SRC_COLOR:
637 dR = 1.0F - Rs;
638 dG = 1.0F - Gs;
639 dB = 1.0F - Bs;
640 break;
641 case GL_SRC_ALPHA:
642 dR = dG = dB = As;
643 break;
644 case GL_ONE_MINUS_SRC_ALPHA:
645 dR = dG = dB = 1.0F - As;
646 break;
647 case GL_DST_ALPHA:
648 dR = dG = dB = Ad;
649 break;
650 case GL_ONE_MINUS_DST_ALPHA:
651 dR = dG = dB = 1.0F - Ad;
652 break;
653 case GL_CONSTANT_COLOR:
654 dR = ctx->Color.BlendColor[0];
655 dG = ctx->Color.BlendColor[1];
656 dB = ctx->Color.BlendColor[2];
657 break;
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];
662 break;
663 case GL_CONSTANT_ALPHA:
664 dR = dG = dB = ctx->Color.BlendColor[3];
665 break;
666 case GL_ONE_MINUS_CONSTANT_ALPHA:
667 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
668 break;
669 case GL_DST_COLOR:
670 dR = Rd;
671 dG = Gd;
672 dB = Bd;
673 break;
674 case GL_ONE_MINUS_DST_COLOR:
675 dR = 1.0F - Rd;
676 dG = 1.0F - Gd;
677 dB = 1.0F - Bd;
678 break;
679 default:
680 /* this should never happen */
681 dR = dG = dB = 0.0F;
682 _mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float");
683 return;
684 }
685
686 /* Dest Alpha factor */
687 switch (ctx->Color.Blend[0].DstA) {
688 case GL_ZERO:
689 dA = 0.0F;
690 break;
691 case GL_ONE:
692 dA = 1.0F;
693 break;
694 case GL_SRC_COLOR:
695 dA = As;
696 break;
697 case GL_ONE_MINUS_SRC_COLOR:
698 dA = 1.0F - As;
699 break;
700 case GL_SRC_ALPHA:
701 dA = As;
702 break;
703 case GL_ONE_MINUS_SRC_ALPHA:
704 dA = 1.0F - As;
705 break;
706 case GL_DST_ALPHA:
707 dA = Ad;
708 break;
709 case GL_ONE_MINUS_DST_ALPHA:
710 dA = 1.0F - Ad;
711 break;
712 case GL_CONSTANT_COLOR:
713 dA = ctx->Color.BlendColor[3];
714 break;
715 case GL_ONE_MINUS_CONSTANT_COLOR:
716 dA = 1.0F - ctx->Color.BlendColor[3];
717 break;
718 case GL_CONSTANT_ALPHA:
719 dA = ctx->Color.BlendColor[3];
720 break;
721 case GL_ONE_MINUS_CONSTANT_ALPHA:
722 dA = 1.0F - ctx->Color.BlendColor[3];
723 break;
724 case GL_DST_COLOR:
725 dA = Ad;
726 break;
727 case GL_ONE_MINUS_DST_COLOR:
728 dA = 1.0F - Ad;
729 break;
730 default:
731 /* this should never happen */
732 dA = 0.0F;
733 _mesa_problem(ctx, "Bad blend dest A factor in blend_general_float");
734 return;
735 }
736
737 /* compute the blended RGB */
738 switch (ctx->Color.Blend[0].EquationRGB) {
739 case GL_FUNC_ADD:
740 r = Rs * sR + Rd * dR;
741 g = Gs * sG + Gd * dG;
742 b = Bs * sB + Bd * dB;
743 a = As * sA + Ad * dA;
744 break;
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;
750 break;
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;
756 break;
757 case GL_MIN:
758 r = MIN2( Rd, Rs );
759 g = MIN2( Gd, Gs );
760 b = MIN2( Bd, Bs );
761 break;
762 case GL_MAX:
763 r = MAX2( Rd, Rs );
764 g = MAX2( Gd, Gs );
765 b = MAX2( Bd, Bs );
766 break;
767 default:
768 /* should never get here */
769 r = g = b = 0.0F; /* silence uninitialized var warning */
770 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
771 return;
772 }
773
774 /* compute the blended alpha */
775 switch (ctx->Color.Blend[0].EquationA) {
776 case GL_FUNC_ADD:
777 a = As * sA + Ad * dA;
778 break;
779 case GL_FUNC_SUBTRACT:
780 a = As * sA - Ad * dA;
781 break;
782 case GL_FUNC_REVERSE_SUBTRACT:
783 a = Ad * dA - As * sA;
784 break;
785 case GL_MIN:
786 a = MIN2( Ad, As );
787 break;
788 case GL_MAX:
789 a = MAX2( Ad, As );
790 break;
791 default:
792 /* should never get here */
793 a = 0.0F; /* silence uninitialized var warning */
794 _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
795 return;
796 }
797
798 /* final clamping */
799 #if 0
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 );
804 #else
805 ASSIGN_4V(rgba[i], r, g, b, a);
806 #endif
807 }
808 }
809 }
810
811
812 /**
813 * Do any blending operation, any chanType.
814 */
815 static void
blend_general(struct gl_context * ctx,GLuint n,const GLubyte mask[],void * src,const void * dst,GLenum chanType)816 blend_general(struct gl_context *ctx, GLuint n, const GLubyte mask[],
817 void *src, const void *dst, GLenum chanType)
818 {
819 GLfloat (*rgbaF)[4], (*destF)[4];
820
821 rgbaF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
822 destF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
823 if (!rgbaF || !destF) {
824 free(rgbaF);
825 free(destF);
826 _mesa_error(ctx, GL_OUT_OF_MEMORY, "blending");
827 return;
828 }
829
830 if (chanType == GL_UNSIGNED_BYTE) {
831 GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
832 const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
833 GLuint i;
834 /* convert ubytes to floats */
835 for (i = 0; i < n; i++) {
836 if (mask[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]);
845 }
846 }
847 /* do blend */
848 blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
849 /* convert back to ubytes */
850 for (i = 0; i < n; i++) {
851 if (mask[i])
852 _mesa_unclamped_float_rgba_to_ubyte(rgba[i], rgbaF[i]);
853 }
854 }
855 else if (chanType == GL_UNSIGNED_SHORT) {
856 GLushort (*rgba)[4] = (GLushort (*)[4]) src;
857 const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
858 GLuint i;
859 /* convert ushorts to floats */
860 for (i = 0; i < n; i++) {
861 if (mask[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]);
870 }
871 }
872 /* do blend */
873 blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
874 /* convert back to ushorts */
875 for (i = 0; i < n; i++) {
876 if (mask[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]);
881 }
882 }
883 }
884 else {
885 blend_general_float(ctx, n, mask, (GLfloat (*)[4]) src,
886 (GLfloat (*)[4]) dst, chanType);
887 }
888
889 free(rgbaF);
890 free(destF);
891 }
892
893
894
895 /**
896 * Analyze current blending parameters to pick fastest blending function.
897 * Result: the ctx->Color.BlendFunc pointer is updated.
898 */
899 void
_swrast_choose_blend_func(struct gl_context * ctx,GLenum chanType)900 _swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType)
901 {
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;
908
909 if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) {
910 swrast->BlendFunc = blend_general;
911 }
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;
917 }
918 else
919 #endif
920 swrast->BlendFunc = blend_min;
921 }
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;
927 }
928 else
929 #endif
930 swrast->BlendFunc = blend_max;
931 }
932 else if (srcRGB != srcA || dstRGB != dstA) {
933 swrast->BlendFunc = blend_general;
934 }
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;
940 }
941 else
942 #endif
943 {
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;
948 else
949 swrast->BlendFunc = blend_transparency_float;
950 }
951 }
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;
956 }
957 else
958 #endif
959 swrast->BlendFunc = blend_add;
960 }
961 else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT)
962 && (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR))
963 ||
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;
969 }
970 else
971 #endif
972 swrast->BlendFunc = blend_modulate;
973 }
974 else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
975 swrast->BlendFunc = blend_noop;
976 }
977 else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
978 swrast->BlendFunc = blend_replace;
979 }
980 else {
981 swrast->BlendFunc = blend_general;
982 }
983 }
984
985
986
987 /**
988 * Apply the blending operator to a span of pixels.
989 * We can handle horizontal runs of pixels (spans) or arrays of x/y
990 * pixel coordinates.
991 */
992 void
_swrast_blend_span(struct gl_context * ctx,struct gl_renderbuffer * rb,SWspan * span)993 _swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span)
994 {
995 SWcontext *swrast = SWRAST_CONTEXT(ctx);
996 void *rbPixels;
997
998 assert(span->end <= SWRAST_MAX_WIDTH);
999 assert(span->arrayMask & SPAN_RGBA);
1000 assert(!ctx->Color.ColorLogicOpEnabled);
1001
1002 rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
1003
1004 swrast->BlendFunc(ctx, span->end, span->array->mask,
1005 span->array->rgba, rbPixels, span->array->ChanType);
1006 }
1007