mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-04-28 20:27:58 +03:00
wayland_server: implement wl_buffer destroy listener
Fixes a segfault, where a wl_buffer was destroyed while in use. Also it allows us to replace the custom caching mechanism and instead find existing buffers by their destroy listener.
This commit is contained in:
parent
09176cade8
commit
fd541bec75
1 changed files with 28 additions and 27 deletions
|
@ -31,6 +31,7 @@ struct _BufferData {
|
||||||
gboolean destroyed;
|
gboolean destroyed;
|
||||||
SurfaceViewWidget *surface_view_widget;
|
SurfaceViewWidget *surface_view_widget;
|
||||||
struct wl_resource *wl_buffer;
|
struct wl_resource *wl_buffer;
|
||||||
|
struct wl_listener buffer_destroy_listener;
|
||||||
GdkGLTextureBuilder *texture_builder;
|
GdkGLTextureBuilder *texture_builder;
|
||||||
};
|
};
|
||||||
G_DECLARE_FINAL_TYPE(BufferData, buffer_data, ATL, BUFFER_DATA, GObject);
|
G_DECLARE_FINAL_TYPE(BufferData, buffer_data, ATL, BUFFER_DATA, GObject);
|
||||||
|
@ -56,7 +57,7 @@ struct surface {
|
||||||
SurfaceViewWidget *surface_view_widget;
|
SurfaceViewWidget *surface_view_widget;
|
||||||
struct wl_resource *frame_callback;
|
struct wl_resource *frame_callback;
|
||||||
struct wl_event_source *frame_timer;
|
struct wl_event_source *frame_timer;
|
||||||
BufferData *buffers[3];
|
BufferData *attached_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* runs on main thread */
|
/* runs on main thread */
|
||||||
|
@ -124,30 +125,30 @@ static gboolean render_texture(void *data)
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void buffer_destroy_listener(struct wl_listener *listener, void *data) {
|
||||||
|
BufferData *buffer = wl_container_of(listener, buffer, buffer_destroy_listener);
|
||||||
|
buffer->destroyed = TRUE;
|
||||||
|
g_object_unref(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
static void surface_attach(struct wl_client *client, struct wl_resource *resource, struct wl_resource *wl_buffer, int32_t x, int32_t y)
|
static void surface_attach(struct wl_client *client, struct wl_resource *resource, struct wl_resource *wl_buffer, int32_t x, int32_t y)
|
||||||
{
|
{
|
||||||
struct surface *surface = wl_resource_get_user_data(resource);
|
struct surface *surface = wl_resource_get_user_data(resource);
|
||||||
// Order buffer cache by least recently used.
|
if (surface->attached_buffer)
|
||||||
BufferData *buffer = surface->buffers[0];
|
g_object_unref(surface->attached_buffer);
|
||||||
if (buffer && buffer->wl_buffer == wl_buffer)
|
// check if we already have this buffer
|
||||||
return;
|
struct wl_listener *listener = wl_resource_get_destroy_listener(wl_buffer, buffer_destroy_listener);
|
||||||
buffer = surface->buffers[1];
|
BufferData *buffer;
|
||||||
surface->buffers[1] = surface->buffers[0];
|
if (listener) {
|
||||||
surface->buffers[0] = buffer;
|
buffer = wl_container_of(listener, buffer, buffer_destroy_listener);
|
||||||
if (buffer && buffer->wl_buffer == wl_buffer)
|
} else {
|
||||||
return;
|
buffer = g_object_new(buffer_data_get_type(), NULL);
|
||||||
buffer = surface->buffers[2];
|
buffer->wl_buffer = wl_buffer;
|
||||||
surface->buffers[2] = surface->buffers[0];
|
buffer->surface_view_widget = g_object_ref(surface->surface_view_widget);
|
||||||
surface->buffers[0] = buffer;
|
buffer->buffer_destroy_listener.notify = buffer_destroy_listener;
|
||||||
if (buffer && buffer->wl_buffer == wl_buffer)
|
wl_resource_add_destroy_listener(wl_buffer, &buffer->buffer_destroy_listener);
|
||||||
return;
|
}
|
||||||
// If the buffer is not in the cache, create it and drop the oldest one.
|
surface->attached_buffer = g_object_ref(buffer);
|
||||||
if (buffer)
|
|
||||||
g_object_unref(buffer);
|
|
||||||
buffer = g_object_new(buffer_data_get_type(), NULL);
|
|
||||||
buffer->wl_buffer = wl_buffer;
|
|
||||||
buffer->surface_view_widget = g_object_ref(surface->surface_view_widget);
|
|
||||||
surface->buffers[0] = buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback)
|
static void surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback)
|
||||||
|
@ -180,14 +181,14 @@ static int frame_timer(void *data)
|
||||||
static void surface_commit(struct wl_client *client, struct wl_resource *resource)
|
static void surface_commit(struct wl_client *client, struct wl_resource *resource)
|
||||||
{
|
{
|
||||||
struct surface *surface = wl_resource_get_user_data(resource);
|
struct surface *surface = wl_resource_get_user_data(resource);
|
||||||
g_idle_add(render_texture, g_object_ref(surface->buffers[0]));
|
g_idle_add(render_texture, g_object_ref(surface->attached_buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void surface_destroy(struct wl_client *client, struct wl_resource *resource) {
|
static void surface_destroy(struct wl_client *client, struct wl_resource *resource)
|
||||||
|
{
|
||||||
struct surface *surface = wl_resource_get_user_data(resource);
|
struct surface *surface = wl_resource_get_user_data(resource);
|
||||||
for (int i = 0; i < 3; i++) if (surface->buffers[i]) {
|
if (surface->attached_buffer) {
|
||||||
surface->buffers[i]->destroyed = TRUE;
|
g_object_unref(surface->attached_buffer);
|
||||||
g_object_unref(surface->buffers[i]);
|
|
||||||
}
|
}
|
||||||
surface->surface_view_widget->frame_callback = NULL;
|
surface->surface_view_widget->frame_callback = NULL;
|
||||||
surface->surface_view_widget->frame_callback_data = NULL;
|
surface->surface_view_widget->frame_callback_data = NULL;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue