mirror of
https://github.com/brl/mutter.git
synced 2024-11-22 08:00:42 -05:00
get_texture_bits_via_offscreen(): use meta texture format
When reading a texture back by first wrapping it as an offscreen framebuffer and using _read_pixels_into_bitmap() we now make sure the offscreen framebuffer has an internal format that matches the meta-texture being read not that of the current sub-texture being iterated. In the case of atlas textures the subtexture is a shared texture whose format doesn't reflect the premultipled alpha status of individual atlas-textures, nor whether the alpha component is valid. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit 6ee425d4f10acd8b008a2c17e5c701fc1d850f59)
This commit is contained in:
parent
99cdcc9e3c
commit
3f780e2f3f
@ -223,6 +223,22 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
/* XXX: For a public api we might instead want a way to explicitly
|
||||
* set the _premult status of a framebuffer or what components we
|
||||
* care about instead of exposing the CoglPixelFormat
|
||||
* internal_format.
|
||||
*
|
||||
* The current use case for this api is where we create an offscreen
|
||||
* framebuffer for a shared atlas texture that has a format of
|
||||
* RGBA_8888 disregarding the premultiplied alpha status for
|
||||
* individual atlased textures or whether the alpha component is being
|
||||
* discarded. We want to overried the internal_format that will be
|
||||
* derived from the texture.
|
||||
*/
|
||||
void
|
||||
_cogl_framebuffer_set_internal_format (CoglFramebuffer *framebuffer,
|
||||
CoglPixelFormat internal_format);
|
||||
|
||||
void _cogl_framebuffer_free (CoglFramebuffer *framebuffer);
|
||||
|
||||
const CoglWinsysVtable *
|
||||
|
@ -164,6 +164,13 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
|
||||
ctx->framebuffers = g_list_prepend (ctx->framebuffers, framebuffer);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_framebuffer_set_internal_format (CoglFramebuffer *framebuffer,
|
||||
CoglPixelFormat internal_format)
|
||||
{
|
||||
framebuffer->internal_format = internal_format;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_framebuffer_free (CoglFramebuffer *framebuffer)
|
||||
{
|
||||
|
@ -802,27 +802,29 @@ EXIT:
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
get_texture_bits_via_offscreen (CoglTexture *texture,
|
||||
get_texture_bits_via_offscreen (CoglTexture *meta_texture,
|
||||
CoglTexture *sub_texture,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
uint8_t *dst_bits,
|
||||
unsigned int dst_rowstride,
|
||||
CoglPixelFormat dst_format)
|
||||
CoglPixelFormat closest_format)
|
||||
{
|
||||
CoglContext *ctx = texture->context;
|
||||
CoglContext *ctx = sub_texture->context;
|
||||
CoglOffscreen *offscreen;
|
||||
CoglFramebuffer *framebuffer;
|
||||
CoglBitmap *bitmap;
|
||||
CoglBool ret;
|
||||
CoglError *ignore_error = NULL;
|
||||
CoglPixelFormat real_format;
|
||||
|
||||
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
|
||||
return FALSE;
|
||||
|
||||
offscreen = _cogl_offscreen_new_with_texture_full
|
||||
(texture,
|
||||
(sub_texture,
|
||||
COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL,
|
||||
0);
|
||||
|
||||
@ -833,9 +835,23 @@ get_texture_bits_via_offscreen (CoglTexture *texture,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Currently the framebuffer's internal format corresponds to the
|
||||
* internal format of @sub_texture but in the case of atlas textures
|
||||
* it's possible that this format doesn't reflect the correct
|
||||
* premultiplied alpha status or what components are valid since
|
||||
* atlas textures are always stored in a shared texture with a
|
||||
* format of _RGBA_8888.
|
||||
*
|
||||
* Here we override the internal format to make sure the
|
||||
* framebuffer's internal format matches the internal format of the
|
||||
* parent meta_texture instead.
|
||||
*/
|
||||
real_format = _cogl_texture_get_format (meta_texture);
|
||||
_cogl_framebuffer_set_internal_format (framebuffer, real_format);
|
||||
|
||||
bitmap = cogl_bitmap_new_for_data (ctx,
|
||||
width, height,
|
||||
dst_format,
|
||||
closest_format,
|
||||
dst_rowstride,
|
||||
dst_bits);
|
||||
ret = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
|
||||
@ -904,6 +920,7 @@ get_texture_bits_via_copy (CoglTexture *texture,
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CoglTexture *meta_texture;
|
||||
int orig_width;
|
||||
int orig_height;
|
||||
CoglBitmap *target_bmp;
|
||||
@ -913,17 +930,18 @@ typedef struct
|
||||
} CoglTextureGetData;
|
||||
|
||||
static void
|
||||
texture_get_cb (CoglTexture *texture,
|
||||
texture_get_cb (CoglTexture *subtexture,
|
||||
const float *subtexture_coords,
|
||||
const float *virtual_coords,
|
||||
void *user_data)
|
||||
{
|
||||
CoglTextureGetData *tg_data = user_data;
|
||||
CoglPixelFormat format = cogl_bitmap_get_format (tg_data->target_bmp);
|
||||
int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
|
||||
CoglTexture *meta_texture = tg_data->meta_texture;
|
||||
CoglPixelFormat closest_format = cogl_bitmap_get_format (tg_data->target_bmp);
|
||||
int bpp = _cogl_pixel_format_get_bytes_per_pixel (closest_format);
|
||||
unsigned int rowstride = cogl_bitmap_get_rowstride (tg_data->target_bmp);
|
||||
int subtexture_width = cogl_texture_get_width (texture);
|
||||
int subtexture_height = cogl_texture_get_height (texture);
|
||||
int subtexture_width = cogl_texture_get_width (subtexture);
|
||||
int subtexture_height = cogl_texture_get_height (subtexture);
|
||||
|
||||
int x_in_subtexture = (int) (0.5 + subtexture_width * subtexture_coords[0]);
|
||||
int y_in_subtexture = (int) (0.5 + subtexture_height * subtexture_coords[1]);
|
||||
@ -944,33 +962,35 @@ texture_get_cb (CoglTexture *texture,
|
||||
/* If we can read everything as a single slice, then go ahead and do that
|
||||
* to avoid allocating an FBO. We'll leave it up to the GL implementation to
|
||||
* do glGetTexImage as efficiently as possible. (GLES doesn't have that,
|
||||
* so we'll fall through) */
|
||||
* so we'll fall through)
|
||||
*/
|
||||
if (x_in_subtexture == 0 && y_in_subtexture == 0 &&
|
||||
width == subtexture_width && height == subtexture_height)
|
||||
{
|
||||
if (texture->vtable->get_data (texture,
|
||||
format,
|
||||
if (subtexture->vtable->get_data (subtexture,
|
||||
closest_format,
|
||||
rowstride,
|
||||
dst_bits))
|
||||
return;
|
||||
}
|
||||
|
||||
/* Next best option is a FBO and glReadPixels */
|
||||
if (get_texture_bits_via_offscreen (texture,
|
||||
if (get_texture_bits_via_offscreen (meta_texture,
|
||||
subtexture,
|
||||
x_in_subtexture, y_in_subtexture,
|
||||
width, height,
|
||||
dst_bits,
|
||||
rowstride,
|
||||
format))
|
||||
closest_format))
|
||||
return;
|
||||
|
||||
/* Getting ugly: read the entire texture, copy out the part we want */
|
||||
if (get_texture_bits_via_copy (texture,
|
||||
if (get_texture_bits_via_copy (subtexture,
|
||||
x_in_subtexture, y_in_subtexture,
|
||||
width, height,
|
||||
dst_bits,
|
||||
rowstride,
|
||||
format))
|
||||
closest_format))
|
||||
return;
|
||||
|
||||
/* No luck, the caller will fall back to the draw-to-backbuffer and
|
||||
@ -1084,6 +1104,7 @@ cogl_texture_get_data (CoglTexture *texture,
|
||||
&ignore_error);
|
||||
if (tg_data.target_bits)
|
||||
{
|
||||
tg_data.meta_texture = texture;
|
||||
tg_data.orig_width = tex_width;
|
||||
tg_data.orig_height = tex_height;
|
||||
tg_data.target_bmp = target_bmp;
|
||||
|
Loading…
Reference in New Issue
Block a user