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 <robert@linux.intel.com>
This commit is contained in:
Owen W. Taylor 2009-05-09 14:39:01 -04:00 committed by Robert Bragg
parent 888a261999
commit c3448314d5
10 changed files with 67 additions and 34 deletions

View File

@ -608,7 +608,8 @@ clutter_texture_paint (ClutterActor *self)
clutter_actor_get_name (self) ? clutter_actor_get_name (self)
: "unknown");
cogl_material_set_color4ub (priv->material, 0xff, 0xff, 0xff, paint_opacity);
cogl_material_set_color4ub (priv->material,
paint_opacity, paint_opacity, paint_opacity, paint_opacity);
clutter_actor_get_allocation_box (self, &box);

View File

@ -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,
* </programlisting>
* </section>
*
* 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.

View File

@ -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.

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -239,8 +239,10 @@ _cogl_pango_display_list_render_texture (CoglHandle material,
const CoglColor *color,
CoglPangoDisplayListNode *node)
{
CoglColor premult_color = *color;
cogl_material_set_layer (material, 0, node->d.texture.texture);
cogl_material_set_color (material, color);
cogl_color_premultiply (&premult_color);
cogl_material_set_color (material, &premult_color);
cogl_set_source (material);
if (node->d.texture.vertex_buffer == COGL_INVALID_HANDLE)
@ -311,6 +313,7 @@ _cogl_pango_display_list_render (CoglPangoDisplayList *dl,
cogl_color_get_alpha_byte (color));
else
draw_color = *color;
cogl_color_premultiply (&draw_color);
switch (node->type)
{

View File

@ -124,16 +124,20 @@ cogl_pango_renderer_init (CoglPangoRenderer *priv)
/* The default combine mode of materials is to modulate (A x B) the texture
* RGBA channels with the RGBA channels of the previous layer (which in our
* case is just the solid font color)
* case is just the font color)
*
* Since our glyph cache textures are component alpha textures, and so the
* RGB channels are defined as (0, 0, 0) we don't want to modulate the RGB
* channels, instead we want to simply replace them with our solid font
* color...
* Since the RGB for an alpha texture is defined as 0, this gives us:
*
* result.rgb = color.rgb * 0
* result.a = color.a * texture.a
*
* What we want is premultiplied rgba values:
*
* result.rgba = color.rgb * texture.a
* result.a = color.a * texture.a
*/
cogl_material_set_layer_combine (priv->glyph_material, 0, /* layer */
"RGB = REPLACE (PREVIOUS)"
"A = MODULATE (PREVIOUS, TEXTURE)",
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
NULL);
priv->solid_material = cogl_material_new ();

View File

@ -106,7 +106,7 @@ test_coglbox_paint(ClutterActor *self)
cogl_set_draw_buffer (COGL_WINDOW_BUFFER, 0);
material = cogl_material_new ();
cogl_material_set_color4ub (material, 0xff, 0xff, 0xff, 0x88);
cogl_material_set_color4ub (material, 0x88, 0x88, 0x88, 0x88);
cogl_material_set_layer (material, 0, priv->texture_id);
cogl_set_source (material);
cogl_rectangle_with_texture_coords (100, 100,