From 4420369d700d9db1563f8647e1889c6a0972ea2c Mon Sep 17 00:00:00 2001 From: marha Date: Thu, 15 Sep 2011 15:01:30 +0200 Subject: libxtrans libXmu libXext mesa pixman git update 15 sept 2011 --- mesalib/src/glsl/ast_to_hir.cpp | 39 +- mesalib/src/glsl/ir.cpp | 5 +- mesalib/src/glsl/ir.h | 8 - mesalib/src/glsl/ir_clone.cpp | 1 - mesalib/src/mesa/drivers/common/meta.c | 10 +- mesalib/src/mesa/drivers/dri/common/dri_util.c | 4 +- mesalib/src/mesa/drivers/windows/gdi/wmesa.c | 9 +- mesalib/src/mesa/main/attrib.c | 8 +- mesalib/src/mesa/main/blend.c | 1665 ++++++++++--------- mesalib/src/mesa/main/clear.c | 82 +- mesalib/src/mesa/main/colormac.h | 11 + mesalib/src/mesa/main/dd.h | 3 +- mesalib/src/mesa/main/get.c | 11 +- mesalib/src/mesa/main/image.c | 8 +- mesalib/src/mesa/main/mtypes.h | 32 +- mesalib/src/mesa/main/uniforms.c | 22 + mesalib/src/mesa/state_tracker/st_cb_clear.c | 14 +- mesalib/src/mesa/state_tracker/st_format.c | 5 +- mesalib/src/mesa/swrast/s_blend.c | 2024 ++++++++++++------------ mesalib/src/mesa/swrast/s_clear.c | 41 +- 20 files changed, 2006 insertions(+), 1996 deletions(-) (limited to 'mesalib/src') diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index 484786c5f..ce29d5a87 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -2120,25 +2120,6 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, var->depth_layout = ir_depth_layout_unchanged; else var->depth_layout = ir_depth_layout_none; - - /* From page 46 (page 52 of the PDF) of the GLSL ES specification: - * - * "Array variables are l-values and may be passed to parameters - * declared as out or inout. However, they may not be used as - * the target of an assignment." - * - * From page 32 (page 38 of the PDF) of the GLSL 1.10 spec: - * - * "Other binary or unary expressions, non-dereferenced arrays, - * function names, swizzles with repeated fields, and constants - * cannot be l-values." - * - * So we only mark 1.10 as non-lvalues, and check for array - * assignment in 100 specifically in do_assignment. - */ - if (var->type->is_array() && state->language_version != 110) { - var->array_lvalue = true; - } } /** @@ -2953,6 +2934,26 @@ ast_parameter_declarator::hir(exec_list *instructions, type = glsl_type::error_type; } + /* From page 39 (page 45 of the PDF) of the GLSL 1.10 spec: + * + * "When calling a function, expressions that do not evaluate to + * l-values cannot be passed to parameters declared as out or inout." + * + * From page 32 (page 38 of the PDF) of the GLSL 1.10 spec: + * + * "Other binary or unary expressions, non-dereferenced arrays, + * function names, swizzles with repeated fields, and constants + * cannot be l-values." + * + * So for GLSL 1.10, passing an array as an out or inout parameter is not + * allowed. This restriction is removed in GLSL 1.20, and in GLSL ES. + */ + if ((var->mode == ir_var_inout || var->mode == ir_var_out) + && type->is_array() && state->language_version == 110) { + _mesa_glsl_error(&loc, state, "Arrays cannot be out or inout parameters in GLSL 1.10"); + type = glsl_type::error_type; + } + instructions->push_tail(var); /* Parameter declarations do not have r-values. diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp index 41ed4f114..d6594cd9a 100644 --- a/mesalib/src/glsl/ir.cpp +++ b/mesalib/src/glsl/ir.cpp @@ -1105,9 +1105,6 @@ ir_dereference::is_lvalue() const if ((var == NULL) || var->read_only) return false; - if (this->type->is_array() && !var->array_lvalue) - return false; - /* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec: * * "Samplers cannot be treated as l-values; hence cannot be used @@ -1323,7 +1320,7 @@ ir_swizzle::variable_referenced() const ir_variable::ir_variable(const struct glsl_type *type, const char *name, ir_variable_mode mode) : max_array_access(0), read_only(false), centroid(false), invariant(false), - mode(mode), interpolation(ir_var_smooth), array_lvalue(false) + mode(mode), interpolation(ir_var_smooth) { this->ir_type = ir_type_variable; this->type = type; diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index 2e899f3ed..cc4e68002 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -345,14 +345,6 @@ public: */ unsigned interpolation:2; - /** - * Flag that the whole array is assignable - * - * In GLSL 1.20 and later whole arrays are assignable (and comparable for - * equality). This flag enables this behavior. - */ - unsigned array_lvalue:1; - /** * \name ARB_fragment_coord_conventions * @{ diff --git a/mesalib/src/glsl/ir_clone.cpp b/mesalib/src/glsl/ir_clone.cpp index f0757365d..c1befa95c 100644 --- a/mesalib/src/glsl/ir_clone.cpp +++ b/mesalib/src/glsl/ir_clone.cpp @@ -47,7 +47,6 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const var->centroid = this->centroid; var->invariant = this->invariant; var->interpolation = this->interpolation; - var->array_lvalue = this->array_lvalue; var->location = this->location; var->warn_extension = this->warn_extension; var->origin_upper_left = this->origin_upper_left; diff --git a/mesalib/src/mesa/drivers/common/meta.c b/mesalib/src/mesa/drivers/common/meta.c index 2ebcd35bd..482bd98a2 100644 --- a/mesalib/src/mesa/drivers/common/meta.c +++ b/mesalib/src/mesa/drivers/common/meta.c @@ -1569,10 +1569,10 @@ _mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers) /* vertex colors */ for (i = 0; i < 4; i++) { - verts[i].r = ctx->Color.ClearColorUnclamped[0]; - verts[i].g = ctx->Color.ClearColorUnclamped[1]; - verts[i].b = ctx->Color.ClearColorUnclamped[2]; - verts[i].a = ctx->Color.ClearColorUnclamped[3]; + verts[i].r = ctx->Color.ClearColor.f[0]; + verts[i].g = ctx->Color.ClearColor.f[1]; + verts[i].b = ctx->Color.ClearColor.f[2]; + verts[i].a = ctx->Color.ClearColor.f[3]; } /* upload new vertex data */ @@ -1679,7 +1679,7 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers) _mesa_UseProgramObjectARB(clear->ShaderProg); _mesa_Uniform4fvARB(clear->ColorLocation, 1, - ctx->Color.ClearColorUnclamped); + ctx->Color.ClearColor.f); _mesa_BindVertexArray(clear->ArrayObj); _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO); diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.c b/mesalib/src/mesa/drivers/dri/common/dri_util.c index 6d6401934..cdd413737 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.c +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.c @@ -816,8 +816,10 @@ driCreateNewScreen(int scrn, (void) loaderPrivate; - if (driDriverAPI.InitScreen == NULL) + if (driDriverAPI.InitScreen == NULL) { + __driUtilMessage("driver does not support DRI1"); return NULL; + } psp = calloc(1, sizeof *psp); if (!psp) diff --git a/mesalib/src/mesa/drivers/windows/gdi/wmesa.c b/mesalib/src/mesa/drivers/windows/gdi/wmesa.c index 35a150d06..14d15ed6c 100644 --- a/mesalib/src/mesa/drivers/windows/gdi/wmesa.c +++ b/mesalib/src/mesa/drivers/windows/gdi/wmesa.c @@ -249,14 +249,15 @@ static void wmesa_flush(struct gl_context *ctx) /* * Set the color used to clear the color buffer. */ -static void clear_color(struct gl_context *ctx, const GLfloat color[4]) +static void clear_color(struct gl_context *ctx, + const union gl_color_union color) { WMesaContext pwc = wmesa_context(ctx); GLubyte col[3]; - CLAMPED_FLOAT_TO_UBYTE(col[0], color[0]); - CLAMPED_FLOAT_TO_UBYTE(col[1], color[1]); - CLAMPED_FLOAT_TO_UBYTE(col[2], color[2]); + UNCLAMPED_FLOAT_TO_UBYTE(col[0], color.f[0]); + UNCLAMPED_FLOAT_TO_UBYTE(col[1], color.f[1]); + UNCLAMPED_FLOAT_TO_UBYTE(col[2], color.f[2]); pwc->clearColorRef = RGB(col[0], col[1], col[2]); DeleteObject(pwc->clearPen); DeleteObject(pwc->clearBrush); diff --git a/mesalib/src/mesa/main/attrib.c b/mesalib/src/mesa/main/attrib.c index 573100402..9767740a3 100644 --- a/mesalib/src/mesa/main/attrib.c +++ b/mesalib/src/mesa/main/attrib.c @@ -884,10 +884,10 @@ _mesa_PopAttrib(void) color = (const struct gl_colorbuffer_attrib *) attr->data; _mesa_ClearIndex((GLfloat) color->ClearIndex); - _mesa_ClearColor(color->ClearColorUnclamped[0], - color->ClearColorUnclamped[1], - color->ClearColorUnclamped[2], - color->ClearColorUnclamped[3]); + _mesa_ClearColor(color->ClearColor.f[0], + color->ClearColor.f[1], + color->ClearColor.f[2], + color->ClearColor.f[3]); _mesa_IndexMask(color->IndexMask); if (!ctx->Extensions.EXT_draw_buffers2) { _mesa_ColorMask((GLboolean) (color->ColorMask[0][0] != 0), diff --git a/mesalib/src/mesa/main/blend.c b/mesalib/src/mesa/main/blend.c index 94a457f58..4214a661b 100644 --- a/mesalib/src/mesa/main/blend.c +++ b/mesalib/src/mesa/main/blend.c @@ -1,833 +1,832 @@ -/** - * \file blend.c - * Blending operations. - */ - -/* - * Mesa 3-D graphics library - * Version: 6.5.1 - * - * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - - -#include "glheader.h" -#include "blend.h" -#include "context.h" -#include "enums.h" -#include "macros.h" -#include "mtypes.h" - - - -/** - * Check if given blend source factor is legal. - * \return GL_TRUE if legal, GL_FALSE otherwise. - */ -static GLboolean -legal_src_factor(const struct gl_context *ctx, GLenum factor) -{ - switch (factor) { - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - return ctx->Extensions.NV_blend_square; - case GL_ZERO: - case GL_ONE: - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_SRC_ALPHA_SATURATE: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Check if given blend destination factor is legal. - * \return GL_TRUE if legal, GL_FALSE otherwise. - */ -static GLboolean -legal_dst_factor(const struct gl_context *ctx, GLenum factor) -{ - switch (factor) { - case GL_DST_COLOR: - case GL_ONE_MINUS_DST_COLOR: - return ctx->Extensions.NV_blend_square; - case GL_ZERO: - case GL_ONE: - case GL_SRC_COLOR: - case GL_ONE_MINUS_SRC_COLOR: - case GL_SRC_ALPHA: - case GL_ONE_MINUS_SRC_ALPHA: - case GL_DST_ALPHA: - case GL_ONE_MINUS_DST_ALPHA: - case GL_CONSTANT_COLOR: - case GL_ONE_MINUS_CONSTANT_COLOR: - case GL_CONSTANT_ALPHA: - case GL_ONE_MINUS_CONSTANT_ALPHA: - return GL_TRUE; - default: - return GL_FALSE; - } -} - - -/** - * Check if src/dest RGB/A blend factors are legal. If not generate - * a GL error. - * \return GL_TRUE if factors are legal, GL_FALSE otherwise. - */ -static GLboolean -validate_blend_factors(struct gl_context *ctx, const char *func, - GLenum sfactorRGB, GLenum dfactorRGB, - GLenum sfactorA, GLenum dfactorA) -{ - if (!legal_src_factor(ctx, sfactorRGB)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(sfactorRGB = %s)", func, - _mesa_lookup_enum_by_nr(sfactorRGB)); - return GL_FALSE; - } - - if (!legal_dst_factor(ctx, dfactorRGB)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(dfactorRGB = %s)", func, - _mesa_lookup_enum_by_nr(dfactorRGB)); - return GL_FALSE; - } - - if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(sfactorA = %s)", func, - _mesa_lookup_enum_by_nr(sfactorA)); - return GL_FALSE; - } - - if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "%s(dfactorA = %s)", func, - _mesa_lookup_enum_by_nr(dfactorA)); - return GL_FALSE; - } - - return GL_TRUE; -} - - -/** - * Specify the blending operation. - * - * \param sfactor source factor operator. - * \param dfactor destination factor operator. - * - * \sa glBlendFunc, glBlendFuncSeparateEXT - */ -void GLAPIENTRY -_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) -{ - _mesa_BlendFuncSeparateEXT(sfactor, dfactor, sfactor, dfactor); -} - - -/** - * Set the separate blend source/dest factors for all draw buffers. - * - * \param sfactorRGB RGB source factor operator. - * \param dfactorRGB RGB destination factor operator. - * \param sfactorA alpha source factor operator. - * \param dfactorA alpha destination factor operator. - */ -void GLAPIENTRY -_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, - GLenum sfactorA, GLenum dfactorA ) -{ - GLuint buf, numBuffers; - GLboolean changed; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", - _mesa_lookup_enum_by_nr(sfactorRGB), - _mesa_lookup_enum_by_nr(dfactorRGB), - _mesa_lookup_enum_by_nr(sfactorA), - _mesa_lookup_enum_by_nr(dfactorA)); - - if (!validate_blend_factors(ctx, "glBlendFuncSeparate", - sfactorRGB, dfactorRGB, - sfactorA, dfactorA)) { - return; - } - - numBuffers = ctx->Extensions.ARB_draw_buffers_blend - ? ctx->Const.MaxDrawBuffers : 1; - - changed = GL_FALSE; - for (buf = 0; buf < numBuffers; buf++) { - if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB || - ctx->Color.Blend[buf].DstRGB != dfactorRGB || - ctx->Color.Blend[buf].SrcA != sfactorA || - ctx->Color.Blend[buf].DstA != dfactorA) { - changed = GL_TRUE; - break; - } - } - if (!changed) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - - for (buf = 0; buf < numBuffers; buf++) { - ctx->Color.Blend[buf].SrcRGB = sfactorRGB; - ctx->Color.Blend[buf].DstRGB = dfactorRGB; - ctx->Color.Blend[buf].SrcA = sfactorA; - ctx->Color.Blend[buf].DstA = dfactorA; - } - ctx->Color._BlendFuncPerBuffer = GL_FALSE; - - if (ctx->Driver.BlendFuncSeparate) { - ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB, - sfactorA, dfactorA); - } -} - - -#if _HAVE_FULL_GL - - -/** - * Set blend source/dest factors for one color buffer/target. - */ -void GLAPIENTRY -_mesa_BlendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) -{ - _mesa_BlendFuncSeparatei(buf, sfactor, dfactor, sfactor, dfactor); -} - - -/** - * Set separate blend source/dest factors for one color buffer/target. - */ -void GLAPIENTRY -_mesa_BlendFuncSeparatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB, - GLenum sfactorA, GLenum dfactorA) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.ARB_draw_buffers_blend) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()"); - return; - } - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", - buf); - return; - } - - if (!validate_blend_factors(ctx, "glBlendFuncSeparatei", - sfactorRGB, dfactorRGB, - sfactorA, dfactorA)) { - return; - } - - if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB && - ctx->Color.Blend[buf].DstRGB == dfactorRGB && - ctx->Color.Blend[buf].SrcA == sfactorA && - ctx->Color.Blend[buf].DstA == dfactorA) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - - ctx->Color.Blend[buf].SrcRGB = sfactorRGB; - ctx->Color.Blend[buf].DstRGB = dfactorRGB; - ctx->Color.Blend[buf].SrcA = sfactorA; - ctx->Color.Blend[buf].DstA = dfactorA; - ctx->Color._BlendFuncPerBuffer = GL_TRUE; - - if (ctx->Driver.BlendFuncSeparatei) { - ctx->Driver.BlendFuncSeparatei(ctx, buf, sfactorRGB, dfactorRGB, - sfactorA, dfactorA); - } -} - - -/** - * Check if given blend equation is legal. - * \return GL_TRUE if legal, GL_FALSE otherwise. - */ -static GLboolean -legal_blend_equation(const struct gl_context *ctx, - GLenum mode, GLboolean is_separate) -{ - switch (mode) { - case GL_FUNC_ADD: - return GL_TRUE; - case GL_MIN: - case GL_MAX: - return ctx->Extensions.EXT_blend_minmax; - case GL_LOGIC_OP: - /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter. - */ - return ctx->Extensions.EXT_blend_logic_op && !is_separate; - case GL_FUNC_SUBTRACT: - case GL_FUNC_REVERSE_SUBTRACT: - return ctx->Extensions.EXT_blend_subtract; - default: - return GL_FALSE; - } -} - - -/* This is really an extension function! */ -void GLAPIENTRY -_mesa_BlendEquation( GLenum mode ) -{ - GLuint buf, numBuffers; - GLboolean changed; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquation(%s)\n", - _mesa_lookup_enum_by_nr(mode)); - - if (!legal_blend_equation(ctx, mode, GL_FALSE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); - return; - } - - numBuffers = ctx->Extensions.ARB_draw_buffers_blend - ? ctx->Const.MaxDrawBuffers : 1; - - changed = GL_FALSE; - for (buf = 0; buf < numBuffers; buf++) { - if (ctx->Color.Blend[buf].EquationRGB != mode || - ctx->Color.Blend[buf].EquationA != mode) { - changed = GL_TRUE; - break; - } - } - if (!changed) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - for (buf = 0; buf < numBuffers; buf++) { - ctx->Color.Blend[buf].EquationRGB = mode; - ctx->Color.Blend[buf].EquationA = mode; - } - ctx->Color._BlendEquationPerBuffer = GL_FALSE; - - if (ctx->Driver.BlendEquationSeparate) - (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); -} - - -/** - * Set blend equation for one color buffer/target. - */ -void GLAPIENTRY -_mesa_BlendEquationi(GLuint buf, GLenum mode) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", - buf, _mesa_lookup_enum_by_nr(mode)); - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", - buf); - return; - } - - if (!legal_blend_equation(ctx, mode, GL_FALSE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); - return; - } - - if (ctx->Color.Blend[buf].EquationRGB == mode && - ctx->Color.Blend[buf].EquationA == mode) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.Blend[buf].EquationRGB = mode; - ctx->Color.Blend[buf].EquationA = mode; - ctx->Color._BlendEquationPerBuffer = GL_TRUE; - - if (ctx->Driver.BlendEquationSeparatei) - ctx->Driver.BlendEquationSeparatei(ctx, buf, mode, mode); -} - - -void GLAPIENTRY -_mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA ) -{ - GLuint buf, numBuffers; - GLboolean changed; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", - _mesa_lookup_enum_by_nr(modeRGB), - _mesa_lookup_enum_by_nr(modeA)); - - if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlendEquationSeparateEXT not supported by driver"); - return; - } - - if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); - return; - } - - if (!legal_blend_equation(ctx, modeA, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); - return; - } - - numBuffers = ctx->Extensions.ARB_draw_buffers_blend - ? ctx->Const.MaxDrawBuffers : 1; - - changed = GL_FALSE; - for (buf = 0; buf < numBuffers; buf++) { - if (ctx->Color.Blend[buf].EquationRGB != modeRGB || - ctx->Color.Blend[buf].EquationA != modeA) { - changed = GL_TRUE; - break; - } - } - if (!changed) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - for (buf = 0; buf < numBuffers; buf++) { - ctx->Color.Blend[buf].EquationRGB = modeRGB; - ctx->Color.Blend[buf].EquationA = modeA; - } - ctx->Color._BlendEquationPerBuffer = GL_FALSE; - - if (ctx->Driver.BlendEquationSeparate) - ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); -} - - -/** - * Set separate blend equations for one color buffer/target. - */ -void GLAPIENTRY -_mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, - _mesa_lookup_enum_by_nr(modeRGB), - _mesa_lookup_enum_by_nr(modeA)); - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", - buf); - return; - } - - if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); - return; - } - - if (!legal_blend_equation(ctx, modeA, GL_TRUE)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); - return; - } - - if (ctx->Color.Blend[buf].EquationRGB == modeRGB && - ctx->Color.Blend[buf].EquationA == modeA) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.Blend[buf].EquationRGB = modeRGB; - ctx->Color.Blend[buf].EquationA = modeA; - ctx->Color._BlendEquationPerBuffer = GL_TRUE; - - if (ctx->Driver.BlendEquationSeparatei) - ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA); -} - - - -#endif /* _HAVE_FULL_GL */ - - -/** - * Set the blending color. - * - * \param red red color component. - * \param green green color component. - * \param blue blue color component. - * \param alpha alpha color component. - * - * \sa glBlendColor(). - * - * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a - * change, flushes the vertices and notifies the driver via - * dd_function_table::BlendColor callback. - */ -void GLAPIENTRY -_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) -{ - GLfloat tmp[4]; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - tmp[0] = red; - tmp[1] = green; - tmp[2] = blue; - tmp[3] = alpha; - - if (TEST_EQ_4V(tmp, ctx->Color.BlendColorUnclamped)) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - COPY_4FV( ctx->Color.BlendColorUnclamped, tmp ); - - ctx->Color.BlendColor[0] = CLAMP(tmp[0], 0.0F, 1.0F); - ctx->Color.BlendColor[1] = CLAMP(tmp[1], 0.0F, 1.0F); - ctx->Color.BlendColor[2] = CLAMP(tmp[2], 0.0F, 1.0F); - ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F); - - if (ctx->Driver.BlendColor) - (*ctx->Driver.BlendColor)(ctx, ctx->Color.BlendColor); -} - - -/** - * Specify the alpha test function. - * - * \param func alpha comparison function. - * \param ref reference value. - * - * Verifies the parameters and updates gl_colorbuffer_attrib. - * On a change, flushes the vertices and notifies the driver via - * dd_function_table::AlphaFunc callback. - */ -void GLAPIENTRY -_mesa_AlphaFunc( GLenum func, GLclampf ref ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", - _mesa_lookup_enum_by_nr(func), ref); - - switch (func) { - case GL_NEVER: - case GL_LESS: - case GL_EQUAL: - case GL_LEQUAL: - case GL_GREATER: - case GL_NOTEQUAL: - case GL_GEQUAL: - case GL_ALWAYS: - if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref) - return; /* no change */ - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.AlphaFunc = func; - ctx->Color.AlphaRefUnclamped = ref; - ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F); - - if (ctx->Driver.AlphaFunc) - ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef); - return; - - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); - return; - } -} - - -/** - * Specify a logic pixel operation for color index rendering. - * - * \param opcode operation. - * - * Verifies that \p opcode is a valid enum and updates -gl_colorbuffer_attrib::LogicOp. - * On a change, flushes the vertices and notifies the driver via the - * dd_function_table::LogicOpcode callback. - */ -void GLAPIENTRY -_mesa_LogicOp( GLenum opcode ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_lookup_enum_by_nr(opcode)); - - switch (opcode) { - case GL_CLEAR: - case GL_SET: - case GL_COPY: - case GL_COPY_INVERTED: - case GL_NOOP: - case GL_INVERT: - case GL_AND: - case GL_NAND: - case GL_OR: - case GL_NOR: - case GL_XOR: - case GL_EQUIV: - case GL_AND_REVERSE: - case GL_AND_INVERTED: - case GL_OR_REVERSE: - case GL_OR_INVERTED: - break; - default: - _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); - return; - } - - if (ctx->Color.LogicOp == opcode) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.LogicOp = opcode; - - if (ctx->Driver.LogicOpcode) - ctx->Driver.LogicOpcode( ctx, opcode ); -} - -#if _HAVE_FULL_GL -void GLAPIENTRY -_mesa_IndexMask( GLuint mask ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (ctx->Color.IndexMask == mask) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.IndexMask = mask; -} -#endif - - -/** - * Enable or disable writing of frame buffer color components. - * - * \param red whether to mask writing of the red color component. - * \param green whether to mask writing of the green color component. - * \param blue whether to mask writing of the blue color component. - * \param alpha whether to mask writing of the alpha color component. - * - * \sa glColorMask(). - * - * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a - * change, flushes the vertices and notifies the driver via the - * dd_function_table::ColorMask callback. - */ -void GLAPIENTRY -_mesa_ColorMask( GLboolean red, GLboolean green, - GLboolean blue, GLboolean alpha ) -{ - GET_CURRENT_CONTEXT(ctx); - GLubyte tmp[4]; - GLuint i; - GLboolean flushed; - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n", - red, green, blue, alpha); - - /* Shouldn't have any information about channel depth in core mesa - * -- should probably store these as the native booleans: - */ - tmp[RCOMP] = red ? 0xff : 0x0; - tmp[GCOMP] = green ? 0xff : 0x0; - tmp[BCOMP] = blue ? 0xff : 0x0; - tmp[ACOMP] = alpha ? 0xff : 0x0; - - flushed = GL_FALSE; - for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { - if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { - if (!flushed) { - FLUSH_VERTICES(ctx, _NEW_COLOR); - } - flushed = GL_TRUE; - COPY_4UBV(ctx->Color.ColorMask[i], tmp); - } - } - - if (ctx->Driver.ColorMask) - ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); -} - - -/** - * For GL_EXT_draw_buffers2 and GL3 - */ -void GLAPIENTRY -_mesa_ColorMaskIndexed( GLuint buf, GLboolean red, GLboolean green, - GLboolean blue, GLboolean alpha ) -{ - GLubyte tmp[4]; - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n", - buf, red, green, blue, alpha); - - if (buf >= ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf); - return; - } - - /* Shouldn't have any information about channel depth in core mesa - * -- should probably store these as the native booleans: - */ - tmp[RCOMP] = red ? 0xff : 0x0; - tmp[GCOMP] = green ? 0xff : 0x0; - tmp[BCOMP] = blue ? 0xff : 0x0; - tmp[ACOMP] = alpha ? 0xff : 0x0; - - if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) - return; - - FLUSH_VERTICES(ctx, _NEW_COLOR); - COPY_4UBV(ctx->Color.ColorMask[buf], tmp); - - if (ctx->Driver.ColorMaskIndexed) - ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha); -} - - -void GLAPIENTRY -_mesa_ClampColorARB(GLenum target, GLenum clamp) -{ - GET_CURRENT_CONTEXT(ctx); - - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); - return; - } - - switch (target) { - case GL_CLAMP_VERTEX_COLOR_ARB: - FLUSH_VERTICES(ctx, _NEW_LIGHT); - ctx->Light.ClampVertexColor = clamp; - break; - case GL_CLAMP_FRAGMENT_COLOR_ARB: - FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP); - ctx->Color.ClampFragmentColor = clamp; - break; - case GL_CLAMP_READ_COLOR_ARB: - FLUSH_VERTICES(ctx, _NEW_COLOR); - ctx->Color.ClampReadColor = clamp; - break; - default: - _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)"); - return; - } -} - - - - -/**********************************************************************/ -/** \name Initialization */ -/*@{*/ - -/** - * Initialization of the context's Color attribute group. - * - * \param ctx GL context. - * - * Initializes the related fields in the context color attribute group, - * __struct gl_contextRec::Color. - */ -void _mesa_init_color( struct gl_context * ctx ) -{ - GLuint i; - - /* Color buffer group */ - ctx->Color.IndexMask = ~0u; - memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); - ctx->Color.ClearIndex = 0; - ASSIGN_4V( ctx->Color.ClearColor, 0, 0, 0, 0 ); - ASSIGN_4V( ctx->Color.ClearColorUnclamped, 0, 0, 0, 0 ); - ctx->Color.AlphaEnabled = GL_FALSE; - ctx->Color.AlphaFunc = GL_ALWAYS; - ctx->Color.AlphaRef = 0; - ctx->Color.BlendEnabled = 0x0; - for (i = 0; i < Elements(ctx->Color.Blend); i++) { - ctx->Color.Blend[i].SrcRGB = GL_ONE; - ctx->Color.Blend[i].DstRGB = GL_ZERO; - ctx->Color.Blend[i].SrcA = GL_ONE; - ctx->Color.Blend[i].DstA = GL_ZERO; - ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; - ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; - } - ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); - ASSIGN_4V( ctx->Color.BlendColorUnclamped, 0.0, 0.0, 0.0, 0.0 ); - ctx->Color.IndexLogicOpEnabled = GL_FALSE; - ctx->Color.ColorLogicOpEnabled = GL_FALSE; - ctx->Color._LogicOpEnabled = GL_FALSE; - ctx->Color.LogicOp = GL_COPY; - ctx->Color.DitherFlag = GL_TRUE; - - if (ctx->Visual.doubleBufferMode) { - ctx->Color.DrawBuffer[0] = GL_BACK; - } - else { - ctx->Color.DrawBuffer[0] = GL_FRONT; - } - - ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; - ctx->Color._ClampFragmentColor = GL_TRUE; - ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; - ctx->Color._ClampReadColor = GL_TRUE; -} - -/*@}*/ +/** + * \file blend.c + * Blending operations. + */ + +/* + * Mesa 3-D graphics library + * Version: 6.5.1 + * + * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + + +#include "glheader.h" +#include "blend.h" +#include "context.h" +#include "enums.h" +#include "macros.h" +#include "mtypes.h" + + + +/** + * Check if given blend source factor is legal. + * \return GL_TRUE if legal, GL_FALSE otherwise. + */ +static GLboolean +legal_src_factor(const struct gl_context *ctx, GLenum factor) +{ + switch (factor) { + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + return ctx->Extensions.NV_blend_square; + case GL_ZERO: + case GL_ONE: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_SRC_ALPHA_SATURATE: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Check if given blend destination factor is legal. + * \return GL_TRUE if legal, GL_FALSE otherwise. + */ +static GLboolean +legal_dst_factor(const struct gl_context *ctx, GLenum factor) +{ + switch (factor) { + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + return ctx->Extensions.NV_blend_square; + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +/** + * Check if src/dest RGB/A blend factors are legal. If not generate + * a GL error. + * \return GL_TRUE if factors are legal, GL_FALSE otherwise. + */ +static GLboolean +validate_blend_factors(struct gl_context *ctx, const char *func, + GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA) +{ + if (!legal_src_factor(ctx, sfactorRGB)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(sfactorRGB = %s)", func, + _mesa_lookup_enum_by_nr(sfactorRGB)); + return GL_FALSE; + } + + if (!legal_dst_factor(ctx, dfactorRGB)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(dfactorRGB = %s)", func, + _mesa_lookup_enum_by_nr(dfactorRGB)); + return GL_FALSE; + } + + if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(sfactorA = %s)", func, + _mesa_lookup_enum_by_nr(sfactorA)); + return GL_FALSE; + } + + if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "%s(dfactorA = %s)", func, + _mesa_lookup_enum_by_nr(dfactorA)); + return GL_FALSE; + } + + return GL_TRUE; +} + + +/** + * Specify the blending operation. + * + * \param sfactor source factor operator. + * \param dfactor destination factor operator. + * + * \sa glBlendFunc, glBlendFuncSeparateEXT + */ +void GLAPIENTRY +_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) +{ + _mesa_BlendFuncSeparateEXT(sfactor, dfactor, sfactor, dfactor); +} + + +/** + * Set the separate blend source/dest factors for all draw buffers. + * + * \param sfactorRGB RGB source factor operator. + * \param dfactorRGB RGB destination factor operator. + * \param sfactorA alpha source factor operator. + * \param dfactorA alpha destination factor operator. + */ +void GLAPIENTRY +_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA ) +{ + GLuint buf, numBuffers; + GLboolean changed; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", + _mesa_lookup_enum_by_nr(sfactorRGB), + _mesa_lookup_enum_by_nr(dfactorRGB), + _mesa_lookup_enum_by_nr(sfactorA), + _mesa_lookup_enum_by_nr(dfactorA)); + + if (!validate_blend_factors(ctx, "glBlendFuncSeparate", + sfactorRGB, dfactorRGB, + sfactorA, dfactorA)) { + return; + } + + numBuffers = ctx->Extensions.ARB_draw_buffers_blend + ? ctx->Const.MaxDrawBuffers : 1; + + changed = GL_FALSE; + for (buf = 0; buf < numBuffers; buf++) { + if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB || + ctx->Color.Blend[buf].DstRGB != dfactorRGB || + ctx->Color.Blend[buf].SrcA != sfactorA || + ctx->Color.Blend[buf].DstA != dfactorA) { + changed = GL_TRUE; + break; + } + } + if (!changed) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + + for (buf = 0; buf < numBuffers; buf++) { + ctx->Color.Blend[buf].SrcRGB = sfactorRGB; + ctx->Color.Blend[buf].DstRGB = dfactorRGB; + ctx->Color.Blend[buf].SrcA = sfactorA; + ctx->Color.Blend[buf].DstA = dfactorA; + } + ctx->Color._BlendFuncPerBuffer = GL_FALSE; + + if (ctx->Driver.BlendFuncSeparate) { + ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB, + sfactorA, dfactorA); + } +} + + +#if _HAVE_FULL_GL + + +/** + * Set blend source/dest factors for one color buffer/target. + */ +void GLAPIENTRY +_mesa_BlendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) +{ + _mesa_BlendFuncSeparatei(buf, sfactor, dfactor, sfactor, dfactor); +} + + +/** + * Set separate blend source/dest factors for one color buffer/target. + */ +void GLAPIENTRY +_mesa_BlendFuncSeparatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.ARB_draw_buffers_blend) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()"); + return; + } + + if (buf >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", + buf); + return; + } + + if (!validate_blend_factors(ctx, "glBlendFuncSeparatei", + sfactorRGB, dfactorRGB, + sfactorA, dfactorA)) { + return; + } + + if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB && + ctx->Color.Blend[buf].DstRGB == dfactorRGB && + ctx->Color.Blend[buf].SrcA == sfactorA && + ctx->Color.Blend[buf].DstA == dfactorA) + return; /* no change */ + + FLUSH_VERTICES(ctx, _NEW_COLOR); + + ctx->Color.Blend[buf].SrcRGB = sfactorRGB; + ctx->Color.Blend[buf].DstRGB = dfactorRGB; + ctx->Color.Blend[buf].SrcA = sfactorA; + ctx->Color.Blend[buf].DstA = dfactorA; + ctx->Color._BlendFuncPerBuffer = GL_TRUE; + + if (ctx->Driver.BlendFuncSeparatei) { + ctx->Driver.BlendFuncSeparatei(ctx, buf, sfactorRGB, dfactorRGB, + sfactorA, dfactorA); + } +} + + +/** + * Check if given blend equation is legal. + * \return GL_TRUE if legal, GL_FALSE otherwise. + */ +static GLboolean +legal_blend_equation(const struct gl_context *ctx, + GLenum mode, GLboolean is_separate) +{ + switch (mode) { + case GL_FUNC_ADD: + return GL_TRUE; + case GL_MIN: + case GL_MAX: + return ctx->Extensions.EXT_blend_minmax; + case GL_LOGIC_OP: + /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter. + */ + return ctx->Extensions.EXT_blend_logic_op && !is_separate; + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + return ctx->Extensions.EXT_blend_subtract; + default: + return GL_FALSE; + } +} + + +/* This is really an extension function! */ +void GLAPIENTRY +_mesa_BlendEquation( GLenum mode ) +{ + GLuint buf, numBuffers; + GLboolean changed; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBlendEquation(%s)\n", + _mesa_lookup_enum_by_nr(mode)); + + if (!legal_blend_equation(ctx, mode, GL_FALSE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); + return; + } + + numBuffers = ctx->Extensions.ARB_draw_buffers_blend + ? ctx->Const.MaxDrawBuffers : 1; + + changed = GL_FALSE; + for (buf = 0; buf < numBuffers; buf++) { + if (ctx->Color.Blend[buf].EquationRGB != mode || + ctx->Color.Blend[buf].EquationA != mode) { + changed = GL_TRUE; + break; + } + } + if (!changed) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + for (buf = 0; buf < numBuffers; buf++) { + ctx->Color.Blend[buf].EquationRGB = mode; + ctx->Color.Blend[buf].EquationA = mode; + } + ctx->Color._BlendEquationPerBuffer = GL_FALSE; + + if (ctx->Driver.BlendEquationSeparate) + (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); +} + + +/** + * Set blend equation for one color buffer/target. + */ +void GLAPIENTRY +_mesa_BlendEquationi(GLuint buf, GLenum mode) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", + buf, _mesa_lookup_enum_by_nr(mode)); + + if (buf >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", + buf); + return; + } + + if (!legal_blend_equation(ctx, mode, GL_FALSE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); + return; + } + + if (ctx->Color.Blend[buf].EquationRGB == mode && + ctx->Color.Blend[buf].EquationA == mode) + return; /* no change */ + + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.Blend[buf].EquationRGB = mode; + ctx->Color.Blend[buf].EquationA = mode; + ctx->Color._BlendEquationPerBuffer = GL_TRUE; + + if (ctx->Driver.BlendEquationSeparatei) + ctx->Driver.BlendEquationSeparatei(ctx, buf, mode, mode); +} + + +void GLAPIENTRY +_mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA ) +{ + GLuint buf, numBuffers; + GLboolean changed; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", + _mesa_lookup_enum_by_nr(modeRGB), + _mesa_lookup_enum_by_nr(modeA)); + + if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlendEquationSeparateEXT not supported by driver"); + return; + } + + if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); + return; + } + + if (!legal_blend_equation(ctx, modeA, GL_TRUE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); + return; + } + + numBuffers = ctx->Extensions.ARB_draw_buffers_blend + ? ctx->Const.MaxDrawBuffers : 1; + + changed = GL_FALSE; + for (buf = 0; buf < numBuffers; buf++) { + if (ctx->Color.Blend[buf].EquationRGB != modeRGB || + ctx->Color.Blend[buf].EquationA != modeA) { + changed = GL_TRUE; + break; + } + } + if (!changed) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + for (buf = 0; buf < numBuffers; buf++) { + ctx->Color.Blend[buf].EquationRGB = modeRGB; + ctx->Color.Blend[buf].EquationA = modeA; + } + ctx->Color._BlendEquationPerBuffer = GL_FALSE; + + if (ctx->Driver.BlendEquationSeparate) + ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); +} + + +/** + * Set separate blend equations for one color buffer/target. + */ +void GLAPIENTRY +_mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, + _mesa_lookup_enum_by_nr(modeRGB), + _mesa_lookup_enum_by_nr(modeA)); + + if (buf >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", + buf); + return; + } + + if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); + return; + } + + if (!legal_blend_equation(ctx, modeA, GL_TRUE)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); + return; + } + + if (ctx->Color.Blend[buf].EquationRGB == modeRGB && + ctx->Color.Blend[buf].EquationA == modeA) + return; /* no change */ + + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.Blend[buf].EquationRGB = modeRGB; + ctx->Color.Blend[buf].EquationA = modeA; + ctx->Color._BlendEquationPerBuffer = GL_TRUE; + + if (ctx->Driver.BlendEquationSeparatei) + ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA); +} + + + +#endif /* _HAVE_FULL_GL */ + + +/** + * Set the blending color. + * + * \param red red color component. + * \param green green color component. + * \param blue blue color component. + * \param alpha alpha color component. + * + * \sa glBlendColor(). + * + * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a + * change, flushes the vertices and notifies the driver via + * dd_function_table::BlendColor callback. + */ +void GLAPIENTRY +_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) +{ + GLfloat tmp[4]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + tmp[0] = red; + tmp[1] = green; + tmp[2] = blue; + tmp[3] = alpha; + + if (TEST_EQ_4V(tmp, ctx->Color.BlendColorUnclamped)) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + COPY_4FV( ctx->Color.BlendColorUnclamped, tmp ); + + ctx->Color.BlendColor[0] = CLAMP(tmp[0], 0.0F, 1.0F); + ctx->Color.BlendColor[1] = CLAMP(tmp[1], 0.0F, 1.0F); + ctx->Color.BlendColor[2] = CLAMP(tmp[2], 0.0F, 1.0F); + ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F); + + if (ctx->Driver.BlendColor) + (*ctx->Driver.BlendColor)(ctx, ctx->Color.BlendColor); +} + + +/** + * Specify the alpha test function. + * + * \param func alpha comparison function. + * \param ref reference value. + * + * Verifies the parameters and updates gl_colorbuffer_attrib. + * On a change, flushes the vertices and notifies the driver via + * dd_function_table::AlphaFunc callback. + */ +void GLAPIENTRY +_mesa_AlphaFunc( GLenum func, GLclampf ref ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", + _mesa_lookup_enum_by_nr(func), ref); + + switch (func) { + case GL_NEVER: + case GL_LESS: + case GL_EQUAL: + case GL_LEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + case GL_GEQUAL: + case GL_ALWAYS: + if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref) + return; /* no change */ + + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.AlphaFunc = func; + ctx->Color.AlphaRefUnclamped = ref; + ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F); + + if (ctx->Driver.AlphaFunc) + ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef); + return; + + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); + return; + } +} + + +/** + * Specify a logic pixel operation for color index rendering. + * + * \param opcode operation. + * + * Verifies that \p opcode is a valid enum and updates +gl_colorbuffer_attrib::LogicOp. + * On a change, flushes the vertices and notifies the driver via the + * dd_function_table::LogicOpcode callback. + */ +void GLAPIENTRY +_mesa_LogicOp( GLenum opcode ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_lookup_enum_by_nr(opcode)); + + switch (opcode) { + case GL_CLEAR: + case GL_SET: + case GL_COPY: + case GL_COPY_INVERTED: + case GL_NOOP: + case GL_INVERT: + case GL_AND: + case GL_NAND: + case GL_OR: + case GL_NOR: + case GL_XOR: + case GL_EQUIV: + case GL_AND_REVERSE: + case GL_AND_INVERTED: + case GL_OR_REVERSE: + case GL_OR_INVERTED: + break; + default: + _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); + return; + } + + if (ctx->Color.LogicOp == opcode) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.LogicOp = opcode; + + if (ctx->Driver.LogicOpcode) + ctx->Driver.LogicOpcode( ctx, opcode ); +} + +#if _HAVE_FULL_GL +void GLAPIENTRY +_mesa_IndexMask( GLuint mask ) +{ + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (ctx->Color.IndexMask == mask) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.IndexMask = mask; +} +#endif + + +/** + * Enable or disable writing of frame buffer color components. + * + * \param red whether to mask writing of the red color component. + * \param green whether to mask writing of the green color component. + * \param blue whether to mask writing of the blue color component. + * \param alpha whether to mask writing of the alpha color component. + * + * \sa glColorMask(). + * + * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a + * change, flushes the vertices and notifies the driver via the + * dd_function_table::ColorMask callback. + */ +void GLAPIENTRY +_mesa_ColorMask( GLboolean red, GLboolean green, + GLboolean blue, GLboolean alpha ) +{ + GET_CURRENT_CONTEXT(ctx); + GLubyte tmp[4]; + GLuint i; + GLboolean flushed; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n", + red, green, blue, alpha); + + /* Shouldn't have any information about channel depth in core mesa + * -- should probably store these as the native booleans: + */ + tmp[RCOMP] = red ? 0xff : 0x0; + tmp[GCOMP] = green ? 0xff : 0x0; + tmp[BCOMP] = blue ? 0xff : 0x0; + tmp[ACOMP] = alpha ? 0xff : 0x0; + + flushed = GL_FALSE; + for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { + if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { + if (!flushed) { + FLUSH_VERTICES(ctx, _NEW_COLOR); + } + flushed = GL_TRUE; + COPY_4UBV(ctx->Color.ColorMask[i], tmp); + } + } + + if (ctx->Driver.ColorMask) + ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); +} + + +/** + * For GL_EXT_draw_buffers2 and GL3 + */ +void GLAPIENTRY +_mesa_ColorMaskIndexed( GLuint buf, GLboolean red, GLboolean green, + GLboolean blue, GLboolean alpha ) +{ + GLubyte tmp[4]; + GET_CURRENT_CONTEXT(ctx); + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n", + buf, red, green, blue, alpha); + + if (buf >= ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf); + return; + } + + /* Shouldn't have any information about channel depth in core mesa + * -- should probably store these as the native booleans: + */ + tmp[RCOMP] = red ? 0xff : 0x0; + tmp[GCOMP] = green ? 0xff : 0x0; + tmp[BCOMP] = blue ? 0xff : 0x0; + tmp[ACOMP] = alpha ? 0xff : 0x0; + + if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) + return; + + FLUSH_VERTICES(ctx, _NEW_COLOR); + COPY_4UBV(ctx->Color.ColorMask[buf], tmp); + + if (ctx->Driver.ColorMaskIndexed) + ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha); +} + + +void GLAPIENTRY +_mesa_ClampColorARB(GLenum target, GLenum clamp) +{ + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { + _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); + return; + } + + switch (target) { + case GL_CLAMP_VERTEX_COLOR_ARB: + FLUSH_VERTICES(ctx, _NEW_LIGHT); + ctx->Light.ClampVertexColor = clamp; + break; + case GL_CLAMP_FRAGMENT_COLOR_ARB: + FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP); + ctx->Color.ClampFragmentColor = clamp; + break; + case GL_CLAMP_READ_COLOR_ARB: + FLUSH_VERTICES(ctx, _NEW_COLOR); + ctx->Color.ClampReadColor = clamp; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)"); + return; + } +} + + + + +/**********************************************************************/ +/** \name Initialization */ +/*@{*/ + +/** + * Initialization of the context's Color attribute group. + * + * \param ctx GL context. + * + * Initializes the related fields in the context color attribute group, + * __struct gl_contextRec::Color. + */ +void _mesa_init_color( struct gl_context * ctx ) +{ + GLuint i; + + /* Color buffer group */ + ctx->Color.IndexMask = ~0u; + memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); + ctx->Color.ClearIndex = 0; + ASSIGN_4V( ctx->Color.ClearColor.f, 0, 0, 0, 0 ); + ctx->Color.AlphaEnabled = GL_FALSE; + ctx->Color.AlphaFunc = GL_ALWAYS; + ctx->Color.AlphaRef = 0; + ctx->Color.BlendEnabled = 0x0; + for (i = 0; i < Elements(ctx->Color.Blend); i++) { + ctx->Color.Blend[i].SrcRGB = GL_ONE; + ctx->Color.Blend[i].DstRGB = GL_ZERO; + ctx->Color.Blend[i].SrcA = GL_ONE; + ctx->Color.Blend[i].DstA = GL_ZERO; + ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; + ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; + } + ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); + ASSIGN_4V( ctx->Color.BlendColorUnclamped, 0.0, 0.0, 0.0, 0.0 ); + ctx->Color.IndexLogicOpEnabled = GL_FALSE; + ctx->Color.ColorLogicOpEnabled = GL_FALSE; + ctx->Color._LogicOpEnabled = GL_FALSE; + ctx->Color.LogicOp = GL_COPY; + ctx->Color.DitherFlag = GL_TRUE; + + if (ctx->Visual.doubleBufferMode) { + ctx->Color.DrawBuffer[0] = GL_BACK; + } + else { + ctx->Color.DrawBuffer[0] = GL_FRONT; + } + + ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; + ctx->Color._ClampFragmentColor = GL_TRUE; + ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; + ctx->Color._ClampReadColor = GL_TRUE; +} + +/*@}*/ diff --git a/mesalib/src/mesa/main/clear.c b/mesalib/src/mesa/main/clear.c index fa95e4522..301fe694c 100644 --- a/mesalib/src/mesa/main/clear.c +++ b/mesalib/src/mesa/main/clear.c @@ -83,16 +83,11 @@ _mesa_ClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) tmp[2] = blue; tmp[3] = alpha; - if (TEST_EQ_4V(tmp, ctx->Color.ClearColorUnclamped)) + if (TEST_EQ_4V(tmp, ctx->Color.ClearColor.f)) return; /* no change */ FLUSH_VERTICES(ctx, _NEW_COLOR); - COPY_4V(ctx->Color.ClearColorUnclamped, tmp); - - ctx->Color.ClearColor[0] = CLAMP(tmp[0], 0.0F, 1.0F); - ctx->Color.ClearColor[1] = CLAMP(tmp[1], 0.0F, 1.0F); - ctx->Color.ClearColor[2] = CLAMP(tmp[2], 0.0F, 1.0F); - ctx->Color.ClearColor[3] = CLAMP(tmp[3], 0.0F, 1.0F); + COPY_4V(ctx->Color.ClearColor.f, tmp); if (ctx->Driver.ClearColor) { /* it's OK to call glClearColor in CI mode but it should be a NOP */ @@ -110,25 +105,22 @@ _mesa_ClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) void GLAPIENTRY _mesa_ClearColorIiEXT(GLint r, GLint g, GLint b, GLint a) { - GLfloat tmp[4]; + GLint tmp[4]; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); - tmp[0] = (GLfloat) r; - tmp[1] = (GLfloat) g; - tmp[2] = (GLfloat) b; - tmp[3] = (GLfloat) a; + tmp[0] = r; + tmp[1] = g; + tmp[2] = b; + tmp[3] = a; - if (TEST_EQ_4V(tmp, ctx->Color.ClearColor)) + if (TEST_EQ_4V(tmp, ctx->Color.ClearColor.i)) return; /* no change */ FLUSH_VERTICES(ctx, _NEW_COLOR); + COPY_4V(ctx->Color.ClearColor.i, tmp); - /* XXX we should eventually have a float/int/uint union for - * the ctx->Color.ClearColor state. - */ - COPY_4V(ctx->Color.ClearColor, tmp); - + /* these should be NOP calls for drivers supporting EXT_texture_integer */ if (ctx->Driver.ClearColor) { ctx->Driver.ClearColor(ctx, ctx->Color.ClearColor); } @@ -141,25 +133,22 @@ _mesa_ClearColorIiEXT(GLint r, GLint g, GLint b, GLint a) void GLAPIENTRY _mesa_ClearColorIuiEXT(GLuint r, GLuint g, GLuint b, GLuint a) { - GLfloat tmp[4]; + GLuint tmp[4]; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); - tmp[0] = (GLfloat) r; - tmp[1] = (GLfloat) g; - tmp[2] = (GLfloat) b; - tmp[3] = (GLfloat) a; + tmp[0] = r; + tmp[1] = g; + tmp[2] = b; + tmp[3] = a; - if (TEST_EQ_4V(tmp, ctx->Color.ClearColor)) + if (TEST_EQ_4V(tmp, ctx->Color.ClearColor.ui)) return; /* no change */ FLUSH_VERTICES(ctx, _NEW_COLOR); + COPY_4V(ctx->Color.ClearColor.ui, tmp); - /* XXX we should eventually have a float/int/uint union for - * the ctx->Color.ClearColor state. - */ - COPY_4V(ctx->Color.ClearColor, tmp); - + /* these should be NOP calls for drivers supporting EXT_texture_integer */ if (ctx->Driver.ClearColor) { ctx->Driver.ClearColor(ctx, ctx->Color.ClearColor); } @@ -364,21 +353,18 @@ _mesa_ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value) return; } else if (mask) { - /* XXX note: we're putting the integer clear values into the - * floating point state var. This will not always work. We'll - * need a new ctx->Driver.ClearBuffer() hook.... - */ - GLclampf clearSave[4]; + union gl_color_union clearSave; + /* save color */ - COPY_4V(clearSave, ctx->Color.ClearColor); + clearSave = ctx->Color.ClearColor; /* set color */ - COPY_4V_CAST(ctx->Color.ClearColor, value, GLclampf); + COPY_4V(ctx->Color.ClearColor.i, value); if (ctx->Driver.ClearColor) ctx->Driver.ClearColor(ctx, ctx->Color.ClearColor); /* clear buffer(s) */ ctx->Driver.Clear(ctx, mask); /* restore color */ - COPY_4V(ctx->Color.ClearColor, clearSave); + ctx->Color.ClearColor = clearSave; if (ctx->Driver.ClearColor) ctx->Driver.ClearColor(ctx, clearSave); } @@ -418,21 +404,18 @@ _mesa_ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value) return; } else if (mask) { - /* XXX note: we're putting the uint clear values into the - * floating point state var. This will not always work. We'll - * need a new ctx->Driver.ClearBuffer() hook.... - */ - GLclampf clearSave[4]; + union gl_color_union clearSave; + /* save color */ - COPY_4V(clearSave, ctx->Color.ClearColor); + clearSave = ctx->Color.ClearColor; /* set color */ - COPY_4V_CAST(ctx->Color.ClearColor, value, GLclampf); + COPY_4V(ctx->Color.ClearColor.ui, value); if (ctx->Driver.ClearColor) ctx->Driver.ClearColor(ctx, ctx->Color.ClearColor); /* clear buffer(s) */ ctx->Driver.Clear(ctx, mask); /* restore color */ - COPY_4V(ctx->Color.ClearColor, clearSave); + ctx->Color.ClearColor = clearSave; if (ctx->Driver.ClearColor) ctx->Driver.ClearColor(ctx, clearSave); } @@ -495,17 +478,18 @@ _mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value) return; } else if (mask) { - GLclampf clearSave[4]; + union gl_color_union clearSave; + /* save color */ - COPY_4V(clearSave, ctx->Color.ClearColor); + clearSave = ctx->Color.ClearColor; /* set color */ - COPY_4V_CAST(ctx->Color.ClearColor, value, GLclampf); + COPY_4V_CAST(ctx->Color.ClearColor.f, value, GLclampf); if (ctx->Driver.ClearColor) ctx->Driver.ClearColor(ctx, ctx->Color.ClearColor); /* clear buffer(s) */ ctx->Driver.Clear(ctx, mask); /* restore color */ - COPY_4V(ctx->Color.ClearColor, clearSave); + ctx->Color.ClearColor = clearSave; if (ctx->Driver.ClearColor) ctx->Driver.ClearColor(ctx, clearSave); } diff --git a/mesalib/src/mesa/main/colormac.h b/mesalib/src/mesa/main/colormac.h index d308c48b6..4b7c3b4a0 100644 --- a/mesalib/src/mesa/main/colormac.h +++ b/mesalib/src/mesa/main/colormac.h @@ -169,6 +169,17 @@ do { \ } while (0) +/** + * Convert four float values in [0,1] to ubytes in [0,255] with clamping. + */ +static inline void +_mesa_unclamped_float_rgba_to_ubyte(GLubyte dst[4], const GLfloat src[4]) +{ + int i; + for (i = 0; i < 4; i++) + UNCLAMPED_FLOAT_TO_UBYTE(dst[i], src[i]); +} + /** * \name Generic color packing macros. All inputs should be GLubytes. diff --git a/mesalib/src/mesa/main/dd.h b/mesalib/src/mesa/main/dd.h index b77e4f092..d6cc0196d 100644 --- a/mesalib/src/mesa/main/dd.h +++ b/mesalib/src/mesa/main/dd.h @@ -589,7 +589,8 @@ struct dd_function_table { GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorA, GLenum dfactorA); /** Specify clear values for the color buffers */ - void (*ClearColor)(struct gl_context *ctx, const GLfloat color[4]); + void (*ClearColor)(struct gl_context *ctx, + const union gl_color_union color); /** Specify the clear value for the depth buffer */ void (*ClearDepth)(struct gl_context *ctx, GLclampd d); /** Specify the clear value for the stencil buffer */ diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c index 069254b18..a777bd8c4 100644 --- a/mesalib/src/mesa/main/get.c +++ b/mesalib/src/mesa/main/get.c @@ -1673,10 +1673,13 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu COPY_4FV(v->value_float_4, ctx->Fog.ColorUnclamped); break; case GL_COLOR_CLEAR_VALUE: - if(ctx->Color._ClampFragmentColor) - COPY_4FV(v->value_float_4, ctx->Color.ClearColor); - else - COPY_4FV(v->value_float_4, ctx->Color.ClearColorUnclamped); + if(ctx->Color._ClampFragmentColor) { + v->value_float_4[0] = CLAMP(ctx->Color.ClearColor.f[0], 0.0F, 1.0F); + v->value_float_4[1] = CLAMP(ctx->Color.ClearColor.f[1], 0.0F, 1.0F); + v->value_float_4[2] = CLAMP(ctx->Color.ClearColor.f[2], 0.0F, 1.0F); + v->value_float_4[3] = CLAMP(ctx->Color.ClearColor.f[3], 0.0F, 1.0F); + } else + COPY_4FV(v->value_float_4, ctx->Color.ClearColor.f); break; case GL_BLEND_COLOR_EXT: if(ctx->Color._ClampFragmentColor) diff --git a/mesalib/src/mesa/main/image.c b/mesalib/src/mesa/main/image.c index 3e75e7c6b..66d7eec65 100644 --- a/mesalib/src/mesa/main/image.c +++ b/mesalib/src/mesa/main/image.c @@ -1513,12 +1513,8 @@ _mesa_convert_colors(GLenum srcType, const GLvoid *src, GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst); GLuint i; for (i = 0; i < count; i++) { - if (!mask || mask[i]) { - UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][RCOMP], src4[i][RCOMP]); - UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][GCOMP], src4[i][GCOMP]); - UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][BCOMP], src4[i][BCOMP]); - UNCLAMPED_FLOAT_TO_UBYTE(dst1[i][ACOMP], src4[i][ACOMP]); - } + if (!mask || mask[i]) + _mesa_unclamped_float_rgba_to_ubyte(dst1[i], src4[i]); } if (useTemp) memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte)); diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index ae500b4c2..8671ecda9 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -720,17 +720,27 @@ struct gl_accum_attrib }; +/** + * Used for storing clear color, texture border color, etc. + * The float values are typically unclamped. + */ +union gl_color_union +{ + GLfloat f[4]; + GLint i[4]; + GLuint ui[4]; +}; + + /** * Color buffer attribute group (GL_COLOR_BUFFER_BIT). */ struct gl_colorbuffer_attrib { - GLuint ClearIndex; /**< Index to use for glClear */ - GLfloat ClearColorUnclamped[4]; /**< Color to use for glClear*/ - GLclampf ClearColor[4]; /**< Color to use for glClear */ - - GLuint IndexMask; /**< Color index write mask */ - GLubyte ColorMask[MAX_DRAW_BUFFERS][4];/**< Each flag is 0xff or 0x0 */ + GLuint ClearIndex; /**< Index for glClear */ + union gl_color_union ClearColor; /**< Color for glClear, unclamped */ + GLuint IndexMask; /**< Color index write mask */ + GLubyte ColorMask[MAX_DRAW_BUFFERS][4]; /**< Each flag is 0xff or 0x0 */ GLenum DrawBuffer[MAX_DRAW_BUFFERS]; /**< Which buffer to draw into */ @@ -750,8 +760,8 @@ struct gl_colorbuffer_attrib /*@{*/ GLbitfield BlendEnabled; /**< Per-buffer blend enable flags */ - /* NOTE: this does _not_ depend on fragment clamping or any other clamping control, - * only on the fixed-pointness of the render target. + /* NOTE: this does _not_ depend on fragment clamping or any other clamping + * control, only on the fixed-pointness of the render target. * The query does however depend on fragment color clamping. */ GLfloat BlendColorUnclamped[4]; /**< Blending color */ @@ -1356,11 +1366,7 @@ struct gl_sampler_object GLenum WrapR; /**< R-axis texture image wrap mode */ GLenum MinFilter; /**< minification filter */ GLenum MagFilter; /**< magnification filter */ - union { - GLfloat f[4]; - GLuint ui[4]; - GLint i[4]; - } BorderColor; /**< Interpreted according to texture format */ + union gl_color_union BorderColor; /**< Interpreted according to texture format */ GLfloat MinLod; /**< min lambda, OpenGL 1.2 */ GLfloat MaxLod; /**< max lambda, OpenGL 1.2 */ GLfloat LodBias; /**< OpenGL 1.4 */ diff --git a/mesalib/src/mesa/main/uniforms.c b/mesalib/src/mesa/main/uniforms.c index b0f9c33b8..2323819aa 100644 --- a/mesalib/src/mesa/main/uniforms.c +++ b/mesalib/src/mesa/main/uniforms.c @@ -111,21 +111,43 @@ is_sampler_type(GLenum type) { switch (type) { case GL_SAMPLER_1D: + case GL_INT_SAMPLER_1D: + case GL_UNSIGNED_INT_SAMPLER_1D: case GL_SAMPLER_2D: + case GL_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_2D: case GL_SAMPLER_3D: + case GL_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_3D: case GL_SAMPLER_CUBE: + case GL_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_CUBE: case GL_SAMPLER_1D_SHADOW: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_2D_RECT_ARB: + case GL_INT_SAMPLER_2D_RECT: + case GL_UNSIGNED_INT_SAMPLER_2D_RECT: case GL_SAMPLER_2D_RECT_SHADOW_ARB: case GL_SAMPLER_1D_ARRAY_EXT: + case GL_INT_SAMPLER_1D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: case GL_SAMPLER_2D_ARRAY_EXT: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: case GL_SAMPLER_1D_ARRAY_SHADOW_EXT: case GL_SAMPLER_2D_ARRAY_SHADOW_EXT: case GL_SAMPLER_CUBE_MAP_ARRAY: case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW: case GL_SAMPLER_BUFFER: + case GL_INT_SAMPLER_BUFFER: + case GL_UNSIGNED_INT_SAMPLER_BUFFER: + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_INT_SAMPLER_2D_MULTISAMPLE: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return GL_TRUE; default: return GL_FALSE; diff --git a/mesalib/src/mesa/state_tracker/st_cb_clear.c b/mesalib/src/mesa/state_tracker/st_cb_clear.c index 117000ba7..a4799e3cc 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_clear.c +++ b/mesalib/src/mesa/state_tracker/st_cb_clear.c @@ -323,9 +323,9 @@ clear_with_quad(struct gl_context *ctx, set_vertex_shader(st); if (ctx->DrawBuffer->_ColorDrawBuffers[0]) { - st_translate_color(ctx->Color.ClearColorUnclamped, - ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat, - clearColor); + st_translate_color(ctx->Color.ClearColor.f, + ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat, + clearColor); } /* draw quad matching scissor rect */ @@ -582,12 +582,12 @@ st_Clear(struct gl_context *ctx, GLbitfield mask) clear_buffers |= PIPE_CLEAR_DEPTHSTENCIL; if (ctx->DrawBuffer->_ColorDrawBuffers[0]) { - st_translate_color(ctx->Color.ClearColor, - ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat, - clearColor); + st_translate_color(ctx->Color.ClearColor.f, + ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat, + clearColor); } - st->pipe->clear(st->pipe, clear_buffers, ctx->Color.ClearColorUnclamped, + st->pipe->clear(st->pipe, clear_buffers, clearColor, ctx->Depth.Clear, ctx->Stencil.Clear); } if (mask & BUFFER_BIT_ACCUM) diff --git a/mesalib/src/mesa/state_tracker/st_format.c b/mesalib/src/mesa/state_tracker/st_format.c index bd4f0860c..6eb8a506b 100644 --- a/mesalib/src/mesa/state_tracker/st_format.c +++ b/mesalib/src/mesa/state_tracker/st_format.c @@ -1441,8 +1441,9 @@ st_sampler_compat_formats(enum pipe_format format1, enum pipe_format format2) * This is used for translating texture border color and the clear * color. For example, the clear color is interpreted according to * the renderbuffer's base format. For example, if clearing a - * GL_LUMINANCE buffer, ClearColor[0] = luminance and ClearColor[1] = - * alpha. Similarly for texture border colors. + * GL_LUMINANCE buffer, we'll return colorOut[0] = colorOut[1] = + * colorOut[2] = colorIn[0]. + * Similarly for texture border colors. */ void st_translate_color(const GLfloat colorIn[4], GLenum baseFormat, diff --git a/mesalib/src/mesa/swrast/s_blend.c b/mesalib/src/mesa/swrast/s_blend.c index 125364913..3760f91d6 100644 --- a/mesalib/src/mesa/swrast/s_blend.c +++ b/mesalib/src/mesa/swrast/s_blend.c @@ -1,1014 +1,1010 @@ -/* - * Mesa 3-D graphics library - * Version: 7.1 - * - * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/** - * \file swrast/s_blend.c - * \brief software blending. - * \author Brian Paul - * - * Only a few blend modes have been optimized (min, max, transparency, add) - * more optimized cases can easily be added if needed. - * Celestia uses glBlendFunc(GL_SRC_ALPHA, GL_ONE), for example. - */ - - - -#include "main/glheader.h" -#include "main/context.h" -#include "main/colormac.h" -#include "main/macros.h" - -#include "s_blend.h" -#include "s_context.h" -#include "s_span.h" - - -#if defined(USE_MMX_ASM) -#include "x86/mmx.h" -#include "x86/common_x86_asm.h" -#define _BLENDAPI _ASMAPI -#else -#define _BLENDAPI -#endif - - -/** - * Integer divide by 255 - * Declare "int divtemp" before using. - * This satisfies Glean and should be reasonably fast. - * Contributed by Nathan Hand. - */ -#define DIV255(X) (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16) - - - -/** - * Special case for glBlendFunc(GL_ZERO, GL_ONE). - * No-op means the framebuffer values remain unchanged. - * Any chanType ok. - */ -static void _BLENDAPI -blend_noop(struct gl_context *ctx, GLuint n, const GLubyte mask[], - GLvoid *src, const GLvoid *dst, GLenum chanType) -{ - GLint bytes; - - ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ZERO); - ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE); - (void) ctx; - - /* just memcpy */ - if (chanType == GL_UNSIGNED_BYTE) - bytes = 4 * n * sizeof(GLubyte); - else if (chanType == GL_UNSIGNED_SHORT) - bytes = 4 * n * sizeof(GLushort); - else - bytes = 4 * n * sizeof(GLfloat); - - memcpy(src, dst, bytes); -} - - -/** - * Special case for glBlendFunc(GL_ONE, GL_ZERO) - * Any chanType ok. - */ -static void _BLENDAPI -blend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[], - GLvoid *src, const GLvoid *dst, GLenum chanType) -{ - ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE); - ASSERT(ctx->Color.Blend[0].DstRGB == GL_ZERO); - (void) ctx; - (void) n; - (void) mask; - (void) src; - (void) dst; -} - - -/** - * Common transparency blending mode: - * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA). - */ -static void _BLENDAPI -blend_transparency_ubyte(struct gl_context *ctx, GLuint n, const GLubyte mask[], - GLvoid *src, const GLvoid *dst, GLenum chanType) -{ - GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; - const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; - GLuint i; - - ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA); - ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA); - ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA); - ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA); - ASSERT(chanType == GL_UNSIGNED_BYTE); - - (void) ctx; - - for (i = 0; i < n; i++) { - if (mask[i]) { - const GLint t = rgba[i][ACOMP]; /* t is in [0, 255] */ - if (t == 0) { - /* 0% alpha */ - COPY_4UBV(rgba[i], dest[i]); - } - else if (t != 255) { - GLint divtemp; - const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP]; - const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP]; - const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP]; - const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP]; - ASSERT(r <= 255); - ASSERT(g <= 255); - ASSERT(b <= 255); - ASSERT(a <= 255); - rgba[i][RCOMP] = (GLubyte) r; - rgba[i][GCOMP] = (GLubyte) g; - rgba[i][BCOMP] = (GLubyte) b; - rgba[i][ACOMP] = (GLubyte) a; - } - } - } -} - - -static void _BLENDAPI -blend_transparency_ushort(struct gl_context *ctx, GLuint n, const GLubyte mask[], - GLvoid *src, const GLvoid *dst, GLenum chanType) -{ - GLushort (*rgba)[4] = (GLushort (*)[4]) src; - const GLushort (*dest)[4] = (const GLushort (*)[4]) dst; - GLuint i; - - ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA); - ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA); - ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA); - ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA); - ASSERT(chanType == GL_UNSIGNED_SHORT); - - (void) ctx; - - for (i = 0; i < n; i++) { - if (mask[i]) { - const GLint t = rgba[i][ACOMP]; - if (t == 0) { - /* 0% alpha */ - COPY_4V(rgba[i], dest[i]); - } - else if (t != 65535) { - const GLfloat tt = (GLfloat) t / 65535.0F; - GLushort r = (GLushort) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]); - GLushort g = (GLushort) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]); - GLushort b = (GLushort) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]); - GLushort a = (GLushort) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]); - ASSIGN_4V(rgba[i], r, g, b, a); - } - } - } -} - - -static void _BLENDAPI -blend_transparency_float(struct gl_context *ctx, GLuint n, const GLubyte mask[], - GLvoid *src, const GLvoid *dst, GLenum chanType) -{ - GLfloat (*rgba)[4] = (GLfloat (*)[4]) src; - const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst; - GLuint i; - - ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA); - ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA); - ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA); - ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA); - ASSERT(chanType == GL_FLOAT); - - (void) ctx; - - for (i = 0; i < n; i++) { - if (mask[i]) { - const GLfloat t = rgba[i][ACOMP]; /* t in [0, 1] */ - if (t == 0.0F) { - /* 0% alpha */ - COPY_4V(rgba[i], dest[i]); - } - else if (t != 1.0F) { - GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * t + dest[i][RCOMP]; - GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * t + dest[i][GCOMP]; - GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * t + dest[i][BCOMP]; - GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * t + dest[i][ACOMP]; - ASSIGN_4V(rgba[i], r, g, b, a); - } - } - } -} - - - -/** - * Add src and dest: glBlendFunc(GL_ONE, GL_ONE). - * Any chanType ok. - */ -static void _BLENDAPI -blend_add(struct gl_context *ctx, GLuint n, const GLubyte mask[], - GLvoid *src, const GLvoid *dst, GLenum chanType) -{ - GLuint i; - - ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); - ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE); - ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE); - (void) ctx; - - if (chanType == GL_UNSIGNED_BYTE) { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; - const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; - for (i=0;iColor.Blend[0].EquationRGB == GL_MIN); - ASSERT(ctx->Color.Blend[0].EquationA == GL_MIN); - (void) ctx; - - if (chanType == GL_UNSIGNED_BYTE) { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; - const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; - for (i=0;iColor.Blend[0].EquationRGB == GL_MAX); - ASSERT(ctx->Color.Blend[0].EquationA == GL_MAX); - (void) ctx; - - if (chanType == GL_UNSIGNED_BYTE) { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; - const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; - for (i=0;i> 16; - rgba[i][GCOMP] = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16; - rgba[i][BCOMP] = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16; - rgba[i][ACOMP] = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16; - } - } - } - else { - GLfloat (*rgba)[4] = (GLfloat (*)[4]) src; - const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst; - ASSERT(chanType == GL_FLOAT); - for (i=0;iColor.Blend[0].SrcRGB) { - case GL_ZERO: - sR = sG = sB = 0.0F; - break; - case GL_ONE: - sR = sG = sB = 1.0F; - break; - case GL_DST_COLOR: - sR = Rd; - sG = Gd; - sB = Bd; - break; - case GL_ONE_MINUS_DST_COLOR: - sR = 1.0F - Rd; - sG = 1.0F - Gd; - sB = 1.0F - Bd; - break; - case GL_SRC_ALPHA: - sR = sG = sB = As; - break; - case GL_ONE_MINUS_SRC_ALPHA: - sR = sG = sB = 1.0F - As; - break; - case GL_DST_ALPHA: - sR = sG = sB = Ad; - break; - case GL_ONE_MINUS_DST_ALPHA: - sR = sG = sB = 1.0F - Ad; - break; - case GL_SRC_ALPHA_SATURATE: - if (As < 1.0F - Ad) { - sR = sG = sB = As; - } - else { - sR = sG = sB = 1.0F - Ad; - } - break; - case GL_CONSTANT_COLOR: - sR = ctx->Color.BlendColor[0]; - sG = ctx->Color.BlendColor[1]; - sB = ctx->Color.BlendColor[2]; - break; - case GL_ONE_MINUS_CONSTANT_COLOR: - sR = 1.0F - ctx->Color.BlendColor[0]; - sG = 1.0F - ctx->Color.BlendColor[1]; - sB = 1.0F - ctx->Color.BlendColor[2]; - break; - case GL_CONSTANT_ALPHA: - sR = sG = sB = ctx->Color.BlendColor[3]; - break; - case GL_ONE_MINUS_CONSTANT_ALPHA: - sR = sG = sB = 1.0F - ctx->Color.BlendColor[3]; - break; - case GL_SRC_COLOR: - sR = Rs; - sG = Gs; - sB = Bs; - break; - case GL_ONE_MINUS_SRC_COLOR: - sR = 1.0F - Rs; - sG = 1.0F - Gs; - sB = 1.0F - Bs; - break; - default: - /* this should never happen */ - _mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float"); - return; - } - - /* Source Alpha factor */ - switch (ctx->Color.Blend[0].SrcA) { - case GL_ZERO: - sA = 0.0F; - break; - case GL_ONE: - sA = 1.0F; - break; - case GL_DST_COLOR: - sA = Ad; - break; - case GL_ONE_MINUS_DST_COLOR: - sA = 1.0F - Ad; - break; - case GL_SRC_ALPHA: - sA = As; - break; - case GL_ONE_MINUS_SRC_ALPHA: - sA = 1.0F - As; - break; - case GL_DST_ALPHA: - sA = Ad; - break; - case GL_ONE_MINUS_DST_ALPHA: - sA = 1.0F - Ad; - break; - case GL_SRC_ALPHA_SATURATE: - sA = 1.0; - break; - case GL_CONSTANT_COLOR: - sA = ctx->Color.BlendColor[3]; - break; - case GL_ONE_MINUS_CONSTANT_COLOR: - sA = 1.0F - ctx->Color.BlendColor[3]; - break; - case GL_CONSTANT_ALPHA: - sA = ctx->Color.BlendColor[3]; - break; - case GL_ONE_MINUS_CONSTANT_ALPHA: - sA = 1.0F - ctx->Color.BlendColor[3]; - break; - case GL_SRC_COLOR: - sA = As; - break; - case GL_ONE_MINUS_SRC_COLOR: - sA = 1.0F - As; - break; - default: - /* this should never happen */ - sA = 0.0F; - _mesa_problem(ctx, "Bad blend source A factor in blend_general_float"); - return; - } - - /* Dest RGB factor */ - switch (ctx->Color.Blend[0].DstRGB) { - case GL_ZERO: - dR = dG = dB = 0.0F; - break; - case GL_ONE: - dR = dG = dB = 1.0F; - break; - case GL_SRC_COLOR: - dR = Rs; - dG = Gs; - dB = Bs; - break; - case GL_ONE_MINUS_SRC_COLOR: - dR = 1.0F - Rs; - dG = 1.0F - Gs; - dB = 1.0F - Bs; - break; - case GL_SRC_ALPHA: - dR = dG = dB = As; - break; - case GL_ONE_MINUS_SRC_ALPHA: - dR = dG = dB = 1.0F - As; - break; - case GL_DST_ALPHA: - dR = dG = dB = Ad; - break; - case GL_ONE_MINUS_DST_ALPHA: - dR = dG = dB = 1.0F - Ad; - break; - case GL_CONSTANT_COLOR: - dR = ctx->Color.BlendColor[0]; - dG = ctx->Color.BlendColor[1]; - dB = ctx->Color.BlendColor[2]; - break; - case GL_ONE_MINUS_CONSTANT_COLOR: - dR = 1.0F - ctx->Color.BlendColor[0]; - dG = 1.0F - ctx->Color.BlendColor[1]; - dB = 1.0F - ctx->Color.BlendColor[2]; - break; - case GL_CONSTANT_ALPHA: - dR = dG = dB = ctx->Color.BlendColor[3]; - break; - case GL_ONE_MINUS_CONSTANT_ALPHA: - dR = dG = dB = 1.0F - ctx->Color.BlendColor[3]; - break; - case GL_DST_COLOR: - dR = Rd; - dG = Gd; - dB = Bd; - break; - case GL_ONE_MINUS_DST_COLOR: - dR = 1.0F - Rd; - dG = 1.0F - Gd; - dB = 1.0F - Bd; - break; - default: - /* this should never happen */ - dR = dG = dB = 0.0F; - _mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float"); - return; - } - - /* Dest Alpha factor */ - switch (ctx->Color.Blend[0].DstA) { - case GL_ZERO: - dA = 0.0F; - break; - case GL_ONE: - dA = 1.0F; - break; - case GL_SRC_COLOR: - dA = As; - break; - case GL_ONE_MINUS_SRC_COLOR: - dA = 1.0F - As; - break; - case GL_SRC_ALPHA: - dA = As; - break; - case GL_ONE_MINUS_SRC_ALPHA: - dA = 1.0F - As; - break; - case GL_DST_ALPHA: - dA = Ad; - break; - case GL_ONE_MINUS_DST_ALPHA: - dA = 1.0F - Ad; - break; - case GL_CONSTANT_COLOR: - dA = ctx->Color.BlendColor[3]; - break; - case GL_ONE_MINUS_CONSTANT_COLOR: - dA = 1.0F - ctx->Color.BlendColor[3]; - break; - case GL_CONSTANT_ALPHA: - dA = ctx->Color.BlendColor[3]; - break; - case GL_ONE_MINUS_CONSTANT_ALPHA: - dA = 1.0F - ctx->Color.BlendColor[3]; - break; - case GL_DST_COLOR: - dA = Ad; - break; - case GL_ONE_MINUS_DST_COLOR: - dA = 1.0F - Ad; - break; - default: - /* this should never happen */ - dA = 0.0F; - _mesa_problem(ctx, "Bad blend dest A factor in blend_general_float"); - return; - } - - /* compute the blended RGB */ - switch (ctx->Color.Blend[0].EquationRGB) { - case GL_FUNC_ADD: - r = Rs * sR + Rd * dR; - g = Gs * sG + Gd * dG; - b = Bs * sB + Bd * dB; - a = As * sA + Ad * dA; - break; - case GL_FUNC_SUBTRACT: - r = Rs * sR - Rd * dR; - g = Gs * sG - Gd * dG; - b = Bs * sB - Bd * dB; - a = As * sA - Ad * dA; - break; - case GL_FUNC_REVERSE_SUBTRACT: - r = Rd * dR - Rs * sR; - g = Gd * dG - Gs * sG; - b = Bd * dB - Bs * sB; - a = Ad * dA - As * sA; - break; - case GL_MIN: - r = MIN2( Rd, Rs ); - g = MIN2( Gd, Gs ); - b = MIN2( Bd, Bs ); - break; - case GL_MAX: - r = MAX2( Rd, Rs ); - g = MAX2( Gd, Gs ); - b = MAX2( Bd, Bs ); - break; - default: - /* should never get here */ - r = g = b = 0.0F; /* silence uninitialized var warning */ - _mesa_problem(ctx, "unexpected BlendEquation in blend_general()"); - return; - } - - /* compute the blended alpha */ - switch (ctx->Color.Blend[0].EquationA) { - case GL_FUNC_ADD: - a = As * sA + Ad * dA; - break; - case GL_FUNC_SUBTRACT: - a = As * sA - Ad * dA; - break; - case GL_FUNC_REVERSE_SUBTRACT: - a = Ad * dA - As * sA; - break; - case GL_MIN: - a = MIN2( Ad, As ); - break; - case GL_MAX: - a = MAX2( Ad, As ); - break; - default: - /* should never get here */ - a = 0.0F; /* silence uninitialized var warning */ - _mesa_problem(ctx, "unexpected BlendEquation in blend_general()"); - return; - } - - /* final clamping */ -#if 0 - rgba[i][RCOMP] = MAX2( r, 0.0F ); - rgba[i][GCOMP] = MAX2( g, 0.0F ); - rgba[i][BCOMP] = MAX2( b, 0.0F ); - rgba[i][ACOMP] = CLAMP( a, 0.0F, 1.0F ); -#else - ASSIGN_4V(rgba[i], r, g, b, a); -#endif - } - } -} - - -/** - * Do any blending operation, any chanType. - */ -static void -blend_general(struct gl_context *ctx, GLuint n, const GLubyte mask[], - void *src, const void *dst, GLenum chanType) -{ - GLfloat (*rgbaF)[4], (*destF)[4]; - - rgbaF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); - destF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); - if (!rgbaF || !destF) { - free(rgbaF); - free(destF); - _mesa_error(ctx, GL_OUT_OF_MEMORY, "blending"); - return; - } - - if (chanType == GL_UNSIGNED_BYTE) { - GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; - const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; - GLuint i; - /* convert ubytes to floats */ - for (i = 0; i < n; i++) { - if (mask[i]) { - rgbaF[i][RCOMP] = UBYTE_TO_FLOAT(rgba[i][RCOMP]); - rgbaF[i][GCOMP] = UBYTE_TO_FLOAT(rgba[i][GCOMP]); - rgbaF[i][BCOMP] = UBYTE_TO_FLOAT(rgba[i][BCOMP]); - rgbaF[i][ACOMP] = UBYTE_TO_FLOAT(rgba[i][ACOMP]); - destF[i][RCOMP] = UBYTE_TO_FLOAT(dest[i][RCOMP]); - destF[i][GCOMP] = UBYTE_TO_FLOAT(dest[i][GCOMP]); - destF[i][BCOMP] = UBYTE_TO_FLOAT(dest[i][BCOMP]); - destF[i][ACOMP] = UBYTE_TO_FLOAT(dest[i][ACOMP]); - } - } - /* do blend */ - blend_general_float(ctx, n, mask, rgbaF, destF, chanType); - /* convert back to ubytes */ - for (i = 0; i < n; i++) { - if (mask[i]) { - UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][RCOMP], rgbaF[i][RCOMP]); - UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][GCOMP], rgbaF[i][GCOMP]); - UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][BCOMP], rgbaF[i][BCOMP]); - UNCLAMPED_FLOAT_TO_UBYTE(rgba[i][ACOMP], rgbaF[i][ACOMP]); - } - } - } - else if (chanType == GL_UNSIGNED_SHORT) { - GLushort (*rgba)[4] = (GLushort (*)[4]) src; - const GLushort (*dest)[4] = (const GLushort (*)[4]) dst; - GLuint i; - /* convert ushorts to floats */ - for (i = 0; i < n; i++) { - if (mask[i]) { - rgbaF[i][RCOMP] = USHORT_TO_FLOAT(rgba[i][RCOMP]); - rgbaF[i][GCOMP] = USHORT_TO_FLOAT(rgba[i][GCOMP]); - rgbaF[i][BCOMP] = USHORT_TO_FLOAT(rgba[i][BCOMP]); - rgbaF[i][ACOMP] = USHORT_TO_FLOAT(rgba[i][ACOMP]); - destF[i][RCOMP] = USHORT_TO_FLOAT(dest[i][RCOMP]); - destF[i][GCOMP] = USHORT_TO_FLOAT(dest[i][GCOMP]); - destF[i][BCOMP] = USHORT_TO_FLOAT(dest[i][BCOMP]); - destF[i][ACOMP] = USHORT_TO_FLOAT(dest[i][ACOMP]); - } - } - /* do blend */ - blend_general_float(ctx, n, mask, rgbaF, destF, chanType); - /* convert back to ushorts */ - for (i = 0; i < n; i++) { - if (mask[i]) { - UNCLAMPED_FLOAT_TO_USHORT(rgba[i][RCOMP], rgbaF[i][RCOMP]); - UNCLAMPED_FLOAT_TO_USHORT(rgba[i][GCOMP], rgbaF[i][GCOMP]); - UNCLAMPED_FLOAT_TO_USHORT(rgba[i][BCOMP], rgbaF[i][BCOMP]); - UNCLAMPED_FLOAT_TO_USHORT(rgba[i][ACOMP], rgbaF[i][ACOMP]); - } - } - } - else { - blend_general_float(ctx, n, mask, (GLfloat (*)[4]) src, - (GLfloat (*)[4]) dst, chanType); - } - - free(rgbaF); - free(destF); -} - - - -/** - * Analyze current blending parameters to pick fastest blending function. - * Result: the ctx->Color.BlendFunc pointer is updated. - */ -void -_swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - const GLenum eq = ctx->Color.Blend[0].EquationRGB; - const GLenum srcRGB = ctx->Color.Blend[0].SrcRGB; - const GLenum dstRGB = ctx->Color.Blend[0].DstRGB; - const GLenum srcA = ctx->Color.Blend[0].SrcA; - const GLenum dstA = ctx->Color.Blend[0].DstA; - - if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) { - swrast->BlendFunc = blend_general; - } - else if (eq == GL_MIN) { - /* Note: GL_MIN ignores the blending weight factors */ -#if defined(USE_MMX_ASM) - if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) { - swrast->BlendFunc = _mesa_mmx_blend_min; - } - else -#endif - swrast->BlendFunc = blend_min; - } - else if (eq == GL_MAX) { - /* Note: GL_MAX ignores the blending weight factors */ -#if defined(USE_MMX_ASM) - if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) { - swrast->BlendFunc = _mesa_mmx_blend_max; - } - else -#endif - swrast->BlendFunc = blend_max; - } - else if (srcRGB != srcA || dstRGB != dstA) { - swrast->BlendFunc = blend_general; - } - else if (eq == GL_FUNC_ADD && srcRGB == GL_SRC_ALPHA - && dstRGB == GL_ONE_MINUS_SRC_ALPHA) { -#if defined(USE_MMX_ASM) - if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) { - swrast->BlendFunc = _mesa_mmx_blend_transparency; - } - else -#endif - { - if (chanType == GL_UNSIGNED_BYTE) - swrast->BlendFunc = blend_transparency_ubyte; - else if (chanType == GL_UNSIGNED_SHORT) - swrast->BlendFunc = blend_transparency_ushort; - else - swrast->BlendFunc = blend_transparency_float; - } - } - else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ONE) { -#if defined(USE_MMX_ASM) - if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) { - swrast->BlendFunc = _mesa_mmx_blend_add; - } - else -#endif - swrast->BlendFunc = blend_add; - } - else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT) - && (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR)) - || - ((eq == GL_FUNC_ADD || eq == GL_FUNC_SUBTRACT) - && (srcRGB == GL_DST_COLOR && dstRGB == GL_ZERO))) { -#if defined(USE_MMX_ASM) - if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) { - swrast->BlendFunc = _mesa_mmx_blend_modulate; - } - else -#endif - swrast->BlendFunc = blend_modulate; - } - else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) { - swrast->BlendFunc = blend_noop; - } - else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) { - swrast->BlendFunc = blend_replace; - } - else { - swrast->BlendFunc = blend_general; - } -} - - - -/** - * Apply the blending operator to a span of pixels. - * We can handle horizontal runs of pixels (spans) or arrays of x/y - * pixel coordinates. - */ -void -_swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span) -{ - SWcontext *swrast = SWRAST_CONTEXT(ctx); - void *rbPixels; - - ASSERT(span->end <= MAX_WIDTH); - ASSERT(span->arrayMask & SPAN_RGBA); - ASSERT(rb->DataType == span->array->ChanType); - ASSERT(!ctx->Color._LogicOpEnabled); - - rbPixels = _swrast_get_dest_rgba(ctx, rb, span); - - swrast->BlendFunc(ctx, span->end, span->array->mask, - span->array->rgba, rbPixels, span->array->ChanType); -} +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * \file swrast/s_blend.c + * \brief software blending. + * \author Brian Paul + * + * Only a few blend modes have been optimized (min, max, transparency, add) + * more optimized cases can easily be added if needed. + * Celestia uses glBlendFunc(GL_SRC_ALPHA, GL_ONE), for example. + */ + + + +#include "main/glheader.h" +#include "main/context.h" +#include "main/colormac.h" +#include "main/macros.h" + +#include "s_blend.h" +#include "s_context.h" +#include "s_span.h" + + +#if defined(USE_MMX_ASM) +#include "x86/mmx.h" +#include "x86/common_x86_asm.h" +#define _BLENDAPI _ASMAPI +#else +#define _BLENDAPI +#endif + + +/** + * Integer divide by 255 + * Declare "int divtemp" before using. + * This satisfies Glean and should be reasonably fast. + * Contributed by Nathan Hand. + */ +#define DIV255(X) (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16) + + + +/** + * Special case for glBlendFunc(GL_ZERO, GL_ONE). + * No-op means the framebuffer values remain unchanged. + * Any chanType ok. + */ +static void _BLENDAPI +blend_noop(struct gl_context *ctx, GLuint n, const GLubyte mask[], + GLvoid *src, const GLvoid *dst, GLenum chanType) +{ + GLint bytes; + + ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ZERO); + ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE); + (void) ctx; + + /* just memcpy */ + if (chanType == GL_UNSIGNED_BYTE) + bytes = 4 * n * sizeof(GLubyte); + else if (chanType == GL_UNSIGNED_SHORT) + bytes = 4 * n * sizeof(GLushort); + else + bytes = 4 * n * sizeof(GLfloat); + + memcpy(src, dst, bytes); +} + + +/** + * Special case for glBlendFunc(GL_ONE, GL_ZERO) + * Any chanType ok. + */ +static void _BLENDAPI +blend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[], + GLvoid *src, const GLvoid *dst, GLenum chanType) +{ + ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE); + ASSERT(ctx->Color.Blend[0].DstRGB == GL_ZERO); + (void) ctx; + (void) n; + (void) mask; + (void) src; + (void) dst; +} + + +/** + * Common transparency blending mode: + * glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA). + */ +static void _BLENDAPI +blend_transparency_ubyte(struct gl_context *ctx, GLuint n, const GLubyte mask[], + GLvoid *src, const GLvoid *dst, GLenum chanType) +{ + GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; + const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; + GLuint i; + + ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA); + ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA); + ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA); + ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA); + ASSERT(chanType == GL_UNSIGNED_BYTE); + + (void) ctx; + + for (i = 0; i < n; i++) { + if (mask[i]) { + const GLint t = rgba[i][ACOMP]; /* t is in [0, 255] */ + if (t == 0) { + /* 0% alpha */ + COPY_4UBV(rgba[i], dest[i]); + } + else if (t != 255) { + GLint divtemp; + const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP]; + const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP]; + const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP]; + const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP]; + ASSERT(r <= 255); + ASSERT(g <= 255); + ASSERT(b <= 255); + ASSERT(a <= 255); + rgba[i][RCOMP] = (GLubyte) r; + rgba[i][GCOMP] = (GLubyte) g; + rgba[i][BCOMP] = (GLubyte) b; + rgba[i][ACOMP] = (GLubyte) a; + } + } + } +} + + +static void _BLENDAPI +blend_transparency_ushort(struct gl_context *ctx, GLuint n, const GLubyte mask[], + GLvoid *src, const GLvoid *dst, GLenum chanType) +{ + GLushort (*rgba)[4] = (GLushort (*)[4]) src; + const GLushort (*dest)[4] = (const GLushort (*)[4]) dst; + GLuint i; + + ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA); + ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA); + ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA); + ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA); + ASSERT(chanType == GL_UNSIGNED_SHORT); + + (void) ctx; + + for (i = 0; i < n; i++) { + if (mask[i]) { + const GLint t = rgba[i][ACOMP]; + if (t == 0) { + /* 0% alpha */ + COPY_4V(rgba[i], dest[i]); + } + else if (t != 65535) { + const GLfloat tt = (GLfloat) t / 65535.0F; + GLushort r = (GLushort) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]); + GLushort g = (GLushort) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]); + GLushort b = (GLushort) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]); + GLushort a = (GLushort) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]); + ASSIGN_4V(rgba[i], r, g, b, a); + } + } + } +} + + +static void _BLENDAPI +blend_transparency_float(struct gl_context *ctx, GLuint n, const GLubyte mask[], + GLvoid *src, const GLvoid *dst, GLenum chanType) +{ + GLfloat (*rgba)[4] = (GLfloat (*)[4]) src; + const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst; + GLuint i; + + ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA); + ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA); + ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA); + ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA); + ASSERT(chanType == GL_FLOAT); + + (void) ctx; + + for (i = 0; i < n; i++) { + if (mask[i]) { + const GLfloat t = rgba[i][ACOMP]; /* t in [0, 1] */ + if (t == 0.0F) { + /* 0% alpha */ + COPY_4V(rgba[i], dest[i]); + } + else if (t != 1.0F) { + GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * t + dest[i][RCOMP]; + GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * t + dest[i][GCOMP]; + GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * t + dest[i][BCOMP]; + GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * t + dest[i][ACOMP]; + ASSIGN_4V(rgba[i], r, g, b, a); + } + } + } +} + + + +/** + * Add src and dest: glBlendFunc(GL_ONE, GL_ONE). + * Any chanType ok. + */ +static void _BLENDAPI +blend_add(struct gl_context *ctx, GLuint n, const GLubyte mask[], + GLvoid *src, const GLvoid *dst, GLenum chanType) +{ + GLuint i; + + ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD); + ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE); + ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE); + (void) ctx; + + if (chanType == GL_UNSIGNED_BYTE) { + GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; + const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; + for (i=0;iColor.Blend[0].EquationRGB == GL_MIN); + ASSERT(ctx->Color.Blend[0].EquationA == GL_MIN); + (void) ctx; + + if (chanType == GL_UNSIGNED_BYTE) { + GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; + const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; + for (i=0;iColor.Blend[0].EquationRGB == GL_MAX); + ASSERT(ctx->Color.Blend[0].EquationA == GL_MAX); + (void) ctx; + + if (chanType == GL_UNSIGNED_BYTE) { + GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; + const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; + for (i=0;i> 16; + rgba[i][GCOMP] = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16; + rgba[i][BCOMP] = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16; + rgba[i][ACOMP] = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16; + } + } + } + else { + GLfloat (*rgba)[4] = (GLfloat (*)[4]) src; + const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst; + ASSERT(chanType == GL_FLOAT); + for (i=0;iColor.Blend[0].SrcRGB) { + case GL_ZERO: + sR = sG = sB = 0.0F; + break; + case GL_ONE: + sR = sG = sB = 1.0F; + break; + case GL_DST_COLOR: + sR = Rd; + sG = Gd; + sB = Bd; + break; + case GL_ONE_MINUS_DST_COLOR: + sR = 1.0F - Rd; + sG = 1.0F - Gd; + sB = 1.0F - Bd; + break; + case GL_SRC_ALPHA: + sR = sG = sB = As; + break; + case GL_ONE_MINUS_SRC_ALPHA: + sR = sG = sB = 1.0F - As; + break; + case GL_DST_ALPHA: + sR = sG = sB = Ad; + break; + case GL_ONE_MINUS_DST_ALPHA: + sR = sG = sB = 1.0F - Ad; + break; + case GL_SRC_ALPHA_SATURATE: + if (As < 1.0F - Ad) { + sR = sG = sB = As; + } + else { + sR = sG = sB = 1.0F - Ad; + } + break; + case GL_CONSTANT_COLOR: + sR = ctx->Color.BlendColor[0]; + sG = ctx->Color.BlendColor[1]; + sB = ctx->Color.BlendColor[2]; + break; + case GL_ONE_MINUS_CONSTANT_COLOR: + sR = 1.0F - ctx->Color.BlendColor[0]; + sG = 1.0F - ctx->Color.BlendColor[1]; + sB = 1.0F - ctx->Color.BlendColor[2]; + break; + case GL_CONSTANT_ALPHA: + sR = sG = sB = ctx->Color.BlendColor[3]; + break; + case GL_ONE_MINUS_CONSTANT_ALPHA: + sR = sG = sB = 1.0F - ctx->Color.BlendColor[3]; + break; + case GL_SRC_COLOR: + sR = Rs; + sG = Gs; + sB = Bs; + break; + case GL_ONE_MINUS_SRC_COLOR: + sR = 1.0F - Rs; + sG = 1.0F - Gs; + sB = 1.0F - Bs; + break; + default: + /* this should never happen */ + _mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float"); + return; + } + + /* Source Alpha factor */ + switch (ctx->Color.Blend[0].SrcA) { + case GL_ZERO: + sA = 0.0F; + break; + case GL_ONE: + sA = 1.0F; + break; + case GL_DST_COLOR: + sA = Ad; + break; + case GL_ONE_MINUS_DST_COLOR: + sA = 1.0F - Ad; + break; + case GL_SRC_ALPHA: + sA = As; + break; + case GL_ONE_MINUS_SRC_ALPHA: + sA = 1.0F - As; + break; + case GL_DST_ALPHA: + sA = Ad; + break; + case GL_ONE_MINUS_DST_ALPHA: + sA = 1.0F - Ad; + break; + case GL_SRC_ALPHA_SATURATE: + sA = 1.0; + break; + case GL_CONSTANT_COLOR: + sA = ctx->Color.BlendColor[3]; + break; + case GL_ONE_MINUS_CONSTANT_COLOR: + sA = 1.0F - ctx->Color.BlendColor[3]; + break; + case GL_CONSTANT_ALPHA: + sA = ctx->Color.BlendColor[3]; + break; + case GL_ONE_MINUS_CONSTANT_ALPHA: + sA = 1.0F - ctx->Color.BlendColor[3]; + break; + case GL_SRC_COLOR: + sA = As; + break; + case GL_ONE_MINUS_SRC_COLOR: + sA = 1.0F - As; + break; + default: + /* this should never happen */ + sA = 0.0F; + _mesa_problem(ctx, "Bad blend source A factor in blend_general_float"); + return; + } + + /* Dest RGB factor */ + switch (ctx->Color.Blend[0].DstRGB) { + case GL_ZERO: + dR = dG = dB = 0.0F; + break; + case GL_ONE: + dR = dG = dB = 1.0F; + break; + case GL_SRC_COLOR: + dR = Rs; + dG = Gs; + dB = Bs; + break; + case GL_ONE_MINUS_SRC_COLOR: + dR = 1.0F - Rs; + dG = 1.0F - Gs; + dB = 1.0F - Bs; + break; + case GL_SRC_ALPHA: + dR = dG = dB = As; + break; + case GL_ONE_MINUS_SRC_ALPHA: + dR = dG = dB = 1.0F - As; + break; + case GL_DST_ALPHA: + dR = dG = dB = Ad; + break; + case GL_ONE_MINUS_DST_ALPHA: + dR = dG = dB = 1.0F - Ad; + break; + case GL_CONSTANT_COLOR: + dR = ctx->Color.BlendColor[0]; + dG = ctx->Color.BlendColor[1]; + dB = ctx->Color.BlendColor[2]; + break; + case GL_ONE_MINUS_CONSTANT_COLOR: + dR = 1.0F - ctx->Color.BlendColor[0]; + dG = 1.0F - ctx->Color.BlendColor[1]; + dB = 1.0F - ctx->Color.BlendColor[2]; + break; + case GL_CONSTANT_ALPHA: + dR = dG = dB = ctx->Color.BlendColor[3]; + break; + case GL_ONE_MINUS_CONSTANT_ALPHA: + dR = dG = dB = 1.0F - ctx->Color.BlendColor[3]; + break; + case GL_DST_COLOR: + dR = Rd; + dG = Gd; + dB = Bd; + break; + case GL_ONE_MINUS_DST_COLOR: + dR = 1.0F - Rd; + dG = 1.0F - Gd; + dB = 1.0F - Bd; + break; + default: + /* this should never happen */ + dR = dG = dB = 0.0F; + _mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float"); + return; + } + + /* Dest Alpha factor */ + switch (ctx->Color.Blend[0].DstA) { + case GL_ZERO: + dA = 0.0F; + break; + case GL_ONE: + dA = 1.0F; + break; + case GL_SRC_COLOR: + dA = As; + break; + case GL_ONE_MINUS_SRC_COLOR: + dA = 1.0F - As; + break; + case GL_SRC_ALPHA: + dA = As; + break; + case GL_ONE_MINUS_SRC_ALPHA: + dA = 1.0F - As; + break; + case GL_DST_ALPHA: + dA = Ad; + break; + case GL_ONE_MINUS_DST_ALPHA: + dA = 1.0F - Ad; + break; + case GL_CONSTANT_COLOR: + dA = ctx->Color.BlendColor[3]; + break; + case GL_ONE_MINUS_CONSTANT_COLOR: + dA = 1.0F - ctx->Color.BlendColor[3]; + break; + case GL_CONSTANT_ALPHA: + dA = ctx->Color.BlendColor[3]; + break; + case GL_ONE_MINUS_CONSTANT_ALPHA: + dA = 1.0F - ctx->Color.BlendColor[3]; + break; + case GL_DST_COLOR: + dA = Ad; + break; + case GL_ONE_MINUS_DST_COLOR: + dA = 1.0F - Ad; + break; + default: + /* this should never happen */ + dA = 0.0F; + _mesa_problem(ctx, "Bad blend dest A factor in blend_general_float"); + return; + } + + /* compute the blended RGB */ + switch (ctx->Color.Blend[0].EquationRGB) { + case GL_FUNC_ADD: + r = Rs * sR + Rd * dR; + g = Gs * sG + Gd * dG; + b = Bs * sB + Bd * dB; + a = As * sA + Ad * dA; + break; + case GL_FUNC_SUBTRACT: + r = Rs * sR - Rd * dR; + g = Gs * sG - Gd * dG; + b = Bs * sB - Bd * dB; + a = As * sA - Ad * dA; + break; + case GL_FUNC_REVERSE_SUBTRACT: + r = Rd * dR - Rs * sR; + g = Gd * dG - Gs * sG; + b = Bd * dB - Bs * sB; + a = Ad * dA - As * sA; + break; + case GL_MIN: + r = MIN2( Rd, Rs ); + g = MIN2( Gd, Gs ); + b = MIN2( Bd, Bs ); + break; + case GL_MAX: + r = MAX2( Rd, Rs ); + g = MAX2( Gd, Gs ); + b = MAX2( Bd, Bs ); + break; + default: + /* should never get here */ + r = g = b = 0.0F; /* silence uninitialized var warning */ + _mesa_problem(ctx, "unexpected BlendEquation in blend_general()"); + return; + } + + /* compute the blended alpha */ + switch (ctx->Color.Blend[0].EquationA) { + case GL_FUNC_ADD: + a = As * sA + Ad * dA; + break; + case GL_FUNC_SUBTRACT: + a = As * sA - Ad * dA; + break; + case GL_FUNC_REVERSE_SUBTRACT: + a = Ad * dA - As * sA; + break; + case GL_MIN: + a = MIN2( Ad, As ); + break; + case GL_MAX: + a = MAX2( Ad, As ); + break; + default: + /* should never get here */ + a = 0.0F; /* silence uninitialized var warning */ + _mesa_problem(ctx, "unexpected BlendEquation in blend_general()"); + return; + } + + /* final clamping */ +#if 0 + rgba[i][RCOMP] = MAX2( r, 0.0F ); + rgba[i][GCOMP] = MAX2( g, 0.0F ); + rgba[i][BCOMP] = MAX2( b, 0.0F ); + rgba[i][ACOMP] = CLAMP( a, 0.0F, 1.0F ); +#else + ASSIGN_4V(rgba[i], r, g, b, a); +#endif + } + } +} + + +/** + * Do any blending operation, any chanType. + */ +static void +blend_general(struct gl_context *ctx, GLuint n, const GLubyte mask[], + void *src, const void *dst, GLenum chanType) +{ + GLfloat (*rgbaF)[4], (*destF)[4]; + + rgbaF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); + destF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat)); + if (!rgbaF || !destF) { + free(rgbaF); + free(destF); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "blending"); + return; + } + + if (chanType == GL_UNSIGNED_BYTE) { + GLubyte (*rgba)[4] = (GLubyte (*)[4]) src; + const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst; + GLuint i; + /* convert ubytes to floats */ + for (i = 0; i < n; i++) { + if (mask[i]) { + rgbaF[i][RCOMP] = UBYTE_TO_FLOAT(rgba[i][RCOMP]); + rgbaF[i][GCOMP] = UBYTE_TO_FLOAT(rgba[i][GCOMP]); + rgbaF[i][BCOMP] = UBYTE_TO_FLOAT(rgba[i][BCOMP]); + rgbaF[i][ACOMP] = UBYTE_TO_FLOAT(rgba[i][ACOMP]); + destF[i][RCOMP] = UBYTE_TO_FLOAT(dest[i][RCOMP]); + destF[i][GCOMP] = UBYTE_TO_FLOAT(dest[i][GCOMP]); + destF[i][BCOMP] = UBYTE_TO_FLOAT(dest[i][BCOMP]); + destF[i][ACOMP] = UBYTE_TO_FLOAT(dest[i][ACOMP]); + } + } + /* do blend */ + blend_general_float(ctx, n, mask, rgbaF, destF, chanType); + /* convert back to ubytes */ + for (i = 0; i < n; i++) { + if (mask[i]) + _mesa_unclamped_float_rgba_to_ubyte(rgba[i], rgbaF[i]); + } + } + else if (chanType == GL_UNSIGNED_SHORT) { + GLushort (*rgba)[4] = (GLushort (*)[4]) src; + const GLushort (*dest)[4] = (const GLushort (*)[4]) dst; + GLuint i; + /* convert ushorts to floats */ + for (i = 0; i < n; i++) { + if (mask[i]) { + rgbaF[i][RCOMP] = USHORT_TO_FLOAT(rgba[i][RCOMP]); + rgbaF[i][GCOMP] = USHORT_TO_FLOAT(rgba[i][GCOMP]); + rgbaF[i][BCOMP] = USHORT_TO_FLOAT(rgba[i][BCOMP]); + rgbaF[i][ACOMP] = USHORT_TO_FLOAT(rgba[i][ACOMP]); + destF[i][RCOMP] = USHORT_TO_FLOAT(dest[i][RCOMP]); + destF[i][GCOMP] = USHORT_TO_FLOAT(dest[i][GCOMP]); + destF[i][BCOMP] = USHORT_TO_FLOAT(dest[i][BCOMP]); + destF[i][ACOMP] = USHORT_TO_FLOAT(dest[i][ACOMP]); + } + } + /* do blend */ + blend_general_float(ctx, n, mask, rgbaF, destF, chanType); + /* convert back to ushorts */ + for (i = 0; i < n; i++) { + if (mask[i]) { + UNCLAMPED_FLOAT_TO_USHORT(rgba[i][RCOMP], rgbaF[i][RCOMP]); + UNCLAMPED_FLOAT_TO_USHORT(rgba[i][GCOMP], rgbaF[i][GCOMP]); + UNCLAMPED_FLOAT_TO_USHORT(rgba[i][BCOMP], rgbaF[i][BCOMP]); + UNCLAMPED_FLOAT_TO_USHORT(rgba[i][ACOMP], rgbaF[i][ACOMP]); + } + } + } + else { + blend_general_float(ctx, n, mask, (GLfloat (*)[4]) src, + (GLfloat (*)[4]) dst, chanType); + } + + free(rgbaF); + free(destF); +} + + + +/** + * Analyze current blending parameters to pick fastest blending function. + * Result: the ctx->Color.BlendFunc pointer is updated. + */ +void +_swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + const GLenum eq = ctx->Color.Blend[0].EquationRGB; + const GLenum srcRGB = ctx->Color.Blend[0].SrcRGB; + const GLenum dstRGB = ctx->Color.Blend[0].DstRGB; + const GLenum srcA = ctx->Color.Blend[0].SrcA; + const GLenum dstA = ctx->Color.Blend[0].DstA; + + if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) { + swrast->BlendFunc = blend_general; + } + else if (eq == GL_MIN) { + /* Note: GL_MIN ignores the blending weight factors */ +#if defined(USE_MMX_ASM) + if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) { + swrast->BlendFunc = _mesa_mmx_blend_min; + } + else +#endif + swrast->BlendFunc = blend_min; + } + else if (eq == GL_MAX) { + /* Note: GL_MAX ignores the blending weight factors */ +#if defined(USE_MMX_ASM) + if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) { + swrast->BlendFunc = _mesa_mmx_blend_max; + } + else +#endif + swrast->BlendFunc = blend_max; + } + else if (srcRGB != srcA || dstRGB != dstA) { + swrast->BlendFunc = blend_general; + } + else if (eq == GL_FUNC_ADD && srcRGB == GL_SRC_ALPHA + && dstRGB == GL_ONE_MINUS_SRC_ALPHA) { +#if defined(USE_MMX_ASM) + if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) { + swrast->BlendFunc = _mesa_mmx_blend_transparency; + } + else +#endif + { + if (chanType == GL_UNSIGNED_BYTE) + swrast->BlendFunc = blend_transparency_ubyte; + else if (chanType == GL_UNSIGNED_SHORT) + swrast->BlendFunc = blend_transparency_ushort; + else + swrast->BlendFunc = blend_transparency_float; + } + } + else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ONE) { +#if defined(USE_MMX_ASM) + if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) { + swrast->BlendFunc = _mesa_mmx_blend_add; + } + else +#endif + swrast->BlendFunc = blend_add; + } + else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT) + && (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR)) + || + ((eq == GL_FUNC_ADD || eq == GL_FUNC_SUBTRACT) + && (srcRGB == GL_DST_COLOR && dstRGB == GL_ZERO))) { +#if defined(USE_MMX_ASM) + if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) { + swrast->BlendFunc = _mesa_mmx_blend_modulate; + } + else +#endif + swrast->BlendFunc = blend_modulate; + } + else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) { + swrast->BlendFunc = blend_noop; + } + else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) { + swrast->BlendFunc = blend_replace; + } + else { + swrast->BlendFunc = blend_general; + } +} + + + +/** + * Apply the blending operator to a span of pixels. + * We can handle horizontal runs of pixels (spans) or arrays of x/y + * pixel coordinates. + */ +void +_swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span) +{ + SWcontext *swrast = SWRAST_CONTEXT(ctx); + void *rbPixels; + + ASSERT(span->end <= MAX_WIDTH); + ASSERT(span->arrayMask & SPAN_RGBA); + ASSERT(rb->DataType == span->array->ChanType); + ASSERT(!ctx->Color._LogicOpEnabled); + + rbPixels = _swrast_get_dest_rgba(ctx, rb, span); + + swrast->BlendFunc(ctx, span->end, span->array->mask, + span->array->rgba, rbPixels, span->array->ChanType); +} diff --git a/mesalib/src/mesa/swrast/s_clear.c b/mesalib/src/mesa/swrast/s_clear.c index 9e9b53116..980d29bba 100644 --- a/mesalib/src/mesa/swrast/s_clear.c +++ b/mesalib/src/mesa/swrast/s_clear.c @@ -60,20 +60,17 @@ clear_rgba_buffer_with_masking(struct gl_context *ctx, struct gl_renderbuffer *r span.array->ChanType = rb->DataType; if (span.array->ChanType == GL_UNSIGNED_BYTE) { GLubyte clearColor[4]; - UNCLAMPED_FLOAT_TO_UBYTE(clearColor[RCOMP], ctx->Color.ClearColor[0]); - UNCLAMPED_FLOAT_TO_UBYTE(clearColor[GCOMP], ctx->Color.ClearColor[1]); - UNCLAMPED_FLOAT_TO_UBYTE(clearColor[BCOMP], ctx->Color.ClearColor[2]); - UNCLAMPED_FLOAT_TO_UBYTE(clearColor[ACOMP], ctx->Color.ClearColor[3]); + _mesa_unclamped_float_rgba_to_ubyte(clearColor, ctx->Color.ClearColor.f); for (i = 0; i < width; i++) { COPY_4UBV(span.array->rgba[i], clearColor); } } else if (span.array->ChanType == GL_UNSIGNED_SHORT) { GLushort clearColor[4]; - UNCLAMPED_FLOAT_TO_USHORT(clearColor[RCOMP], ctx->Color.ClearColor[0]); - UNCLAMPED_FLOAT_TO_USHORT(clearColor[GCOMP], ctx->Color.ClearColor[1]); - UNCLAMPED_FLOAT_TO_USHORT(clearColor[BCOMP], ctx->Color.ClearColor[2]); - UNCLAMPED_FLOAT_TO_USHORT(clearColor[ACOMP], ctx->Color.ClearColor[3]); + UNCLAMPED_FLOAT_TO_USHORT(clearColor[RCOMP], ctx->Color.ClearColor.f[0]); + UNCLAMPED_FLOAT_TO_USHORT(clearColor[GCOMP], ctx->Color.ClearColor.f[1]); + UNCLAMPED_FLOAT_TO_USHORT(clearColor[BCOMP], ctx->Color.ClearColor.f[2]); + UNCLAMPED_FLOAT_TO_USHORT(clearColor[ACOMP], ctx->Color.ClearColor.f[3]); for (i = 0; i < width; i++) { COPY_4V_CAST(span.array->rgba[i], clearColor, GLchan); } @@ -81,10 +78,10 @@ clear_rgba_buffer_with_masking(struct gl_context *ctx, struct gl_renderbuffer *r else { ASSERT(span.array->ChanType == GL_FLOAT); for (i = 0; i < width; i++) { - CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][0], ctx->Color.ClearColor[0]); - CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][1], ctx->Color.ClearColor[1]); - CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][2], ctx->Color.ClearColor[2]); - CLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][3], ctx->Color.ClearColor[3]); + UNCLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][0], ctx->Color.ClearColor.f[0]); + UNCLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][1], ctx->Color.ClearColor.f[1]); + UNCLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][2], ctx->Color.ClearColor.f[2]); + UNCLAMPED_FLOAT_TO_CHAN(span.array->rgba[i][3], ctx->Color.ClearColor.f[3]); } } @@ -115,6 +112,7 @@ clear_rgba_buffer(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint buf GLubyte clear8[4]; GLushort clear16[4]; GLvoid *clearVal; + GLfloat clearFloat[4]; GLint i; ASSERT(ctx->Color.ColorMask[buf][0] && @@ -126,21 +124,22 @@ clear_rgba_buffer(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint buf switch (rb->DataType) { case GL_UNSIGNED_BYTE: - UNCLAMPED_FLOAT_TO_UBYTE(clear8[0], ctx->Color.ClearColor[0]); - UNCLAMPED_FLOAT_TO_UBYTE(clear8[1], ctx->Color.ClearColor[1]); - UNCLAMPED_FLOAT_TO_UBYTE(clear8[2], ctx->Color.ClearColor[2]); - UNCLAMPED_FLOAT_TO_UBYTE(clear8[3], ctx->Color.ClearColor[3]); + _mesa_unclamped_float_rgba_to_ubyte(clear8, ctx->Color.ClearColor.f); clearVal = clear8; break; case GL_UNSIGNED_SHORT: - UNCLAMPED_FLOAT_TO_USHORT(clear16[0], ctx->Color.ClearColor[0]); - UNCLAMPED_FLOAT_TO_USHORT(clear16[1], ctx->Color.ClearColor[1]); - UNCLAMPED_FLOAT_TO_USHORT(clear16[2], ctx->Color.ClearColor[2]); - UNCLAMPED_FLOAT_TO_USHORT(clear16[3], ctx->Color.ClearColor[3]); + UNCLAMPED_FLOAT_TO_USHORT(clear16[0], ctx->Color.ClearColor.f[0]); + UNCLAMPED_FLOAT_TO_USHORT(clear16[1], ctx->Color.ClearColor.f[1]); + UNCLAMPED_FLOAT_TO_USHORT(clear16[2], ctx->Color.ClearColor.f[2]); + UNCLAMPED_FLOAT_TO_USHORT(clear16[3], ctx->Color.ClearColor.f[3]); clearVal = clear16; break; case GL_FLOAT: - clearVal = ctx->Color.ClearColor; + clearFloat[0] = CLAMP(ctx->Color.ClearColor.f[0], 0.0F, 1.0F); + clearFloat[1] = CLAMP(ctx->Color.ClearColor.f[1], 0.0F, 1.0F); + clearFloat[2] = CLAMP(ctx->Color.ClearColor.f[2], 0.0F, 1.0F); + clearFloat[3] = CLAMP(ctx->Color.ClearColor.f[3], 0.0F, 1.0F); + clearVal = clearFloat; break; default: _mesa_problem(ctx, "Bad rb DataType in clear_color_buffer"); -- cgit v1.2.3