1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.1
4  *
5  * Copyright (C) 1999-2008  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 /**
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 #define _BLENDAPI _ASMAPI
52 #else
53 #define _BLENDAPI
54 #endif
55 
56 
57 /**
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.
62  */
63 #define DIV255(X)  (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)
64 
65 
66 
67 /**
68  * Special case for glBlendFunc(GL_ZERO, GL_ONE).
69  * No-op means the framebuffer values remain unchanged.
70  * Any chanType ok.
71  */
72 static void _BLENDAPI
blend_noop(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)73 blend_noop(struct gl_context *ctx, GLuint n, const GLubyte mask[],
74            GLvoid *src, const GLvoid *dst, GLenum chanType)
75 {
76    GLint bytes;
77 
78    ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
79    ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
80    ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ZERO);
81    ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE);
82    (void) ctx;
83 
84    /* just memcpy */
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);
89    else
90       bytes = 4 * n * sizeof(GLfloat);
91 
92    memcpy(src, dst, bytes);
93 }
94 
95 
96 /**
97  * Special case for glBlendFunc(GL_ONE, GL_ZERO)
98  * Any chanType ok.
99  */
100 static void _BLENDAPI
blend_replace(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)101 blend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[],
102               GLvoid *src, const GLvoid *dst, GLenum chanType)
103 {
104    ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
105    ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
106    ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE);
107    ASSERT(ctx->Color.Blend[0].DstRGB == GL_ZERO);
108    (void) ctx;
109    (void) n;
110    (void) mask;
111    (void) src;
112    (void) dst;
113 }
114 
115 
116 /**
117  * Common transparency blending mode:
118  * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
119  */
120 static void _BLENDAPI
blend_transparency_ubyte(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)121 blend_transparency_ubyte(struct gl_context *ctx, GLuint n, const GLubyte mask[],
122                          GLvoid *src, const GLvoid *dst, GLenum chanType)
123 {
124    GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
125    const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
126    GLuint i;
127 
128    ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
129    ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
130    ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
131    ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
132    ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
133    ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
134    ASSERT(chanType == GL_UNSIGNED_BYTE);
135 
136    (void) ctx;
137 
138    for (i = 0; i < n; i++) {
139       if (mask[i]) {
140          const GLint t = rgba[i][ACOMP];  /* t is in [0, 255] */
141          if (t == 0) {
142             /* 0% alpha */
143             COPY_4UBV(rgba[i], dest[i]);
144          }
145          else if (t != 255) {
146 	    GLint divtemp;
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             ASSERT(r <= 255);
152             ASSERT(g <= 255);
153             ASSERT(b <= 255);
154             ASSERT(a <= 255);
155             rgba[i][RCOMP] = (GLubyte) r;
156             rgba[i][GCOMP] = (GLubyte) g;
157             rgba[i][BCOMP] = (GLubyte) b;
158             rgba[i][ACOMP] = (GLubyte) a;
159          }
160       }
161    }
162 }
163 
164 
165 static void _BLENDAPI
blend_transparency_ushort(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)166 blend_transparency_ushort(struct gl_context *ctx, GLuint n, const GLubyte mask[],
167                           GLvoid *src, const GLvoid *dst, GLenum chanType)
168 {
169    GLushort (*rgba)[4] = (GLushort (*)[4]) src;
170    const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
171    GLuint i;
172 
173    ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
174    ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
175    ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
176    ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
177    ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
178    ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
179    ASSERT(chanType == GL_UNSIGNED_SHORT);
180 
181    (void) ctx;
182 
183    for (i = 0; i < n; i++) {
184       if (mask[i]) {
185          const GLint t = rgba[i][ACOMP];
186          if (t == 0) {
187             /* 0% alpha */
188             COPY_4V(rgba[i], dest[i]);
189          }
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);
197          }
198       }
199    }
200 }
201 
202 
203 static void _BLENDAPI
blend_transparency_float(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)204 blend_transparency_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
205                          GLvoid *src, const GLvoid *dst, GLenum chanType)
206 {
207    GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
208    const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
209    GLuint i;
210 
211    ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
212    ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
213    ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
214    ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
215    ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
216    ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
217    ASSERT(chanType == GL_FLOAT);
218 
219    (void) ctx;
220 
221    for (i = 0; i < n; i++) {
222       if (mask[i]) {
223          const GLfloat t = rgba[i][ACOMP];  /* t in [0, 1] */
224          if (t == 0.0F) {
225             /* 0% alpha */
226             COPY_4V(rgba[i], dest[i]);
227          }
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);
234          }
235       }
236    }
237 }
238 
239 
240 
241 /**
242  * Add src and dest: glBlendFunc(GL_ONE, GL_ONE).
243  * Any chanType ok.
244  */
245 static void _BLENDAPI
blend_add(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)246 blend_add(struct gl_context *ctx, GLuint n, const GLubyte mask[],
247           GLvoid *src, const GLvoid *dst, GLenum chanType)
248 {
249    GLuint i;
250 
251    ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
252    ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
253    ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE);
254    ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE);
255    (void) ctx;
256 
257    if (chanType == GL_UNSIGNED_BYTE) {
258       GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
259       const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
260       for (i=0;i<n;i++) {
261          if (mask[i]) {
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 );
270          }
271       }
272    }
273    else if (chanType == GL_UNSIGNED_SHORT) {
274       GLushort (*rgba)[4] = (GLushort (*)[4]) src;
275       const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
276       for (i=0;i<n;i++) {
277          if (mask[i]) {
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 );
286          }
287       }
288    }
289    else {
290       GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
291       const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
292       ASSERT(chanType == GL_FLOAT);
293       for (i=0;i<n;i++) {
294          if (mask[i]) {
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];
300          }
301       }
302    }
303 }
304 
305 
306 
307 /**
308  * Blend min function.
309  * Any chanType ok.
310  */
311 static void _BLENDAPI
blend_min(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)312 blend_min(struct gl_context *ctx, GLuint n, const GLubyte mask[],
313           GLvoid *src, const GLvoid *dst, GLenum chanType)
314 {
315    GLuint i;
316    ASSERT(ctx->Color.Blend[0].EquationRGB == GL_MIN);
317    ASSERT(ctx->Color.Blend[0].EquationA == GL_MIN);
318    (void) ctx;
319 
320    if (chanType == GL_UNSIGNED_BYTE) {
321       GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
322       const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
323       for (i=0;i<n;i++) {
324          if (mask[i]) {
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] );
329          }
330       }
331    }
332    else if (chanType == GL_UNSIGNED_SHORT) {
333       GLushort (*rgba)[4] = (GLushort (*)[4]) src;
334       const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
335       for (i=0;i<n;i++) {
336          if (mask[i]) {
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] );
341          }
342       }
343    }
344    else {
345       GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
346       const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
347       ASSERT(chanType == GL_FLOAT);
348       for (i=0;i<n;i++) {
349          if (mask[i]) {
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] );
354          }
355       }
356    }
357 }
358 
359 
360 /**
361  * Blend max function.
362  * Any chanType ok.
363  */
364 static void _BLENDAPI
blend_max(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)365 blend_max(struct gl_context *ctx, GLuint n, const GLubyte mask[],
366           GLvoid *src, const GLvoid *dst, GLenum chanType)
367 {
368    GLuint i;
369    ASSERT(ctx->Color.Blend[0].EquationRGB == GL_MAX);
370    ASSERT(ctx->Color.Blend[0].EquationA == GL_MAX);
371    (void) ctx;
372 
373    if (chanType == GL_UNSIGNED_BYTE) {
374       GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
375       const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
376       for (i=0;i<n;i++) {
377          if (mask[i]) {
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] );
382          }
383       }
384    }
385    else if (chanType == GL_UNSIGNED_SHORT) {
386       GLushort (*rgba)[4] = (GLushort (*)[4]) src;
387       const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
388       for (i=0;i<n;i++) {
389          if (mask[i]) {
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] );
394          }
395       }
396    }
397    else {
398       GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
399       const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
400       ASSERT(chanType == GL_FLOAT);
401       for (i=0;i<n;i++) {
402          if (mask[i]) {
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] );
407          }
408       }
409    }
410 }
411 
412 
413 
414 /**
415  * Modulate:  result = src * dest
416  * Any chanType ok.
417  */
418 static void _BLENDAPI
blend_modulate(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLvoid * src,const GLvoid * dst,GLenum chanType)419 blend_modulate(struct gl_context *ctx, GLuint n, const GLubyte mask[],
420                GLvoid *src, const GLvoid *dst, GLenum chanType)
421 {
422    GLuint i;
423    (void) ctx;
424 
425    if (chanType == GL_UNSIGNED_BYTE) {
426       GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
427       const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
428       for (i=0;i<n;i++) {
429          if (mask[i]) {
430 	    GLint divtemp;
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]);
435          }
436       }
437    }
438    else if (chanType == GL_UNSIGNED_SHORT) {
439       GLushort (*rgba)[4] = (GLushort (*)[4]) src;
440       const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
441       for (i=0;i<n;i++) {
442          if (mask[i]) {
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;
447          }
448       }
449    }
450    else {
451       GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
452       const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
453       ASSERT(chanType == GL_FLOAT);
454       for (i=0;i<n;i++) {
455          if (mask[i]) {
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];
460          }
461       }
462    }
463 }
464 
465 
466 /**
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
472  */
473 static void
blend_general_float(struct gl_context * ctx,GLuint n,const GLubyte mask[],GLfloat rgba[][4],GLfloat dest[][4],GLenum chanType)474 blend_general_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
475                     GLfloat rgba[][4], GLfloat dest[][4],
476                     GLenum chanType)
477 {
478    GLuint i;
479 
480    for (i = 0; i < n; i++) {
481       if (mask[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];
487 
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];
493 
494          GLfloat sR, sG, sB, sA;  /* Source factor */
495          GLfloat dR, dG, dB, dA;  /* Dest factor */
496          GLfloat r, g, b, a;      /* result color */
497 
498          /* XXX for the case of constant blend terms we could init
499           * the sX and dX variables just once before the loop.
500           */
501 
502          /* Source RGB factor */
503          switch (ctx->Color.Blend[0].SrcRGB) {
504             case GL_ZERO:
505                sR = sG = sB = 0.0F;
506                break;
507             case GL_ONE:
508                sR = sG = sB = 1.0F;
509                break;
510             case GL_DST_COLOR:
511                sR = Rd;
512                sG = Gd;
513                sB = Bd;
514                break;
515             case GL_ONE_MINUS_DST_COLOR:
516                sR = 1.0F - Rd;
517                sG = 1.0F - Gd;
518                sB = 1.0F - Bd;
519                break;
520             case GL_SRC_ALPHA:
521                sR = sG = sB = As;
522                break;
523             case GL_ONE_MINUS_SRC_ALPHA:
524                sR = sG = sB = 1.0F - As;
525                break;
526             case GL_DST_ALPHA:
527                sR = sG = sB = Ad;
528                break;
529             case GL_ONE_MINUS_DST_ALPHA:
530                sR = sG = sB = 1.0F - Ad;
531                break;
532             case GL_SRC_ALPHA_SATURATE:
533                if (As < 1.0F - Ad) {
534                   sR = sG = sB = As;
535                }
536                else {
537                   sR = sG = sB = 1.0F - Ad;
538                }
539                break;
540             case GL_CONSTANT_COLOR:
541                sR = ctx->Color.BlendColor[0];
542                sG = ctx->Color.BlendColor[1];
543                sB = ctx->Color.BlendColor[2];
544                break;
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];
549                break;
550             case GL_CONSTANT_ALPHA:
551                sR = sG = sB = ctx->Color.BlendColor[3];
552                break;
553             case GL_ONE_MINUS_CONSTANT_ALPHA:
554                sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
555                break;
556             case GL_SRC_COLOR:
557                sR = Rs;
558                sG = Gs;
559                sB = Bs;
560                break;
561             case GL_ONE_MINUS_SRC_COLOR:
562                sR = 1.0F - Rs;
563                sG = 1.0F - Gs;
564                sB = 1.0F - Bs;
565                break;
566             default:
567                /* this should never happen */
568                _mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float");
569                return;
570          }
571 
572          /* Source Alpha factor */
573          switch (ctx->Color.Blend[0].SrcA) {
574             case GL_ZERO:
575                sA = 0.0F;
576                break;
577             case GL_ONE:
578                sA = 1.0F;
579                break;
580             case GL_DST_COLOR:
581                sA = Ad;
582                break;
583             case GL_ONE_MINUS_DST_COLOR:
584                sA = 1.0F - Ad;
585                break;
586             case GL_SRC_ALPHA:
587                sA = As;
588                break;
589             case GL_ONE_MINUS_SRC_ALPHA:
590                sA = 1.0F - As;
591                break;
592             case GL_DST_ALPHA:
593                sA = Ad;
594                break;
595             case GL_ONE_MINUS_DST_ALPHA:
596                sA = 1.0F - Ad;
597                break;
598             case GL_SRC_ALPHA_SATURATE:
599                sA = 1.0;
600                break;
601             case GL_CONSTANT_COLOR:
602                sA = ctx->Color.BlendColor[3];
603                break;
604             case GL_ONE_MINUS_CONSTANT_COLOR:
605                sA = 1.0F - ctx->Color.BlendColor[3];
606                break;
607             case GL_CONSTANT_ALPHA:
608                sA = ctx->Color.BlendColor[3];
609                break;
610             case GL_ONE_MINUS_CONSTANT_ALPHA:
611                sA = 1.0F - ctx->Color.BlendColor[3];
612                break;
613             case GL_SRC_COLOR:
614                sA = As;
615                break;
616             case GL_ONE_MINUS_SRC_COLOR:
617                sA = 1.0F - As;
618                break;
619             default:
620                /* this should never happen */
621                sA = 0.0F;
622                _mesa_problem(ctx, "Bad blend source A factor in blend_general_float");
623                return;
624          }
625 
626          /* Dest RGB factor */
627          switch (ctx->Color.Blend[0].DstRGB) {
628             case GL_ZERO:
629                dR = dG = dB = 0.0F;
630                break;
631             case GL_ONE:
632                dR = dG = dB = 1.0F;
633                break;
634             case GL_SRC_COLOR:
635                dR = Rs;
636                dG = Gs;
637                dB = Bs;
638                break;
639             case GL_ONE_MINUS_SRC_COLOR:
640                dR = 1.0F - Rs;
641                dG = 1.0F - Gs;
642                dB = 1.0F - Bs;
643                break;
644             case GL_SRC_ALPHA:
645                dR = dG = dB = As;
646                break;
647             case GL_ONE_MINUS_SRC_ALPHA:
648                dR = dG = dB = 1.0F - As;
649                break;
650             case GL_DST_ALPHA:
651                dR = dG = dB = Ad;
652                break;
653             case GL_ONE_MINUS_DST_ALPHA:
654                dR = dG = dB = 1.0F - Ad;
655                break;
656             case GL_CONSTANT_COLOR:
657                dR = ctx->Color.BlendColor[0];
658                dG = ctx->Color.BlendColor[1];
659                dB = ctx->Color.BlendColor[2];
660                break;
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];
665                break;
666             case GL_CONSTANT_ALPHA:
667                dR = dG = dB = ctx->Color.BlendColor[3];
668                break;
669             case GL_ONE_MINUS_CONSTANT_ALPHA:
670                dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
671                break;
672             case GL_DST_COLOR:
673                dR = Rd;
674                dG = Gd;
675                dB = Bd;
676                break;
677             case GL_ONE_MINUS_DST_COLOR:
678                dR = 1.0F - Rd;
679                dG = 1.0F - Gd;
680                dB = 1.0F - Bd;
681                break;
682             default:
683                /* this should never happen */
684                dR = dG = dB = 0.0F;
685                _mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float");
686                return;
687          }
688 
689          /* Dest Alpha factor */
690          switch (ctx->Color.Blend[0].DstA) {
691             case GL_ZERO:
692                dA = 0.0F;
693                break;
694             case GL_ONE:
695                dA = 1.0F;
696                break;
697             case GL_SRC_COLOR:
698                dA = As;
699                break;
700             case GL_ONE_MINUS_SRC_COLOR:
701                dA = 1.0F - As;
702                break;
703             case GL_SRC_ALPHA:
704                dA = As;
705                break;
706             case GL_ONE_MINUS_SRC_ALPHA:
707                dA = 1.0F - As;
708                break;
709             case GL_DST_ALPHA:
710                dA = Ad;
711                break;
712             case GL_ONE_MINUS_DST_ALPHA:
713                dA = 1.0F - Ad;
714                break;
715             case GL_CONSTANT_COLOR:
716                dA = ctx->Color.BlendColor[3];
717                break;
718             case GL_ONE_MINUS_CONSTANT_COLOR:
719                dA = 1.0F - ctx->Color.BlendColor[3];
720                break;
721             case GL_CONSTANT_ALPHA:
722                dA = ctx->Color.BlendColor[3];
723                break;
724             case GL_ONE_MINUS_CONSTANT_ALPHA:
725                dA = 1.0F - ctx->Color.BlendColor[3];
726                break;
727             case GL_DST_COLOR:
728                dA = Ad;
729                break;
730             case GL_ONE_MINUS_DST_COLOR:
731                dA = 1.0F - Ad;
732                break;
733             default:
734                /* this should never happen */
735                dA = 0.0F;
736                _mesa_problem(ctx, "Bad blend dest A factor in blend_general_float");
737                return;
738          }
739 
740          /* compute the blended RGB */
741          switch (ctx->Color.Blend[0].EquationRGB) {
742          case GL_FUNC_ADD:
743             r = Rs * sR + Rd * dR;
744             g = Gs * sG + Gd * dG;
745             b = Bs * sB + Bd * dB;
746             a = As * sA + Ad * dA;
747             break;
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;
753             break;
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;
759             break;
760          case GL_MIN:
761 	    r = MIN2( Rd, Rs );
762 	    g = MIN2( Gd, Gs );
763 	    b = MIN2( Bd, Bs );
764             break;
765          case GL_MAX:
766 	    r = MAX2( Rd, Rs );
767 	    g = MAX2( Gd, Gs );
768 	    b = MAX2( Bd, Bs );
769             break;
770 	 default:
771             /* should never get here */
772             r = g = b = 0.0F;  /* silence uninitialized var warning */
773             _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
774             return;
775          }
776 
777          /* compute the blended alpha */
778          switch (ctx->Color.Blend[0].EquationA) {
779          case GL_FUNC_ADD:
780             a = As * sA + Ad * dA;
781             break;
782          case GL_FUNC_SUBTRACT:
783             a = As * sA - Ad * dA;
784             break;
785          case GL_FUNC_REVERSE_SUBTRACT:
786             a = Ad * dA - As * sA;
787             break;
788          case GL_MIN:
789 	    a = MIN2( Ad, As );
790             break;
791          case GL_MAX:
792 	    a = MAX2( Ad, As );
793             break;
794          default:
795             /* should never get here */
796             a = 0.0F;  /* silence uninitialized var warning */
797             _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
798             return;
799          }
800 
801          /* final clamping */
802 #if 0
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 );
807 #else
808          ASSIGN_4V(rgba[i], r, g, b, a);
809 #endif
810       }
811    }
812 }
813 
814 
815 /**
816  * Do any blending operation, any chanType.
817  */
818 static void
blend_general(struct gl_context * ctx,GLuint n,const GLubyte mask[],void * src,const void * dst,GLenum chanType)819 blend_general(struct gl_context *ctx, GLuint n, const GLubyte mask[],
820               void *src, const void *dst, GLenum chanType)
821 {
822    GLfloat (*rgbaF)[4], (*destF)[4];
823 
824    rgbaF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
825    destF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
826    if (!rgbaF || !destF) {
827       free(rgbaF);
828       free(destF);
829       _mesa_error(ctx, GL_OUT_OF_MEMORY, "blending");
830       return;
831    }
832 
833    if (chanType == GL_UNSIGNED_BYTE) {
834       GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
835       const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
836       GLuint i;
837       /* convert ubytes to floats */
838       for (i = 0; i < n; i++) {
839          if (mask[i]) {
840             rgbaF[i][RCOMP] = UBYTE_TO_FLOAT(rgba[i][RCOMP]);
841             rgbaF[i][GCOMP] = UBYTE_TO_FLOAT(rgba[i][GCOMP]);
842             rgbaF[i][BCOMP] = UBYTE_TO_FLOAT(rgba[i][BCOMP]);
843             rgbaF[i][ACOMP] = UBYTE_TO_FLOAT(rgba[i][ACOMP]);
844             destF[i][RCOMP] = UBYTE_TO_FLOAT(dest[i][RCOMP]);
845             destF[i][GCOMP] = UBYTE_TO_FLOAT(dest[i][GCOMP]);
846             destF[i][BCOMP] = UBYTE_TO_FLOAT(dest[i][BCOMP]);
847             destF[i][ACOMP] = UBYTE_TO_FLOAT(dest[i][ACOMP]);
848          }
849       }
850       /* do blend */
851       blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
852       /* convert back to ubytes */
853       for (i = 0; i < n; i++) {
854          if (mask[i])
855 	   _mesa_unclamped_float_rgba_to_ubyte(rgba[i], rgbaF[i]);
856       }
857    }
858    else if (chanType == GL_UNSIGNED_SHORT) {
859       GLushort (*rgba)[4] = (GLushort (*)[4]) src;
860       const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
861       GLuint i;
862       /* convert ushorts to floats */
863       for (i = 0; i < n; i++) {
864          if (mask[i]) {
865             rgbaF[i][RCOMP] = USHORT_TO_FLOAT(rgba[i][RCOMP]);
866             rgbaF[i][GCOMP] = USHORT_TO_FLOAT(rgba[i][GCOMP]);
867             rgbaF[i][BCOMP] = USHORT_TO_FLOAT(rgba[i][BCOMP]);
868             rgbaF[i][ACOMP] = USHORT_TO_FLOAT(rgba[i][ACOMP]);
869             destF[i][RCOMP] = USHORT_TO_FLOAT(dest[i][RCOMP]);
870             destF[i][GCOMP] = USHORT_TO_FLOAT(dest[i][GCOMP]);
871             destF[i][BCOMP] = USHORT_TO_FLOAT(dest[i][BCOMP]);
872             destF[i][ACOMP] = USHORT_TO_FLOAT(dest[i][ACOMP]);
873          }
874       }
875       /* do blend */
876       blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
877       /* convert back to ushorts */
878       for (i = 0; i < n; i++) {
879          if (mask[i]) {
880             UNCLAMPED_FLOAT_TO_USHORT(rgba[i][RCOMP], rgbaF[i][RCOMP]);
881             UNCLAMPED_FLOAT_TO_USHORT(rgba[i][GCOMP], rgbaF[i][GCOMP]);
882             UNCLAMPED_FLOAT_TO_USHORT(rgba[i][BCOMP], rgbaF[i][BCOMP]);
883             UNCLAMPED_FLOAT_TO_USHORT(rgba[i][ACOMP], rgbaF[i][ACOMP]);
884          }
885       }
886    }
887    else {
888       blend_general_float(ctx, n, mask, (GLfloat (*)[4]) src,
889                           (GLfloat (*)[4]) dst, chanType);
890    }
891 
892    free(rgbaF);
893    free(destF);
894 }
895 
896 
897 
898 /**
899  * Analyze current blending parameters to pick fastest blending function.
900  * Result: the ctx->Color.BlendFunc pointer is updated.
901  */
902 void
_swrast_choose_blend_func(struct gl_context * ctx,GLenum chanType)903 _swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType)
904 {
905    SWcontext *swrast = SWRAST_CONTEXT(ctx);
906    const GLenum eq = ctx->Color.Blend[0].EquationRGB;
907    const GLenum srcRGB = ctx->Color.Blend[0].SrcRGB;
908    const GLenum dstRGB = ctx->Color.Blend[0].DstRGB;
909    const GLenum srcA = ctx->Color.Blend[0].SrcA;
910    const GLenum dstA = ctx->Color.Blend[0].DstA;
911 
912    if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) {
913       swrast->BlendFunc = blend_general;
914    }
915    else if (eq == GL_MIN) {
916       /* Note: GL_MIN ignores the blending weight factors */
917 #if defined(USE_MMX_ASM)
918       if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
919          swrast->BlendFunc = _mesa_mmx_blend_min;
920       }
921       else
922 #endif
923          swrast->BlendFunc = blend_min;
924    }
925    else if (eq == GL_MAX) {
926       /* Note: GL_MAX ignores the blending weight factors */
927 #if defined(USE_MMX_ASM)
928       if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
929          swrast->BlendFunc = _mesa_mmx_blend_max;
930       }
931       else
932 #endif
933          swrast->BlendFunc = blend_max;
934    }
935    else if (srcRGB != srcA || dstRGB != dstA) {
936       swrast->BlendFunc = blend_general;
937    }
938    else if (eq == GL_FUNC_ADD && srcRGB == GL_SRC_ALPHA
939             && dstRGB == GL_ONE_MINUS_SRC_ALPHA) {
940 #if defined(USE_MMX_ASM)
941       if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
942          swrast->BlendFunc = _mesa_mmx_blend_transparency;
943       }
944       else
945 #endif
946       {
947          if (chanType == GL_UNSIGNED_BYTE)
948             swrast->BlendFunc = blend_transparency_ubyte;
949          else if (chanType == GL_UNSIGNED_SHORT)
950             swrast->BlendFunc = blend_transparency_ushort;
951          else
952             swrast->BlendFunc = blend_transparency_float;
953       }
954    }
955    else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ONE) {
956 #if defined(USE_MMX_ASM)
957       if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
958          swrast->BlendFunc = _mesa_mmx_blend_add;
959       }
960       else
961 #endif
962          swrast->BlendFunc = blend_add;
963    }
964    else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT)
965 	     && (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR))
966 	    ||
967 	    ((eq == GL_FUNC_ADD || eq == GL_FUNC_SUBTRACT)
968 	     && (srcRGB == GL_DST_COLOR && dstRGB == GL_ZERO))) {
969 #if defined(USE_MMX_ASM)
970       if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
971          swrast->BlendFunc = _mesa_mmx_blend_modulate;
972       }
973       else
974 #endif
975          swrast->BlendFunc = blend_modulate;
976    }
977    else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
978       swrast->BlendFunc = blend_noop;
979    }
980    else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
981       swrast->BlendFunc = blend_replace;
982    }
983    else {
984       swrast->BlendFunc = blend_general;
985    }
986 }
987 
988 
989 
990 /**
991  * Apply the blending operator to a span of pixels.
992  * We can handle horizontal runs of pixels (spans) or arrays of x/y
993  * pixel coordinates.
994  */
995 void
_swrast_blend_span(struct gl_context * ctx,struct gl_renderbuffer * rb,SWspan * span)996 _swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span)
997 {
998    SWcontext *swrast = SWRAST_CONTEXT(ctx);
999    void *rbPixels;
1000 
1001    ASSERT(span->end <= SWRAST_MAX_WIDTH);
1002    ASSERT(span->arrayMask & SPAN_RGBA);
1003    ASSERT(!ctx->Color.ColorLogicOpEnabled);
1004 
1005    rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
1006 
1007    swrast->BlendFunc(ctx, span->end, span->array->mask,
1008                      span->array->rgba, rbPixels, span->array->ChanType);
1009 }
1010