mirror of
https://github.com/brl/mutter.git
synced 2024-11-23 00:20:42 -05:00
Bug 1406 - Handling of premultiplication in clutter
Merge branch 'premultiplication' [cogl-texture docs] Improves the documentation of the internal_format args [test-premult] Adds a unit test for texture upload premultiplication semantics [fog] Document that fogging only works with opaque or unmultipled colors [test-blend-strings] Explicitly request RGBA_888 tex format for test textures [premultiplication] Be more conservative with what data gets premultiplied [bitmap] Fixes _cogl_bitmap_fallback_unpremult [cogl-bitmap] Fix minor copy and paste error in _cogl_bitmap_fallback_premult Avoid unnecesary unpremultiplication when saving to local data Don't unpremultiply Cairo data Default to a blend function that expects premultiplied colors Implement premultiplication for CoglBitmap Use correct texture format for pixmap textures and FBO's Add cogl_color_premultiply()
This commit is contained in:
commit
96827db740
@ -292,14 +292,13 @@ clutter_cairo_texture_surface_resize_internal (ClutterCairoTexture *cairo)
|
||||
cairo,
|
||||
clutter_cairo_texture_surface_destroy);
|
||||
|
||||
/* The texture data will be all zeroes so we can use it to create a
|
||||
* blank Cogl texture even though its in a different format
|
||||
/* Create a blank Cogl texture
|
||||
*/
|
||||
clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (cairo),
|
||||
priv->cr_surface_data,
|
||||
TRUE, priv->width, priv->height,
|
||||
priv->rowstride,
|
||||
4, 0, NULL);
|
||||
4, CLUTTER_TEXTURE_RGB_FLAG_PREMULT, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -451,9 +450,7 @@ clutter_cairo_texture_context_destroy (void *data)
|
||||
|
||||
gint cairo_width, cairo_height, cairo_rowstride;
|
||||
gint surface_width, surface_height;
|
||||
guchar *pixbuf_data, *dst, *cairo_data;
|
||||
guint *src, pixbuf_rowstride;
|
||||
gint x, y;
|
||||
guchar *cairo_data;
|
||||
|
||||
priv = CLUTTER_CAIRO_TEXTURE_GET_PRIVATE (cairo);
|
||||
|
||||
@ -473,56 +470,19 @@ clutter_cairo_texture_context_destroy (void *data)
|
||||
}
|
||||
|
||||
cairo_rowstride = priv->rowstride;
|
||||
cairo_data = priv->cr_surface_data;
|
||||
pixbuf_data = g_malloc (cairo_width * cairo_height * 4);
|
||||
pixbuf_rowstride = cairo_width * 4;
|
||||
|
||||
/* BAH BAH BAH ! un-pre-multiply alpha...
|
||||
*
|
||||
* FIXME: Need to figure out if GL has a premult texture
|
||||
* format, or we need to change the order of the
|
||||
* paint sequence in Clutter. or go back to battling
|
||||
* glitz (ugh).
|
||||
*
|
||||
* in theory, this could be moved to a shader, but apparently
|
||||
* the performance gain is not really worth it.
|
||||
*/
|
||||
for (y = 0; y < cairo_height; y++)
|
||||
{
|
||||
src = (unsigned int *) (cairo_data
|
||||
+ ((y + ctxt->rect.y) * cairo_rowstride)
|
||||
+ (ctxt->rect.x * 4));
|
||||
dst = pixbuf_data + y * pixbuf_rowstride;
|
||||
|
||||
for (x = 0; x < cairo_width; x++)
|
||||
{
|
||||
guchar alpha = (*src >> 24) & 0xff;
|
||||
|
||||
if (alpha == 0)
|
||||
dst[0] = dst[1] = dst[2] = dst[3] = alpha;
|
||||
else
|
||||
{
|
||||
dst[0] = (((*src >> 16) & 0xff) * 255 ) / alpha;
|
||||
dst[1] = (((*src >> 8) & 0xff) * 255 ) / alpha;
|
||||
dst[2] = (((*src >> 0) & 0xff) * 255 ) / alpha;
|
||||
dst[3] = alpha;
|
||||
}
|
||||
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
cairo_data = (priv->cr_surface_data
|
||||
+ ctxt->rect.y * cairo_rowstride
|
||||
+ ctxt->rect.x * 4);
|
||||
|
||||
clutter_texture_set_area_from_rgb_data (CLUTTER_TEXTURE (cairo),
|
||||
pixbuf_data,
|
||||
cairo_data,
|
||||
TRUE,
|
||||
ctxt->rect.x,
|
||||
ctxt->rect.y,
|
||||
cairo_width, cairo_height,
|
||||
pixbuf_rowstride,
|
||||
4, 0, NULL);
|
||||
cairo_rowstride,
|
||||
4, CLUTTER_TEXTURE_RGB_FLAG_PREMULT, NULL);
|
||||
|
||||
g_free (pixbuf_data);
|
||||
g_free (ctxt);
|
||||
|
||||
if (CLUTTER_ACTOR_IS_VISIBLE (cairo))
|
||||
|
@ -1788,6 +1788,16 @@ clutter_stage_set_use_fog (ClutterStage *stage,
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* Note: The fogging functions only work correctly when the visible actors 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 actors.
|
||||
*
|
||||
* We can look to improve this in the future when we can depend on
|
||||
* fragment shaders.
|
||||
*
|
||||
* Since: 0.6
|
||||
*/
|
||||
void
|
||||
|
@ -296,7 +296,7 @@ clutter_texture_realize (ClutterActor *actor)
|
||||
tex = cogl_texture_new_with_size (priv->width,
|
||||
priv->height,
|
||||
flags,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888);
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE);
|
||||
|
||||
cogl_material_set_layer (priv->material, 0, tex);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -1224,7 +1225,7 @@ clutter_texture_save_to_local_data (ClutterTexture *texture)
|
||||
|
||||
if (cogl_texture_get_data (cogl_texture,
|
||||
priv->local_data_has_alpha
|
||||
? COGL_PIXEL_FORMAT_RGBA_8888
|
||||
? COGL_PIXEL_FORMAT_RGBA_8888_PRE
|
||||
: COGL_PIXEL_FORMAT_RGB_888,
|
||||
priv->local_data_rowstride,
|
||||
priv->local_data) == 0)
|
||||
@ -1251,7 +1252,7 @@ clutter_texture_load_from_local_data (ClutterTexture *texture)
|
||||
priv->local_data_height,
|
||||
priv->local_data_rowstride,
|
||||
priv->local_data_has_alpha ? 4: 3,
|
||||
0, NULL);
|
||||
CLUTTER_TEXTURE_RGB_FLAG_PREMULT, NULL);
|
||||
|
||||
g_free (priv->local_data);
|
||||
priv->local_data = NULL;
|
||||
@ -2243,7 +2244,7 @@ on_fbo_source_size_change (GObject *object,
|
||||
tex = cogl_texture_new_with_size (MAX (priv->width, 1),
|
||||
MAX (priv->height, 1),
|
||||
flags,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888);
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE);
|
||||
|
||||
cogl_material_set_layer (priv->material, 0, tex);
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
@ -455,8 +464,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.
|
||||
|
@ -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,11 +175,46 @@ _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
|
||||
* 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,
|
||||
@ -324,34 +365,86 @@ _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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
src += bpp;
|
||||
dst += bpp;
|
||||
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 |= COGL_PREMULT_BIT;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -1085,18 +1085,12 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format,
|
||||
GLenum glformat = 0;
|
||||
GLenum gltype = 0;
|
||||
|
||||
/* No premultiplied formats accepted by GL
|
||||
* (FIXME: latest hardware?) */
|
||||
/* FIXME: check YUV support */
|
||||
|
||||
if (format & COGL_PREMULT_BIT)
|
||||
format = (format & COGL_UNPREMULT_MASK);
|
||||
|
||||
/* Everything else accepted
|
||||
* (FIXME: check YUV support) */
|
||||
required_format = format;
|
||||
|
||||
/* Find GL equivalents */
|
||||
switch (format)
|
||||
switch (format & COGL_UNPREMULT_MASK)
|
||||
{
|
||||
case COGL_PIXEL_FORMAT_A_8:
|
||||
glintformat = GL_ALPHA;
|
||||
@ -1195,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,
|
||||
|
@ -1184,18 +1184,12 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format,
|
||||
GLenum glformat = 0;
|
||||
GLenum gltype = 0;
|
||||
|
||||
/* No premultiplied formats accepted by GL
|
||||
* (FIXME: latest hardware?) */
|
||||
/* FIXME: check YUV support */
|
||||
|
||||
if (format & COGL_PREMULT_BIT)
|
||||
format = (format & COGL_UNPREMULT_MASK);
|
||||
|
||||
/* Everything else accepted
|
||||
* (FIXME: check YUV support) */
|
||||
required_format = format;
|
||||
|
||||
/* Find GL equivalents */
|
||||
switch (format)
|
||||
switch (format & COGL_UNPREMULT_MASK)
|
||||
{
|
||||
case COGL_PIXEL_FORMAT_A_8:
|
||||
glintformat = GL_ALPHA;
|
||||
@ -1226,6 +1220,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
|
||||
@ -1270,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,
|
||||
|
@ -359,14 +359,16 @@ create_cogl_texture (ClutterTexture *texture,
|
||||
handle = cogl_texture_new_from_foreign (tex, CGL_TEXTURE_RECTANGLE_ARB,
|
||||
width, height,
|
||||
0, 0,
|
||||
cogl_format | COGL_BGR_BIT);
|
||||
cogl_format | COGL_BGR_BIT |
|
||||
COGL_PREMULT_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
handle
|
||||
= cogl_texture_new_with_size (width, height,
|
||||
COGL_TEXTURE_NO_SLICING,
|
||||
cogl_format | COGL_BGR_BIT);
|
||||
cogl_format | COGL_BGR_BIT |
|
||||
COGL_PREMULT_BIT);
|
||||
|
||||
using_rectangle = FALSE;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 ();
|
||||
|
@ -871,7 +871,8 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
|
||||
width, height,
|
||||
bytes_per_line,
|
||||
4,
|
||||
CLUTTER_TEXTURE_RGB_FLAG_BGR,
|
||||
CLUTTER_TEXTURE_RGB_FLAG_BGR |
|
||||
CLUTTER_TEXTURE_RGB_FLAG_PREMULT,
|
||||
&error);
|
||||
else
|
||||
clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (texture),
|
||||
@ -880,7 +881,8 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
|
||||
width, height,
|
||||
bytes_per_line,
|
||||
4,
|
||||
CLUTTER_TEXTURE_RGB_FLAG_BGR,
|
||||
CLUTTER_TEXTURE_RGB_FLAG_BGR |
|
||||
CLUTTER_TEXTURE_RGB_FLAG_PREMULT,
|
||||
&error);
|
||||
|
||||
|
||||
|
@ -29,6 +29,7 @@ test_conformance_SOURCES = \
|
||||
test-blend-strings.c \
|
||||
test-color.c \
|
||||
test-clutter-units.c \
|
||||
test-premult.c \
|
||||
$(NULL)
|
||||
|
||||
# For convenience, this provides a way to easily run individual unit tests:
|
||||
|
@ -172,11 +172,13 @@ make_texture (guint32 color)
|
||||
*(--p) = r;
|
||||
}
|
||||
|
||||
/* Note: we don't use COGL_PIXEL_FORMAT_ANY for the internal format here
|
||||
* since we don't want to allow Cogl to premultiply our data. */
|
||||
tex = cogl_texture_new_from_data (QUAD_WIDTH,
|
||||
QUAD_WIDTH,
|
||||
COGL_TEXTURE_NONE,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888,
|
||||
COGL_PIXEL_FORMAT_ANY,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888,
|
||||
QUAD_WIDTH * 4,
|
||||
tex_data);
|
||||
|
||||
|
@ -136,6 +136,7 @@ main (int argc, char **argv)
|
||||
|
||||
TEST_CONFORM_SIMPLE ("/texture", test_backface_culling);
|
||||
TEST_CONFORM_SIMPLE ("/texture", test_npot_texture);
|
||||
TEST_CONFORM_SIMPLE ("/texture", test_premult);
|
||||
|
||||
TEST_CONFORM_SIMPLE ("/path", test_path);
|
||||
|
||||
|
388
tests/conform/test-premult.c
Normal file
388
tests/conform/test-premult.c
Normal file
@ -0,0 +1,388 @@
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <cogl/cogl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "test-conform-common.h"
|
||||
|
||||
static const ClutterColor stage_color = { 0x0, 0x0, 0x0, 0xff };
|
||||
|
||||
#define QUAD_WIDTH 20
|
||||
|
||||
#define RED 0
|
||||
#define GREEN 1
|
||||
#define BLUE 2
|
||||
#define ALPHA 3
|
||||
|
||||
#define MASK_RED(COLOR) ((COLOR & 0xff000000) >> 24);
|
||||
#define MASK_GREEN(COLOR) ((COLOR & 0xff0000) >> 16);
|
||||
#define MASK_BLUE(COLOR) ((COLOR & 0xff00) >> 8);
|
||||
#define MASK_ALPHA(COLOR) (COLOR & 0xff);
|
||||
|
||||
#define SKIP_FRAMES 2
|
||||
|
||||
typedef struct _TestState
|
||||
{
|
||||
guint frame;
|
||||
ClutterGeometry stage_geom;
|
||||
CoglHandle passthrough_material;
|
||||
} TestState;
|
||||
|
||||
|
||||
static void
|
||||
check_pixel (GLubyte *pixel, guint32 color)
|
||||
{
|
||||
guint8 r = MASK_RED (color);
|
||||
guint8 g = MASK_GREEN (color);
|
||||
guint8 b = MASK_BLUE (color);
|
||||
guint8 a = MASK_ALPHA (color);
|
||||
|
||||
if (g_test_verbose ())
|
||||
g_print (" expected = %x, %x, %x, %x\n",
|
||||
r, g, b, a);
|
||||
/* FIXME - allow for hardware in-precision */
|
||||
g_assert (pixel[RED] == r);
|
||||
g_assert (pixel[GREEN] == g);
|
||||
g_assert (pixel[BLUE] == b);
|
||||
|
||||
/* FIXME
|
||||
* We ignore the alpha, since we don't know if our render target is
|
||||
* RGB or RGBA */
|
||||
/* g_assert (pixel[ALPHA] == a); */
|
||||
}
|
||||
|
||||
static guchar *
|
||||
gen_tex_data (guint32 color)
|
||||
{
|
||||
guchar *tex_data, *p;
|
||||
guint8 r = MASK_RED (color);
|
||||
guint8 g = MASK_GREEN (color);
|
||||
guint8 b = MASK_BLUE (color);
|
||||
guint8 a = MASK_ALPHA (color);
|
||||
|
||||
tex_data = g_malloc (QUAD_WIDTH * QUAD_WIDTH * 4);
|
||||
|
||||
for (p = tex_data + QUAD_WIDTH * QUAD_WIDTH * 4; p > tex_data;)
|
||||
{
|
||||
*(--p) = a;
|
||||
*(--p) = b;
|
||||
*(--p) = g;
|
||||
*(--p) = r;
|
||||
}
|
||||
|
||||
return tex_data;
|
||||
}
|
||||
|
||||
static CoglHandle
|
||||
make_texture (guint32 color,
|
||||
CoglPixelFormat src_format,
|
||||
CoglPixelFormat internal_format)
|
||||
{
|
||||
CoglHandle tex;
|
||||
guchar *tex_data = gen_tex_data (color);
|
||||
|
||||
tex = cogl_texture_new_from_data (QUAD_WIDTH,
|
||||
QUAD_WIDTH,
|
||||
COGL_TEXTURE_NONE,
|
||||
src_format,
|
||||
internal_format,
|
||||
QUAD_WIDTH * 4,
|
||||
tex_data);
|
||||
|
||||
g_free (tex_data);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
static void
|
||||
check_texture (TestState *state,
|
||||
int x,
|
||||
int y,
|
||||
CoglHandle tex,
|
||||
guint32 expected_result)
|
||||
{
|
||||
GLubyte pixel[4];
|
||||
GLint y_off;
|
||||
GLint x_off;
|
||||
|
||||
cogl_material_set_layer (state->passthrough_material, 0, tex);
|
||||
|
||||
cogl_set_source (state->passthrough_material);
|
||||
cogl_rectangle (x * QUAD_WIDTH,
|
||||
y * QUAD_WIDTH,
|
||||
x * QUAD_WIDTH + QUAD_WIDTH,
|
||||
y * QUAD_WIDTH + QUAD_WIDTH);
|
||||
|
||||
/* See what we got... */
|
||||
|
||||
/* NB: glReadPixels is done in GL screen space so y = 0 is at the bottom */
|
||||
y_off = state->stage_geom.height - y * QUAD_WIDTH - (QUAD_WIDTH / 2);
|
||||
x_off = x * QUAD_WIDTH + (QUAD_WIDTH / 2);
|
||||
|
||||
/* XXX:
|
||||
* We haven't always had good luck with GL drivers implementing glReadPixels
|
||||
* reliably and skipping the first two frames improves our chances... */
|
||||
if (state->frame <= SKIP_FRAMES)
|
||||
return;
|
||||
|
||||
glReadPixels (x_off, y_off, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
|
||||
if (g_test_verbose ())
|
||||
{
|
||||
g_print ("check texture (%d, %d):\n", x, y);
|
||||
g_print (" result = %02x, %02x, %02x, %02x\n",
|
||||
pixel[RED], pixel[GREEN], pixel[BLUE], pixel[ALPHA]);
|
||||
}
|
||||
|
||||
check_pixel (pixel, expected_result);
|
||||
}
|
||||
|
||||
static void
|
||||
on_paint (ClutterActor *actor, TestState *state)
|
||||
{
|
||||
int frame_num;
|
||||
CoglHandle tex;
|
||||
guchar *tex_data;
|
||||
|
||||
/* If the user explicitly specifies an unmultiplied internal format then
|
||||
* Cogl shouldn't automatically premultiply the given texture data... */
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("make_texture (0xff00ff80, "
|
||||
"src = RGBA_8888, internal = RGBA_8888)\n");
|
||||
tex = make_texture (0xff00ff80,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888); /* internal format */
|
||||
check_texture (state, 0, 0, /* position */
|
||||
tex,
|
||||
0xff00ff80); /* expected */
|
||||
|
||||
/* If the user explicitly requests a premultiplied internal format and
|
||||
* gives unmultiplied src data then Cogl should always premultiply that
|
||||
* for us */
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("make_texture (0xff00ff80, "
|
||||
"src = RGBA_8888, internal = RGBA_8888_PRE)\n");
|
||||
tex = make_texture (0xff00ff80,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE); /* internal format */
|
||||
check_texture (state, 1, 0, /* position */
|
||||
tex,
|
||||
0x80008080); /* expected */
|
||||
|
||||
/* If the user gives COGL_PIXEL_FORMAT_ANY for the internal format then
|
||||
* by default Cogl should premultiply the given texture data...
|
||||
* (In the future there will be additional Cogl API to control this
|
||||
* behaviour) */
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("make_texture (0xff00ff80, "
|
||||
"src = RGBA_8888, internal = ANY)\n");
|
||||
tex = make_texture (0xff00ff80,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
|
||||
COGL_PIXEL_FORMAT_ANY); /* internal format */
|
||||
check_texture (state, 2, 0, /* position */
|
||||
tex,
|
||||
0x80008080); /* expected */
|
||||
|
||||
/* If the user requests a premultiplied internal texture format and supplies
|
||||
* premultiplied source data, Cogl should never modify that source data...
|
||||
*/
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("make_texture (0x80008080, "
|
||||
"src = RGBA_8888_PRE, "
|
||||
"internal = RGBA_8888_PRE)\n");
|
||||
tex = make_texture (0x80008080,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE); /* internal format */
|
||||
check_texture (state, 3, 0, /* position */
|
||||
tex,
|
||||
0x80008080); /* expected */
|
||||
|
||||
/* If the user requests an unmultiplied internal texture format, but
|
||||
* supplies premultiplied source data, then Cogl should always
|
||||
* un-premultiply the source data... */
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("make_texture (0x80008080, "
|
||||
"src = RGBA_8888_PRE, internal = RGBA_8888)\n");
|
||||
tex = make_texture (0x80008080,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888); /* internal format */
|
||||
check_texture (state, 4, 0, /* position */
|
||||
tex,
|
||||
0xff00ff80); /* expected */
|
||||
|
||||
/* If the user allows any internal texture format and provides premultipled
|
||||
* source data then by default Cogl shouldn't modify the source data...
|
||||
* (In the future there will be additional Cogl API to control this
|
||||
* behaviour) */
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("make_texture (0x80008080, "
|
||||
"src = RGBA_8888_PRE, internal = ANY)\n");
|
||||
tex = make_texture (0x80008080,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
|
||||
COGL_PIXEL_FORMAT_ANY); /* internal format */
|
||||
check_texture (state, 5, 0, /* position */
|
||||
tex,
|
||||
0x80008080); /* expected */
|
||||
|
||||
/*
|
||||
* Test cogl_texture_set_region() ....
|
||||
*/
|
||||
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("make_texture (0xDEADBEEF, "
|
||||
"src = RGBA_8888, internal = RGBA_8888)\n");
|
||||
tex = make_texture (0xDEADBEEF,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888); /* internal format */
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("set_region (0xff00ff80, RGBA_8888)\n");
|
||||
tex_data = gen_tex_data (0xff00ff80);
|
||||
cogl_texture_set_region (tex,
|
||||
0, 0, /* src x, y */
|
||||
0, 0, /* dst x, y */
|
||||
QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */
|
||||
QUAD_WIDTH, QUAD_WIDTH, /* src width, height */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888,
|
||||
0, /* auto compute row stride */
|
||||
tex_data);
|
||||
check_texture (state, 6, 0, /* position */
|
||||
tex,
|
||||
0xff00ff80); /* expected */
|
||||
|
||||
/* Updating a texture region for an unmultiplied texture using premultiplied
|
||||
* region data should result in Cogl unmultiplying the given region data...
|
||||
*/
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("make_texture (0xDEADBEEF, "
|
||||
"src = RGBA_8888, internal = RGBA_8888)\n");
|
||||
tex = make_texture (0xDEADBEEF,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888, /* src format */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888); /* internal format */
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("set_region (0x80008080, RGBA_8888_PRE)\n");
|
||||
tex_data = gen_tex_data (0x80008080);
|
||||
cogl_texture_set_region (tex,
|
||||
0, 0, /* src x, y */
|
||||
0, 0, /* dst x, y */
|
||||
QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */
|
||||
QUAD_WIDTH, QUAD_WIDTH, /* src width, height */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
|
||||
0, /* auto compute row stride */
|
||||
tex_data);
|
||||
check_texture (state, 7, 0, /* position */
|
||||
tex,
|
||||
0xff00ff80); /* expected */
|
||||
|
||||
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("make_texture (0xDEADBEEF, "
|
||||
"src = RGBA_8888_PRE, "
|
||||
"internal = RGBA_8888_PRE)\n");
|
||||
tex = make_texture (0xDEADBEEF,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE); /* internal format */
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("set_region (0x80008080, RGBA_8888_PRE)\n");
|
||||
tex_data = gen_tex_data (0x80008080);
|
||||
cogl_texture_set_region (tex,
|
||||
0, 0, /* src x, y */
|
||||
0, 0, /* dst x, y */
|
||||
QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */
|
||||
QUAD_WIDTH, QUAD_WIDTH, /* src width, height */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
|
||||
0, /* auto compute row stride */
|
||||
tex_data);
|
||||
check_texture (state, 8, 0, /* position */
|
||||
tex,
|
||||
0x80008080); /* expected */
|
||||
|
||||
|
||||
/* Updating a texture region for a premultiplied texture using unmultiplied
|
||||
* region data should result in Cogl premultiplying the given region data...
|
||||
*/
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("make_texture (0xDEADBEEF, "
|
||||
"src = RGBA_8888_PRE, "
|
||||
"internal = RGBA_8888_PRE)\n");
|
||||
tex = make_texture (0xDEADBEEF,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE, /* src format */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE); /* internal format */
|
||||
if (state->frame > SKIP_FRAMES && g_test_verbose ())
|
||||
g_print ("set_region (0xff00ff80, RGBA_8888)\n");
|
||||
tex_data = gen_tex_data (0xff00ff80);
|
||||
cogl_texture_set_region (tex,
|
||||
0, 0, /* src x, y */
|
||||
0, 0, /* dst x, y */
|
||||
QUAD_WIDTH, QUAD_WIDTH, /* dst width, height */
|
||||
QUAD_WIDTH, QUAD_WIDTH, /* src width, height */
|
||||
COGL_PIXEL_FORMAT_RGBA_8888,
|
||||
0, /* auto compute row stride */
|
||||
tex_data);
|
||||
check_texture (state, 9, 0, /* position */
|
||||
tex,
|
||||
0x80008080); /* expected */
|
||||
|
||||
|
||||
/* XXX: Experiments have shown that for some buggy drivers, when using
|
||||
* glReadPixels there is some kind of race, so we delay our test for a
|
||||
* few frames and a few seconds:
|
||||
*/
|
||||
frame_num = state->frame++;
|
||||
if (frame_num < SKIP_FRAMES)
|
||||
g_usleep (G_USEC_PER_SEC);
|
||||
|
||||
/* Comment this out if you want visual feedback for what this test paints */
|
||||
#if 1
|
||||
if (frame_num > SKIP_FRAMES)
|
||||
clutter_main_quit ();
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
queue_redraw (gpointer stage)
|
||||
{
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
test_premult (TestConformSimpleFixture *fixture,
|
||||
gconstpointer data)
|
||||
{
|
||||
TestState state;
|
||||
ClutterActor *stage;
|
||||
ClutterActor *group;
|
||||
guint idle_source;
|
||||
|
||||
state.frame = 0;
|
||||
state.passthrough_material = cogl_material_new ();
|
||||
cogl_material_set_blend (state.passthrough_material,
|
||||
"RGBA = ADD (SRC_COLOR, 0)", NULL);
|
||||
cogl_material_set_layer_combine (state.passthrough_material, 0,
|
||||
"RGBA = REPLACE (TEXTURE)", NULL);
|
||||
|
||||
stage = clutter_stage_get_default ();
|
||||
|
||||
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
|
||||
clutter_actor_get_geometry (stage, &state.stage_geom);
|
||||
|
||||
group = clutter_group_new ();
|
||||
clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
|
||||
|
||||
/* We force continuous redrawing of the stage, since we need to skip
|
||||
* the first few frames, and we wont be doing anything else that
|
||||
* will trigger redrawing. */
|
||||
idle_source = g_idle_add (queue_redraw, stage);
|
||||
|
||||
g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state);
|
||||
|
||||
clutter_actor_show_all (stage);
|
||||
|
||||
clutter_main ();
|
||||
|
||||
g_source_remove (idle_source);
|
||||
|
||||
if (g_test_verbose ())
|
||||
g_print ("OK\n");
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -119,15 +119,12 @@ test_depth_main (int argc, char *argv[])
|
||||
ClutterActor *group, *hand, *label, *rect, *janus, *box;
|
||||
ClutterColor stage_color = { 0xcc, 0xcc, 0xcc, 0xff };
|
||||
ClutterColor rect_color = { 0, 0, 0, 0x88 };
|
||||
ClutterFog stage_fog = { 10.0, -50.0 };
|
||||
GError *error;
|
||||
|
||||
clutter_init (&argc, &argv);
|
||||
|
||||
stage = clutter_stage_get_default ();
|
||||
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
|
||||
clutter_stage_set_fog (CLUTTER_STAGE (stage), &stage_fog);
|
||||
clutter_stage_set_use_fog (CLUTTER_STAGE (stage), TRUE);
|
||||
|
||||
g_signal_connect (stage,
|
||||
"button-press-event", G_CALLBACK (clutter_main_quit),
|
||||
|
Loading…
Reference in New Issue
Block a user