cogl-bitmap-pixbuf: Avoid copying the buffer in more circumstances
When loading an RGB image GdkPixbuf will pad the rowstride so that the beginning of each row is aligned to 4 bytes. This was causing us to fallback to the code that copies the buffer. It is probably safe to avoid copying the buffer if we can detect that the rowstride is simply an alignment of the packed rowstride. This also changes the copying fallback code so that it uses the aligned rowstride. However it is now extremely unlikely that the fallback code would ever be used.
This commit is contained in:
parent
fecb40a043
commit
2ccee98b31
@ -198,6 +198,7 @@ _cogl_bitmap_from_file (const char *filename,
|
|||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int rowstride;
|
int rowstride;
|
||||||
|
int aligned_rowstride;
|
||||||
int bits_per_sample;
|
int bits_per_sample;
|
||||||
int n_channels;
|
int n_channels;
|
||||||
guint8 *pixels;
|
guint8 *pixels;
|
||||||
@ -246,12 +247,26 @@ _cogl_bitmap_from_file (const char *filename,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the pixbuf is tightly packed then we can create a bitmap that
|
/* Work out what the rowstride would be if it was packing the data
|
||||||
directly keeps a reference to the pixbuf to avoid copying the
|
but aligned to 4 bytes */
|
||||||
data. Otherwise we need to copy because according to the
|
aligned_rowstride = (width * n_channels + 3) & ~3;
|
||||||
GdkPixbuf docs we can't be sure whether the last row will be
|
|
||||||
allocated to the length of the full rowstride. */
|
/* The documentation for GdkPixbuf states that is not safe to read
|
||||||
if (rowstride == n_channels * width)
|
all of the data as height*rowstride because the buffer might not
|
||||||
|
be allocated to include the full length of the rowstride for the
|
||||||
|
last row so arguably we should always copy the buffer when
|
||||||
|
rowstride != width*bpp because some places in Cogl assume that it
|
||||||
|
can memcpy(height*rowstride). However that rule is probably only
|
||||||
|
in place so that GdkPixbuf can implement gdk_pixbuf_new_subpixbuf
|
||||||
|
by just sharing the data and setting a large rowstride. That does
|
||||||
|
not apply in this case because we are just creating a new buffer
|
||||||
|
for a file. It seems very unlikely that GdkPixbuf would not
|
||||||
|
allocate the full rowstride in this case and it is highly
|
||||||
|
desirable to avoid copying the buffer. This instead just assumes
|
||||||
|
that whatever buffer pixbuf points into will always be allocated
|
||||||
|
to a 4-byte aligned buffer so we can avoid copying unless the
|
||||||
|
rowstride is unusually large */
|
||||||
|
if (rowstride <= aligned_rowstride)
|
||||||
return _cogl_bitmap_new_from_data (gdk_pixbuf_get_pixels (pixbuf),
|
return _cogl_bitmap_new_from_data (gdk_pixbuf_get_pixels (pixbuf),
|
||||||
pixel_format,
|
pixel_format,
|
||||||
width,
|
width,
|
||||||
@ -261,14 +276,14 @@ _cogl_bitmap_from_file (const char *filename,
|
|||||||
pixbuf);
|
pixbuf);
|
||||||
|
|
||||||
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
||||||
out_data = g_malloc (height * n_channels * width);
|
out_data = g_malloc (aligned_rowstride * height);
|
||||||
out = out_data;
|
out = out_data;
|
||||||
|
|
||||||
for (r = 0; r < height; ++r)
|
for (r = 0; r < height; ++r)
|
||||||
{
|
{
|
||||||
memcpy (out, pixels, n_channels * width);
|
memcpy (out, pixels, n_channels * width);
|
||||||
pixels += rowstride;
|
pixels += rowstride;
|
||||||
out += n_channels * width;
|
out += aligned_rowstride;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destroy GdkPixbuf object */
|
/* Destroy GdkPixbuf object */
|
||||||
@ -278,7 +293,7 @@ _cogl_bitmap_from_file (const char *filename,
|
|||||||
pixel_format,
|
pixel_format,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
n_channels * width,
|
aligned_rowstride,
|
||||||
(CoglBitmapDestroyNotify) g_free,
|
(CoglBitmapDestroyNotify) g_free,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user