Stop pooling background surface buffers

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
pool buffers are marked not busy, 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.
This commit is contained in:
Manuel Stoeckl 2023-03-12 16:48:58 -04:00 committed by Simon Ser
parent ac3b49b657
commit 1d3e62c67f
5 changed files with 38 additions and 26 deletions

View File

@ -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

View File

@ -98,11 +98,10 @@ 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;
@ -110,6 +109,8 @@ struct swaylock_surface {
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

2
main.c
View File

@ -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);

View File

@ -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;

View File

@ -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;
@ -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) {
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_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);
wl_surface_attach(surface->surface, buffer.buffer, 0, 0);
wl_surface_damage_buffer(surface->surface, 0, 0, INT32_MAX, INT32_MAX);
destroy_buffer(&buffer);
surface->last_buffer_width = buffer_width;
surface->last_buffer_height = buffer_height;
}
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);
}