mirror of
https://github.com/swaywm/sway.git
synced 2024-12-01 19:06:38 +00:00
Correctly track saved surfaces during multiple transactions
Fixes #2364. Suppose a view is 600px wide, and we tell it to resize to 601px during a resize operation. We create a transaction, save the 600px buffer and send the configure. This buffer is saved into the associated instruction, and is rendered while we wait for the view to commit a 601px buffer. Before the view commits the 601px buffer, suppose we tell it to resize to 602px. The new transaction will also save the buffer, but it's still the 600px buffer because we haven't received a new one yet. Then suppose the view commits its original 601px buffer. This completes the first transaction, so we apply the 601px width to the container. There's still the second (now only) transaction remaining, so we render the saved buffer from that. But this is still the 600px buffer, and we believe it's 601px. Whoops. The problem here is we can't stack buffers like this. So this commit removes the saved buffer from the instructions, places it in the view instead, and re-saves the latest buffer every time the view completes a transaction and still has further pending transactions. As saved buffers are now specific to views rather than instructions, the functions for saving and removing the saved buffer have been moved to view.c. The calls to save and restore the buffer have been relocated to more appropriate functions too, favouring transaction_commit and transaction_apply rather than transaction_add_container and transaction_destroy.
This commit is contained in:
parent
f91fd78b99
commit
d10ccc1eb1
|
@ -42,17 +42,4 @@ void transaction_notify_view_ready(struct sway_view *view, uint32_t serial);
|
||||||
void transaction_notify_view_ready_by_size(struct sway_view *view,
|
void transaction_notify_view_ready_by_size(struct sway_view *view,
|
||||||
int width, int height);
|
int width, int height);
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the saved texture that should be rendered for a view.
|
|
||||||
*
|
|
||||||
* The addresses pointed at by the width and height pointers will be populated
|
|
||||||
* with the surface's dimensions, which may be different to the texture's
|
|
||||||
* dimensions if output scaling is used.
|
|
||||||
*
|
|
||||||
* This function should only be called if it is known that the view has
|
|
||||||
* instructions.
|
|
||||||
*/
|
|
||||||
struct wlr_texture *transaction_get_saved_texture(struct sway_view *view,
|
|
||||||
int *width, int *height);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -82,6 +82,9 @@ struct sway_view {
|
||||||
bool allow_request_urgent;
|
bool allow_request_urgent;
|
||||||
struct wl_event_source *urgent_timer;
|
struct wl_event_source *urgent_timer;
|
||||||
|
|
||||||
|
struct wlr_buffer *saved_buffer;
|
||||||
|
int saved_buffer_width, saved_buffer_height;
|
||||||
|
|
||||||
bool destroying;
|
bool destroying;
|
||||||
|
|
||||||
list_t *executed_criteria; // struct criteria *
|
list_t *executed_criteria; // struct criteria *
|
||||||
|
@ -323,4 +326,8 @@ void view_set_urgent(struct sway_view *view, bool enable);
|
||||||
|
|
||||||
bool view_is_urgent(struct sway_view *view);
|
bool view_is_urgent(struct sway_view *view);
|
||||||
|
|
||||||
|
void view_remove_saved_buffer(struct sway_view *view);
|
||||||
|
|
||||||
|
void view_save_buffer(struct sway_view *view);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -199,17 +199,14 @@ static void render_saved_view(struct sway_view *view,
|
||||||
struct sway_output *output, pixman_region32_t *damage, float alpha) {
|
struct sway_output *output, pixman_region32_t *damage, float alpha) {
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
|
|
||||||
int width, height;
|
if (!view->saved_buffer || !view->saved_buffer->texture) {
|
||||||
struct wlr_texture *texture =
|
|
||||||
transaction_get_saved_texture(view, &width, &height);
|
|
||||||
if (!texture) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct wlr_box box = {
|
struct wlr_box box = {
|
||||||
.x = view->swayc->current.view_x - output->swayc->current.swayc_x,
|
.x = view->swayc->current.view_x - output->swayc->current.swayc_x,
|
||||||
.y = view->swayc->current.view_y - output->swayc->current.swayc_y,
|
.y = view->swayc->current.view_y - output->swayc->current.swayc_y,
|
||||||
.width = width,
|
.width = view->saved_buffer_width,
|
||||||
.height = height,
|
.height = view->saved_buffer_height,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_box output_box = {
|
struct wlr_box output_box = {
|
||||||
|
@ -229,7 +226,8 @@ static void render_saved_view(struct sway_view *view,
|
||||||
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
|
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
|
||||||
wlr_output->transform_matrix);
|
wlr_output->transform_matrix);
|
||||||
|
|
||||||
render_texture(wlr_output, damage, texture, &box, matrix, alpha);
|
render_texture(wlr_output, damage, view->saved_buffer->texture,
|
||||||
|
&box, matrix, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -238,7 +236,7 @@ static void render_saved_view(struct sway_view *view,
|
||||||
static void render_view(struct sway_output *output, pixman_region32_t *damage,
|
static void render_view(struct sway_output *output, pixman_region32_t *damage,
|
||||||
struct sway_container *con, struct border_colors *colors) {
|
struct sway_container *con, struct border_colors *colors) {
|
||||||
struct sway_view *view = con->sway_view;
|
struct sway_view *view = con->sway_view;
|
||||||
if (view->swayc->instructions->length) {
|
if (view->saved_buffer) {
|
||||||
render_saved_view(view, output, damage, view->swayc->alpha);
|
render_saved_view(view, output, damage, view->swayc->alpha);
|
||||||
} else {
|
} else {
|
||||||
render_view_surfaces(view, output, damage, view->swayc->alpha);
|
render_view_surfaces(view, output, damage, view->swayc->alpha);
|
||||||
|
@ -841,7 +839,7 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
|
|
||||||
// TODO: handle views smaller than the output
|
// TODO: handle views smaller than the output
|
||||||
if (fullscreen_con->type == C_VIEW) {
|
if (fullscreen_con->type == C_VIEW) {
|
||||||
if (fullscreen_con->instructions->length) {
|
if (fullscreen_con->sway_view->saved_buffer) {
|
||||||
render_saved_view(fullscreen_con->sway_view,
|
render_saved_view(fullscreen_con->sway_view,
|
||||||
output, damage, 1.0f);
|
output, damage, 1.0f);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -41,8 +41,6 @@ struct sway_transaction_instruction {
|
||||||
struct sway_transaction *transaction;
|
struct sway_transaction *transaction;
|
||||||
struct sway_container *container;
|
struct sway_container *container;
|
||||||
struct sway_container_state state;
|
struct sway_container_state state;
|
||||||
struct wlr_buffer *saved_buffer;
|
|
||||||
int saved_buffer_width, saved_buffer_height;
|
|
||||||
uint32_t serial;
|
uint32_t serial;
|
||||||
bool ready;
|
bool ready;
|
||||||
};
|
};
|
||||||
|
@ -57,27 +55,6 @@ static struct sway_transaction *transaction_create() {
|
||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_saved_view_buffer(
|
|
||||||
struct sway_transaction_instruction *instruction) {
|
|
||||||
if (instruction->saved_buffer) {
|
|
||||||
wlr_buffer_unref(instruction->saved_buffer);
|
|
||||||
instruction->saved_buffer = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void save_view_buffer(struct sway_view *view,
|
|
||||||
struct sway_transaction_instruction *instruction) {
|
|
||||||
if (!sway_assert(instruction->saved_buffer == NULL,
|
|
||||||
"Didn't expect instruction to have a saved buffer already")) {
|
|
||||||
remove_saved_view_buffer(instruction);
|
|
||||||
}
|
|
||||||
if (view->surface && wlr_surface_has_buffer(view->surface)) {
|
|
||||||
instruction->saved_buffer = wlr_buffer_ref(view->surface->buffer);
|
|
||||||
instruction->saved_buffer_width = view->surface->current.width;
|
|
||||||
instruction->saved_buffer_height = view->surface->current.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void transaction_destroy(struct sway_transaction *transaction) {
|
static void transaction_destroy(struct sway_transaction *transaction) {
|
||||||
// Free instructions
|
// Free instructions
|
||||||
for (int i = 0; i < transaction->instructions->length; ++i) {
|
for (int i = 0; i < transaction->instructions->length; ++i) {
|
||||||
|
@ -93,7 +70,6 @@ static void transaction_destroy(struct sway_transaction *transaction) {
|
||||||
if (con->destroying && !con->instructions->length) {
|
if (con->destroying && !con->instructions->length) {
|
||||||
container_free(con);
|
container_free(con);
|
||||||
}
|
}
|
||||||
remove_saved_view_buffer(instruction);
|
|
||||||
free(instruction);
|
free(instruction);
|
||||||
}
|
}
|
||||||
list_free(transaction->instructions);
|
list_free(transaction->instructions);
|
||||||
|
@ -158,9 +134,6 @@ static void transaction_add_container(struct sway_transaction *transaction,
|
||||||
|
|
||||||
copy_pending_state(container, &instruction->state);
|
copy_pending_state(container, &instruction->state);
|
||||||
|
|
||||||
if (container->type == C_VIEW) {
|
|
||||||
save_view_buffer(container->sway_view, instruction);
|
|
||||||
}
|
|
||||||
list_add(transaction->instructions, instruction);
|
list_add(transaction->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,6 +193,15 @@ static void transaction_apply(struct sway_transaction *transaction) {
|
||||||
|
|
||||||
memcpy(&container->current, &instruction->state,
|
memcpy(&container->current, &instruction->state,
|
||||||
sizeof(struct sway_container_state));
|
sizeof(struct sway_container_state));
|
||||||
|
|
||||||
|
if (container->type == C_VIEW) {
|
||||||
|
if (container->sway_view->saved_buffer) {
|
||||||
|
view_remove_saved_buffer(container->sway_view);
|
||||||
|
}
|
||||||
|
if (container->instructions->length > 1) {
|
||||||
|
view_save_buffer(container->sway_view);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,6 +276,9 @@ static void transaction_commit(struct sway_transaction *transaction) {
|
||||||
// mapping and its default geometry doesn't intersect an output.
|
// mapping and its default geometry doesn't intersect an output.
|
||||||
struct timespec when;
|
struct timespec when;
|
||||||
wlr_surface_send_frame_done(con->sway_view->surface, &when);
|
wlr_surface_send_frame_done(con->sway_view->surface, &when);
|
||||||
|
if (!con->sway_view->saved_buffer) {
|
||||||
|
view_save_buffer(con->sway_view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
list_add(con->instructions, instruction);
|
list_add(con->instructions, instruction);
|
||||||
}
|
}
|
||||||
|
@ -400,18 +385,6 @@ void transaction_notify_view_ready_by_size(struct sway_view *view,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_texture *transaction_get_saved_texture(struct sway_view *view,
|
|
||||||
int *width, int *height) {
|
|
||||||
struct sway_transaction_instruction *instruction =
|
|
||||||
view->swayc->instructions->items[0];
|
|
||||||
if (!instruction->saved_buffer) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*width = instruction->saved_buffer_width;
|
|
||||||
*height = instruction->saved_buffer_height;
|
|
||||||
return instruction->saved_buffer->texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void transaction_commit_dirty(void) {
|
void transaction_commit_dirty(void) {
|
||||||
if (!server.dirty_containers->length) {
|
if (!server.dirty_containers->length) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <wayland-server.h>
|
#include <wayland-server.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
|
#include <wlr/types/wlr_buffer.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#ifdef HAVE_XWAYLAND
|
#ifdef HAVE_XWAYLAND
|
||||||
|
@ -1070,3 +1071,22 @@ void view_set_urgent(struct sway_view *view, bool enable) {
|
||||||
bool view_is_urgent(struct sway_view *view) {
|
bool view_is_urgent(struct sway_view *view) {
|
||||||
return view->urgent.tv_sec || view->urgent.tv_nsec;
|
return view->urgent.tv_sec || view->urgent.tv_nsec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void view_remove_saved_buffer(struct sway_view *view) {
|
||||||
|
if (!sway_assert(view->saved_buffer, "Expected a saved buffer")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wlr_buffer_unref(view->saved_buffer);
|
||||||
|
view->saved_buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void view_save_buffer(struct sway_view *view) {
|
||||||
|
if (!sway_assert(!view->saved_buffer, "Didn't expect saved buffer")) {
|
||||||
|
view_remove_saved_buffer(view);
|
||||||
|
}
|
||||||
|
if (view->surface && wlr_surface_has_buffer(view->surface)) {
|
||||||
|
view->saved_buffer = wlr_buffer_ref(view->surface->buffer);
|
||||||
|
view->saved_buffer_width = view->surface->current.width;
|
||||||
|
view->saved_buffer_height = view->surface->current.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue