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_drm_syncobj_timeline;
struct wlr_surface; struct wlr_surface;
struct wlr_raster_source {
struct wlr_texture *texture;
struct wl_list link;
struct wl_listener renderer_destroy;
};
struct wlr_raster { struct wlr_raster {
// May be NULL // May be NULL
struct wlr_buffer *buffer; struct wlr_buffer *buffer;
struct wl_list sources;
uint32_t width, height; uint32_t width, height;
bool opaque; bool opaque;
@ -39,7 +48,6 @@ struct wlr_raster {
struct wl_listener buffer_release; struct wl_listener buffer_release;
struct wlr_texture *texture;
struct wl_listener renderer_destroy; struct wl_listener renderer_destroy;
}; };

View file

@ -24,6 +24,7 @@ struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer,
return NULL; return NULL;
} }
wl_list_init(&raster->sources);
wl_signal_init(&raster->events.destroy); wl_signal_init(&raster->events.destroy);
assert(buffer); assert(buffer);
@ -45,6 +46,12 @@ struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer,
return raster; 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) { static void raster_consider_destroy(struct wlr_raster *raster) {
if (raster->n_locks > 0) { if (raster->n_locks > 0) {
return; return;
@ -52,9 +59,10 @@ static void raster_consider_destroy(struct wlr_raster *raster) {
wl_signal_emit_mutable(&raster->events.destroy, NULL); wl_signal_emit_mutable(&raster->events.destroy, NULL);
if (raster->texture) { struct wlr_raster_source *source, *source_tmp;
wl_list_remove(&raster->renderer_destroy.link); wl_list_for_each_safe(source, source_tmp, &raster->sources, link) {
wlr_texture_destroy(raster->texture); wlr_texture_destroy(source->texture);
raster_source_destroy(source);
} }
wl_list_remove(&raster->buffer_release.link); 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) { static void raster_detach(struct wlr_raster *raster, struct wlr_texture *texture) {
assert(texture); if (!texture) {
assert(raster->texture == texture); return;
}
wl_list_remove(&raster->renderer_destroy.link); struct wlr_raster_source *source;
raster->texture = NULL; 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) { static void handle_renderer_destroy(struct wl_listener *listener, void *data) {
struct wlr_raster *raster = wl_container_of(listener, raster, renderer_destroy); struct wlr_raster_source *source = wl_container_of(listener, source, renderer_destroy);
raster_detach(raster, raster->texture); raster_source_destroy(source);
} }
static void raster_attach(struct wlr_raster *raster, struct wlr_texture *texture) { static void raster_attach(struct wlr_raster *raster, struct wlr_texture *texture) {
assert(texture->width == raster->width && texture->height == raster->height); assert(texture->width == raster->width && texture->height == raster->height);
assert(!raster->texture);
raster->renderer_destroy.notify = handle_renderer_destroy; struct wlr_raster_source *source;
wl_signal_add(&texture->renderer->events.destroy, &raster->renderer_destroy); 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_texture *wlr_raster_obtain_texture(struct wlr_raster *raster,
struct wlr_renderer *renderer) { struct wlr_renderer *renderer) {
if (raster->texture) { struct wlr_texture *texture = wlr_raster_get_texture(raster, renderer);
assert(raster->texture->renderer == renderer); if (texture) {
return raster->texture; return texture;
} }
assert(raster->buffer); assert(raster->buffer);
@ -116,7 +154,7 @@ struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster,
return client_buffer->texture; 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) { if (texture) {
raster_attach(raster, 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); 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 the new raster already has a texture, there's nothing we can do to help.
if (state->new_raster->texture) { if (!wl_list_empty(&state->new_raster->sources)) {
assert(state->new_raster->texture->renderer == state->old_raster->texture->renderer);
destroy_raster_update_state(state); destroy_raster_update_state(state);
return; return;
} }
struct wlr_texture *texture = state->old_raster->texture; struct wlr_raster_source *source, *tmp_source;
if (!texture) { wl_list_for_each_safe(source, tmp_source, &state->old_raster->sources, link) {
destroy_raster_update_state(state); struct wlr_texture *texture = source->texture;
return; if (wlr_texture_update_from_buffer(texture, state->buffer, &state->damage)) {
} raster_detach(state->old_raster, texture);
raster_attach(state->new_raster, 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); 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 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); wlr_buffer_lock(raster->buffer);
surface_raster->locking_buffer = true; 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); 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, raster = raster_update(surface_raster->raster,
surface->current.buffer, &surface->buffer_damage, &options); surface->current.buffer, &surface->buffer_damage, &options);
} else { } else {