1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg
26848b8605Smrg/**
27848b8605Smrg * \file swrast/s_blend.c
28848b8605Smrg * \brief software blending.
29848b8605Smrg * \author Brian Paul
30848b8605Smrg *
31848b8605Smrg * Only a few blend modes have been optimized (min, max, transparency, add)
32848b8605Smrg * more optimized cases can easily be added if needed.
33848b8605Smrg * Celestia uses glBlendFunc(GL_SRC_ALPHA, GL_ONE), for example.
34848b8605Smrg */
35848b8605Smrg
36848b8605Smrg
37848b8605Smrg
38848b8605Smrg#include "main/glheader.h"
39848b8605Smrg#include "main/context.h"
40848b8605Smrg#include "main/colormac.h"
41848b8605Smrg#include "main/macros.h"
42848b8605Smrg
43848b8605Smrg#include "s_blend.h"
44848b8605Smrg#include "s_context.h"
45848b8605Smrg#include "s_span.h"
46848b8605Smrg
47848b8605Smrg
48848b8605Smrg#if defined(USE_MMX_ASM)
49848b8605Smrg#include "x86/mmx.h"
50848b8605Smrg#include "x86/common_x86_asm.h"
51848b8605Smrg#endif
52848b8605Smrg
53848b8605Smrg
54848b8605Smrg/**
55848b8605Smrg * Integer divide by 255
56848b8605Smrg * Declare "int divtemp" before using.
57848b8605Smrg * This satisfies Glean and should be reasonably fast.
58848b8605Smrg * Contributed by Nathan Hand.
59848b8605Smrg */
60848b8605Smrg#define DIV255(X)  (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)
61848b8605Smrg
62848b8605Smrg
63848b8605Smrg
64848b8605Smrg/**
65848b8605Smrg * Special case for glBlendFunc(GL_ZERO, GL_ONE).
66848b8605Smrg * No-op means the framebuffer values remain unchanged.
67848b8605Smrg * Any chanType ok.
68848b8605Smrg */
69b8e80941Smrgstatic void
70848b8605Smrgblend_noop(struct gl_context *ctx, GLuint n, const GLubyte mask[],
71848b8605Smrg           GLvoid *src, const GLvoid *dst, GLenum chanType)
72848b8605Smrg{
73848b8605Smrg   GLint bytes;
74848b8605Smrg
75b8e80941Smrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
76b8e80941Smrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
77b8e80941Smrg   assert(ctx->Color.Blend[0].SrcRGB == GL_ZERO);
78b8e80941Smrg   assert(ctx->Color.Blend[0].DstRGB == GL_ONE);
79848b8605Smrg   (void) ctx;
80848b8605Smrg
81848b8605Smrg   /* just memcpy */
82848b8605Smrg   if (chanType == GL_UNSIGNED_BYTE)
83848b8605Smrg      bytes = 4 * n * sizeof(GLubyte);
84848b8605Smrg   else if (chanType == GL_UNSIGNED_SHORT)
85848b8605Smrg      bytes = 4 * n * sizeof(GLushort);
86848b8605Smrg   else
87848b8605Smrg      bytes = 4 * n * sizeof(GLfloat);
88848b8605Smrg
89848b8605Smrg   memcpy(src, dst, bytes);
90848b8605Smrg}
91848b8605Smrg
92848b8605Smrg
93848b8605Smrg/**
94848b8605Smrg * Special case for glBlendFunc(GL_ONE, GL_ZERO)
95848b8605Smrg * Any chanType ok.
96848b8605Smrg */
97b8e80941Smrgstatic void
98848b8605Smrgblend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[],
99848b8605Smrg              GLvoid *src, const GLvoid *dst, GLenum chanType)
100848b8605Smrg{
101b8e80941Smrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
102b8e80941Smrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
103b8e80941Smrg   assert(ctx->Color.Blend[0].SrcRGB == GL_ONE);
104b8e80941Smrg   assert(ctx->Color.Blend[0].DstRGB == GL_ZERO);
105848b8605Smrg   (void) ctx;
106848b8605Smrg   (void) n;
107848b8605Smrg   (void) mask;
108848b8605Smrg   (void) src;
109848b8605Smrg   (void) dst;
110848b8605Smrg}
111848b8605Smrg
112848b8605Smrg
113848b8605Smrg/**
114848b8605Smrg * Common transparency blending mode:
115848b8605Smrg * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
116848b8605Smrg */
117b8e80941Smrgstatic void
118848b8605Smrgblend_transparency_ubyte(struct gl_context *ctx, GLuint n, const GLubyte mask[],
119848b8605Smrg                         GLvoid *src, const GLvoid *dst, GLenum chanType)
120848b8605Smrg{
121848b8605Smrg   GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
122848b8605Smrg   const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
123848b8605Smrg   GLuint i;
124848b8605Smrg
125b8e80941Smrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
126b8e80941Smrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
127b8e80941Smrg   assert(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
128b8e80941Smrg   assert(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
129b8e80941Smrg   assert(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
130b8e80941Smrg   assert(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
131b8e80941Smrg   assert(chanType == GL_UNSIGNED_BYTE);
132848b8605Smrg
133848b8605Smrg   (void) ctx;
134848b8605Smrg
135848b8605Smrg   for (i = 0; i < n; i++) {
136848b8605Smrg      if (mask[i]) {
137848b8605Smrg         const GLint t = rgba[i][ACOMP];  /* t is in [0, 255] */
138848b8605Smrg         if (t == 0) {
139848b8605Smrg            /* 0% alpha */
140848b8605Smrg            COPY_4UBV(rgba[i], dest[i]);
141848b8605Smrg         }
142848b8605Smrg         else if (t != 255) {
143848b8605Smrg	    GLint divtemp;
144848b8605Smrg            const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP];
145848b8605Smrg            const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP];
146848b8605Smrg            const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP];
147848b8605Smrg            const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP];
148b8e80941Smrg            assert(r <= 255);
149b8e80941Smrg            assert(g <= 255);
150b8e80941Smrg            assert(b <= 255);
151b8e80941Smrg            assert(a <= 255);
152848b8605Smrg            rgba[i][RCOMP] = (GLubyte) r;
153848b8605Smrg            rgba[i][GCOMP] = (GLubyte) g;
154848b8605Smrg            rgba[i][BCOMP] = (GLubyte) b;
155848b8605Smrg            rgba[i][ACOMP] = (GLubyte) a;
156848b8605Smrg         }
157848b8605Smrg      }
158848b8605Smrg   }
159848b8605Smrg}
160848b8605Smrg
161848b8605Smrg
162b8e80941Smrgstatic void
163848b8605Smrgblend_transparency_ushort(struct gl_context *ctx, GLuint n, const GLubyte mask[],
164848b8605Smrg                          GLvoid *src, const GLvoid *dst, GLenum chanType)
165848b8605Smrg{
166848b8605Smrg   GLushort (*rgba)[4] = (GLushort (*)[4]) src;
167848b8605Smrg   const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
168848b8605Smrg   GLuint i;
169848b8605Smrg
170b8e80941Smrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
171b8e80941Smrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
172b8e80941Smrg   assert(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
173b8e80941Smrg   assert(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
174b8e80941Smrg   assert(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
175b8e80941Smrg   assert(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
176b8e80941Smrg   assert(chanType == GL_UNSIGNED_SHORT);
177848b8605Smrg
178848b8605Smrg   (void) ctx;
179848b8605Smrg
180848b8605Smrg   for (i = 0; i < n; i++) {
181848b8605Smrg      if (mask[i]) {
182848b8605Smrg         const GLint t = rgba[i][ACOMP];
183848b8605Smrg         if (t == 0) {
184848b8605Smrg            /* 0% alpha */
185848b8605Smrg            COPY_4V(rgba[i], dest[i]);
186848b8605Smrg         }
187848b8605Smrg         else if (t != 65535) {
188848b8605Smrg            const GLfloat tt = (GLfloat) t / 65535.0F;
189848b8605Smrg            GLushort r = (GLushort) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
190848b8605Smrg            GLushort g = (GLushort) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
191848b8605Smrg            GLushort b = (GLushort) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
192848b8605Smrg            GLushort a = (GLushort) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
193848b8605Smrg            ASSIGN_4V(rgba[i], r, g, b, a);
194848b8605Smrg         }
195848b8605Smrg      }
196848b8605Smrg   }
197848b8605Smrg}
198848b8605Smrg
199848b8605Smrg
200b8e80941Smrgstatic void
201848b8605Smrgblend_transparency_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
202848b8605Smrg                         GLvoid *src, const GLvoid *dst, GLenum chanType)
203848b8605Smrg{
204848b8605Smrg   GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
205848b8605Smrg   const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
206848b8605Smrg   GLuint i;
207848b8605Smrg
208b8e80941Smrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
209b8e80941Smrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
210b8e80941Smrg   assert(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
211b8e80941Smrg   assert(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
212b8e80941Smrg   assert(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
213b8e80941Smrg   assert(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
214b8e80941Smrg   assert(chanType == GL_FLOAT);
215848b8605Smrg
216848b8605Smrg   (void) ctx;
217848b8605Smrg
218848b8605Smrg   for (i = 0; i < n; i++) {
219848b8605Smrg      if (mask[i]) {
220848b8605Smrg         const GLfloat t = rgba[i][ACOMP];  /* t in [0, 1] */
221848b8605Smrg         if (t == 0.0F) {
222848b8605Smrg            /* 0% alpha */
223848b8605Smrg            COPY_4V(rgba[i], dest[i]);
224848b8605Smrg         }
225848b8605Smrg         else if (t != 1.0F) {
226848b8605Smrg            GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * t + dest[i][RCOMP];
227848b8605Smrg            GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * t + dest[i][GCOMP];
228848b8605Smrg            GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * t + dest[i][BCOMP];
229848b8605Smrg            GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * t + dest[i][ACOMP];
230848b8605Smrg            ASSIGN_4V(rgba[i], r, g, b, a);
231848b8605Smrg         }
232848b8605Smrg      }
233848b8605Smrg   }
234848b8605Smrg}
235848b8605Smrg
236848b8605Smrg
237848b8605Smrg
238848b8605Smrg/**
239848b8605Smrg * Add src and dest: glBlendFunc(GL_ONE, GL_ONE).
240848b8605Smrg * Any chanType ok.
241848b8605Smrg */
242b8e80941Smrgstatic void
243848b8605Smrgblend_add(struct gl_context *ctx, GLuint n, const GLubyte mask[],
244848b8605Smrg          GLvoid *src, const GLvoid *dst, GLenum chanType)
245848b8605Smrg{
246848b8605Smrg   GLuint i;
247848b8605Smrg
248b8e80941Smrg   assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
249b8e80941Smrg   assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
250b8e80941Smrg   assert(ctx->Color.Blend[0].SrcRGB == GL_ONE);
251b8e80941Smrg   assert(ctx->Color.Blend[0].DstRGB == GL_ONE);
252848b8605Smrg   (void) ctx;
253848b8605Smrg
254848b8605Smrg   if (chanType == GL_UNSIGNED_BYTE) {
255848b8605Smrg      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
256848b8605Smrg      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
257848b8605Smrg      for (i=0;i<n;i++) {
258848b8605Smrg         if (mask[i]) {
259848b8605Smrg            GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
260848b8605Smrg            GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
261848b8605Smrg            GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
262848b8605Smrg            GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
263848b8605Smrg            rgba[i][RCOMP] = (GLubyte) MIN2( r, 255 );
264848b8605Smrg            rgba[i][GCOMP] = (GLubyte) MIN2( g, 255 );
265848b8605Smrg            rgba[i][BCOMP] = (GLubyte) MIN2( b, 255 );
266848b8605Smrg            rgba[i][ACOMP] = (GLubyte) MIN2( a, 255 );
267848b8605Smrg         }
268848b8605Smrg      }
269848b8605Smrg   }
270848b8605Smrg   else if (chanType == GL_UNSIGNED_SHORT) {
271848b8605Smrg      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
272848b8605Smrg      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
273848b8605Smrg      for (i=0;i<n;i++) {
274848b8605Smrg         if (mask[i]) {
275848b8605Smrg            GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
276848b8605Smrg            GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
277848b8605Smrg            GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
278848b8605Smrg            GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
279848b8605Smrg            rgba[i][RCOMP] = (GLshort) MIN2( r, 255 );
280848b8605Smrg            rgba[i][GCOMP] = (GLshort) MIN2( g, 255 );
281848b8605Smrg            rgba[i][BCOMP] = (GLshort) MIN2( b, 255 );
282848b8605Smrg            rgba[i][ACOMP] = (GLshort) MIN2( a, 255 );
283848b8605Smrg         }
284848b8605Smrg      }
285848b8605Smrg   }
286848b8605Smrg   else {
287848b8605Smrg      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
288848b8605Smrg      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
289b8e80941Smrg      assert(chanType == GL_FLOAT);
290848b8605Smrg      for (i=0;i<n;i++) {
291848b8605Smrg         if (mask[i]) {
292848b8605Smrg            /* don't RGB clamp to max */
293848b8605Smrg            rgba[i][RCOMP] += dest[i][RCOMP];
294848b8605Smrg            rgba[i][GCOMP] += dest[i][GCOMP];
295848b8605Smrg            rgba[i][BCOMP] += dest[i][BCOMP];
296848b8605Smrg            rgba[i][ACOMP] += dest[i][ACOMP];
297848b8605Smrg         }
298848b8605Smrg      }
299848b8605Smrg   }
300848b8605Smrg}
301848b8605Smrg
302848b8605Smrg
303848b8605Smrg
304848b8605Smrg/**
305848b8605Smrg * Blend min function.
306848b8605Smrg * Any chanType ok.
307848b8605Smrg */
308b8e80941Smrgstatic void
309848b8605Smrgblend_min(struct gl_context *ctx, GLuint n, const GLubyte mask[],
310848b8605Smrg          GLvoid *src, const GLvoid *dst, GLenum chanType)
311848b8605Smrg{
312848b8605Smrg   GLuint i;
313b8e80941Smrg   assert(ctx->Color.Blend[0].EquationRGB == GL_MIN);
314b8e80941Smrg   assert(ctx->Color.Blend[0].EquationA == GL_MIN);
315848b8605Smrg   (void) ctx;
316848b8605Smrg
317848b8605Smrg   if (chanType == GL_UNSIGNED_BYTE) {
318848b8605Smrg      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
319848b8605Smrg      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
320848b8605Smrg      for (i=0;i<n;i++) {
321848b8605Smrg         if (mask[i]) {
322848b8605Smrg            rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
323848b8605Smrg            rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
324848b8605Smrg            rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
325848b8605Smrg            rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
326848b8605Smrg         }
327848b8605Smrg      }
328848b8605Smrg   }
329848b8605Smrg   else if (chanType == GL_UNSIGNED_SHORT) {
330848b8605Smrg      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
331848b8605Smrg      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
332848b8605Smrg      for (i=0;i<n;i++) {
333848b8605Smrg         if (mask[i]) {
334848b8605Smrg            rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
335848b8605Smrg            rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
336848b8605Smrg            rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
337848b8605Smrg            rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
338848b8605Smrg         }
339848b8605Smrg      }
340848b8605Smrg   }
341848b8605Smrg   else {
342848b8605Smrg      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
343848b8605Smrg      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
344b8e80941Smrg      assert(chanType == GL_FLOAT);
345848b8605Smrg      for (i=0;i<n;i++) {
346848b8605Smrg         if (mask[i]) {
347848b8605Smrg            rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
348848b8605Smrg            rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
349848b8605Smrg            rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
350848b8605Smrg            rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
351848b8605Smrg         }
352848b8605Smrg      }
353848b8605Smrg   }
354848b8605Smrg}
355848b8605Smrg
356848b8605Smrg
357848b8605Smrg/**
358848b8605Smrg * Blend max function.
359848b8605Smrg * Any chanType ok.
360848b8605Smrg */
361b8e80941Smrgstatic void
362848b8605Smrgblend_max(struct gl_context *ctx, GLuint n, const GLubyte mask[],
363848b8605Smrg          GLvoid *src, const GLvoid *dst, GLenum chanType)
364848b8605Smrg{
365848b8605Smrg   GLuint i;
366b8e80941Smrg   assert(ctx->Color.Blend[0].EquationRGB == GL_MAX);
367b8e80941Smrg   assert(ctx->Color.Blend[0].EquationA == GL_MAX);
368848b8605Smrg   (void) ctx;
369848b8605Smrg
370848b8605Smrg   if (chanType == GL_UNSIGNED_BYTE) {
371848b8605Smrg      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
372848b8605Smrg      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
373848b8605Smrg      for (i=0;i<n;i++) {
374848b8605Smrg         if (mask[i]) {
375848b8605Smrg            rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
376848b8605Smrg            rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
377848b8605Smrg            rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
378848b8605Smrg            rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
379848b8605Smrg         }
380848b8605Smrg      }
381848b8605Smrg   }
382848b8605Smrg   else if (chanType == GL_UNSIGNED_SHORT) {
383848b8605Smrg      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
384848b8605Smrg      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
385848b8605Smrg      for (i=0;i<n;i++) {
386848b8605Smrg         if (mask[i]) {
387848b8605Smrg            rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
388848b8605Smrg            rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
389848b8605Smrg            rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
390848b8605Smrg            rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
391848b8605Smrg         }
392848b8605Smrg      }
393848b8605Smrg   }
394848b8605Smrg   else {
395848b8605Smrg      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
396848b8605Smrg      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
397b8e80941Smrg      assert(chanType == GL_FLOAT);
398848b8605Smrg      for (i=0;i<n;i++) {
399848b8605Smrg         if (mask[i]) {
400848b8605Smrg            rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
401848b8605Smrg            rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
402848b8605Smrg            rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
403848b8605Smrg            rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
404848b8605Smrg         }
405848b8605Smrg      }
406848b8605Smrg   }
407848b8605Smrg}
408848b8605Smrg
409848b8605Smrg
410848b8605Smrg
411848b8605Smrg/**
412848b8605Smrg * Modulate:  result = src * dest
413848b8605Smrg * Any chanType ok.
414848b8605Smrg */
415b8e80941Smrgstatic void
416848b8605Smrgblend_modulate(struct gl_context *ctx, GLuint n, const GLubyte mask[],
417848b8605Smrg               GLvoid *src, const GLvoid *dst, GLenum chanType)
418848b8605Smrg{
419848b8605Smrg   GLuint i;
420848b8605Smrg   (void) ctx;
421848b8605Smrg
422848b8605Smrg   if (chanType == GL_UNSIGNED_BYTE) {
423848b8605Smrg      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
424848b8605Smrg      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
425848b8605Smrg      for (i=0;i<n;i++) {
426848b8605Smrg         if (mask[i]) {
427848b8605Smrg	    GLint divtemp;
428848b8605Smrg            rgba[i][RCOMP] = DIV255(rgba[i][RCOMP] * dest[i][RCOMP]);
429848b8605Smrg            rgba[i][GCOMP] = DIV255(rgba[i][GCOMP] * dest[i][GCOMP]);
430848b8605Smrg            rgba[i][BCOMP] = DIV255(rgba[i][BCOMP] * dest[i][BCOMP]);
431848b8605Smrg            rgba[i][ACOMP] = DIV255(rgba[i][ACOMP] * dest[i][ACOMP]);
432848b8605Smrg         }
433848b8605Smrg      }
434848b8605Smrg   }
435848b8605Smrg   else if (chanType == GL_UNSIGNED_SHORT) {
436848b8605Smrg      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
437848b8605Smrg      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
438848b8605Smrg      for (i=0;i<n;i++) {
439848b8605Smrg         if (mask[i]) {
440848b8605Smrg            rgba[i][RCOMP] = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
441848b8605Smrg            rgba[i][GCOMP] = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
442848b8605Smrg            rgba[i][BCOMP] = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
443848b8605Smrg            rgba[i][ACOMP] = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
444848b8605Smrg         }
445848b8605Smrg      }
446848b8605Smrg   }
447848b8605Smrg   else {
448848b8605Smrg      GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
449848b8605Smrg      const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
450b8e80941Smrg      assert(chanType == GL_FLOAT);
451848b8605Smrg      for (i=0;i<n;i++) {
452848b8605Smrg         if (mask[i]) {
453848b8605Smrg            rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
454848b8605Smrg            rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
455848b8605Smrg            rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
456848b8605Smrg            rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
457848b8605Smrg         }
458848b8605Smrg      }
459848b8605Smrg   }
460848b8605Smrg}
461848b8605Smrg
462848b8605Smrg
463848b8605Smrg/**
464848b8605Smrg * Do any blending operation, using floating point.
465848b8605Smrg * \param n  number of pixels
466848b8605Smrg * \param mask  fragment writemask array
467848b8605Smrg * \param rgba  array of incoming (and modified) pixels
468848b8605Smrg * \param dest  array of pixels from the dest color buffer
469848b8605Smrg */
470848b8605Smrgstatic void
471848b8605Smrgblend_general_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
472848b8605Smrg                    GLfloat rgba[][4], GLfloat dest[][4],
473848b8605Smrg                    GLenum chanType)
474848b8605Smrg{
475848b8605Smrg   GLuint i;
476848b8605Smrg
477848b8605Smrg   for (i = 0; i < n; i++) {
478848b8605Smrg      if (mask[i]) {
479848b8605Smrg         /* Incoming/source Color */
480848b8605Smrg         const GLfloat Rs = rgba[i][RCOMP];
481848b8605Smrg         const GLfloat Gs = rgba[i][GCOMP];
482848b8605Smrg         const GLfloat Bs = rgba[i][BCOMP];
483848b8605Smrg         const GLfloat As = rgba[i][ACOMP];
484848b8605Smrg
485848b8605Smrg         /* Frame buffer/dest color */
486848b8605Smrg         const GLfloat Rd = dest[i][RCOMP];
487848b8605Smrg         const GLfloat Gd = dest[i][GCOMP];
488848b8605Smrg         const GLfloat Bd = dest[i][BCOMP];
489848b8605Smrg         const GLfloat Ad = dest[i][ACOMP];
490848b8605Smrg
491848b8605Smrg         GLfloat sR, sG, sB, sA;  /* Source factor */
492848b8605Smrg         GLfloat dR, dG, dB, dA;  /* Dest factor */
493848b8605Smrg         GLfloat r, g, b, a;      /* result color */
494848b8605Smrg
495848b8605Smrg         /* XXX for the case of constant blend terms we could init
496848b8605Smrg          * the sX and dX variables just once before the loop.
497848b8605Smrg          */
498848b8605Smrg
499848b8605Smrg         /* Source RGB factor */
500848b8605Smrg         switch (ctx->Color.Blend[0].SrcRGB) {
501848b8605Smrg            case GL_ZERO:
502848b8605Smrg               sR = sG = sB = 0.0F;
503848b8605Smrg               break;
504848b8605Smrg            case GL_ONE:
505848b8605Smrg               sR = sG = sB = 1.0F;
506848b8605Smrg               break;
507848b8605Smrg            case GL_DST_COLOR:
508848b8605Smrg               sR = Rd;
509848b8605Smrg               sG = Gd;
510848b8605Smrg               sB = Bd;
511848b8605Smrg               break;
512848b8605Smrg            case GL_ONE_MINUS_DST_COLOR:
513848b8605Smrg               sR = 1.0F - Rd;
514848b8605Smrg               sG = 1.0F - Gd;
515848b8605Smrg               sB = 1.0F - Bd;
516848b8605Smrg               break;
517848b8605Smrg            case GL_SRC_ALPHA:
518848b8605Smrg               sR = sG = sB = As;
519848b8605Smrg               break;
520848b8605Smrg            case GL_ONE_MINUS_SRC_ALPHA:
521848b8605Smrg               sR = sG = sB = 1.0F - As;
522848b8605Smrg               break;
523848b8605Smrg            case GL_DST_ALPHA:
524848b8605Smrg               sR = sG = sB = Ad;
525848b8605Smrg               break;
526848b8605Smrg            case GL_ONE_MINUS_DST_ALPHA:
527848b8605Smrg               sR = sG = sB = 1.0F - Ad;
528848b8605Smrg               break;
529848b8605Smrg            case GL_SRC_ALPHA_SATURATE:
530848b8605Smrg               if (As < 1.0F - Ad) {
531848b8605Smrg                  sR = sG = sB = As;
532848b8605Smrg               }
533848b8605Smrg               else {
534848b8605Smrg                  sR = sG = sB = 1.0F - Ad;
535848b8605Smrg               }
536848b8605Smrg               break;
537848b8605Smrg            case GL_CONSTANT_COLOR:
538848b8605Smrg               sR = ctx->Color.BlendColor[0];
539848b8605Smrg               sG = ctx->Color.BlendColor[1];
540848b8605Smrg               sB = ctx->Color.BlendColor[2];
541848b8605Smrg               break;
542848b8605Smrg            case GL_ONE_MINUS_CONSTANT_COLOR:
543848b8605Smrg               sR = 1.0F - ctx->Color.BlendColor[0];
544848b8605Smrg               sG = 1.0F - ctx->Color.BlendColor[1];
545848b8605Smrg               sB = 1.0F - ctx->Color.BlendColor[2];
546848b8605Smrg               break;
547848b8605Smrg            case GL_CONSTANT_ALPHA:
548848b8605Smrg               sR = sG = sB = ctx->Color.BlendColor[3];
549848b8605Smrg               break;
550848b8605Smrg            case GL_ONE_MINUS_CONSTANT_ALPHA:
551848b8605Smrg               sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
552848b8605Smrg               break;
553848b8605Smrg            case GL_SRC_COLOR:
554848b8605Smrg               sR = Rs;
555848b8605Smrg               sG = Gs;
556848b8605Smrg               sB = Bs;
557848b8605Smrg               break;
558848b8605Smrg            case GL_ONE_MINUS_SRC_COLOR:
559848b8605Smrg               sR = 1.0F - Rs;
560848b8605Smrg               sG = 1.0F - Gs;
561848b8605Smrg               sB = 1.0F - Bs;
562848b8605Smrg               break;
563848b8605Smrg            default:
564848b8605Smrg               /* this should never happen */
565848b8605Smrg               _mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float");
566848b8605Smrg               return;
567848b8605Smrg         }
568848b8605Smrg
569848b8605Smrg         /* Source Alpha factor */
570848b8605Smrg         switch (ctx->Color.Blend[0].SrcA) {
571848b8605Smrg            case GL_ZERO:
572848b8605Smrg               sA = 0.0F;
573848b8605Smrg               break;
574848b8605Smrg            case GL_ONE:
575848b8605Smrg               sA = 1.0F;
576848b8605Smrg               break;
577848b8605Smrg            case GL_DST_COLOR:
578848b8605Smrg               sA = Ad;
579848b8605Smrg               break;
580848b8605Smrg            case GL_ONE_MINUS_DST_COLOR:
581848b8605Smrg               sA = 1.0F - Ad;
582848b8605Smrg               break;
583848b8605Smrg            case GL_SRC_ALPHA:
584848b8605Smrg               sA = As;
585848b8605Smrg               break;
586848b8605Smrg            case GL_ONE_MINUS_SRC_ALPHA:
587848b8605Smrg               sA = 1.0F - As;
588848b8605Smrg               break;
589848b8605Smrg            case GL_DST_ALPHA:
590848b8605Smrg               sA = Ad;
591848b8605Smrg               break;
592848b8605Smrg            case GL_ONE_MINUS_DST_ALPHA:
593848b8605Smrg               sA = 1.0F - Ad;
594848b8605Smrg               break;
595848b8605Smrg            case GL_SRC_ALPHA_SATURATE:
596848b8605Smrg               sA = 1.0;
597848b8605Smrg               break;
598848b8605Smrg            case GL_CONSTANT_COLOR:
599848b8605Smrg               sA = ctx->Color.BlendColor[3];
600848b8605Smrg               break;
601848b8605Smrg            case GL_ONE_MINUS_CONSTANT_COLOR:
602848b8605Smrg               sA = 1.0F - ctx->Color.BlendColor[3];
603848b8605Smrg               break;
604848b8605Smrg            case GL_CONSTANT_ALPHA:
605848b8605Smrg               sA = ctx->Color.BlendColor[3];
606848b8605Smrg               break;
607848b8605Smrg            case GL_ONE_MINUS_CONSTANT_ALPHA:
608848b8605Smrg               sA = 1.0F - ctx->Color.BlendColor[3];
609848b8605Smrg               break;
610848b8605Smrg            case GL_SRC_COLOR:
611848b8605Smrg               sA = As;
612848b8605Smrg               break;
613848b8605Smrg            case GL_ONE_MINUS_SRC_COLOR:
614848b8605Smrg               sA = 1.0F - As;
615848b8605Smrg               break;
616848b8605Smrg            default:
617848b8605Smrg               /* this should never happen */
618848b8605Smrg               sA = 0.0F;
619848b8605Smrg               _mesa_problem(ctx, "Bad blend source A factor in blend_general_float");
620848b8605Smrg               return;
621848b8605Smrg         }
622848b8605Smrg
623848b8605Smrg         /* Dest RGB factor */
624848b8605Smrg         switch (ctx->Color.Blend[0].DstRGB) {
625848b8605Smrg            case GL_ZERO:
626848b8605Smrg               dR = dG = dB = 0.0F;
627848b8605Smrg               break;
628848b8605Smrg            case GL_ONE:
629848b8605Smrg               dR = dG = dB = 1.0F;
630848b8605Smrg               break;
631848b8605Smrg            case GL_SRC_COLOR:
632848b8605Smrg               dR = Rs;
633848b8605Smrg               dG = Gs;
634848b8605Smrg               dB = Bs;
635848b8605Smrg               break;
636848b8605Smrg            case GL_ONE_MINUS_SRC_COLOR:
637848b8605Smrg               dR = 1.0F - Rs;
638848b8605Smrg               dG = 1.0F - Gs;
639848b8605Smrg               dB = 1.0F - Bs;
640848b8605Smrg               break;
641848b8605Smrg            case GL_SRC_ALPHA:
642848b8605Smrg               dR = dG = dB = As;
643848b8605Smrg               break;
644848b8605Smrg            case GL_ONE_MINUS_SRC_ALPHA:
645848b8605Smrg               dR = dG = dB = 1.0F - As;
646848b8605Smrg               break;
647848b8605Smrg            case GL_DST_ALPHA:
648848b8605Smrg               dR = dG = dB = Ad;
649848b8605Smrg               break;
650848b8605Smrg            case GL_ONE_MINUS_DST_ALPHA:
651848b8605Smrg               dR = dG = dB = 1.0F - Ad;
652848b8605Smrg               break;
653848b8605Smrg            case GL_CONSTANT_COLOR:
654848b8605Smrg               dR = ctx->Color.BlendColor[0];
655848b8605Smrg               dG = ctx->Color.BlendColor[1];
656848b8605Smrg               dB = ctx->Color.BlendColor[2];
657848b8605Smrg               break;
658848b8605Smrg            case GL_ONE_MINUS_CONSTANT_COLOR:
659848b8605Smrg               dR = 1.0F - ctx->Color.BlendColor[0];
660848b8605Smrg               dG = 1.0F - ctx->Color.BlendColor[1];
661848b8605Smrg               dB = 1.0F - ctx->Color.BlendColor[2];
662848b8605Smrg               break;
663848b8605Smrg            case GL_CONSTANT_ALPHA:
664848b8605Smrg               dR = dG = dB = ctx->Color.BlendColor[3];
665848b8605Smrg               break;
666848b8605Smrg            case GL_ONE_MINUS_CONSTANT_ALPHA:
667848b8605Smrg               dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
668848b8605Smrg               break;
669848b8605Smrg            case GL_DST_COLOR:
670848b8605Smrg               dR = Rd;
671848b8605Smrg               dG = Gd;
672848b8605Smrg               dB = Bd;
673848b8605Smrg               break;
674848b8605Smrg            case GL_ONE_MINUS_DST_COLOR:
675848b8605Smrg               dR = 1.0F - Rd;
676848b8605Smrg               dG = 1.0F - Gd;
677848b8605Smrg               dB = 1.0F - Bd;
678848b8605Smrg               break;
679848b8605Smrg            default:
680848b8605Smrg               /* this should never happen */
681848b8605Smrg               dR = dG = dB = 0.0F;
682848b8605Smrg               _mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float");
683848b8605Smrg               return;
684848b8605Smrg         }
685848b8605Smrg
686848b8605Smrg         /* Dest Alpha factor */
687848b8605Smrg         switch (ctx->Color.Blend[0].DstA) {
688848b8605Smrg            case GL_ZERO:
689848b8605Smrg               dA = 0.0F;
690848b8605Smrg               break;
691848b8605Smrg            case GL_ONE:
692848b8605Smrg               dA = 1.0F;
693848b8605Smrg               break;
694848b8605Smrg            case GL_SRC_COLOR:
695848b8605Smrg               dA = As;
696848b8605Smrg               break;
697848b8605Smrg            case GL_ONE_MINUS_SRC_COLOR:
698848b8605Smrg               dA = 1.0F - As;
699848b8605Smrg               break;
700848b8605Smrg            case GL_SRC_ALPHA:
701848b8605Smrg               dA = As;
702848b8605Smrg               break;
703848b8605Smrg            case GL_ONE_MINUS_SRC_ALPHA:
704848b8605Smrg               dA = 1.0F - As;
705848b8605Smrg               break;
706848b8605Smrg            case GL_DST_ALPHA:
707848b8605Smrg               dA = Ad;
708848b8605Smrg               break;
709848b8605Smrg            case GL_ONE_MINUS_DST_ALPHA:
710848b8605Smrg               dA = 1.0F - Ad;
711848b8605Smrg               break;
712848b8605Smrg            case GL_CONSTANT_COLOR:
713848b8605Smrg               dA = ctx->Color.BlendColor[3];
714848b8605Smrg               break;
715848b8605Smrg            case GL_ONE_MINUS_CONSTANT_COLOR:
716848b8605Smrg               dA = 1.0F - ctx->Color.BlendColor[3];
717848b8605Smrg               break;
718848b8605Smrg            case GL_CONSTANT_ALPHA:
719848b8605Smrg               dA = ctx->Color.BlendColor[3];
720848b8605Smrg               break;
721848b8605Smrg            case GL_ONE_MINUS_CONSTANT_ALPHA:
722848b8605Smrg               dA = 1.0F - ctx->Color.BlendColor[3];
723848b8605Smrg               break;
724848b8605Smrg            case GL_DST_COLOR:
725848b8605Smrg               dA = Ad;
726848b8605Smrg               break;
727848b8605Smrg            case GL_ONE_MINUS_DST_COLOR:
728848b8605Smrg               dA = 1.0F - Ad;
729848b8605Smrg               break;
730848b8605Smrg            default:
731848b8605Smrg               /* this should never happen */
732848b8605Smrg               dA = 0.0F;
733848b8605Smrg               _mesa_problem(ctx, "Bad blend dest A factor in blend_general_float");
734848b8605Smrg               return;
735848b8605Smrg         }
736848b8605Smrg
737848b8605Smrg         /* compute the blended RGB */
738848b8605Smrg         switch (ctx->Color.Blend[0].EquationRGB) {
739848b8605Smrg         case GL_FUNC_ADD:
740848b8605Smrg            r = Rs * sR + Rd * dR;
741848b8605Smrg            g = Gs * sG + Gd * dG;
742848b8605Smrg            b = Bs * sB + Bd * dB;
743848b8605Smrg            a = As * sA + Ad * dA;
744848b8605Smrg            break;
745848b8605Smrg         case GL_FUNC_SUBTRACT:
746848b8605Smrg            r = Rs * sR - Rd * dR;
747848b8605Smrg            g = Gs * sG - Gd * dG;
748848b8605Smrg            b = Bs * sB - Bd * dB;
749848b8605Smrg            a = As * sA - Ad * dA;
750848b8605Smrg            break;
751848b8605Smrg         case GL_FUNC_REVERSE_SUBTRACT:
752848b8605Smrg            r = Rd * dR - Rs * sR;
753848b8605Smrg            g = Gd * dG - Gs * sG;
754848b8605Smrg            b = Bd * dB - Bs * sB;
755848b8605Smrg            a = Ad * dA - As * sA;
756848b8605Smrg            break;
757848b8605Smrg         case GL_MIN:
758848b8605Smrg	    r = MIN2( Rd, Rs );
759848b8605Smrg	    g = MIN2( Gd, Gs );
760848b8605Smrg	    b = MIN2( Bd, Bs );
761848b8605Smrg            break;
762848b8605Smrg         case GL_MAX:
763848b8605Smrg	    r = MAX2( Rd, Rs );
764848b8605Smrg	    g = MAX2( Gd, Gs );
765848b8605Smrg	    b = MAX2( Bd, Bs );
766848b8605Smrg            break;
767848b8605Smrg	 default:
768848b8605Smrg            /* should never get here */
769848b8605Smrg            r = g = b = 0.0F;  /* silence uninitialized var warning */
770848b8605Smrg            _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
771848b8605Smrg            return;
772848b8605Smrg         }
773848b8605Smrg
774848b8605Smrg         /* compute the blended alpha */
775848b8605Smrg         switch (ctx->Color.Blend[0].EquationA) {
776848b8605Smrg         case GL_FUNC_ADD:
777848b8605Smrg            a = As * sA + Ad * dA;
778848b8605Smrg            break;
779848b8605Smrg         case GL_FUNC_SUBTRACT:
780848b8605Smrg            a = As * sA - Ad * dA;
781848b8605Smrg            break;
782848b8605Smrg         case GL_FUNC_REVERSE_SUBTRACT:
783848b8605Smrg            a = Ad * dA - As * sA;
784848b8605Smrg            break;
785848b8605Smrg         case GL_MIN:
786848b8605Smrg	    a = MIN2( Ad, As );
787848b8605Smrg            break;
788848b8605Smrg         case GL_MAX:
789848b8605Smrg	    a = MAX2( Ad, As );
790848b8605Smrg            break;
791848b8605Smrg         default:
792848b8605Smrg            /* should never get here */
793848b8605Smrg            a = 0.0F;  /* silence uninitialized var warning */
794848b8605Smrg            _mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
795848b8605Smrg            return;
796848b8605Smrg         }
797848b8605Smrg
798848b8605Smrg         /* final clamping */
799848b8605Smrg#if 0
800848b8605Smrg         rgba[i][RCOMP] = MAX2( r, 0.0F );
801848b8605Smrg         rgba[i][GCOMP] = MAX2( g, 0.0F );
802848b8605Smrg         rgba[i][BCOMP] = MAX2( b, 0.0F );
803848b8605Smrg         rgba[i][ACOMP] = CLAMP( a, 0.0F, 1.0F );
804848b8605Smrg#else
805848b8605Smrg         ASSIGN_4V(rgba[i], r, g, b, a);
806848b8605Smrg#endif
807848b8605Smrg      }
808848b8605Smrg   }
809848b8605Smrg}
810848b8605Smrg
811848b8605Smrg
812848b8605Smrg/**
813848b8605Smrg * Do any blending operation, any chanType.
814848b8605Smrg */
815848b8605Smrgstatic void
816848b8605Smrgblend_general(struct gl_context *ctx, GLuint n, const GLubyte mask[],
817848b8605Smrg              void *src, const void *dst, GLenum chanType)
818848b8605Smrg{
819848b8605Smrg   GLfloat (*rgbaF)[4], (*destF)[4];
820848b8605Smrg
821848b8605Smrg   rgbaF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
822848b8605Smrg   destF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
823848b8605Smrg   if (!rgbaF || !destF) {
824848b8605Smrg      free(rgbaF);
825848b8605Smrg      free(destF);
826848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "blending");
827848b8605Smrg      return;
828848b8605Smrg   }
829848b8605Smrg
830848b8605Smrg   if (chanType == GL_UNSIGNED_BYTE) {
831848b8605Smrg      GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
832848b8605Smrg      const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
833848b8605Smrg      GLuint i;
834848b8605Smrg      /* convert ubytes to floats */
835848b8605Smrg      for (i = 0; i < n; i++) {
836848b8605Smrg         if (mask[i]) {
837848b8605Smrg            rgbaF[i][RCOMP] = UBYTE_TO_FLOAT(rgba[i][RCOMP]);
838848b8605Smrg            rgbaF[i][GCOMP] = UBYTE_TO_FLOAT(rgba[i][GCOMP]);
839848b8605Smrg            rgbaF[i][BCOMP] = UBYTE_TO_FLOAT(rgba[i][BCOMP]);
840848b8605Smrg            rgbaF[i][ACOMP] = UBYTE_TO_FLOAT(rgba[i][ACOMP]);
841848b8605Smrg            destF[i][RCOMP] = UBYTE_TO_FLOAT(dest[i][RCOMP]);
842848b8605Smrg            destF[i][GCOMP] = UBYTE_TO_FLOAT(dest[i][GCOMP]);
843848b8605Smrg            destF[i][BCOMP] = UBYTE_TO_FLOAT(dest[i][BCOMP]);
844848b8605Smrg            destF[i][ACOMP] = UBYTE_TO_FLOAT(dest[i][ACOMP]);
845848b8605Smrg         }
846848b8605Smrg      }
847848b8605Smrg      /* do blend */
848848b8605Smrg      blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
849848b8605Smrg      /* convert back to ubytes */
850848b8605Smrg      for (i = 0; i < n; i++) {
851848b8605Smrg         if (mask[i])
852848b8605Smrg	   _mesa_unclamped_float_rgba_to_ubyte(rgba[i], rgbaF[i]);
853848b8605Smrg      }
854848b8605Smrg   }
855848b8605Smrg   else if (chanType == GL_UNSIGNED_SHORT) {
856848b8605Smrg      GLushort (*rgba)[4] = (GLushort (*)[4]) src;
857848b8605Smrg      const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
858848b8605Smrg      GLuint i;
859848b8605Smrg      /* convert ushorts to floats */
860848b8605Smrg      for (i = 0; i < n; i++) {
861848b8605Smrg         if (mask[i]) {
862848b8605Smrg            rgbaF[i][RCOMP] = USHORT_TO_FLOAT(rgba[i][RCOMP]);
863848b8605Smrg            rgbaF[i][GCOMP] = USHORT_TO_FLOAT(rgba[i][GCOMP]);
864848b8605Smrg            rgbaF[i][BCOMP] = USHORT_TO_FLOAT(rgba[i][BCOMP]);
865848b8605Smrg            rgbaF[i][ACOMP] = USHORT_TO_FLOAT(rgba[i][ACOMP]);
866848b8605Smrg            destF[i][RCOMP] = USHORT_TO_FLOAT(dest[i][RCOMP]);
867848b8605Smrg            destF[i][GCOMP] = USHORT_TO_FLOAT(dest[i][GCOMP]);
868848b8605Smrg            destF[i][BCOMP] = USHORT_TO_FLOAT(dest[i][BCOMP]);
869848b8605Smrg            destF[i][ACOMP] = USHORT_TO_FLOAT(dest[i][ACOMP]);
870848b8605Smrg         }
871848b8605Smrg      }
872848b8605Smrg      /* do blend */
873848b8605Smrg      blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
874848b8605Smrg      /* convert back to ushorts */
875848b8605Smrg      for (i = 0; i < n; i++) {
876848b8605Smrg         if (mask[i]) {
877848b8605Smrg            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][RCOMP], rgbaF[i][RCOMP]);
878848b8605Smrg            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][GCOMP], rgbaF[i][GCOMP]);
879848b8605Smrg            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][BCOMP], rgbaF[i][BCOMP]);
880848b8605Smrg            UNCLAMPED_FLOAT_TO_USHORT(rgba[i][ACOMP], rgbaF[i][ACOMP]);
881848b8605Smrg         }
882848b8605Smrg      }
883848b8605Smrg   }
884848b8605Smrg   else {
885848b8605Smrg      blend_general_float(ctx, n, mask, (GLfloat (*)[4]) src,
886848b8605Smrg                          (GLfloat (*)[4]) dst, chanType);
887848b8605Smrg   }
888848b8605Smrg
889848b8605Smrg   free(rgbaF);
890848b8605Smrg   free(destF);
891848b8605Smrg}
892848b8605Smrg
893848b8605Smrg
894848b8605Smrg
895848b8605Smrg/**
896848b8605Smrg * Analyze current blending parameters to pick fastest blending function.
897848b8605Smrg * Result: the ctx->Color.BlendFunc pointer is updated.
898848b8605Smrg */
899848b8605Smrgvoid
900848b8605Smrg_swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType)
901848b8605Smrg{
902848b8605Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
903848b8605Smrg   const GLenum eq = ctx->Color.Blend[0].EquationRGB;
904848b8605Smrg   const GLenum srcRGB = ctx->Color.Blend[0].SrcRGB;
905848b8605Smrg   const GLenum dstRGB = ctx->Color.Blend[0].DstRGB;
906848b8605Smrg   const GLenum srcA = ctx->Color.Blend[0].SrcA;
907848b8605Smrg   const GLenum dstA = ctx->Color.Blend[0].DstA;
908848b8605Smrg
909848b8605Smrg   if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) {
910848b8605Smrg      swrast->BlendFunc = blend_general;
911848b8605Smrg   }
912848b8605Smrg   else if (eq == GL_MIN) {
913848b8605Smrg      /* Note: GL_MIN ignores the blending weight factors */
914848b8605Smrg#if defined(USE_MMX_ASM)
915848b8605Smrg      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
916848b8605Smrg         swrast->BlendFunc = _mesa_mmx_blend_min;
917848b8605Smrg      }
918848b8605Smrg      else
919848b8605Smrg#endif
920848b8605Smrg         swrast->BlendFunc = blend_min;
921848b8605Smrg   }
922848b8605Smrg   else if (eq == GL_MAX) {
923848b8605Smrg      /* Note: GL_MAX ignores the blending weight factors */
924848b8605Smrg#if defined(USE_MMX_ASM)
925848b8605Smrg      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
926848b8605Smrg         swrast->BlendFunc = _mesa_mmx_blend_max;
927848b8605Smrg      }
928848b8605Smrg      else
929848b8605Smrg#endif
930848b8605Smrg         swrast->BlendFunc = blend_max;
931848b8605Smrg   }
932848b8605Smrg   else if (srcRGB != srcA || dstRGB != dstA) {
933848b8605Smrg      swrast->BlendFunc = blend_general;
934848b8605Smrg   }
935848b8605Smrg   else if (eq == GL_FUNC_ADD && srcRGB == GL_SRC_ALPHA
936848b8605Smrg            && dstRGB == GL_ONE_MINUS_SRC_ALPHA) {
937848b8605Smrg#if defined(USE_MMX_ASM)
938848b8605Smrg      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
939848b8605Smrg         swrast->BlendFunc = _mesa_mmx_blend_transparency;
940848b8605Smrg      }
941848b8605Smrg      else
942848b8605Smrg#endif
943848b8605Smrg      {
944848b8605Smrg         if (chanType == GL_UNSIGNED_BYTE)
945848b8605Smrg            swrast->BlendFunc = blend_transparency_ubyte;
946848b8605Smrg         else if (chanType == GL_UNSIGNED_SHORT)
947848b8605Smrg            swrast->BlendFunc = blend_transparency_ushort;
948848b8605Smrg         else
949848b8605Smrg            swrast->BlendFunc = blend_transparency_float;
950848b8605Smrg      }
951848b8605Smrg   }
952848b8605Smrg   else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ONE) {
953848b8605Smrg#if defined(USE_MMX_ASM)
954848b8605Smrg      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
955848b8605Smrg         swrast->BlendFunc = _mesa_mmx_blend_add;
956848b8605Smrg      }
957848b8605Smrg      else
958848b8605Smrg#endif
959848b8605Smrg         swrast->BlendFunc = blend_add;
960848b8605Smrg   }
961848b8605Smrg   else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT)
962848b8605Smrg	     && (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR))
963848b8605Smrg	    ||
964848b8605Smrg	    ((eq == GL_FUNC_ADD || eq == GL_FUNC_SUBTRACT)
965848b8605Smrg	     && (srcRGB == GL_DST_COLOR && dstRGB == GL_ZERO))) {
966848b8605Smrg#if defined(USE_MMX_ASM)
967848b8605Smrg      if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
968848b8605Smrg         swrast->BlendFunc = _mesa_mmx_blend_modulate;
969848b8605Smrg      }
970848b8605Smrg      else
971848b8605Smrg#endif
972848b8605Smrg         swrast->BlendFunc = blend_modulate;
973848b8605Smrg   }
974848b8605Smrg   else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
975848b8605Smrg      swrast->BlendFunc = blend_noop;
976848b8605Smrg   }
977848b8605Smrg   else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
978848b8605Smrg      swrast->BlendFunc = blend_replace;
979848b8605Smrg   }
980848b8605Smrg   else {
981848b8605Smrg      swrast->BlendFunc = blend_general;
982848b8605Smrg   }
983848b8605Smrg}
984848b8605Smrg
985848b8605Smrg
986848b8605Smrg
987848b8605Smrg/**
988848b8605Smrg * Apply the blending operator to a span of pixels.
989848b8605Smrg * We can handle horizontal runs of pixels (spans) or arrays of x/y
990848b8605Smrg * pixel coordinates.
991848b8605Smrg */
992848b8605Smrgvoid
993848b8605Smrg_swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span)
994848b8605Smrg{
995848b8605Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
996848b8605Smrg   void *rbPixels;
997848b8605Smrg
998b8e80941Smrg   assert(span->end <= SWRAST_MAX_WIDTH);
999b8e80941Smrg   assert(span->arrayMask & SPAN_RGBA);
1000b8e80941Smrg   assert(!ctx->Color.ColorLogicOpEnabled);
1001848b8605Smrg
1002848b8605Smrg   rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
1003848b8605Smrg
1004848b8605Smrg   swrast->BlendFunc(ctx, span->end, span->array->mask,
1005848b8605Smrg                     span->array->rgba, rbPixels, span->array->ChanType);
1006848b8605Smrg}
1007