Skip to content

Commit

Permalink
view: Save all buffers associated with view
Browse files Browse the repository at this point in the history
During the execution of a resize transaction, the buffer associated
with a view's surface is saved and reused until the client acknowledges
the resulting configure event.

However, only one the main buffer of the main surface was stored and
rendered, meaning that subsurfaces disappear during resize.

Iterate over all, store and render buffers from all surfaces in the view
to ensure that correct rendering is preserved.
  • Loading branch information
kennylevinsen committed May 30, 2020
1 parent 8386655 commit 70764f7
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 50 deletions.
9 changes: 7 additions & 2 deletions include/sway/tree/view.h
Expand Up @@ -55,6 +55,12 @@ struct sway_view_impl {
void (*destroy)(struct sway_view *view);
};

struct sway_saved_buffer {
struct wlr_client_buffer *buffer;
int x, y;
int width, height;
};

struct sway_view {
enum sway_view_type type;
const struct sway_view_impl *impl;
Expand All @@ -80,8 +86,7 @@ struct sway_view {
bool allow_request_urgent;
struct wl_event_source *urgent_timer;

struct wlr_client_buffer *saved_buffer;
int saved_buffer_width, saved_buffer_height;
list_t *saved_buffers;

// The geometry for whatever the client is committing, regardless of
// transaction state. Updated on every commit.
Expand Down
2 changes: 1 addition & 1 deletion sway/desktop/output.c
Expand Up @@ -511,7 +511,7 @@ static bool scan_out_fullscreen_view(struct sway_output *output,
return false;
}

if (view->saved_buffer) {
if (view->saved_buffers->length != 0) {
return false;
}

Expand Down
61 changes: 34 additions & 27 deletions sway/desktop/render.c
Expand Up @@ -280,37 +280,44 @@ static void render_saved_view(struct sway_view *view,
struct sway_output *output, pixman_region32_t *damage, float alpha) {
struct wlr_output *wlr_output = output->wlr_output;

if (!view->saved_buffer || !view->saved_buffer->texture) {
if (view->saved_buffers->length == 0) {
return;
}
struct wlr_box box = {
.x = view->container->surface_x - output->lx -
view->saved_geometry.x,
.y = view->container->surface_y - output->ly -
view->saved_geometry.y,
.width = view->saved_buffer_width,
.height = view->saved_buffer_height,
};

struct wlr_box output_box = {
.width = output->width,
.height = output->height,
};
for (int bufidx = 0; bufidx < view->saved_buffers->length; bufidx++) {
struct sway_saved_buffer *buffer = view->saved_buffers->items[bufidx];
if (!buffer->buffer->texture) {
return;
}

struct wlr_box intersection;
bool intersects = wlr_box_intersection(&intersection, &output_box, &box);
if (!intersects) {
return;
}
struct wlr_box box = {
.x = view->container->surface_x - output->lx -
view->saved_geometry.x + buffer->x,
.y = view->container->surface_y - output->ly -
view->saved_geometry.y + buffer->y,
.width = buffer->width,
.height = buffer->height,
};

struct wlr_box output_box = {
.width = output->width,
.height = output->height,
};

struct wlr_box intersection;
bool intersects = wlr_box_intersection(&intersection, &output_box, &box);
if (!intersects) {
return;
}

scale_box(&box, wlr_output->scale);
scale_box(&box, wlr_output->scale);

float matrix[9];
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
wlr_output->transform_matrix);
float matrix[9];
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
wlr_output->transform_matrix);

render_texture(wlr_output, damage, view->saved_buffer->texture,
&box, matrix, alpha);
render_texture(wlr_output, damage, buffer->buffer->texture,
&box, matrix, alpha);
}

// FIXME: we should set the surface that this saved buffer originates from
// as sampled here.
Expand All @@ -323,7 +330,7 @@ static void render_saved_view(struct sway_view *view,
static void render_view(struct sway_output *output, pixman_region32_t *damage,
struct sway_container *con, struct border_colors *colors) {
struct sway_view *view = con->view;
if (view->saved_buffer) {
if (view->saved_buffers->length > 0) {
render_saved_view(view, output, damage, view->container->alpha);
} else if (view->surface) {
render_view_toplevels(view, output, damage, view->container->alpha);
Expand Down Expand Up @@ -1020,7 +1027,7 @@ void output_render(struct sway_output *output, struct timespec *when,
}

if (fullscreen_con->view) {
if (fullscreen_con->view->saved_buffer) {
if (fullscreen_con->view->saved_buffers->length != 0) {
render_saved_view(fullscreen_con->view, output, damage, 1.0f);
} else if (fullscreen_con->view->surface) {
render_view_toplevels(fullscreen_con->view,
Expand Down
23 changes: 13 additions & 10 deletions sway/desktop/transaction.c
Expand Up @@ -210,14 +210,17 @@ static void apply_container_state(struct sway_container *container,
struct sway_view *view = container->view;
// Damage the old location
desktop_damage_whole_container(container);
if (view && view->saved_buffer) {
struct wlr_box box = {
.x = container->current.content_x - view->saved_geometry.x,
.y = container->current.content_y - view->saved_geometry.y,
.width = view->saved_buffer_width,
.height = view->saved_buffer_height,
};
desktop_damage_box(&box);
if (view && view->saved_buffers->length != 0) {
for (int bufidx = 0; bufidx < view->saved_buffers->length; bufidx++) {
struct sway_saved_buffer *buf = view->saved_buffers->items[bufidx];
struct wlr_box box = {
.x = container->current.content_x - view->saved_geometry.x + buf->x,
.y = container->current.content_y - view->saved_geometry.y + buf->y,
.width = buf->width,
.height = buf->height,
};
desktop_damage_box(&box);
}
}

// There are separate children lists for each instruction state, the
Expand All @@ -229,7 +232,7 @@ static void apply_container_state(struct sway_container *container,

memcpy(&container->current, state, sizeof(struct sway_container_state));

if (view && view->saved_buffer) {
if (view && view->saved_buffers->length != 0) {
if (!container->node.destroying || container->node.ntxnrefs == 1) {
view_remove_saved_buffer(view);
}
Expand Down Expand Up @@ -432,7 +435,7 @@ static void transaction_commit(struct sway_transaction *transaction) {
wlr_surface_send_frame_done(
node->sway_container->view->surface, &now);
}
if (node_is_view(node) && !node->sway_container->view->saved_buffer) {
if (node_is_view(node) && node->sway_container->view->saved_buffers->length == 0) {
view_save_buffer(node->sway_container->view);
memcpy(&node->sway_container->view->saved_geometry,
&node->sway_container->view->geometry,
Expand Down
36 changes: 26 additions & 10 deletions sway/tree/view.c
Expand Up @@ -36,6 +36,7 @@ void view_init(struct sway_view *view, enum sway_view_type type,
view->type = type;
view->impl = impl;
view->executed_criteria = create_list();
view->saved_buffers = create_list();
view->allow_request_urgent = true;
view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
wl_signal_init(&view->events.unmap);
Expand Down Expand Up @@ -1176,23 +1177,38 @@ bool view_is_urgent(struct sway_view *view) {
}

void view_remove_saved_buffer(struct sway_view *view) {
if (!sway_assert(view->saved_buffer, "Expected a saved buffer")) {
if (!sway_assert(view->saved_buffers->length != 0, "Expected a saved buffer")) {
return;
}
wlr_buffer_unlock(&view->saved_buffer->base);
view->saved_buffer = NULL;
while (view->saved_buffers->length != 0) {
struct sway_saved_buffer *saved_buffer = view->saved_buffers->items[0];
wlr_buffer_unlock(&saved_buffer->buffer->base);
free(saved_buffer);
list_del(view->saved_buffers, 0);
}
}

static void view_save_buffer_iterator(struct wlr_surface *surface,
int sx, int sy, void *data) {
struct sway_view *view = data;

if (surface && wlr_surface_has_buffer(surface)) {
wlr_buffer_lock(&surface->buffer->base);
struct sway_saved_buffer *saved_buffer = calloc(1, sizeof(struct sway_saved_buffer));
list_add(view->saved_buffers, saved_buffer);
saved_buffer->buffer = surface->buffer;
saved_buffer->width = surface->current.width;
saved_buffer->height = surface->current.height;
saved_buffer->x = sx;
saved_buffer->y = sy;
}
}

void view_save_buffer(struct sway_view *view) {
if (!sway_assert(!view->saved_buffer, "Didn't expect saved buffer")) {
if (!sway_assert(view->saved_buffers->length == 0, "Didn't expect saved buffer")) {
view_remove_saved_buffer(view);
}
if (view->surface && wlr_surface_has_buffer(view->surface)) {
wlr_buffer_lock(&view->surface->buffer->base);
view->saved_buffer = view->surface->buffer;
view->saved_buffer_width = view->surface->current.width;
view->saved_buffer_height = view->surface->current.height;
}
view_for_each_surface(view, view_save_buffer_iterator, view);
}

bool view_is_transient_for(struct sway_view *child,
Expand Down

0 comments on commit 70764f7

Please sign in to comment.