From dcc4f1416995f9d16363e77b71d851e25bf53dab Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Sat, 9 May 2009 14:39:01 -0400 Subject: [PATCH 1/8] Add cogl_color_premultiply() Add a convenience function to convert an ARGB color from non-premultiplied to premultiplied form. http://bugzilla.openedhand.com/show_bug.cgi?id=1406 Signed-off-by: Robert Bragg --- cogl-color.h | 12 ++++++++++++ common/cogl-color.c | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/cogl-color.h b/cogl-color.h index 0cbc479a4..73de891de 100644 --- a/cogl-color.h +++ b/cogl-color.h @@ -228,6 +228,18 @@ float cogl_color_get_blue (const CoglColor *color); */ float cogl_color_get_alpha (const CoglColor *color); +/** + * cogl_color_premultiply: + * @color: the color to premultiply + * + * Converts a non-premultiplied color to a pre-multiplied color. For + * example, semi-transparent red is (1.0, 0, 0, 0.5) when non-premultiplied + * and (0.5, 0, 0, 0.5) when premultiplied. + * + * Since: 1.0 + */ +void cogl_color_premultiply (CoglColor *color); + G_END_DECLS #endif /* __COGL_COLOR_H__ */ diff --git a/common/cogl-color.c b/common/cogl-color.c index 306005f2f..df338fcc4 100644 --- a/common/cogl-color.c +++ b/common/cogl-color.c @@ -153,6 +153,14 @@ cogl_color_get_alpha (const CoglColor *color) return ((float) color->alpha / 255.0); } +void +cogl_color_premultiply (CoglColor *color) +{ + color->red = (color->red * color->alpha + 128) / 255; + color->green = (color->green * color->alpha + 128) / 255; + color->blue = (color->blue * color->alpha + 128) / 255; +} + void cogl_set_source_color4ub (guint8 red, guint8 green, From b0887a0d7593fdcacb2d5ac626fcc074cc4f722a Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Sat, 9 May 2009 14:39:01 -0400 Subject: [PATCH 2/8] Implement premultiplication for CoglBitmap cogl-bitmap.c cogl-bitmap-pixbuf.c cogl-bitmap-fallback.c cogl-bitmap-private.h: Add _cogl_bitmap_can_premult(), _cogl_bitmap_premult() and implement a reasonably fast implementation in the "fallback" code. http://bugzilla.openedhand.com/show_bug.cgi?id=1406 Signed-off-by: Robert Bragg --- common/cogl-bitmap-fallback.c | 93 +++++++++++++++++++++++++++++++++++ common/cogl-bitmap-pixbuf.c | 13 +++++ common/cogl-bitmap-private.h | 14 ++++++ common/cogl-bitmap.c | 26 +++++++--- 4 files changed, 140 insertions(+), 6 deletions(-) diff --git a/common/cogl-bitmap-fallback.c b/common/cogl-bitmap-fallback.c index e118459e1..a7e9704d9 100644 --- a/common/cogl-bitmap-fallback.c +++ b/common/cogl-bitmap-fallback.c @@ -180,6 +180,41 @@ _cogl_unpremult_alpha_first (const guchar *src, guchar *dst) dst[3] = ((((gulong) src[3] >> 0) & 0xff) * 255 ) / alpha; } +/* No division form of floor((c*a + 128)/255) (I first encountered + * this in the RENDER implementation in the X server.) Being exact + * is important for a == 255 - we want to get exactly c. + */ +#define MULT(d,c,a,t) G_STMT_START { t = c * a + 128; d = ((t >> 8) + t) >> 8; } G_STMT_END + +inline static void +_cogl_premult_alpha_last (const guchar *src, guchar *dst) +{ + guchar alpha = src[3]; + /* Using a separate temporary per component has given slightly better + * code generation with GCC in the past; it shouldn't do any worse in + * any case. + */ + guint t1, t2, t3; + MULT(dst[0], src[0], alpha, t1); + MULT(dst[1], src[1], alpha, t2); + MULT(dst[2], src[2], alpha, t3); + dst[3] = alpha; +} + +inline static void +_cogl_premult_alpha_first (const guchar *src, guchar *dst) +{ + guchar alpha = src[0]; + guint t1, t2, t3; + + dst[0] = alpha; + MULT(dst[1], src[1], alpha, t1); + MULT(dst[2], src[2], alpha, t2); + MULT(dst[3], src[3], alpha, t3); +} + +#undef MULT + gboolean _cogl_bitmap_fallback_can_convert (CoglPixelFormat src, CoglPixelFormat dst) { @@ -211,6 +246,12 @@ _cogl_bitmap_fallback_can_unpremult (CoglPixelFormat format) return ((format & COGL_UNORDERED_MASK) == COGL_PIXEL_FORMAT_32); } +gboolean +_cogl_bitmap_fallback_can_premult (CoglPixelFormat format) +{ + return ((format & COGL_UNORDERED_MASK) == COGL_PIXEL_FORMAT_32); +} + gboolean _cogl_bitmap_fallback_convert (const CoglBitmap *bmp, CoglBitmap *dst_bmp, @@ -358,6 +399,58 @@ _cogl_bitmap_fallback_unpremult (const CoglBitmap *bmp, return TRUE; } +gboolean +_cogl_bitmap_fallback_premult (const CoglBitmap *bmp, + CoglBitmap *dst_bmp) +{ + guchar *src; + guchar *dst; + gint bpp; + gint x,y; + + /* Make sure format supported for un-premultiplication */ + if (!_cogl_bitmap_fallback_can_premult (bmp->format)) + return FALSE; + + bpp = _cogl_get_format_bpp (bmp->format); + + /* Initialize destination bitmap */ + *dst_bmp = *bmp; + dst_bmp->format = (bmp->format & COGL_UNPREMULT_MASK); + + /* Allocate a new buffer to hold converted data */ + dst_bmp->data = g_malloc (sizeof(guchar) + * dst_bmp->height + * dst_bmp->rowstride); + + for (y = 0; y < bmp->height; y++) + { + src = (guchar*)bmp->data + y * bmp->rowstride; + dst = (guchar*)dst_bmp->data + y * dst_bmp->rowstride; + + if (bmp->format & COGL_AFIRST_BIT) + { + for (x = 0; x < bmp->width; x++) + { + _cogl_premult_alpha_first (src, dst); + src += bpp; + dst += bpp; + } + } + else + { + for (x = 0; x < bmp->width; x++) + { + _cogl_premult_alpha_last (src, dst); + src += bpp; + dst += bpp; + } + } + } + + return TRUE; +} + gboolean _cogl_bitmap_fallback_from_file (CoglBitmap *bmp, const gchar *filename) diff --git a/common/cogl-bitmap-pixbuf.c b/common/cogl-bitmap-pixbuf.c index f1e500534..1b75cd0ba 100644 --- a/common/cogl-bitmap-pixbuf.c +++ b/common/cogl-bitmap-pixbuf.c @@ -49,6 +49,12 @@ _cogl_bitmap_can_unpremult (CoglPixelFormat format) return FALSE; } +gboolean +_cogl_bitmap_can_premult (CoglPixelFormat format) +{ + return FALSE; +} + gboolean _cogl_bitmap_convert (const CoglBitmap *bmp, CoglBitmap *dst_bmp, @@ -64,6 +70,13 @@ _cogl_bitmap_unpremult (const CoglBitmap *bmp, return FALSE; } +gboolean +_cogl_bitmap_premult (const CoglBitmap *bmp, + CoglBitmap *dst_bmp) +{ + return FALSE; +} + #ifdef USE_QUARTZ /* lacking GdkPixbuf and other useful GError domains, define one of our own */ diff --git a/common/cogl-bitmap-private.h b/common/cogl-bitmap-private.h index f54961bd0..b6e425733 100644 --- a/common/cogl-bitmap-private.h +++ b/common/cogl-bitmap-private.h @@ -52,6 +52,12 @@ _cogl_bitmap_can_unpremult (CoglPixelFormat format); gboolean _cogl_bitmap_fallback_can_unpremult (CoglPixelFormat format); +gboolean +_cogl_bitmap_can_premult (CoglPixelFormat format); + +gboolean +_cogl_bitmap_fallback_can_premult (CoglPixelFormat format); + gboolean _cogl_bitmap_convert (const CoglBitmap *bmp, CoglBitmap *dst_bmp, @@ -69,6 +75,14 @@ gboolean _cogl_bitmap_fallback_unpremult (const CoglBitmap *bmp, CoglBitmap *dst_bmp); +gboolean +_cogl_bitmap_premult (const CoglBitmap *bmp, + CoglBitmap *dst_bmp); + +gboolean +_cogl_bitmap_fallback_premult (const CoglBitmap *bmp, + CoglBitmap *dst_bmp); + gboolean _cogl_bitmap_from_file (CoglBitmap *bmp, const gchar *filename, diff --git a/common/cogl-bitmap.c b/common/cogl-bitmap.c index f4c322abb..3dc7fd534 100644 --- a/common/cogl-bitmap.c +++ b/common/cogl-bitmap.c @@ -87,8 +87,8 @@ _cogl_bitmap_convert_and_premult (const CoglBitmap *bmp, } /* Do we need to unpremultiply */ - if ((bmp->format & COGL_PREMULT_BIT) == 0 && - (dst_format & COGL_PREMULT_BIT) > 0) + if ((bmp->format & COGL_PREMULT_BIT) > 0 && + (dst_format & COGL_PREMULT_BIT) == 0) { /* Try unpremultiplying using imaging library */ if (!_cogl_bitmap_unpremult (&new_bmp, &tmp_bmp)) @@ -112,14 +112,28 @@ _cogl_bitmap_convert_and_premult (const CoglBitmap *bmp, } /* Do we need to premultiply */ - if ((bmp->format & COGL_PREMULT_BIT) > 0 && - (dst_format & COGL_PREMULT_BIT) == 0) + if ((bmp->format & COGL_PREMULT_BIT) == 0 && + (dst_format & COGL_PREMULT_BIT) > 0) { - /* FIXME: implement premultiplication */ + /* Try premultiplying using imaging library */ + if (!_cogl_bitmap_premult (&new_bmp, &tmp_bmp)) + { + /* ... or try fallback */ + if (!_cogl_bitmap_fallback_premult (&new_bmp, &tmp_bmp)) + { + if (new_bmp_owner) + g_free (new_bmp.data); + + return FALSE; + } + } + + /* Update bitmap with new data */ if (new_bmp_owner) g_free (new_bmp.data); - return FALSE; + new_bmp = tmp_bmp; + new_bmp_owner = TRUE; } /* Output new bitmap info */ From f0de41331a19bf9da1b6e7f27388d4f062fec8d2 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Sat, 9 May 2009 14:39:01 -0400 Subject: [PATCH 3/8] 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 From dde3257b6c032dbcc0711fcb59900aa226bd0425 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sun, 7 Jun 2009 20:29:13 +0100 Subject: [PATCH 4/8] [cogl-bitmap] Fix minor copy and paste error in _cogl_bitmap_fallback_premult The returned bitmap format should include the COGL_PREMULT_BIT flag not have it explicitly removed as for _cogl_bitmap_fallback_unpremult. --- common/cogl-bitmap-fallback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/cogl-bitmap-fallback.c b/common/cogl-bitmap-fallback.c index a7e9704d9..e750a7ccf 100644 --- a/common/cogl-bitmap-fallback.c +++ b/common/cogl-bitmap-fallback.c @@ -416,7 +416,7 @@ _cogl_bitmap_fallback_premult (const CoglBitmap *bmp, /* Initialize destination bitmap */ *dst_bmp = *bmp; - dst_bmp->format = (bmp->format & COGL_UNPREMULT_MASK); + dst_bmp->format |= COGL_PREMULT_BIT; /* Allocate a new buffer to hold converted data */ dst_bmp->data = g_malloc (sizeof(guchar) From 7cb4b934321285f9f46ba72aefc0feda32123f03 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sun, 7 Jun 2009 15:58:56 +0100 Subject: [PATCH 5/8] [bitmap] Fixes _cogl_bitmap_fallback_unpremult The _cogl_unpremult_alpha_{first,last} functions which _cogl_bitmap_fallback_unpremult depends on were incorrectly casting each of the byte components of a texel to a gulong and performing shifts as if it were dealing with the whole texel. It now just uses array indexing to access the byte components without needing to cast or manually shift any bits around. Even though we used to depend on unpremult whenever we used a ClutterCairoTexture, clutter_cairo_texture_context_destroy had it's own unpremult code which worked which is why this bug wouldn't have been noticed before. --- common/cogl-bitmap-fallback.c | 60 +++++++++++++++++------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/common/cogl-bitmap-fallback.c b/common/cogl-bitmap-fallback.c index e750a7ccf..ddff6ea40 100644 --- a/common/cogl-bitmap-fallback.c +++ b/common/cogl-bitmap-fallback.c @@ -163,9 +163,9 @@ _cogl_unpremult_alpha_last (const guchar *src, guchar *dst) { guchar alpha = src[3]; - dst[0] = ((((gulong) src[0] >> 16) & 0xff) * 255 ) / alpha; - dst[1] = ((((gulong) src[1] >> 8) & 0xff) * 255 ) / alpha; - dst[2] = ((((gulong) src[2] >> 0) & 0xff) * 255 ) / alpha; + dst[0] = (src[0] * 255) / alpha; + dst[1] = (src[1] * 255) / alpha; + dst[2] = (src[2] * 255) / alpha; dst[3] = alpha; } @@ -175,9 +175,9 @@ _cogl_unpremult_alpha_first (const guchar *src, guchar *dst) guchar alpha = src[0]; dst[0] = alpha; - dst[1] = ((((gulong) src[1] >> 16) & 0xff) * 255 ) / alpha; - dst[2] = ((((gulong) src[2] >> 8) & 0xff) * 255 ) / alpha; - dst[3] = ((((gulong) src[3] >> 0) & 0xff) * 255 ) / alpha; + dst[1] = (src[1] * 255) / alpha; + dst[2] = (src[2] * 255) / alpha; + dst[3] = (src[3] * 255) / alpha; } /* No division form of floor((c*a + 128)/255) (I first encountered @@ -365,35 +365,35 @@ _cogl_bitmap_fallback_unpremult (const CoglBitmap *bmp, * dst_bmp->height * dst_bmp->rowstride); - /* FIXME: Optimize */ for (y = 0; y < bmp->height; y++) { src = (guchar*)bmp->data + y * bmp->rowstride; dst = (guchar*)dst_bmp->data + y * dst_bmp->rowstride; - for (x = 0; x < bmp->width; x++) - { - /* FIXME: Would be nice to at least remove this inner - * branching, but not sure it can be done without - * rewriting of the whole loop */ - if (bmp->format & COGL_AFIRST_BIT) - { - if (src[0] == 0) - _cogl_unpremult_alpha_0 (src, dst); - else - _cogl_unpremult_alpha_first (src, dst); - } - else - { - if (src[3] == 0) - _cogl_unpremult_alpha_0 (src, dst); - else - _cogl_unpremult_alpha_last (src, dst); - } - - src += bpp; - dst += bpp; - } + if (bmp->format & COGL_AFIRST_BIT) + { + for (x = 0; x < bmp->width; x++) + { + if (src[0] == 0) + _cogl_unpremult_alpha_0 (src, dst); + else + _cogl_unpremult_alpha_first (src, dst); + src += bpp; + dst += bpp; + } + } + else + { + for (x = 0; x < bmp->width; x++) + { + if (src[0] == 0) + _cogl_unpremult_alpha_0 (src, dst); + else + _cogl_unpremult_alpha_last (src, dst); + src += bpp; + dst += bpp; + } + } } return TRUE; From e6da6df8a8d7d5e0ccf88b71dd2a0ad764b0bf6a Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sat, 6 Jun 2009 21:45:05 +0100 Subject: [PATCH 6/8] [premultiplication] Be more conservative with what data gets premultiplied We don't want to force texture data to be premultipled if the user explicitly specifies a non premultiplied internal_format such as COGL_PIXEL_FORMAT_RGBA_8888. So now Cogl will only automatically premultiply data when COGL_PIXEL_FORMAT_ANY is given for the internal_format, or a premultiplied internal format such as COGL_PIXEL_FORMAT_RGBA_8888_PRE is requested but non-premultiplied source data is given. This approach is consistent with OpenVG image formats which have already influenced Cogl's pixel format semantics. --- gl/cogl-texture.c | 24 +++++++++++------------- gles/cogl-texture.c | 24 +++++++++++------------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c index 2ee50617c..877107d3c 100644 --- a/gl/cogl-texture.c +++ b/gl/cogl-texture.c @@ -1085,17 +1085,9 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format, GLenum glformat = 0; GLenum gltype = 0; - /* 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; + /* FIXME: check YUV support */ + + required_format = format; /* Find GL equivalents */ switch (format & COGL_UNPREMULT_MASK) @@ -1197,9 +1189,15 @@ _cogl_texture_bitmap_prepare (CoglTexture *tex, CoglPixelFormat new_data_format; gboolean success; - /* Was there any internal conversion requested? */ + /* Was there any internal conversion requested? + * By default Cogl will use a premultiplied internal format. Later we will + * add control over this. */ if (internal_format == COGL_PIXEL_FORMAT_ANY) - internal_format = tex->bitmap.format; + { + if ((tex->bitmap.format & COGL_A_BIT) && + tex->bitmap.format != COGL_PIXEL_FORMAT_A_8) + internal_format = tex->bitmap.format | COGL_PREMULT_BIT; + } /* Find closest format accepted by GL */ new_data_format = _cogl_pixel_format_to_gl (internal_format, diff --git a/gles/cogl-texture.c b/gles/cogl-texture.c index f9b6e0b78..ab1653e07 100644 --- a/gles/cogl-texture.c +++ b/gles/cogl-texture.c @@ -1184,17 +1184,9 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format, GLenum glformat = 0; GLenum gltype = 0; - /* 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; + /* FIXME: check YUV support */ + + required_format = format; /* Find GL equivalents */ switch (format & COGL_UNPREMULT_MASK) @@ -1273,9 +1265,15 @@ _cogl_texture_bitmap_prepare (CoglTexture *tex, CoglPixelFormat new_data_format; gboolean success; - /* Was there any internal conversion requested? */ + /* Was there any internal conversion requested? + * By default Cogl will use a premultiplied internal format. Later we will + * add control over this. */ if (internal_format == COGL_PIXEL_FORMAT_ANY) - internal_format = tex->bitmap.format; + { + if ((tex->bitmap.format & COGL_A_BIT) && + tex->bitmap.format != COGL_PIXEL_FORMAT_A_8) + internal_format = tex->bitmap.format | COGL_PREMULT_BIT; + } /* Find closest format accepted by GL */ new_data_format = _cogl_pixel_format_to_gl (internal_format, From 58fa6917c266d24eb84d008191b230054ee5e63c Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Sun, 7 Jun 2009 11:54:05 +0100 Subject: [PATCH 7/8] [fog] Document that fogging only works with opaque or unmultipled colors The fixed function fogging provided by OpenGL only works with unmultiplied colors (or if the color has an alpha of 1.0) so since we now premultiply textures and colors by default a note to this affect has been added to clutter_stage_set_fog and cogl_set_fog. test-depth.c no longer uses clutter_stage_set_fog for this reason. In the future when we can depend on fragment shaders we should also be able to support fogging of premultiplied primitives. --- cogl.h.in | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/cogl.h.in b/cogl.h.in index 64d57fc4f..26bcf25c2 100644 --- a/cogl.h.in +++ b/cogl.h.in @@ -386,13 +386,22 @@ gboolean cogl_get_backface_culling_enabled (void); * @z_near: Position along z-axis where no fogging should be applied * @z_far: Position along z-axes where full fogging should be applied * - * Enables fogging. Fogging causes vertices that are further away from - * the eye to be rendered with a different color. The color is determined - * according to the chosen fog mode; at it's simplest the color is - * linearly interpolated so that vertices at @z_near are drawn fully - * with their original color and vertices at @z_far are drawn fully - * with @fog_color. Fogging will remain enabled until you call - * cogl_disable_fog(). + * Enables fogging. Fogging causes vertices that are further away from the eye + * to be rendered with a different color. The color is determined according to + * the chosen fog mode; at it's simplest the color is linearly interpolated so + * that vertices at @z_near are drawn fully with their original color and + * vertices at @z_far are drawn fully with @fog_color. Fogging will remain + * enabled until you call cogl_disable_fog(). + * + * Note: The fogging functions only work correctly when primitives use + * unmultiplied alpha colors. By default Cogl will premultiply textures + * and cogl_set_source_color will premultiply colors, so unless you + * explicitly load your textures requesting an unmultiplied + * internal_format and use cogl_material_set_color you can only use + * fogging with fully opaque primitives. + * + * We can look to improve this in the future when we can depend on + * fragment shaders. */ void cogl_set_fog (const CoglColor *fog_color, CoglFogMode mode, From 9d7a93f641144f928e404c8feda6adf51ddba519 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Thu, 11 Jun 2009 14:31:01 +0100 Subject: [PATCH 8/8] [cogl-texture docs] Improves the documentation of the internal_format args Clarifies that if you give COGL_PIXEL_FORMAT_ANY as the internal format for cogl_texture_new_from_file or cogl_texture_new_from_data then Cogl will choose a premultiplied internal format. --- cogl-texture.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/cogl-texture.h b/cogl-texture.h index 15cadc879..e3a2264a1 100644 --- a/cogl-texture.h +++ b/cogl-texture.h @@ -68,7 +68,13 @@ CoglHandle cogl_texture_new_with_size (guint width, * @filename: the file to load * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @internal_format: the #CoglPixelFormat to use for the GPU storage of the - * texture + * texture. If COGL_PIXEL_FORMAT_ANY is given then a premultiplied + * format similar to the format of the source data will be used. The + * default blending equations of Cogl expect premultiplied color data; + * the main use of passing a non-premultiplied format here is if you + * have non-premultiplied source data and are going to adjust the blend + * mode (see cogl_material_set_blend()) or use the data for something + * other than straight blending. * @error: return location for a #GError or %NULL * * Creates a COGL texture from an image file. @@ -90,7 +96,13 @@ CoglHandle cogl_texture_new_from_file (const gchar *filename, * @flags: Optional flags for the texture, or %COGL_TEXTURE_NONE * @format: the #CoglPixelFormat the buffer is stored in in RAM * @internal_format: the #CoglPixelFormat that will be used for storing - * the buffer on the GPU + * the buffer on the GPU. If COGL_PIXEL_FORMAT_ANY is given then a + * premultiplied format similar to the format of the source data will + * be used. The default blending equations of Cogl expect premultiplied + * color data; the main use of passing a non-premultiplied format here + * is if you have non-premultiplied source data and are going to adjust + * the blend mode (see cogl_material_set_blend()) or use the data for + * something other than straight blending. * @rowstride: the memory offset in bytes between the starts of * scanlines in @data * @data: pointer the memory region where the source buffer resides