wlr_raster: Support multiple renderers

This commit is contained in:
Alexander Orzechowski 2023-04-21 01:14:35 +02:00 committed by Alexander Orzechowski
parent 477c556019
commit 2cca0086fb
2 changed files with 93 additions and 30 deletions

View file

@ -19,10 +19,19 @@ struct wlr_renderer;
struct wlr_drm_syncobj_timeline;
struct wlr_surface;
struct wlr_raster_source {
struct wlr_texture *texture;
struct wl_list link;
struct wl_listener renderer_destroy;
};
struct wlr_raster {
// May be NULL
struct wlr_buffer *buffer;
struct wl_list sources;
uint32_t width, height;
bool opaque;
@ -39,7 +48,6 @@ struct wlr_raster {
struct wl_listener buffer_release;
struct wlr_texture *texture;
struct wl_listener renderer_destroy;
};

View file

@ -24,6 +24,7 @@ struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer,
return NULL;
}
wl_list_init(&raster->sources);
wl_signal_init(&raster->events.destroy);
assert(buffer);
@ -45,6 +46,12 @@ struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer,
return raster;
}
static void raster_source_destroy(struct wlr_raster_source *source) {
wl_list_remove(&source->link);
wl_list_remove(&source->renderer_destroy.link);
free(source);
}
static void raster_consider_destroy(struct wlr_raster *raster) {
if (raster->n_locks > 0) {
return;
@ -52,9 +59,10 @@ static void raster_consider_destroy(struct wlr_raster *raster) {
wl_signal_emit_mutable(&raster->events.destroy, NULL);
if (raster->texture) {
wl_list_remove(&raster->renderer_destroy.link);
wlr_texture_destroy(raster->texture);
struct wlr_raster_source *source, *source_tmp;
wl_list_for_each_safe(source, source_tmp, &raster->sources, link) {
wlr_texture_destroy(source->texture);
raster_source_destroy(source);
}
wl_list_remove(&raster->buffer_release.link);
@ -79,33 +87,63 @@ void wlr_raster_unlock(struct wlr_raster *raster) {
}
static void raster_detach(struct wlr_raster *raster, struct wlr_texture *texture) {
assert(texture);
assert(raster->texture == texture);
if (!texture) {
return;
}
wl_list_remove(&raster->renderer_destroy.link);
raster->texture = NULL;
struct wlr_raster_source *source;
wl_list_for_each(source, &raster->sources, link) {
if (source->texture == texture) {
raster_source_destroy(source);
return;
}
}
assert(false);
}
static void handle_renderer_destroy(struct wl_listener *listener, void *data) {
struct wlr_raster *raster = wl_container_of(listener, raster, renderer_destroy);
raster_detach(raster, raster->texture);
struct wlr_raster_source *source = wl_container_of(listener, source, renderer_destroy);
raster_source_destroy(source);
}
static void raster_attach(struct wlr_raster *raster, struct wlr_texture *texture) {
assert(texture->width == raster->width && texture->height == raster->height);
assert(!raster->texture);
raster->renderer_destroy.notify = handle_renderer_destroy;
wl_signal_add(&texture->renderer->events.destroy, &raster->renderer_destroy);
struct wlr_raster_source *source;
wl_list_for_each(source, &raster->sources, link) {
assert(source->texture != texture);
}
raster->texture = texture;
source = calloc(1, sizeof(*source));
if (!source) {
return;
}
source->renderer_destroy.notify = handle_renderer_destroy;
wl_signal_add(&texture->renderer->events.destroy, &source->renderer_destroy);
wl_list_insert(&raster->sources, &source->link);
source->texture = texture;
}
static struct wlr_texture *wlr_raster_get_texture(struct wlr_raster *raster,
struct wlr_renderer *renderer) {
struct wlr_raster_source *source;
wl_list_for_each(source, &raster->sources, link) {
if (source->texture->renderer == renderer) {
return source->texture;
}
}
return NULL;
}
struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster,
struct wlr_renderer *renderer) {
if (raster->texture) {
assert(raster->texture->renderer == renderer);
return raster->texture;
struct wlr_texture *texture = wlr_raster_get_texture(raster, renderer);
if (texture) {
return texture;
}
assert(raster->buffer);
@ -116,7 +154,7 @@ struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster,
return client_buffer->texture;
}
struct wlr_texture *texture = wlr_texture_from_buffer(renderer, raster->buffer);
texture = wlr_texture_from_buffer(renderer, raster->buffer);
if (texture) {
raster_attach(raster, texture);
}
@ -153,21 +191,18 @@ static void raster_update_handle_old_raster_destroy(struct wl_listener *listener
struct raster_update_state *state = wl_container_of(listener, state, old_raster_destroy);
// if the new raster already has a texture, there's nothing we can do to help.
if (state->new_raster->texture) {
assert(state->new_raster->texture->renderer == state->old_raster->texture->renderer);
if (!wl_list_empty(&state->new_raster->sources)) {
destroy_raster_update_state(state);
return;
}
struct wlr_texture *texture = state->old_raster->texture;
if (!texture) {
destroy_raster_update_state(state);
return;
}
if (wlr_texture_update_from_buffer(texture, state->buffer, &state->damage)) {
raster_detach(state->old_raster, texture);
raster_attach(state->new_raster, texture);
struct wlr_raster_source *source, *tmp_source;
wl_list_for_each_safe(source, tmp_source, &state->old_raster->sources, link) {
struct wlr_texture *texture = source->texture;
if (wlr_texture_update_from_buffer(texture, state->buffer, &state->damage)) {
raster_detach(state->old_raster, texture);
raster_attach(state->new_raster, texture);
}
}
destroy_raster_update_state(state);
@ -254,7 +289,7 @@ static void surface_raster_handle_buffer_prerelease(struct wl_listener *listener
}
// if there was a failed texture upload, keep on locking the buffer
if (!raster->texture) {
if (wl_list_empty(&raster->sources)) {
wlr_buffer_lock(raster->buffer);
surface_raster->locking_buffer = true;
}
@ -372,6 +407,26 @@ struct wlr_raster *wlr_raster_from_surface(struct wlr_surface *surface) {
return wlr_raster_lock(surface_raster->raster);
}
// before we try to update the old raster, remove obsolete textures
struct wlr_raster_source *source, *tmp_source;
wl_list_for_each_safe(source, tmp_source, &surface_raster->raster->sources, link) {
struct wlr_texture *texture = source->texture;
bool found = false;
struct wlr_surface_output *output;
wl_list_for_each(output, &surface->current_outputs, link) {
if (output->output->renderer == texture->renderer) {
found = true;
break;
}
}
if (!found) {
raster_detach(surface_raster->raster, texture);
wlr_texture_destroy(texture);
}
}
raster = raster_update(surface_raster->raster,
surface->current.buffer, &surface->buffer_damage, &options);
} else {