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:
parent
ac3b49b657
commit
1d3e62c67f
@ -15,8 +15,10 @@ struct pool_buffer {
|
|||||||
bool busy;
|
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 *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);
|
void destroy_buffer(struct pool_buffer *buffer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -98,11 +98,10 @@ struct swaylock_surface {
|
|||||||
struct swaylock_state *state;
|
struct swaylock_state *state;
|
||||||
struct wl_output *output;
|
struct wl_output *output;
|
||||||
uint32_t output_global_name;
|
uint32_t output_global_name;
|
||||||
struct wl_surface *surface;
|
struct wl_surface *surface; // surface for background
|
||||||
struct wl_surface *child; // surface made into subsurface
|
struct wl_surface *child; // indicator surface made into subsurface
|
||||||
struct wl_subsurface *subsurface;
|
struct wl_subsurface *subsurface;
|
||||||
struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1;
|
struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1;
|
||||||
struct pool_buffer buffers[2];
|
|
||||||
struct pool_buffer indicator_buffers[2];
|
struct pool_buffer indicator_buffers[2];
|
||||||
bool frame_pending, dirty;
|
bool frame_pending, dirty;
|
||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
@ -110,6 +109,8 @@ struct swaylock_surface {
|
|||||||
enum wl_output_subpixel subpixel;
|
enum wl_output_subpixel subpixel;
|
||||||
char *output_name;
|
char *output_name;
|
||||||
struct wl_list link;
|
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
|
// There is exactly one swaylock_image for each -i argument
|
||||||
|
2
main.c
2
main.c
@ -100,8 +100,6 @@ static void destroy_surface(struct swaylock_surface *surface) {
|
|||||||
if (surface->surface != NULL) {
|
if (surface->surface != NULL) {
|
||||||
wl_surface_destroy(surface->surface);
|
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[0]);
|
||||||
destroy_buffer(&surface->indicator_buffers[1]);
|
destroy_buffer(&surface->indicator_buffers[1]);
|
||||||
wl_output_destroy(surface->output);
|
wl_output_destroy(surface->output);
|
||||||
|
@ -46,7 +46,7 @@ static const struct wl_buffer_listener buffer_listener = {
|
|||||||
.release = buffer_release
|
.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,
|
struct pool_buffer *buf, int32_t width, int32_t height,
|
||||||
uint32_t format) {
|
uint32_t format) {
|
||||||
uint32_t stride = width * 4;
|
uint32_t stride = width * 4;
|
||||||
|
49
render.c
49
render.c
@ -4,6 +4,7 @@
|
|||||||
#include "cairo.h"
|
#include "cairo.h"
|
||||||
#include "background-image.h"
|
#include "background-image.h"
|
||||||
#include "swaylock.h"
|
#include "swaylock.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
const float TYPE_INDICATOR_RANGE = M_PI / 3.0f;
|
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
|
return; // not yet configured
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pool_buffer *buffer = get_next_buffer(state->shm,
|
if (buffer_width != surface->last_buffer_width ||
|
||||||
surface->buffers, buffer_width, buffer_height);
|
buffer_height != surface->last_buffer_height) {
|
||||||
if (buffer == NULL) {
|
struct pool_buffer buffer;
|
||||||
return;
|
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_t *cairo = buffer.cairo;
|
||||||
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
|
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
|
||||||
|
|
||||||
cairo_save(cairo);
|
cairo_save(cairo);
|
||||||
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
|
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
|
||||||
cairo_set_source_u32(cairo, state->args.colors.background);
|
cairo_set_source_u32(cairo, state->args.colors.background);
|
||||||
cairo_paint(cairo);
|
cairo_paint(cairo);
|
||||||
if (surface->image && state->args.mode != BACKGROUND_MODE_SOLID_COLOR) {
|
if (surface->image && state->args.mode != BACKGROUND_MODE_SOLID_COLOR) {
|
||||||
cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
|
cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
|
||||||
render_background_image(cairo, surface->image,
|
render_background_image(cairo, surface->image,
|
||||||
state->args.mode, buffer_width, buffer_height);
|
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_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);
|
wl_surface_commit(surface->surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user