From b9e199b47da7045b86444f82933ba071e696acc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Molinari?= Date: Thu, 1 Aug 2024 10:02:11 +0200 Subject: [PATCH] libweston: Use explicit renderbuffer destruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renderbuffers currently have a libweston-internal base data structure with a ref-counting system to handle their lifetime. The problem is that renderers keep a ref to all renderbuffers in a list per output (to deal with damages) and that it prevents backends from releasing renderbuffer resources when not needed anymore. Renderbuffers are then only released (last ref removed) when the output is destroyed or resized. dma-buf renderbuffers even expose a dedicated function remove_renderbuffer_dmabuf() to explictly request the release of their resources. This commit proposes to get rid of the ref-counting system by exposing a single entry point to explicitly destroy all types of renderbuffers from the renderer. Instead of removing a renderbuffer from its output list and dropping its ref when the output is resized, this commit also introduces the concept of stale renderbuffers which consists in releasing the resources of a renderbuffer when it's discarded by the renderer while keeping it in the output list, with a stale state, until it's explicitly destroyed. Signed-off-by: Loïc Molinari --- libweston/backend-drm/drm-internal.h | 2 +- libweston/backend-drm/drm.c | 4 +- libweston/backend-headless/headless.c | 6 +- libweston/backend-pipewire/pipewire.c | 23 ++-- libweston/backend-rdp/rdp.c | 6 +- libweston/backend-rdp/rdp.h | 3 +- libweston/backend-vnc/vnc.c | 4 +- libweston/backend-wayland/wayland.c | 16 ++- libweston/backend-x11/x11.c | 4 +- libweston/compositor.c | 19 --- libweston/libweston-internal.h | 43 +++---- libweston/noop-renderer.c | 2 +- libweston/pixman-renderer.c | 99 +++++++++------- libweston/pixman-renderer.h | 20 ++-- libweston/renderer-gl/gl-renderer.c | 159 ++++++++++++-------------- libweston/renderer-gl/gl-renderer.h | 8 +- 16 files changed, 196 insertions(+), 222 deletions(-) diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index a1c725811..c66cfb62a 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -580,7 +580,7 @@ struct drm_output { struct drm_writeback_state *wb_state; struct drm_fb *dumb[2]; - struct weston_renderbuffer *renderbuffer[2]; + weston_renderbuffer_t renderbuffer[2]; int current_image; struct vaapi_recorder *recorder; diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index 3be250876..e524bf413 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -1642,7 +1642,7 @@ err: if (output->dumb[i]) drm_fb_unref(output->dumb[i]); if (output->renderbuffer[i]) - weston_renderbuffer_unref(output->renderbuffer[i]); + renderer->destroy_renderbuffer(output->renderbuffer[i]); output->dumb[i] = NULL; output->renderbuffer[i] = NULL; @@ -1668,7 +1668,7 @@ drm_output_fini_pixman(struct drm_output *output) } for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) { - weston_renderbuffer_unref(output->renderbuffer[i]); + renderer->destroy_renderbuffer(output->renderbuffer[i]); drm_fb_unref(output->dumb[i]); output->dumb[i] = NULL; output->renderbuffer[i] = NULL; diff --git a/libweston/backend-headless/headless.c b/libweston/backend-headless/headless.c index 9fe660417..99059e32e 100644 --- a/libweston/backend-headless/headless.c +++ b/libweston/backend-headless/headless.c @@ -81,7 +81,7 @@ struct headless_output { struct weston_mode mode; struct wl_event_source *finish_frame_timer; - struct weston_renderbuffer *renderbuffer; + weston_renderbuffer_t renderbuffer; struct frame *frame; struct { @@ -192,7 +192,7 @@ headless_output_disable_gl(struct headless_output *output) weston_gl_borders_fini(&output->gl.borders, &output->base); - weston_renderbuffer_unref(output->renderbuffer); + renderer->destroy_renderbuffer(output->renderbuffer); output->renderbuffer = NULL; renderer->gl->output_destroy(&output->base); @@ -207,7 +207,7 @@ headless_output_disable_pixman(struct headless_output *output) { struct weston_renderer *renderer = output->base.compositor->renderer; - weston_renderbuffer_unref(output->renderbuffer); + renderer->destroy_renderbuffer(output->renderbuffer); output->renderbuffer = NULL; renderer->pixman->output_destroy(&output->base); } diff --git a/libweston/backend-pipewire/pipewire.c b/libweston/backend-pipewire/pipewire.c index 56bf591ef..6014d42a8 100644 --- a/libweston/backend-pipewire/pipewire.c +++ b/libweston/backend-pipewire/pipewire.c @@ -101,7 +101,7 @@ struct pipewire_head { }; struct pipewire_frame_data { - struct weston_renderbuffer *renderbuffer; + weston_renderbuffer_t renderbuffer; struct pipewire_memfd *memfd; struct pipewire_dmabuf *dmabuf; }; @@ -593,7 +593,7 @@ pipewire_output_stream_param_changed(void *data, uint32_t id, pw_stream_update_params(output->stream, params, 2); } -static struct weston_renderbuffer * +static weston_renderbuffer_t pipewire_output_stream_add_buffer_pixman(struct pipewire_output *output, struct pw_buffer *buffer) { @@ -618,7 +618,7 @@ pipewire_output_stream_add_buffer_pixman(struct pipewire_output *output, ptr, stride); } -static struct weston_renderbuffer * +static weston_renderbuffer_t pipewire_output_stream_add_buffer_gl(struct pipewire_output *output, struct pw_buffer *buffer) { @@ -800,21 +800,20 @@ pipewire_output_stream_remove_buffer(void *data, struct pw_buffer *buffer) pipewire_output_debug(output, "remove buffer: %p", buffer); - if (frame_data->dmabuf) { - struct weston_compositor *ec = output->base.compositor; - const struct weston_renderer *renderer = ec->renderer; - - renderer->remove_renderbuffer_dmabuf(&output->base, - frame_data->renderbuffer); + if (frame_data->dmabuf) pipewire_destroy_dmabuf(output, frame_data->dmabuf); - } + if (frame_data->memfd) { munmap(d[0].data, d[0].maxsize); pipewire_destroy_memfd(output, frame_data->memfd); } - if (frame_data->renderbuffer) - weston_renderbuffer_unref(frame_data->renderbuffer); + if (frame_data->renderbuffer) { + struct weston_compositor *ec = output->base.compositor; + const struct weston_renderer *renderer = ec->renderer; + + renderer->destroy_renderbuffer(frame_data->renderbuffer); + } wl_list_for_each(fence_data, &output->fence_list, link) { if (fence_data->buffer == buffer) fence_data->buffer = NULL; diff --git a/libweston/backend-rdp/rdp.c b/libweston/backend-rdp/rdp.c index dddf987ff..b1c02f964 100644 --- a/libweston/backend-rdp/rdp.c +++ b/libweston/backend-rdp/rdp.c @@ -346,7 +346,7 @@ rdp_output_set_mode(struct weston_output *base, struct weston_mode *mode) struct weston_output *output = base; struct rdp_peers_item *rdpPeer; rdpSettings *settings; - struct weston_renderbuffer *new_renderbuffer; + weston_renderbuffer_t new_renderbuffer; mode->refresh = b->rdp_monitor_refresh_rate; weston_output_set_single_mode(base, mode); @@ -384,7 +384,7 @@ rdp_output_set_mode(struct weston_output *base, struct weston_mode *mode) default: unreachable("cannot have auto renderer at runtime"); } - weston_renderbuffer_unref(rdpOutput->renderbuffer); + renderer->destroy_renderbuffer(rdpOutput->renderbuffer); rdpOutput->renderbuffer = new_renderbuffer; pixman_image_unref(rdpOutput->shadow_surface); rdpOutput->shadow_surface = new_image; @@ -531,7 +531,7 @@ rdp_output_disable(struct weston_output *base) if (!output->base.enabled) return 0; - weston_renderbuffer_unref(output->renderbuffer); + renderer->destroy_renderbuffer(output->renderbuffer); output->renderbuffer = NULL; switch (renderer->type) { case WESTON_RENDERER_PIXMAN: diff --git a/libweston/backend-rdp/rdp.h b/libweston/backend-rdp/rdp.h index 541579fe5..6697cd60c 100644 --- a/libweston/backend-rdp/rdp.h +++ b/libweston/backend-rdp/rdp.h @@ -55,6 +55,7 @@ #include #include "backend.h" +#include "libweston-internal.h" #include "shared/helpers.h" #include "shared/string-helpers.h" @@ -149,7 +150,7 @@ struct rdp_output { struct weston_output base; struct rdp_backend *backend; struct wl_event_source *finish_frame_timer; - struct weston_renderbuffer *renderbuffer; + weston_renderbuffer_t renderbuffer; pixman_image_t *shadow_surface; }; diff --git a/libweston/backend-vnc/vnc.c b/libweston/backend-vnc/vnc.c index 5d950d68d..aa173ed87 100644 --- a/libweston/backend-vnc/vnc.c +++ b/libweston/backend-vnc/vnc.c @@ -674,7 +674,7 @@ vnc_update_buffer(struct nvnc_display *display, struct pixman_region32 *damage) struct vnc_backend *backend = nvnc_get_userdata(server); struct vnc_output *output = backend->output; struct weston_compositor *ec = output->base.compositor; - struct weston_renderbuffer *renderbuffer; + weston_renderbuffer_t renderbuffer; pixman_region32_t local_damage; pixman_region16_t nvnc_damage; struct nvnc_fb *fb; @@ -715,7 +715,7 @@ vnc_update_buffer(struct nvnc_display *display, struct pixman_region32 *damage) } nvnc_set_userdata(fb, renderbuffer, - (nvnc_cleanup_fn)weston_renderbuffer_unref); + (nvnc_cleanup_fn)ec->renderer->destroy_renderbuffer); } vnc_log_damage(backend, damage); diff --git a/libweston/backend-wayland/wayland.c b/libweston/backend-wayland/wayland.c index 509455058..1e1606b66 100644 --- a/libweston/backend-wayland/wayland.c +++ b/libweston/backend-wayland/wayland.c @@ -192,7 +192,7 @@ struct wayland_shm_buffer { int height; int frame_damaged; - struct weston_renderbuffer *renderbuffer; + weston_renderbuffer_t renderbuffer; cairo_surface_t *c_surface; }; @@ -266,9 +266,14 @@ to_wayland_backend(struct weston_backend *base) static void wayland_shm_buffer_destroy(struct wayland_shm_buffer *buffer) { + struct wayland_output *output = buffer->output; + const struct weston_renderer *renderer; + cairo_surface_destroy(buffer->c_surface); - if (buffer->output) - weston_renderbuffer_unref(buffer->renderbuffer); + if (output) { + renderer = output->base.compositor->renderer; + renderer->destroy_renderbuffer(buffer->renderbuffer); + } wl_buffer_destroy(buffer->buffer); munmap(buffer->data, buffer->size); @@ -657,15 +662,16 @@ wayland_backend_destroy_output_surface(struct wayland_output *output) static void wayland_output_destroy_shm_buffers(struct wayland_output *output) { + const struct weston_renderer *renderer = + output->base.compositor->renderer; struct wayland_shm_buffer *buffer, *next; /* Throw away any remaining SHM buffers */ wl_list_for_each_safe(buffer, next, &output->shm.free_buffers, free_link) wayland_shm_buffer_destroy(buffer); - /* These will get thrown away when they get released */ wl_list_for_each(buffer, &output->shm.buffers, link) { if (buffer->renderbuffer) { - weston_renderbuffer_unref(buffer->renderbuffer); + renderer->destroy_renderbuffer(buffer->renderbuffer); buffer->renderbuffer = NULL; } buffer->output = NULL; diff --git a/libweston/backend-x11/x11.c b/libweston/backend-x11/x11.c index 8c87d9ede..7c641238d 100644 --- a/libweston/backend-x11/x11.c +++ b/libweston/backend-x11/x11.c @@ -140,7 +140,7 @@ struct x11_output { xcb_gc_t gc; xcb_shm_seg_t segment; - struct weston_renderbuffer *renderbuffer; + weston_renderbuffer_t renderbuffer; int shm_id; void *buf; uint8_t depth; @@ -568,7 +568,7 @@ x11_output_deinit_shm(struct x11_backend *b, struct x11_output *output) xcb_generic_error_t *err; xcb_free_gc(b->conn, output->gc); - weston_renderbuffer_unref(output->renderbuffer); + b->compositor->renderer->destroy_renderbuffer(output->renderbuffer); output->renderbuffer = NULL; cookie = xcb_shm_detach_checked(b->conn, output->segment); err = xcb_request_check(b->conn, cookie); diff --git a/libweston/compositor.c b/libweston/compositor.c index 95f8d4dfd..1d57a9898 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -10414,25 +10414,6 @@ weston_output_disable_planes_decr(struct weston_output *output) } -WL_EXPORT struct weston_renderbuffer * -weston_renderbuffer_ref(struct weston_renderbuffer *renderbuffer) -{ - renderbuffer->refcount++; - - return renderbuffer; -} - -WL_EXPORT void -weston_renderbuffer_unref(struct weston_renderbuffer *renderbuffer) -{ - assert(renderbuffer->refcount > 0); - - if (--renderbuffer->refcount > 0) - return; - - renderbuffer->destroy(renderbuffer); -} - /** Tell the renderer that the target framebuffer size has changed * * \param output The output that was resized. diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h index 1c7218d68..bb5fd8c22 100644 --- a/libweston/libweston-internal.h +++ b/libweston/libweston-internal.h @@ -46,17 +46,9 @@ /* compositor <-> renderer interface */ -struct weston_renderbuffer { - int refcount; - - void (*destroy)(struct weston_renderbuffer *renderbuffer); -}; - -struct weston_renderbuffer * -weston_renderbuffer_ref(struct weston_renderbuffer *renderbuffer); - -void -weston_renderbuffer_unref(struct weston_renderbuffer *renderbuffer); +/** Opaque pointer to renderbuffer data. + */ +typedef void *weston_renderbuffer_t; struct weston_renderer_options { }; @@ -74,7 +66,7 @@ struct weston_renderer { uint32_t width, uint32_t height); void (*repaint_output)(struct weston_output *output, pixman_region32_t *output_damage, - struct weston_renderbuffer *renderbuffer); + weston_renderbuffer_t renderbuffer); /** See weston_renderer_resize_output() * @@ -112,34 +104,27 @@ struct weston_renderer { * * \param output The output to add the DMABUF renderbuffer for. * \param dmabuf The description object of the DMABUF to import. - * \return A weston_renderbuffer on success, NULL on failure. + * \return A renderbuffer on success, NULL on failure. * - * This function imports the DMABUF memory as renderbuffer and adds - * it to the output. The returned weston_renderbuffer can be passed to + * This function imports the DMABUF memory as renderbuffer and adds it + * to the output. The returned renderbuffer can be passed to * repaint_output() to render into the DMABUF. * * The ownership of the linux_dmabuf_memory is transferred to the - * returned weston_renderbuffer. The linux_dmabuf_memory will be - * destroyed automatically when the weston_renderbuffer is destroyed. + * returned renderbuffer. The linux_dmabuf_memory will be destroyed + * automatically when the renderbuffer is destroyed. */ - struct weston_renderbuffer * + weston_renderbuffer_t (*create_renderbuffer_dmabuf)(struct weston_output *output, struct linux_dmabuf_memory *dmabuf); - /** - * Remove the DAMBUF renderbuffer from the output + /** Destroy a renderbuffer * - * \param output The output to remove a DMABUF renderbuffer from. - * \param renderbuffer The weston_renderbuffer that shall be removed + * \param renderbuffer The renderbuffer to destroy. * - * This function removes the DMABUF renderbuffer from the output. - * - * This allows the backend to signal the renderer that it will no longer - * use the renderbuffer for rendering and the renderer may free the - * resources of the renderbuffer. + * This function destroys a \c renderbuffer. */ - void (*remove_renderbuffer_dmabuf)(struct weston_output *output, - struct weston_renderbuffer *renderbuffer); + void (*destroy_renderbuffer)(weston_renderbuffer_t renderbuffer); /* Allocate a DMABUF that can be imported as renderbuffer * diff --git a/libweston/noop-renderer.c b/libweston/noop-renderer.c index 58d0b6681..47255e21f 100644 --- a/libweston/noop-renderer.c +++ b/libweston/noop-renderer.c @@ -48,7 +48,7 @@ noop_renderer_read_pixels(struct weston_output *output, static void noop_renderer_repaint_output(struct weston_output *output, pixman_region32_t *output_damage, - struct weston_renderbuffer *renderbuffer) + weston_renderbuffer_t renderbuffer) { } diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c index 74552574d..c5b54fb2d 100644 --- a/libweston/pixman-renderer.c +++ b/libweston/pixman-renderer.c @@ -64,10 +64,9 @@ struct pixman_surface_state { }; struct pixman_renderbuffer { - struct weston_renderbuffer base; - pixman_region32_t damage; pixman_image_t *image; + bool stale; struct wl_list link; }; @@ -81,16 +80,11 @@ struct pixman_renderer { struct wl_signal destroy_signal; }; -static inline struct pixman_renderbuffer * -to_pixman_renderbuffer(struct weston_renderbuffer *renderbuffer) -{ - return container_of(renderbuffer, struct pixman_renderbuffer, base); -} - static pixman_image_t * -pixman_renderer_renderbuffer_get_image(struct weston_renderbuffer *renderbuffer) +pixman_renderer_renderbuffer_get_image(weston_renderbuffer_t renderbuffer) { - struct pixman_renderbuffer *rb = to_pixman_renderbuffer(renderbuffer); + struct pixman_renderbuffer *rb = + (struct pixman_renderbuffer *) renderbuffer; return rb->image; } @@ -645,7 +639,7 @@ pixman_renderer_output_set_buffer(struct weston_output *output, static void pixman_renderer_repaint_output(struct weston_output *output, pixman_region32_t *output_damage, - struct weston_renderbuffer *renderbuffer) + weston_renderbuffer_t renderbuffer) { struct pixman_output_state *po = get_output_state(output); struct pixman_renderbuffer *rb; @@ -657,7 +651,7 @@ pixman_renderer_repaint_output(struct weston_output *output, pixman_region32_union(&rb->damage, &rb->damage, output_damage); } - rb = to_pixman_renderbuffer(renderbuffer); + rb = (struct pixman_renderbuffer *) renderbuffer; pixman_renderer_output_set_buffer(output, rb->image); @@ -921,13 +915,54 @@ pixman_renderer_surface_copy_content(struct weston_surface *surface, return 0; } +static void +pixman_renderbuffer_fini(struct pixman_renderbuffer *renderbuffer) +{ + assert(!renderbuffer->stale); + + pixman_region32_fini(&renderbuffer->damage); + pixman_image_unref(renderbuffer->image); + + renderbuffer->stale = true; +} + +static void +pixman_renderer_destroy_renderbuffer(weston_renderbuffer_t renderbuffer) +{ + struct pixman_renderbuffer *rb = + (struct pixman_renderbuffer *) renderbuffer; + + wl_list_remove(&rb->link); + + if (!rb->stale) + pixman_renderbuffer_fini(rb); + + free(rb); +} + +static void +pixman_renderer_discard_renderbuffers(struct pixman_output_state *po, + bool destroy) +{ + struct pixman_renderbuffer *rb, *tmp; + + /* A renderbuffer goes stale after being discarded. Most resources are + * released. It's kept in the output state's renderbuffer list while + * waiting for the backend to destroy it. */ + wl_list_for_each_safe(rb, tmp, &po->renderbuffer_list, link) { + if (destroy) + pixman_renderer_destroy_renderbuffer((weston_renderbuffer_t) rb); + else if (!rb->stale) + pixman_renderbuffer_fini(rb); + } +} + static bool pixman_renderer_resize_output(struct weston_output *output, const struct weston_size *fb_size, const struct weston_geometry *area) { struct pixman_output_state *po = get_output_state(output); - struct pixman_renderbuffer *renderbuffer, *tmp; check_compositing_area(fb_size, area); @@ -942,10 +977,7 @@ pixman_renderer_resize_output(struct weston_output *output, pixman_renderer_output_set_buffer(output, NULL); - wl_list_for_each_safe(renderbuffer, tmp, &po->renderbuffer_list, link) { - wl_list_remove(&renderbuffer->link); - weston_renderbuffer_unref(&renderbuffer->base); - } + pixman_renderer_discard_renderbuffers(po, false); po->fb_size = *fb_size; @@ -1025,6 +1057,8 @@ pixman_renderer_init(struct weston_compositor *ec) renderer->base.destroy = pixman_renderer_destroy; renderer->base.surface_copy_content = pixman_renderer_surface_copy_content; + renderer->base.destroy_renderbuffer = + pixman_renderer_destroy_renderbuffer; renderer->base.type = WESTON_RENDERER_PIXMAN; renderer->base.pixman = &pixman_renderer_interface; ec->renderer = &renderer->base; @@ -1133,7 +1167,6 @@ static void pixman_renderer_output_destroy(struct weston_output *output) { struct pixman_output_state *po = get_output_state(output); - struct pixman_renderbuffer *renderbuffer, *tmp; if (po->shadow_image) pixman_image_unref(po->shadow_image); @@ -1144,18 +1177,12 @@ pixman_renderer_output_destroy(struct weston_output *output) po->shadow_image = NULL; po->hw_buffer = NULL; - wl_list_for_each_safe(renderbuffer, tmp, &po->renderbuffer_list, link) { - wl_list_remove(&renderbuffer->link); - weston_renderbuffer_unref(&renderbuffer->base); - } + pixman_renderer_discard_renderbuffers(po, true); free(po); } -static void -pixman_renderer_renderbuffer_destroy(struct weston_renderbuffer *renderbuffer); - -static struct weston_renderbuffer * +static weston_renderbuffer_t pixman_renderer_create_image_from_ptr(struct weston_output *output, const struct pixel_format_info *format, int width, int height, uint32_t *ptr, @@ -1178,14 +1205,12 @@ pixman_renderer_create_image_from_ptr(struct weston_output *output, pixman_region32_init(&renderbuffer->damage); pixman_region32_copy(&renderbuffer->damage, &output->region); - renderbuffer->base.refcount = 2; - renderbuffer->base.destroy = pixman_renderer_renderbuffer_destroy; wl_list_insert(&po->renderbuffer_list, &renderbuffer->link); - return &renderbuffer->base; + return (weston_renderbuffer_t) renderbuffer; } -static struct weston_renderbuffer * +static weston_renderbuffer_t pixman_renderer_create_image(struct weston_output *output, const struct pixel_format_info *format, int width, int height) @@ -1207,21 +1232,9 @@ pixman_renderer_create_image(struct weston_output *output, pixman_region32_init(&renderbuffer->damage); pixman_region32_copy(&renderbuffer->damage, &output->region); - renderbuffer->base.refcount = 2; - renderbuffer->base.destroy = pixman_renderer_renderbuffer_destroy; wl_list_insert(&po->renderbuffer_list, &renderbuffer->link); - return &renderbuffer->base; -} - -static void -pixman_renderer_renderbuffer_destroy(struct weston_renderbuffer *renderbuffer) -{ - struct pixman_renderbuffer *rb = to_pixman_renderbuffer(renderbuffer); - - pixman_image_unref(rb->image); - pixman_region32_fini(&rb->damage); - free(rb); + return (weston_renderbuffer_t) renderbuffer; } static struct pixman_renderer_interface pixman_renderer_interface = { diff --git a/libweston/pixman-renderer.h b/libweston/pixman-renderer.h index e508ef87e..3c8587238 100644 --- a/libweston/pixman-renderer.h +++ b/libweston/pixman-renderer.h @@ -47,14 +47,14 @@ struct pixman_renderer_interface { const struct pixman_renderer_output_options *options); void (*output_destroy)(struct weston_output *output); - struct weston_renderbuffer *(*create_image_from_ptr)(struct weston_output *output, - const struct pixel_format_info *format, - int width, - int height, - uint32_t *ptr, - int stride); - struct weston_renderbuffer *(*create_image)(struct weston_output *output, - const struct pixel_format_info *format, - int width, int height); - pixman_image_t *(*renderbuffer_get_image)(struct weston_renderbuffer *renderbuffer); + weston_renderbuffer_t (*create_image_from_ptr)(struct weston_output *output, + const struct pixel_format_info *format, + int width, + int height, + uint32_t *ptr, + int stride); + weston_renderbuffer_t (*create_image)(struct weston_output *output, + const struct pixel_format_info *format, + int width, int height); + pixman_image_t *(*renderbuffer_get_image)(weston_renderbuffer_t renderbuffer); }; diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index e0c85ee67..5d807f0e5 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -90,6 +90,12 @@ enum gl_border_status { BORDER_SIZE_CHANGED = 0x10 }; +enum gl_renderbuffer_type { + RENDERBUFFER_DUMMY = 0, + RENDERBUFFER_FBO, + RENDERBUFFER_DMABUF, +}; + struct gl_border_image { GLuint tex; int32_t width, height; @@ -103,9 +109,10 @@ struct gl_fbo_texture { }; struct gl_renderbuffer { - struct weston_renderbuffer base; + enum gl_renderbuffer_type type; pixman_region32_t damage; enum gl_border_status border_damage; + bool stale; /* The fbo value zero represents the default surface framebuffer. */ GLuint fbo; GLuint rb; @@ -677,12 +684,6 @@ gl_fbo_texture_fini(struct gl_fbo_texture *fbotex) fbotex->tex = 0; } -static inline struct gl_renderbuffer * -to_gl_renderbuffer(struct weston_renderbuffer *renderbuffer) -{ - return container_of(renderbuffer, struct gl_renderbuffer, base); -} - static inline struct dmabuf_renderbuffer * to_dmabuf_renderbuffer(struct gl_renderbuffer *renderbuffer) { @@ -690,14 +691,61 @@ to_dmabuf_renderbuffer(struct gl_renderbuffer *renderbuffer) } static void -gl_renderer_renderbuffer_destroy(struct weston_renderbuffer *renderbuffer) +gl_renderbuffer_fini(struct gl_renderbuffer *renderbuffer) { - struct gl_renderbuffer *rb = to_gl_renderbuffer(renderbuffer); + struct dmabuf_renderbuffer *dmabuf_rb; - glDeleteFramebuffers(1, &rb->fbo); - glDeleteRenderbuffers(1, &rb->rb); - pixman_region32_fini(&rb->damage); - free(rb); + assert(!renderbuffer->stale); + + pixman_region32_fini(&renderbuffer->damage); + glDeleteFramebuffers(1, &renderbuffer->fbo); + glDeleteRenderbuffers(1, &renderbuffer->rb); + + if (renderbuffer->type == RENDERBUFFER_DMABUF) { + dmabuf_rb = to_dmabuf_renderbuffer(renderbuffer); + dmabuf_rb->gr->destroy_image(dmabuf_rb->gr->egl_display, + dmabuf_rb->image); + } + + renderbuffer->stale = true; +} + +static void +gl_renderer_destroy_renderbuffer(weston_renderbuffer_t weston_renderbuffer) +{ + struct gl_renderbuffer *rb = + (struct gl_renderbuffer *) weston_renderbuffer; + struct dmabuf_renderbuffer *dmabuf_rb; + + wl_list_remove(&rb->link); + + if (!rb->stale) + gl_renderbuffer_fini(rb); + + if (rb->type == RENDERBUFFER_DMABUF) { + dmabuf_rb = to_dmabuf_renderbuffer(rb); + dmabuf_rb->dmabuf->destroy(dmabuf_rb->dmabuf); + free(dmabuf_rb); + } else { + free(rb); + } +} + +static void +gl_renderer_discard_renderbuffers(struct gl_output_state *go, + bool destroy) +{ + struct gl_renderbuffer *rb, *tmp; + + /* A renderbuffer goes stale after being discarded. Most resources are + * released. It's kept in the output states' renderbuffer list waiting + * for the backend to destroy it. */ + wl_list_for_each_safe(rb, tmp, &go->renderbuffer_list, link) { + if ((rb->type == RENDERBUFFER_DUMMY) || destroy) + gl_renderer_destroy_renderbuffer((weston_renderbuffer_t) rb); + else if (!rb->stale) + gl_renderbuffer_fini(rb); + } } static struct gl_renderbuffer * @@ -708,23 +756,18 @@ gl_renderer_create_dummy_renderbuffer(struct weston_output *output) renderbuffer = xzalloc(sizeof(*renderbuffer)); + renderbuffer->type = RENDERBUFFER_DUMMY; renderbuffer->fbo = 0; pixman_region32_init(&renderbuffer->damage); pixman_region32_copy(&renderbuffer->damage, &output->region); renderbuffer->border_damage = BORDER_ALL_DIRTY; - /* - * A single reference is kept on the renderbuffer_list, - * the caller just borrows it. - */ - renderbuffer->base.refcount = 1; - renderbuffer->base.destroy = gl_renderer_renderbuffer_destroy; wl_list_insert(&go->renderbuffer_list, &renderbuffer->link); return renderbuffer; } -static struct weston_renderbuffer * +static weston_renderbuffer_t gl_renderer_create_fbo(struct weston_output *output, const struct pixel_format_info *format, int width, int height, uint32_t *pixels) @@ -775,18 +818,13 @@ gl_renderer_create_fbo(struct weston_output *output, } renderbuffer->pixels = pixels; + renderbuffer->type = RENDERBUFFER_FBO; pixman_region32_init(&renderbuffer->damage); pixman_region32_copy(&renderbuffer->damage, &output->region); - /* - * One reference is kept on the renderbuffer_list, - * the other is returned to the calling backend. - */ - renderbuffer->base.refcount = 2; - renderbuffer->base.destroy = gl_renderer_renderbuffer_destroy; wl_list_insert(&go->renderbuffer_list, &renderbuffer->link); - return &renderbuffer->base; + return (weston_renderbuffer_t) renderbuffer; } static bool @@ -2337,7 +2375,7 @@ blit_shadow_to_output(struct weston_output *output, static void gl_renderer_repaint_output(struct weston_output *output, pixman_region32_t *output_damage, - struct weston_renderbuffer *renderbuffer) + weston_renderbuffer_t renderbuffer) { struct gl_output_state *go = get_output_state(output); struct weston_compositor *compositor = output->compositor; @@ -2362,7 +2400,7 @@ gl_renderer_repaint_output(struct weston_output *output, } if (renderbuffer) - rb = to_gl_renderbuffer(renderbuffer); + rb = (struct gl_renderbuffer *) renderbuffer; else rb = output_get_dummy_renderbuffer(output); @@ -4020,22 +4058,6 @@ gl_renderer_output_set_border(struct weston_output *output, go->border_status |= 1 << side; } -static void -gl_renderer_remove_renderbuffer(struct gl_renderbuffer *renderbuffer) -{ - wl_list_remove(&renderbuffer->link); - weston_renderbuffer_unref(&renderbuffer->base); -} - -static void -gl_renderer_remove_renderbuffers(struct gl_output_state *go) -{ - struct gl_renderbuffer *renderbuffer, *tmp; - - wl_list_for_each_safe(renderbuffer, tmp, &go->renderbuffer_list, link) - gl_renderer_remove_renderbuffer(renderbuffer); -} - static bool gl_renderer_resize_output(struct weston_output *output, const struct weston_size *fb_size, @@ -4048,7 +4070,7 @@ gl_renderer_resize_output(struct weston_output *output, check_compositing_area(fb_size, area); - gl_renderer_remove_renderbuffers(go); + gl_renderer_discard_renderbuffers(go, false); go->fb_size = *fb_size; go->area = *area; @@ -4199,26 +4221,7 @@ gl_renderer_output_fbo_create(struct weston_output *output, &options->fb_size, &options->area); } -static void -gl_renderer_dmabuf_renderbuffer_destroy(struct weston_renderbuffer *renderbuffer) -{ - struct gl_renderbuffer *gl_renderbuffer = to_gl_renderbuffer(renderbuffer); - struct dmabuf_renderbuffer *dmabuf_renderbuffer = to_dmabuf_renderbuffer(gl_renderbuffer); - struct gl_renderer *gr = dmabuf_renderbuffer->gr; - - glDeleteFramebuffers(1, &gl_renderbuffer->fbo); - glDeleteRenderbuffers(1, &gl_renderbuffer->rb); - pixman_region32_fini(&gl_renderbuffer->damage); - - gr->destroy_image(gr->egl_display, dmabuf_renderbuffer->image); - - /* Destroy the owned dmabuf */ - dmabuf_renderbuffer->dmabuf->destroy(dmabuf_renderbuffer->dmabuf); - - free(dmabuf_renderbuffer); -} - -static struct weston_renderbuffer * +static weston_renderbuffer_t gl_renderer_create_renderbuffer_dmabuf(struct weston_output *output, struct linux_dmabuf_memory *dmabuf) { @@ -4272,26 +4275,12 @@ gl_renderer_create_renderbuffer_dmabuf(struct weston_output *output, rb->gr = gr; rb->dmabuf = dmabuf; + renderbuffer->type = RENDERBUFFER_DMABUF; pixman_region32_init(&renderbuffer->damage); pixman_region32_copy(&renderbuffer->damage, &output->region); - /* - * One reference is kept on the renderbuffer_list, - * the other is returned to the calling backend. - */ - rb->base.base.refcount = 2; - rb->base.base.destroy = gl_renderer_dmabuf_renderbuffer_destroy; - wl_list_insert(&go->renderbuffer_list, &rb->base.link); + wl_list_insert(&go->renderbuffer_list, &renderbuffer->link); - return &rb->base.base; -} - -static void -gl_renderer_remove_renderbuffer_dmabuf(struct weston_output *output, - struct weston_renderbuffer *renderbuffer) -{ - struct gl_renderbuffer *gl_renderbuffer = to_gl_renderbuffer(renderbuffer); - - gl_renderer_remove_renderbuffer(gl_renderbuffer); + return (weston_renderbuffer_t) rb; } #ifdef HAVE_GBM @@ -4403,7 +4392,7 @@ gl_renderer_output_destroy(struct weston_output *output) if (go->render_sync != EGL_NO_SYNC_KHR) gr->destroy_sync(gr->egl_display, go->render_sync); - gl_renderer_remove_renderbuffers(go); + gl_renderer_discard_renderbuffers(go, true); free(go); } @@ -4581,6 +4570,7 @@ gl_renderer_display_create(struct weston_compositor *ec, gr->base.read_pixels = gl_renderer_read_pixels; gr->base.repaint_output = gl_renderer_repaint_output; gr->base.resize_output = gl_renderer_resize_output; + gr->base.destroy_renderbuffer = gl_renderer_destroy_renderbuffer; gr->base.flush_damage = gl_renderer_flush_damage; gr->base.attach = gl_renderer_attach; gr->base.destroy = gl_renderer_destroy; @@ -4649,7 +4639,6 @@ gl_renderer_display_create(struct weston_compositor *ec, gr->base.import_dmabuf = gl_renderer_import_dmabuf; gr->base.get_supported_formats = gl_renderer_get_supported_formats; gr->base.create_renderbuffer_dmabuf = gl_renderer_create_renderbuffer_dmabuf; - gr->base.remove_renderbuffer_dmabuf = gl_renderer_remove_renderbuffer_dmabuf; ret = populate_supported_formats(ec, &gr->supported_formats); if (ret < 0) goto fail_terminate; diff --git a/libweston/renderer-gl/gl-renderer.h b/libweston/renderer-gl/gl-renderer.h index 6fc7f6f03..679277d5b 100644 --- a/libweston/renderer-gl/gl-renderer.h +++ b/libweston/renderer-gl/gl-renderer.h @@ -230,8 +230,8 @@ struct gl_renderer_interface { * glReadPixels to download pixel data into the provided buffer after * repaint. */ - struct weston_renderbuffer *(*create_fbo)(struct weston_output *output, - const struct pixel_format_info *format, - int width, int height, - uint32_t *pixels); + weston_renderbuffer_t (*create_fbo)(struct weston_output *output, + const struct pixel_format_info *format, + int width, int height, + uint32_t *pixels); };