cogl-framebuffer: Try to track format of the framebuffer

Previously in cogl_read_pixels we assume the format of the framebuffer
is always premultiplied because that is the most likely format with
the default Cogl blend mode. However when the framebuffer is bound to
a texture we should be able to make a better guess at the format
because we know the texture keeps track of the premult status. This
patch adds an internal format member to CoglFramebuffer. For onscreen
framebuffers we still assume it is RGBA_8888_PRE but for offscreen to
textures we copy the texture format. cogl_read_pixels uses this to
determine whether the data returned by glReadPixels will be
premultiplied.

http://bugzilla.clutter-project.org/show_bug.cgi?id=2414
This commit is contained in:
Neil Roberts 2010-11-17 17:57:17 +00:00
parent 8fd47276b7
commit 47ccbf472e
3 changed files with 28 additions and 12 deletions

View File

@ -39,6 +39,9 @@ struct _CoglFramebuffer
CoglFramebufferType type; CoglFramebufferType type;
int width; int width;
int height; int height;
/* Format of the pixels in the framebuffer (including the expected
premult state) */
CoglPixelFormat format;
CoglMatrixStack *modelview_stack; CoglMatrixStack *modelview_stack;
CoglMatrixStack *projection_stack; CoglMatrixStack *projection_stack;

View File

@ -139,12 +139,14 @@ _cogl_is_framebuffer (void *object)
static void static void
_cogl_framebuffer_init (CoglFramebuffer *framebuffer, _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
CoglFramebufferType type, CoglFramebufferType type,
CoglPixelFormat format,
int width, int width,
int height) int height)
{ {
framebuffer->type = type; framebuffer->type = type;
framebuffer->width = width; framebuffer->width = width;
framebuffer->height = height; framebuffer->height = height;
framebuffer->format = format;
framebuffer->viewport_x = 0; framebuffer->viewport_x = 0;
framebuffer->viewport_y = 0; framebuffer->viewport_y = 0;
framebuffer->viewport_width = width; framebuffer->viewport_width = width;
@ -540,6 +542,7 @@ _cogl_offscreen_new_to_texture_full (CoglHandle texhandle,
{ {
_cogl_framebuffer_init (COGL_FRAMEBUFFER (offscreen), _cogl_framebuffer_init (COGL_FRAMEBUFFER (offscreen),
COGL_FRAMEBUFFER_TYPE_OFFSCREEN, COGL_FRAMEBUFFER_TYPE_OFFSCREEN,
cogl_texture_get_format (texhandle),
data.level_width, data.level_width,
data.level_height); data.level_height);
@ -594,9 +597,21 @@ _cogl_onscreen_new (void)
* implement CoglOnscreen framebuffers, since we can't, e.g. keep track of * implement CoglOnscreen framebuffers, since we can't, e.g. keep track of
* the window size. */ * the window size. */
/* FIXME: We are assuming onscreen buffers will always be
premultiplied so we'll set the premult flag on the bitmap
format. This will usually be correct because the result of the
default blending operations for Cogl ends up with premultiplied
data in the framebuffer. However it is possible for the
framebuffer to be in whatever format depending on what
CoglPipeline is used to render to it. Eventually we may want to
add a way for an application to inform Cogl that the framebuffer
is not premultiplied in case it is being used for some special
purpose. */
onscreen = g_new0 (CoglOnscreen, 1); onscreen = g_new0 (CoglOnscreen, 1);
_cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen), _cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
COGL_FRAMEBUFFER_TYPE_ONSCREEN, COGL_FRAMEBUFFER_TYPE_ONSCREEN,
COGL_PIXEL_FORMAT_RGBA_8888_PRE,
0xdeadbeef, /* width */ 0xdeadbeef, /* width */
0xdeadbeef); /* height */ 0xdeadbeef); /* height */

View File

@ -603,17 +603,14 @@ _cogl_read_pixels_with_rowstride (int x,
if ((format & COGL_A_BIT)) if ((format & COGL_A_BIT))
{ {
/* FIXME: We are assuming glReadPixels will always give us /* We match the premultiplied state of the target buffer to the
premultiplied data so we'll set the premult flag on the * premultiplied state of the framebuffer so that it will get
bitmap format. This will usually be correct because the * converted to the right format below */
result of the default blending operations for Cogl ends up
with premultiplied data in the framebuffer. However it is if ((framebuffer->format & COGL_PREMULT_BIT))
possible for the framebuffer to be in whatever format bmp_format |= COGL_PREMULT_BIT;
depending on what CoglPipeline is used to render to else
it. Eventually we may want to add a way for an application to bmp_format &= ~COGL_PREMULT_BIT;
inform Cogl that the framebuffer is not premultiplied in case
it is being used for some special purpose. */
bmp_format |= COGL_PREMULT_BIT;
} }
bmp = _cogl_bitmap_new_from_data (pixels, bmp = _cogl_bitmap_new_from_data (pixels,
@ -640,7 +637,8 @@ _cogl_read_pixels_with_rowstride (int x,
guint8 *tmp_data = g_malloc (width * height * 4); guint8 *tmp_data = g_malloc (width * height * 4);
tmp_bmp = _cogl_bitmap_new_from_data (tmp_data, tmp_bmp = _cogl_bitmap_new_from_data (tmp_data,
COGL_PIXEL_FORMAT_RGBA_8888_PRE, COGL_PIXEL_FORMAT_RGBA_8888 |
(bmp_format & COGL_PREMULT_BIT),
width, height, 4 * width, width, height, 4 * width,
(CoglBitmapDestroyNotify) g_free, (CoglBitmapDestroyNotify) g_free,
NULL); NULL);