summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorManuel Stoeckl <code@mstoeckl.com>2021-06-26 12:54:38 -0400
committerSimon Ser <contact@emersion.fr>2021-07-19 11:41:24 +0200
commitf71957fce7f54ee88df75cd5f0d77cc20d518890 (patch)
tree2097ab7a48d8d958d3010551c30c523f85779f83 /main.c
parent69827e97dbdee569f0e0987cf6e24acb48217301 (diff)
downloadswaybg-f71957fce7f54ee88df75cd5f0d77cc20d518890.tar.gz
swaybg-f71957fce7f54ee88df75cd5f0d77cc20d518890.tar.bz2
Load images on every frame render
This change keeps the full-size cairo_surface_t objects unloaded until they are needed to produce buffers for the outputs' surfaces. This can slow down background rendering when output scales or sizes change, or when a new output is created; in exchange, it significantly reduces the amount of memory that swaybg must retain while it is not rendering something. To reduce peak memory usage, dirty outputs are redrawn drawn in batches grouped by which image they use. This ensures at most one image is loaded at a time.
Diffstat (limited to 'main.c')
-rw-r--r--main.c55
1 files changed, 39 insertions, 16 deletions
diff --git a/main.c b/main.c
index d42c596..ee9550f 100644
--- a/main.c
+++ b/main.c
@@ -46,9 +46,9 @@ struct swaybg_state {
};
struct swaybg_image {
- const char *path;
- cairo_surface_t *surface;
struct wl_list link;
+ const char *path;
+ bool load_required;
};
struct swaybg_output_config {
@@ -100,7 +100,7 @@ bool is_valid_color(const char *color) {
return true;
}
-static void render_frame(struct swaybg_output *output) {
+static void render_frame(struct swaybg_output *output, cairo_surface_t *surface) {
int buffer_width = output->width * output->scale,
buffer_height = output->height * output->scale;
struct pool_buffer buffer;
@@ -122,8 +122,9 @@ static void render_frame(struct swaybg_output *output) {
cairo_set_source_u32(cairo, output->config->color);
cairo_paint(cairo);
}
- if (output->config->image->surface) {
- render_background_image(cairo, output->config->image->surface,
+
+ if (surface) {
+ render_background_image(cairo, surface,
output->config->mode, buffer_width, buffer_height);
}
}
@@ -140,9 +141,6 @@ static void destroy_swaybg_image(struct swaybg_image *image) {
if (!image) {
return;
}
- if (image->surface) {
- cairo_surface_destroy(image->surface);
- }
wl_list_remove(&image->link);
free(image);
}
@@ -546,13 +544,6 @@ int main(int argc, char **argv) {
config->image = image;
}
- wl_list_for_each(image, &state.images, link) {
- image->surface = load_background_image(image->path);
- if (!image->surface) {
- swaybg_log(LOG_ERROR, "Failed to load image: %s", image->path);
- }
- }
-
state.display = wl_display_connect(NULL);
if (!state.display) {
swaybg_log(LOG_ERROR, "Unable to connect to the compositor. "
@@ -580,6 +571,7 @@ int main(int argc, char **argv) {
state.run_display = true;
while (wl_display_dispatch(state.display) != -1 && state.run_display) {
+ // Send acks, and determine which images need to be loaded
wl_list_for_each(output, &state.outputs, link) {
if (output->needs_ack) {
output->needs_ack = false;
@@ -587,9 +579,40 @@ int main(int argc, char **argv) {
output->layer_surface,
output->configure_serial);
}
+
+ if (output->dirty && output->config->image) {
+ output->config->image->load_required = true;
+ }
+ }
+
+ // Load images, render associated frames, and unload
+ wl_list_for_each(image, &state.images, link) {
+ if (!image->load_required) {
+ continue;
+ }
+
+ cairo_surface_t *surface = load_background_image(image->path);
+ if (!surface) {
+ swaybg_log(LOG_ERROR, "Failed to load image: %s", image->path);
+ continue;
+ }
+
+ wl_list_for_each(output, &state.outputs, link) {
+ if (output->dirty && output->config->image == image) {
+ output->dirty = false;
+ render_frame(output, surface);
+ }
+ }
+
+ image->load_required = false;
+ cairo_surface_destroy(surface);
+ }
+
+ // Redraw outputs without associated image
+ wl_list_for_each(output, &state.outputs, link) {
if (output->dirty) {
output->dirty = false;
- render_frame(output);
+ render_frame(output, NULL);
}
}
}