From f0de41331a19bf9da1b6e7f27388d4f062fec8d2 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Sat, 9 May 2009 14:39:01 -0400 Subject: [PATCH] Default to a blend function that expects premultiplied colors Many operations, like mixing two textures together or alpha-blending onto a destination with alpha, are done most logically if texture data is in premultiplied form. We also have many sources of premultiplied texture data, like X pixmaps, FBOs, cairo surfaces. Rather than trying to work with two different types of texture data, simplify things by always premultiplying texture data before uploading to GL. Because the default blend function is changed to accommodate this, uses of pure-color CoglMaterial need to be adapted to add premultiplication. gl/cogl-texture.c gles/cogl-texture.c: Always premultiply non-premultiplied texture data before uploading to GL. cogl-material.c cogl-material.h: Switch the default blend functions to ONE, ONE_MINUS_SRC_ALPHA so they work correctly with premultiplied data. cogl.c: Make cogl_set_source_color() premultiply the color. cogl.h.in color-material.h: Add some documentation about premultiplication and its interaction with color values. cogl-pango-render.c clutter-texture.c tests/interactive/test-cogl-offscreen.c: Use premultiplied colors. http://bugzilla.openedhand.com/show_bug.cgi?id=1406 Signed-off-by: Robert Bragg --- cogl-material.h | 10 ++++++++++ cogl.h.in | 9 +++++++-- common/cogl-material.c | 2 +- common/cogl.c | 7 ++++++- gl/cogl-texture.c | 22 ++++++++++++---------- gles/cogl-texture.c | 23 +++++++++++++---------- 6 files changed, 49 insertions(+), 24 deletions(-) diff --git a/cogl-material.h b/cogl-material.h index 510ce8238..44a837564 100644 --- a/cogl-material.h +++ b/cogl-material.h @@ -138,6 +138,11 @@ gboolean cogl_is_material (CoglHandle handle); * * This is the basic color of the material, used when no lighting is enabled. * + * Note that if you don't add any layers to the material then the color + * will be blended unmodified with the destination; the default blend + * expects premultiplied colors: for example, use (0.5, 0.0, 0.0, 0.5) for + * semi-transparent red. See cogl_color_premultiply(). + * * The default value is (1.0, 1.0, 1.0, 1.0) * * Since 1.0 @@ -475,6 +480,11 @@ void cogl_material_set_alpha_test_function (CoglHandle material, * * * + * The default blend string is: + * "RGBA = ADD (SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))" + * That gives normal alpha-blending when the calculated color for the material + * is in premultiplied form. + * * Returns: TRUE if the blend string was successfully parsed, and the described * blending is supported by the underlying driver/hardware. If there * was an error, it returns FALSE. diff --git a/cogl.h.in b/cogl.h.in index a468cf717..64d57fc4f 100644 --- a/cogl.h.in +++ b/cogl.h.in @@ -455,8 +455,13 @@ void cogl_set_source (CoglHandle material); * cogl_set_source_color: * @color: a #CoglColor * - * Sets the source color using normalized values for each component. - * This color will be used for any subsequent drawing operation. + * This is a convenience function for creating a solid fill source material + * from the given color. This color will be used for any subsequent drawing + * operation. + * + * The color will be premultiplied by Cogl, so the color should be + * non-premultiplied. For example: use (1.0, 0.0, 0.0, 0.5) for + * semi-transparent red. * * See also cogl_set_source_color4ub() and cogl_set_source_color4f() * if you already have the color components. diff --git a/common/cogl-material.c b/common/cogl-material.c index 831fa30f1..7e3935bff 100644 --- a/common/cogl-material.c +++ b/common/cogl-material.c @@ -109,7 +109,7 @@ cogl_material_new (void) material->blend_constant[2] = 0; material->blend_constant[3] = 0; #endif - material->blend_src_factor_rgb = GL_SRC_ALPHA; + material->blend_src_factor_rgb = GL_ONE; material->blend_dst_factor_rgb = GL_ONE_MINUS_SRC_ALPHA; material->flags |= COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; diff --git a/common/cogl.c b/common/cogl.c index 336303917..5857db2d3 100644 --- a/common/cogl.c +++ b/common/cogl.c @@ -250,12 +250,17 @@ cogl_get_backface_culling_enabled (void) void cogl_set_source_color (const CoglColor *color) { + CoglColor premultiplied; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* In case cogl_set_source_texture was previously used... */ cogl_material_remove_layer (ctx->default_material, 0); - cogl_material_set_color (ctx->default_material, color); + premultiplied = *color; + cogl_color_premultiply (&premultiplied); + cogl_material_set_color (ctx->default_material, &premultiplied); + cogl_set_source (ctx->default_material); } diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index 3af78f9a0..2ee50617c 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -1085,18 +1085,20 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format, GLenum glformat = 0; GLenum gltype = 0; - /* No premultiplied formats accepted by GL - * (FIXME: latest hardware?) */ - - if (format & COGL_PREMULT_BIT) - format = (format & COGL_UNPREMULT_MASK); - - /* Everything else accepted - * (FIXME: check YUV support) */ - required_format = format; + /* If PREMULT_BIT isn't specified, that means that we premultiply + * textures with alpha before uploading to GL; once we are in GL land, + * everything is premultiplied. + * + * Everything else accepted (FIXME: check YUV support) + */ + if ((format & COGL_A_BIT) != 0 && + format != COGL_PIXEL_FORMAT_A_8) + required_format = format | COGL_PREMULT_BIT; + else + required_format = format; /* Find GL equivalents */ - switch (format) + switch (format & COGL_UNPREMULT_MASK) { case COGL_PIXEL_FORMAT_A_8: glintformat = GL_ALPHA; diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c index ae3e437b8..f9b6e0b78 100644 --- a/gles/cogl-texture.c +++ b/gles/cogl-texture.c @@ -1184,18 +1184,20 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format, GLenum glformat = 0; GLenum gltype = 0; - /* No premultiplied formats accepted by GL - * (FIXME: latest hardware?) */ - - if (format & COGL_PREMULT_BIT) - format = (format & COGL_UNPREMULT_MASK); - - /* Everything else accepted - * (FIXME: check YUV support) */ - required_format = format; + /* If PREMULT_BIT isn't specified, that means that we premultiply + * textures with alpha before uploading to GL; once we are in GL land, + * everything is premultiplied. + * + * Everything else accepted (FIXME: check YUV support) + */ + if ((format & COGL_A_BIT) != 0 && + format != COGL_PIXEL_FORMAT_A_8) + required_format = format | COGL_PREMULT_BIT; + else + required_format = format; /* Find GL equivalents */ - switch (format) + switch (format & COGL_UNPREMULT_MASK) { case COGL_PIXEL_FORMAT_A_8: glintformat = GL_ALPHA; @@ -1226,6 +1228,7 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format, glformat = GL_RGBA; gltype = GL_UNSIGNED_BYTE; required_format = COGL_PIXEL_FORMAT_RGBA_8888; + required_format |= (format & COGL_PREMULT_BIT); break; /* The following three types of channel ordering