rpi: Protect in-use DispmanX resources from premature deletion

The compositor will check if the client destroyed the wl_buffer
while it was in use in a display update, and delete the resource
itself once the update has finished.
This commit is contained in:
Tomeu Vizoso 2013-10-25 10:34:38 +02:00 committed by Kristian Høgsberg
parent 34dad7d69b
commit 7498758525
2 changed files with 46 additions and 33 deletions

View File

@ -303,6 +303,11 @@ vc_dispmanx_get_handle_from_wl_buffer(struct wl_resource *_buffer)
return DISPMANX_NO_HANDLE; return DISPMANX_NO_HANDLE;
} }
static inline void
vc_dispmanx_set_wl_buffer_in_use(struct wl_resource *_buffer, int in_use)
{
}
/* from /opt/vc/include/EGL/eglplatform.h */ /* from /opt/vc/include/EGL/eglplatform.h */
typedef struct { typedef struct {

View File

@ -362,6 +362,28 @@ rpi_resource_update(struct rpi_resource *resource, struct weston_buffer *buffer,
return ret ? -1 : 0; return ret ? -1 : 0;
} }
static void
rpir_egl_buffer_destroy(struct rpir_egl_buffer *egl_buffer)
{
struct weston_buffer *buffer;
if (egl_buffer == NULL)
return;
buffer = egl_buffer->buffer_ref.buffer;
if (buffer == NULL) {
/* The client has already destroyed the wl_buffer, the
* compositor has the responsibility to delete the resource.
*/
vc_dispmanx_resource_delete(egl_buffer->resource_handle);
} else {
vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 0);
weston_buffer_reference(&egl_buffer->buffer_ref, NULL);
}
free(egl_buffer);
}
static struct rpir_surface * static struct rpir_surface *
rpir_surface_create(struct rpi_renderer *renderer) rpir_surface_create(struct rpi_renderer *renderer)
{ {
@ -404,23 +426,9 @@ rpir_surface_destroy(struct rpir_surface *surface)
rpi_resource_release(&surface->resources[1]); rpi_resource_release(&surface->resources[1]);
DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views); DBG("rpir_surface %p destroyed (%u)\n", surface, surface->visible_views);
if (surface->egl_back != NULL) { rpir_egl_buffer_destroy(surface->egl_back);
weston_buffer_reference(&surface->egl_back->buffer_ref, NULL); rpir_egl_buffer_destroy(surface->egl_front);
free(surface->egl_back); rpir_egl_buffer_destroy(surface->egl_old_front);
surface->egl_back = NULL;
}
if (surface->egl_front != NULL) {
weston_buffer_reference(&surface->egl_front->buffer_ref, NULL);
free(surface->egl_front);
surface->egl_front = NULL;
}
if (surface->egl_old_front != NULL) {
weston_buffer_reference(&surface->egl_old_front->buffer_ref, NULL);
free(surface->egl_old_front);
surface->egl_old_front = NULL;
}
free(surface); free(surface);
} }
@ -1002,7 +1010,6 @@ rpir_view_update(struct rpir_view *view, struct rpir_output *output,
int ret; int ret;
int obscured; int obscured;
obscured = is_view_not_visible(view->view); obscured = is_view_not_visible(view->view);
if (obscured) { if (obscured) {
DBG("rpir_view %p totally obscured.\n", view); DBG("rpir_view %p totally obscured.\n", view);
@ -1260,17 +1267,22 @@ rpi_renderer_repaint_output(struct weston_output *base,
rpir_surface_swap_pointers(view->surface); rpir_surface_swap_pointers(view->surface);
} }
if (view->surface->buffer_type == BUFFER_TYPE_EGL && if (view->surface->buffer_type == BUFFER_TYPE_EGL) {
view->surface->egl_front->buffer_ref.buffer == NULL) { struct weston_buffer *buffer;
weston_log("warning: client destroyed current front buffer\n"); buffer = view->surface->egl_front->buffer_ref.buffer;
if (buffer != NULL) {
wl_list_remove(&view->link); vc_dispmanx_set_wl_buffer_in_use(buffer->resource, 1);
if (view->handle == DISPMANX_NO_HANDLE) {
wl_list_init(&view->link);
} else { } else {
rpir_view_dmx_remove(view, output->update); weston_log("warning: client destroyed current front buffer\n");
wl_list_insert(&output->view_cleanup_list,
&view->link); wl_list_remove(&view->link);
if (view->handle == DISPMANX_NO_HANDLE) {
wl_list_init(&view->link);
} else {
rpir_view_dmx_remove(view, output->update);
wl_list_insert(&output->view_cleanup_list,
&view->link);
}
} }
} }
} }
@ -1695,11 +1707,7 @@ rpi_renderer_finish_frame(struct weston_output *base)
if (view->surface->buffer_type != BUFFER_TYPE_EGL) if (view->surface->buffer_type != BUFFER_TYPE_EGL)
continue; continue;
if (view->surface->egl_old_front == NULL) rpir_egl_buffer_destroy(view->surface->egl_old_front);
continue;
weston_buffer_reference(&view->surface->egl_old_front->buffer_ref, NULL);
free(view->surface->egl_old_front);
view->surface->egl_old_front = NULL; view->surface->egl_old_front = NULL;
} }