Skip to content

Commit

Permalink
Stop pooling background surface buffers
Browse files Browse the repository at this point in the history
The wl_buffers for the background surface only need to be updated
when the output dimensions change. Using the fixed pool of two
buffers to cache these buffers does not help, since if a new buffer
is needed, it will have a different size than whatever buffers were
cached. Furthermore, because the pool has fixed size, it is possible
to run out of buffers if configure events arrive faster than
buffers are removed from the pool, which can lead to protocol errors
when the background surface is committed after acknowledging a new
size, but without attaching a buffer that matches that size.
  • Loading branch information
mstoeckl committed Mar 12, 2023
1 parent ac3b49b commit e42aa73
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 26 deletions.
4 changes: 3 additions & 1 deletion include/pool-buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ struct pool_buffer {
bool busy;
};

struct pool_buffer *create_buffer(struct wl_shm *shm, struct pool_buffer *buf,
int32_t width, int32_t height, uint32_t format);
struct pool_buffer *get_next_buffer(struct wl_shm *shm,
struct pool_buffer pool[static 2], uint32_t width, uint32_t height);
struct pool_buffer pool[static 2], uint32_t width, uint32_t height);
void destroy_buffer(struct pool_buffer *buffer);

#endif
7 changes: 4 additions & 3 deletions include/swaylock.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,19 @@ struct swaylock_surface {
struct swaylock_state *state;
struct wl_output *output;
uint32_t output_global_name;
struct wl_surface *surface;
struct wl_surface *child; // surface made into subsurface
struct wl_surface *surface; // surface for background
struct wl_surface *child; // indicator surface made into subsurface
struct wl_subsurface *subsurface;
struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1;
struct pool_buffer buffers[2];
struct pool_buffer indicator_buffers[2];
bool frame_pending, dirty;
uint32_t width, height;
int32_t scale;
enum wl_output_subpixel subpixel;
char *output_name;
struct wl_list link;
// Dimensions of last wl_buffer committed to background surface
int last_buffer_width, last_buffer_height;
};

// There is exactly one swaylock_image for each -i argument
Expand Down
2 changes: 0 additions & 2 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ static void destroy_surface(struct swaylock_surface *surface) {
if (surface->surface != NULL) {
wl_surface_destroy(surface->surface);
}
destroy_buffer(&surface->buffers[0]);
destroy_buffer(&surface->buffers[1]);
destroy_buffer(&surface->indicator_buffers[0]);
destroy_buffer(&surface->indicator_buffers[1]);
wl_output_destroy(surface->output);
Expand Down
2 changes: 1 addition & 1 deletion pool-buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ static const struct wl_buffer_listener buffer_listener = {
.release = buffer_release
};

static struct pool_buffer *create_buffer(struct wl_shm *shm,
struct pool_buffer *create_buffer(struct wl_shm *shm,
struct pool_buffer *buf, int32_t width, int32_t height,
uint32_t format) {
uint32_t stride = width * 4;
Expand Down
49 changes: 30 additions & 19 deletions render.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "cairo.h"
#include "background-image.h"
#include "swaylock.h"
#include "log.h"

#define M_PI 3.14159265358979323846
const float TYPE_INDICATOR_RANGE = M_PI / 3.0f;
Expand Down Expand Up @@ -41,30 +42,40 @@ void render_frame_background(struct swaylock_surface *surface) {
return; // not yet configured
}

struct pool_buffer *buffer = get_next_buffer(state->shm,
surface->buffers, buffer_width, buffer_height);
if (buffer == NULL) {
return;
}
if (buffer_width != surface->last_buffer_width ||
buffer_height != surface->last_buffer_height) {
surface->last_buffer_width = buffer_width;
surface->last_buffer_height = buffer_height;

struct pool_buffer buffer;
if (!create_buffer(state->shm, &buffer, buffer_width, buffer_height,
WL_SHM_FORMAT_ARGB8888)) {
swaylock_log(LOG_ERROR,
"Failed to create new buffer for frame background.");
return;
}

cairo_t *cairo = buffer->cairo;
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
cairo_t *cairo = buffer.cairo;
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);

cairo_save(cairo);
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_source_u32(cairo, state->args.colors.background);
cairo_paint(cairo);
if (surface->image && state->args.mode != BACKGROUND_MODE_SOLID_COLOR) {
cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
render_background_image(cairo, surface->image,
state->args.mode, buffer_width, buffer_height);
}
cairo_restore(cairo);
cairo_identity_matrix(cairo);

cairo_save(cairo);
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_source_u32(cairo, state->args.colors.background);
cairo_paint(cairo);
if (surface->image && state->args.mode != BACKGROUND_MODE_SOLID_COLOR) {
cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
render_background_image(cairo, surface->image,
state->args.mode, buffer_width, buffer_height);
wl_surface_attach(surface->surface, buffer.buffer, 0, 0);
wl_surface_damage_buffer(surface->surface, 0, 0, INT32_MAX, INT32_MAX);
destroy_buffer(&buffer);
}
cairo_restore(cairo);
cairo_identity_matrix(cairo);

wl_surface_set_buffer_scale(surface->surface, surface->scale);
wl_surface_attach(surface->surface, buffer->buffer, 0, 0);
wl_surface_damage_buffer(surface->surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_commit(surface->surface);
}

Expand Down

0 comments on commit e42aa73

Please sign in to comment.