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