mirror of
https://github.com/brl/mutter.git
synced 2024-11-26 01:50: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 width,
|
||||||
int height);
|
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);
|
void _cogl_framebuffer_free (CoglFramebuffer *framebuffer);
|
||||||
|
|
||||||
const CoglWinsysVtable *
|
const CoglWinsysVtable *
|
||||||
|
@ -164,6 +164,13 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
|
|||||||
ctx->framebuffers = g_list_prepend (ctx->framebuffers, 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
|
void
|
||||||
_cogl_framebuffer_free (CoglFramebuffer *framebuffer)
|
_cogl_framebuffer_free (CoglFramebuffer *framebuffer)
|
||||||
{
|
{
|
||||||
|
@ -802,27 +802,29 @@ EXIT:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static CoglBool
|
static CoglBool
|
||||||
get_texture_bits_via_offscreen (CoglTexture *texture,
|
get_texture_bits_via_offscreen (CoglTexture *meta_texture,
|
||||||
|
CoglTexture *sub_texture,
|
||||||
int x,
|
int x,
|
||||||
int y,
|
int y,
|
||||||
int width,
|
int width,
|
||||||
int height,
|
int height,
|
||||||
uint8_t *dst_bits,
|
uint8_t *dst_bits,
|
||||||
unsigned int dst_rowstride,
|
unsigned int dst_rowstride,
|
||||||
CoglPixelFormat dst_format)
|
CoglPixelFormat closest_format)
|
||||||
{
|
{
|
||||||
CoglContext *ctx = texture->context;
|
CoglContext *ctx = sub_texture->context;
|
||||||
CoglOffscreen *offscreen;
|
CoglOffscreen *offscreen;
|
||||||
CoglFramebuffer *framebuffer;
|
CoglFramebuffer *framebuffer;
|
||||||
CoglBitmap *bitmap;
|
CoglBitmap *bitmap;
|
||||||
CoglBool ret;
|
CoglBool ret;
|
||||||
CoglError *ignore_error = NULL;
|
CoglError *ignore_error = NULL;
|
||||||
|
CoglPixelFormat real_format;
|
||||||
|
|
||||||
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
|
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
offscreen = _cogl_offscreen_new_with_texture_full
|
offscreen = _cogl_offscreen_new_with_texture_full
|
||||||
(texture,
|
(sub_texture,
|
||||||
COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL,
|
COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
@ -833,9 +835,23 @@ get_texture_bits_via_offscreen (CoglTexture *texture,
|
|||||||
return FALSE;
|
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,
|
bitmap = cogl_bitmap_new_for_data (ctx,
|
||||||
width, height,
|
width, height,
|
||||||
dst_format,
|
closest_format,
|
||||||
dst_rowstride,
|
dst_rowstride,
|
||||||
dst_bits);
|
dst_bits);
|
||||||
ret = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
|
ret = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
|
||||||
@ -904,6 +920,7 @@ get_texture_bits_via_copy (CoglTexture *texture,
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
CoglTexture *meta_texture;
|
||||||
int orig_width;
|
int orig_width;
|
||||||
int orig_height;
|
int orig_height;
|
||||||
CoglBitmap *target_bmp;
|
CoglBitmap *target_bmp;
|
||||||
@ -913,17 +930,18 @@ typedef struct
|
|||||||
} CoglTextureGetData;
|
} CoglTextureGetData;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
texture_get_cb (CoglTexture *texture,
|
texture_get_cb (CoglTexture *subtexture,
|
||||||
const float *subtexture_coords,
|
const float *subtexture_coords,
|
||||||
const float *virtual_coords,
|
const float *virtual_coords,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
CoglTextureGetData *tg_data = user_data;
|
CoglTextureGetData *tg_data = user_data;
|
||||||
CoglPixelFormat format = cogl_bitmap_get_format (tg_data->target_bmp);
|
CoglTexture *meta_texture = tg_data->meta_texture;
|
||||||
int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
|
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);
|
unsigned int rowstride = cogl_bitmap_get_rowstride (tg_data->target_bmp);
|
||||||
int subtexture_width = cogl_texture_get_width (texture);
|
int subtexture_width = cogl_texture_get_width (subtexture);
|
||||||
int subtexture_height = cogl_texture_get_height (texture);
|
int subtexture_height = cogl_texture_get_height (subtexture);
|
||||||
|
|
||||||
int x_in_subtexture = (int) (0.5 + subtexture_width * subtexture_coords[0]);
|
int x_in_subtexture = (int) (0.5 + subtexture_width * subtexture_coords[0]);
|
||||||
int y_in_subtexture = (int) (0.5 + subtexture_height * subtexture_coords[1]);
|
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
|
/* 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
|
* 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,
|
* 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 &&
|
if (x_in_subtexture == 0 && y_in_subtexture == 0 &&
|
||||||
width == subtexture_width && height == subtexture_height)
|
width == subtexture_width && height == subtexture_height)
|
||||||
{
|
{
|
||||||
if (texture->vtable->get_data (texture,
|
if (subtexture->vtable->get_data (subtexture,
|
||||||
format,
|
closest_format,
|
||||||
rowstride,
|
rowstride,
|
||||||
dst_bits))
|
dst_bits))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next best option is a FBO and glReadPixels */
|
/* 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,
|
x_in_subtexture, y_in_subtexture,
|
||||||
width, height,
|
width, height,
|
||||||
dst_bits,
|
dst_bits,
|
||||||
rowstride,
|
rowstride,
|
||||||
format))
|
closest_format))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Getting ugly: read the entire texture, copy out the part we want */
|
/* 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,
|
x_in_subtexture, y_in_subtexture,
|
||||||
width, height,
|
width, height,
|
||||||
dst_bits,
|
dst_bits,
|
||||||
rowstride,
|
rowstride,
|
||||||
format))
|
closest_format))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* No luck, the caller will fall back to the draw-to-backbuffer and
|
/* 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);
|
&ignore_error);
|
||||||
if (tg_data.target_bits)
|
if (tg_data.target_bits)
|
||||||
{
|
{
|
||||||
|
tg_data.meta_texture = texture;
|
||||||
tg_data.orig_width = tex_width;
|
tg_data.orig_width = tex_width;
|
||||||
tg_data.orig_height = tex_height;
|
tg_data.orig_height = tex_height;
|
||||||
tg_data.target_bmp = target_bmp;
|
tg_data.target_bmp = target_bmp;
|
||||||
|
Loading…
Reference in New Issue
Block a user