Re implement partial texture uploads for surfaces and immediate buffer unlocking

This commit is contained in:
Alexander Orzechowski 2022-06-28 13:11:23 -04:00
parent c71800cf8d
commit 43a3cbe6ae
4 changed files with 108 additions and 9 deletions

View file

@ -93,6 +93,13 @@ struct wlr_surface {
* The buffer position, in surface-local units.
*/
int sx, sy;
/**
* The surface's raster, if any. A surface has an attached raster when it
* commits with a non-null buffer in its pending state. A surface will not
* have a raster if it has never committed one or has committed a null
* buffer.
*/
struct wlr_raster *raster;
/**
* The last commit's buffer damage, in buffer-local coordinates. This
* contains both the damage accumulated by the client via
@ -157,6 +164,9 @@ struct wlr_surface {
} previous;
bool opaque;
struct wlr_raster *old_raster;
struct wl_listener raster_destroy;
};
struct wlr_renderer;

View file

@ -427,8 +427,8 @@ static void output_cursor_commit(struct wlr_output_cursor *cursor,
struct wlr_surface *surface = cursor->surface;
assert(surface != NULL);
if (surface->current.buffer) {
cursor->raster = wlr_raster_create(surface->current.buffer);
if (surface->raster) {
cursor->raster = wlr_raster_lock(surface->raster);
}
// Some clients commit a cursor surface with a NULL buffer to hide it.

View file

@ -66,10 +66,7 @@ static void set_raster_with_surface_state(struct wlr_scene_raster *scene_raster,
wlr_scene_raster_set_dest_size(scene_raster, state->width, state->height);
wlr_scene_raster_set_transform(scene_raster, state->transform);
struct wlr_raster *raster = NULL;
if (surface->current.buffer) {
raster = wlr_raster_create(surface->current.buffer);
}
struct wlr_raster *raster = surface->raster;
if (raster) {
wlr_scene_raster_set_raster_with_damage(scene_raster,
@ -77,8 +74,6 @@ static void set_raster_with_surface_state(struct wlr_scene_raster *scene_raster,
} else {
wlr_scene_raster_set_raster(scene_raster, NULL);
}
wlr_raster_unlock(raster);
}
static void handle_scene_surface_surface_commit(

View file

@ -1,6 +1,7 @@
#include <assert.h>
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wlr/interfaces/wlr_buffer.h>
#include <wlr/render/interface.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_compositor.h>
@ -415,8 +416,34 @@ static void surface_commit_state(struct wlr_surface *surface,
surface_state_move(&surface->current, next);
if (invalid_buffer) {
if (!surface->current.buffer) {
wlr_raster_unlock(surface->raster);
surface->raster = NULL;
}
if (!surface->raster || surface->raster->buffer != surface->current.buffer) {
surface->old_raster = surface->raster;
if (surface->current.buffer) {
surface->raster = wlr_raster_create(surface->current.buffer);
}
if (surface->old_raster) {
// By the time we unlock the buffer next the buffer might
// get destroyed. We need to start listening here.
wl_signal_add(&surface->old_raster->events.destroy,
&surface->raster_destroy);
wlr_raster_unlock(surface->old_raster);
}
}
surface_apply_damage(surface);
wlr_buffer_unlock(surface->current.buffer);
surface->current.buffer = NULL;
}
surface_update_opaque_region(surface);
surface_update_input_region(surface);
@ -450,6 +477,29 @@ static void surface_commit_state(struct wlr_surface *surface,
}
wlr_signal_emit_safe(&surface->events.commit, surface);
if (surface->old_raster) {
wl_list_remove(&surface->raster_destroy.link);
surface->old_raster = NULL;
}
if (invalid_buffer && surface->raster) {
// make sure there is at least one source for the raster before removing
// the buffer
if (wl_list_empty(&surface->raster->sources)) {
wlr_renderer_raster_upload(surface->renderer, surface->raster);
}
// unlock the buffer for shm buffers only. Clients may implement
// optimizations if given the shm buffer back immediately.
//
// For other buffers, we want to continue to lock it so that we
// may direct scanout.
if (!wl_list_empty(&surface->raster->sources) && surface->raster->buffer &&
buffer_is_shm_client_buffer(surface->raster->buffer)) {
wlr_raster_remove_buffer(surface->raster);
}
}
}
static void collect_subsurface_damage_iter(struct wlr_surface *surface,
@ -614,6 +664,8 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) {
surface_output_destroy(surface_output);
}
wlr_raster_unlock(surface->raster);
wlr_signal_emit_safe(&surface->events.destroy, surface);
wlr_addon_set_finish(&surface->addons);
@ -640,6 +692,46 @@ static void surface_handle_renderer_destroy(struct wl_listener *listener,
wl_resource_destroy(surface->resource);
}
static void surface_handle_raster_destroy(struct wl_listener *listener, void *data) {
struct wlr_surface *surface =
wl_container_of(listener, surface, raster_destroy);
// try to reclaim a texture from this raster so we can try to do a partial
// upload next time.
struct wlr_texture *reuse = NULL;
struct wlr_texture *texture, *tmp_texture;
wl_list_for_each_safe(texture, tmp_texture,
&surface->old_raster->sources, link) {
// we can be smarter about this, but for now let's just take the first
// texture
wlr_raster_detach(surface->old_raster, texture);
reuse = texture;
break;
}
surface->old_raster = NULL;
if (!reuse) {
return;
}
// if there are already sources for the new raster, don't bother uploading
// if something else already did for us.
if (!wl_list_empty(&surface->raster->sources)) {
wlr_texture_destroy(reuse);
return;
}
if (!wlr_texture_update_from_raster(reuse,
surface->raster, &surface->buffer_damage)) {
wlr_texture_destroy(reuse);
return;
}
wlr_raster_attach(surface->raster, reuse);
}
static struct wlr_surface *surface_create(struct wl_client *client,
uint32_t version, uint32_t id, struct wlr_renderer *renderer) {
struct wlr_surface *surface = calloc(1, sizeof(struct wlr_surface));
@ -680,11 +772,13 @@ static struct wlr_surface *surface_create(struct wl_client *client,
wl_signal_add(&renderer->events.destroy, &surface->renderer_destroy);
surface->renderer_destroy.notify = surface_handle_renderer_destroy;
surface->raster_destroy.notify = surface_handle_raster_destroy;
return surface;
}
bool wlr_surface_has_buffer(struct wlr_surface *surface) {
return surface->current.buffer != NULL;
return surface->raster != NULL;
}
bool wlr_surface_set_role(struct wlr_surface *surface,