mirror of
https://github.com/labwc/labwc.git
synced 2025-11-02 09:01:47 -05:00
buffer: reduce unnecessary painting to new cairo surfaces
Add buffer_adopt_cairo_surface(), which allows wrapping an existing cairo image surface in a struct lab_data_buffer. This is useful when loading PNGs since most will be loaded as ARGB32 already. Fix a memory leak in the non-ARGB32 PNG case, where we do still need to paint to a new image surface -- we were leaking the original surface. Eliminate an unnecessary temporary image surface in SVG loading and just render the SVG to the image surface held by the lab_data_buffer. I also cleaned up and clarified the buffer API a bit: - Add a pointer to the held cairo_surface_t (so we can still access it if there is no cairo_t). - Remove the free_on_destroy bool (it was always true). - Rename unscaled_width/height to logical_width/height and add an explanatory comment. It was unclear what "unscaled" meant. - Rename buffer_create_wrap() to buffer_create_from_data(). This is laying groundwork for some more icon fixes I am working on (making sure icons are loaded and rendered at the correct scale).
This commit is contained in:
parent
328f873db3
commit
d2b161bdf8
14 changed files with 123 additions and 84 deletions
76
src/buffer.c
76
src/buffer.c
|
|
@ -44,14 +44,12 @@ static void
|
|||
data_buffer_destroy(struct wlr_buffer *wlr_buffer)
|
||||
{
|
||||
struct lab_data_buffer *buffer = data_buffer_from_buffer(wlr_buffer);
|
||||
if (!buffer->free_on_destroy) {
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
if (buffer->cairo) {
|
||||
cairo_surface_t *surf = cairo_get_target(buffer->cairo);
|
||||
cairo_destroy(buffer->cairo);
|
||||
cairo_surface_destroy(surf);
|
||||
}
|
||||
if (buffer->surface) {
|
||||
/* this also frees buffer->data */
|
||||
cairo_surface_destroy(buffer->surface);
|
||||
} else if (buffer->data) {
|
||||
free(buffer->data);
|
||||
buffer->data = NULL;
|
||||
|
|
@ -85,19 +83,35 @@ static const struct wlr_buffer_impl data_buffer_impl = {
|
|||
};
|
||||
|
||||
struct lab_data_buffer *
|
||||
buffer_create_cairo(uint32_t width, uint32_t height, float scale,
|
||||
bool free_on_destroy)
|
||||
buffer_adopt_cairo_surface(cairo_surface_t *surface)
|
||||
{
|
||||
struct lab_data_buffer *buffer = znew(*buffer);
|
||||
buffer->unscaled_width = width;
|
||||
buffer->unscaled_height = height;
|
||||
width *= scale;
|
||||
height *= scale;
|
||||
assert(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE);
|
||||
assert(cairo_image_surface_get_format(surface) == CAIRO_FORMAT_ARGB32);
|
||||
|
||||
/* Allocate the buffer with the scaled size */
|
||||
int width = cairo_image_surface_get_width(surface);
|
||||
int height = cairo_image_surface_get_height(surface);
|
||||
|
||||
struct lab_data_buffer *buffer = znew(*buffer);
|
||||
wlr_buffer_init(&buffer->base, &data_buffer_impl, width, height);
|
||||
cairo_surface_t *surf =
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||
|
||||
buffer->surface = surface;
|
||||
buffer->data = cairo_image_surface_get_data(buffer->surface);
|
||||
buffer->format = DRM_FORMAT_ARGB8888;
|
||||
buffer->stride = cairo_image_surface_get_stride(buffer->surface);
|
||||
buffer->logical_width = width;
|
||||
buffer->logical_height = height;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
struct lab_data_buffer *
|
||||
buffer_create_cairo(uint32_t logical_width, uint32_t logical_height, float scale)
|
||||
{
|
||||
/* Create an image surface with the scaled size */
|
||||
cairo_surface_t *surface =
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
|
||||
lroundf(logical_width * scale),
|
||||
lroundf(logical_height * scale));
|
||||
|
||||
/**
|
||||
* Tell cairo about the device scale so we can keep drawing in unscaled
|
||||
|
|
@ -106,34 +120,30 @@ buffer_create_cairo(uint32_t width, uint32_t height, float scale,
|
|||
*
|
||||
* For a more complete explanation see PR #389
|
||||
*/
|
||||
cairo_surface_set_device_scale(surf, scale, scale);
|
||||
cairo_surface_set_device_scale(surface, scale, scale);
|
||||
|
||||
buffer->cairo = cairo_create(surf);
|
||||
buffer->data = cairo_image_surface_get_data(surf);
|
||||
buffer->format = DRM_FORMAT_ARGB8888;
|
||||
buffer->stride = cairo_image_surface_get_stride(surf);
|
||||
buffer->free_on_destroy = free_on_destroy;
|
||||
/*
|
||||
* Adopt the image surface into a buffer, set the correct
|
||||
* logical size, and create a cairo context for drawing
|
||||
*/
|
||||
struct lab_data_buffer *buffer = buffer_adopt_cairo_surface(surface);
|
||||
buffer->logical_width = logical_width;
|
||||
buffer->logical_height = logical_height;
|
||||
buffer->cairo = cairo_create(surface);
|
||||
|
||||
if (!buffer->data) {
|
||||
cairo_destroy(buffer->cairo);
|
||||
cairo_surface_destroy(surf);
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
struct lab_data_buffer *
|
||||
buffer_create_wrap(void *pixel_data, uint32_t width, uint32_t height,
|
||||
uint32_t stride, bool free_on_destroy)
|
||||
buffer_create_from_data(void *pixel_data, uint32_t width, uint32_t height,
|
||||
uint32_t stride)
|
||||
{
|
||||
struct lab_data_buffer *buffer = znew(*buffer);
|
||||
wlr_buffer_init(&buffer->base, &data_buffer_impl, width, height);
|
||||
buffer->unscaled_width = width;
|
||||
buffer->unscaled_height = height;
|
||||
buffer->logical_width = width;
|
||||
buffer->logical_height = height;
|
||||
buffer->data = pixel_data;
|
||||
buffer->format = DRM_FORMAT_ARGB8888;
|
||||
buffer->stride = stride;
|
||||
buffer->free_on_destroy = free_on_destroy;
|
||||
return buffer;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue