libweston: Use explicit renderbuffer destruction

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 <loic.molinari@collabora.com>
This commit is contained in:
Loïc Molinari 2024-08-01 10:02:11 +02:00
parent 1619a4a1e5
commit b9e199b47d
16 changed files with 196 additions and 222 deletions

View file

@ -580,7 +580,7 @@ struct drm_output {
struct drm_writeback_state *wb_state; struct drm_writeback_state *wb_state;
struct drm_fb *dumb[2]; struct drm_fb *dumb[2];
struct weston_renderbuffer *renderbuffer[2]; weston_renderbuffer_t renderbuffer[2];
int current_image; int current_image;
struct vaapi_recorder *recorder; struct vaapi_recorder *recorder;

View file

@ -1642,7 +1642,7 @@ err:
if (output->dumb[i]) if (output->dumb[i])
drm_fb_unref(output->dumb[i]); drm_fb_unref(output->dumb[i]);
if (output->renderbuffer[i]) if (output->renderbuffer[i])
weston_renderbuffer_unref(output->renderbuffer[i]); renderer->destroy_renderbuffer(output->renderbuffer[i]);
output->dumb[i] = NULL; output->dumb[i] = NULL;
output->renderbuffer[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++) { 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]); drm_fb_unref(output->dumb[i]);
output->dumb[i] = NULL; output->dumb[i] = NULL;
output->renderbuffer[i] = NULL; output->renderbuffer[i] = NULL;

View file

@ -81,7 +81,7 @@ struct headless_output {
struct weston_mode mode; struct weston_mode mode;
struct wl_event_source *finish_frame_timer; struct wl_event_source *finish_frame_timer;
struct weston_renderbuffer *renderbuffer; weston_renderbuffer_t renderbuffer;
struct frame *frame; struct frame *frame;
struct { struct {
@ -192,7 +192,7 @@ headless_output_disable_gl(struct headless_output *output)
weston_gl_borders_fini(&output->gl.borders, &output->base); weston_gl_borders_fini(&output->gl.borders, &output->base);
weston_renderbuffer_unref(output->renderbuffer); renderer->destroy_renderbuffer(output->renderbuffer);
output->renderbuffer = NULL; output->renderbuffer = NULL;
renderer->gl->output_destroy(&output->base); 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; struct weston_renderer *renderer = output->base.compositor->renderer;
weston_renderbuffer_unref(output->renderbuffer); renderer->destroy_renderbuffer(output->renderbuffer);
output->renderbuffer = NULL; output->renderbuffer = NULL;
renderer->pixman->output_destroy(&output->base); renderer->pixman->output_destroy(&output->base);
} }

View file

@ -101,7 +101,7 @@ struct pipewire_head {
}; };
struct pipewire_frame_data { struct pipewire_frame_data {
struct weston_renderbuffer *renderbuffer; weston_renderbuffer_t renderbuffer;
struct pipewire_memfd *memfd; struct pipewire_memfd *memfd;
struct pipewire_dmabuf *dmabuf; 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); 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, pipewire_output_stream_add_buffer_pixman(struct pipewire_output *output,
struct pw_buffer *buffer) struct pw_buffer *buffer)
{ {
@ -618,7 +618,7 @@ pipewire_output_stream_add_buffer_pixman(struct pipewire_output *output,
ptr, stride); ptr, stride);
} }
static struct weston_renderbuffer * static weston_renderbuffer_t
pipewire_output_stream_add_buffer_gl(struct pipewire_output *output, pipewire_output_stream_add_buffer_gl(struct pipewire_output *output,
struct pw_buffer *buffer) 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); pipewire_output_debug(output, "remove buffer: %p", buffer);
if (frame_data->dmabuf) { 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);
pipewire_destroy_dmabuf(output, frame_data->dmabuf); pipewire_destroy_dmabuf(output, frame_data->dmabuf);
}
if (frame_data->memfd) { if (frame_data->memfd) {
munmap(d[0].data, d[0].maxsize); munmap(d[0].data, d[0].maxsize);
pipewire_destroy_memfd(output, frame_data->memfd); pipewire_destroy_memfd(output, frame_data->memfd);
} }
if (frame_data->renderbuffer) if (frame_data->renderbuffer) {
weston_renderbuffer_unref(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) { wl_list_for_each(fence_data, &output->fence_list, link) {
if (fence_data->buffer == buffer) if (fence_data->buffer == buffer)
fence_data->buffer = NULL; fence_data->buffer = NULL;

View file

@ -346,7 +346,7 @@ rdp_output_set_mode(struct weston_output *base, struct weston_mode *mode)
struct weston_output *output = base; struct weston_output *output = base;
struct rdp_peers_item *rdpPeer; struct rdp_peers_item *rdpPeer;
rdpSettings *settings; rdpSettings *settings;
struct weston_renderbuffer *new_renderbuffer; weston_renderbuffer_t new_renderbuffer;
mode->refresh = b->rdp_monitor_refresh_rate; mode->refresh = b->rdp_monitor_refresh_rate;
weston_output_set_single_mode(base, mode); weston_output_set_single_mode(base, mode);
@ -384,7 +384,7 @@ rdp_output_set_mode(struct weston_output *base, struct weston_mode *mode)
default: default:
unreachable("cannot have auto renderer at runtime"); unreachable("cannot have auto renderer at runtime");
} }
weston_renderbuffer_unref(rdpOutput->renderbuffer); renderer->destroy_renderbuffer(rdpOutput->renderbuffer);
rdpOutput->renderbuffer = new_renderbuffer; rdpOutput->renderbuffer = new_renderbuffer;
pixman_image_unref(rdpOutput->shadow_surface); pixman_image_unref(rdpOutput->shadow_surface);
rdpOutput->shadow_surface = new_image; rdpOutput->shadow_surface = new_image;
@ -531,7 +531,7 @@ rdp_output_disable(struct weston_output *base)
if (!output->base.enabled) if (!output->base.enabled)
return 0; return 0;
weston_renderbuffer_unref(output->renderbuffer); renderer->destroy_renderbuffer(output->renderbuffer);
output->renderbuffer = NULL; output->renderbuffer = NULL;
switch (renderer->type) { switch (renderer->type) {
case WESTON_RENDERER_PIXMAN: case WESTON_RENDERER_PIXMAN:

View file

@ -55,6 +55,7 @@
#include <winpr/string.h> #include <winpr/string.h>
#include "backend.h" #include "backend.h"
#include "libweston-internal.h"
#include "shared/helpers.h" #include "shared/helpers.h"
#include "shared/string-helpers.h" #include "shared/string-helpers.h"
@ -149,7 +150,7 @@ struct rdp_output {
struct weston_output base; struct weston_output base;
struct rdp_backend *backend; struct rdp_backend *backend;
struct wl_event_source *finish_frame_timer; struct wl_event_source *finish_frame_timer;
struct weston_renderbuffer *renderbuffer; weston_renderbuffer_t renderbuffer;
pixman_image_t *shadow_surface; pixman_image_t *shadow_surface;
}; };

View file

@ -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_backend *backend = nvnc_get_userdata(server);
struct vnc_output *output = backend->output; struct vnc_output *output = backend->output;
struct weston_compositor *ec = output->base.compositor; struct weston_compositor *ec = output->base.compositor;
struct weston_renderbuffer *renderbuffer; weston_renderbuffer_t renderbuffer;
pixman_region32_t local_damage; pixman_region32_t local_damage;
pixman_region16_t nvnc_damage; pixman_region16_t nvnc_damage;
struct nvnc_fb *fb; 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_set_userdata(fb, renderbuffer,
(nvnc_cleanup_fn)weston_renderbuffer_unref); (nvnc_cleanup_fn)ec->renderer->destroy_renderbuffer);
} }
vnc_log_damage(backend, damage); vnc_log_damage(backend, damage);

View file

@ -192,7 +192,7 @@ struct wayland_shm_buffer {
int height; int height;
int frame_damaged; int frame_damaged;
struct weston_renderbuffer *renderbuffer; weston_renderbuffer_t renderbuffer;
cairo_surface_t *c_surface; cairo_surface_t *c_surface;
}; };
@ -266,9 +266,14 @@ to_wayland_backend(struct weston_backend *base)
static void static void
wayland_shm_buffer_destroy(struct wayland_shm_buffer *buffer) 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); cairo_surface_destroy(buffer->c_surface);
if (buffer->output) if (output) {
weston_renderbuffer_unref(buffer->renderbuffer); renderer = output->base.compositor->renderer;
renderer->destroy_renderbuffer(buffer->renderbuffer);
}
wl_buffer_destroy(buffer->buffer); wl_buffer_destroy(buffer->buffer);
munmap(buffer->data, buffer->size); munmap(buffer->data, buffer->size);
@ -657,15 +662,16 @@ wayland_backend_destroy_output_surface(struct wayland_output *output)
static void static void
wayland_output_destroy_shm_buffers(struct wayland_output *output) wayland_output_destroy_shm_buffers(struct wayland_output *output)
{ {
const struct weston_renderer *renderer =
output->base.compositor->renderer;
struct wayland_shm_buffer *buffer, *next; struct wayland_shm_buffer *buffer, *next;
/* Throw away any remaining SHM buffers */ /* Throw away any remaining SHM buffers */
wl_list_for_each_safe(buffer, next, &output->shm.free_buffers, free_link) wl_list_for_each_safe(buffer, next, &output->shm.free_buffers, free_link)
wayland_shm_buffer_destroy(buffer); wayland_shm_buffer_destroy(buffer);
/* These will get thrown away when they get released */
wl_list_for_each(buffer, &output->shm.buffers, link) { wl_list_for_each(buffer, &output->shm.buffers, link) {
if (buffer->renderbuffer) { if (buffer->renderbuffer) {
weston_renderbuffer_unref(buffer->renderbuffer); renderer->destroy_renderbuffer(buffer->renderbuffer);
buffer->renderbuffer = NULL; buffer->renderbuffer = NULL;
} }
buffer->output = NULL; buffer->output = NULL;

View file

@ -140,7 +140,7 @@ struct x11_output {
xcb_gc_t gc; xcb_gc_t gc;
xcb_shm_seg_t segment; xcb_shm_seg_t segment;
struct weston_renderbuffer *renderbuffer; weston_renderbuffer_t renderbuffer;
int shm_id; int shm_id;
void *buf; void *buf;
uint8_t depth; 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_generic_error_t *err;
xcb_free_gc(b->conn, output->gc); xcb_free_gc(b->conn, output->gc);
weston_renderbuffer_unref(output->renderbuffer); b->compositor->renderer->destroy_renderbuffer(output->renderbuffer);
output->renderbuffer = NULL; output->renderbuffer = NULL;
cookie = xcb_shm_detach_checked(b->conn, output->segment); cookie = xcb_shm_detach_checked(b->conn, output->segment);
err = xcb_request_check(b->conn, cookie); err = xcb_request_check(b->conn, cookie);

View file

@ -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 /** Tell the renderer that the target framebuffer size has changed
* *
* \param output The output that was resized. * \param output The output that was resized.

View file

@ -46,17 +46,9 @@
/* compositor <-> renderer interface */ /* compositor <-> renderer interface */
struct weston_renderbuffer { /** Opaque pointer to renderbuffer data.
int refcount; */
typedef void *weston_renderbuffer_t;
void (*destroy)(struct weston_renderbuffer *renderbuffer);
};
struct weston_renderbuffer *
weston_renderbuffer_ref(struct weston_renderbuffer *renderbuffer);
void
weston_renderbuffer_unref(struct weston_renderbuffer *renderbuffer);
struct weston_renderer_options { struct weston_renderer_options {
}; };
@ -74,7 +66,7 @@ struct weston_renderer {
uint32_t width, uint32_t height); uint32_t width, uint32_t height);
void (*repaint_output)(struct weston_output *output, void (*repaint_output)(struct weston_output *output,
pixman_region32_t *output_damage, pixman_region32_t *output_damage,
struct weston_renderbuffer *renderbuffer); weston_renderbuffer_t renderbuffer);
/** See weston_renderer_resize_output() /** See weston_renderer_resize_output()
* *
@ -112,34 +104,27 @@ struct weston_renderer {
* *
* \param output The output to add the DMABUF renderbuffer for. * \param output The output to add the DMABUF renderbuffer for.
* \param dmabuf The description object of the DMABUF to import. * \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 * This function imports the DMABUF memory as renderbuffer and adds it
* it to the output. The returned weston_renderbuffer can be passed to * to the output. The returned renderbuffer can be passed to
* repaint_output() to render into the DMABUF. * repaint_output() to render into the DMABUF.
* *
* The ownership of the linux_dmabuf_memory is transferred to the * The ownership of the linux_dmabuf_memory is transferred to the
* returned weston_renderbuffer. The linux_dmabuf_memory will be * returned renderbuffer. The linux_dmabuf_memory will be destroyed
* destroyed automatically when the weston_renderbuffer is destroyed. * automatically when the renderbuffer is destroyed.
*/ */
struct weston_renderbuffer * weston_renderbuffer_t
(*create_renderbuffer_dmabuf)(struct weston_output *output, (*create_renderbuffer_dmabuf)(struct weston_output *output,
struct linux_dmabuf_memory *dmabuf); struct linux_dmabuf_memory *dmabuf);
/** /** Destroy a renderbuffer
* Remove the DAMBUF renderbuffer from the output
* *
* \param output The output to remove a DMABUF renderbuffer from. * \param renderbuffer The renderbuffer to destroy.
* \param renderbuffer The weston_renderbuffer that shall be removed
* *
* This function removes the DMABUF renderbuffer from the output. * This function destroys a \c renderbuffer.
*
* 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.
*/ */
void (*remove_renderbuffer_dmabuf)(struct weston_output *output, void (*destroy_renderbuffer)(weston_renderbuffer_t renderbuffer);
struct weston_renderbuffer *renderbuffer);
/* Allocate a DMABUF that can be imported as renderbuffer /* Allocate a DMABUF that can be imported as renderbuffer
* *

View file

@ -48,7 +48,7 @@ noop_renderer_read_pixels(struct weston_output *output,
static void static void
noop_renderer_repaint_output(struct weston_output *output, noop_renderer_repaint_output(struct weston_output *output,
pixman_region32_t *output_damage, pixman_region32_t *output_damage,
struct weston_renderbuffer *renderbuffer) weston_renderbuffer_t renderbuffer)
{ {
} }

View file

@ -64,10 +64,9 @@ struct pixman_surface_state {
}; };
struct pixman_renderbuffer { struct pixman_renderbuffer {
struct weston_renderbuffer base;
pixman_region32_t damage; pixman_region32_t damage;
pixman_image_t *image; pixman_image_t *image;
bool stale;
struct wl_list link; struct wl_list link;
}; };
@ -81,16 +80,11 @@ struct pixman_renderer {
struct wl_signal destroy_signal; 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 * 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; return rb->image;
} }
@ -645,7 +639,7 @@ pixman_renderer_output_set_buffer(struct weston_output *output,
static void static void
pixman_renderer_repaint_output(struct weston_output *output, pixman_renderer_repaint_output(struct weston_output *output,
pixman_region32_t *output_damage, pixman_region32_t *output_damage,
struct weston_renderbuffer *renderbuffer) weston_renderbuffer_t renderbuffer)
{ {
struct pixman_output_state *po = get_output_state(output); struct pixman_output_state *po = get_output_state(output);
struct pixman_renderbuffer *rb; 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); 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); pixman_renderer_output_set_buffer(output, rb->image);
@ -921,13 +915,54 @@ pixman_renderer_surface_copy_content(struct weston_surface *surface,
return 0; 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 static bool
pixman_renderer_resize_output(struct weston_output *output, pixman_renderer_resize_output(struct weston_output *output,
const struct weston_size *fb_size, const struct weston_size *fb_size,
const struct weston_geometry *area) const struct weston_geometry *area)
{ {
struct pixman_output_state *po = get_output_state(output); struct pixman_output_state *po = get_output_state(output);
struct pixman_renderbuffer *renderbuffer, *tmp;
check_compositing_area(fb_size, area); 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); pixman_renderer_output_set_buffer(output, NULL);
wl_list_for_each_safe(renderbuffer, tmp, &po->renderbuffer_list, link) { pixman_renderer_discard_renderbuffers(po, false);
wl_list_remove(&renderbuffer->link);
weston_renderbuffer_unref(&renderbuffer->base);
}
po->fb_size = *fb_size; po->fb_size = *fb_size;
@ -1025,6 +1057,8 @@ pixman_renderer_init(struct weston_compositor *ec)
renderer->base.destroy = pixman_renderer_destroy; renderer->base.destroy = pixman_renderer_destroy;
renderer->base.surface_copy_content = renderer->base.surface_copy_content =
pixman_renderer_surface_copy_content; pixman_renderer_surface_copy_content;
renderer->base.destroy_renderbuffer =
pixman_renderer_destroy_renderbuffer;
renderer->base.type = WESTON_RENDERER_PIXMAN; renderer->base.type = WESTON_RENDERER_PIXMAN;
renderer->base.pixman = &pixman_renderer_interface; renderer->base.pixman = &pixman_renderer_interface;
ec->renderer = &renderer->base; ec->renderer = &renderer->base;
@ -1133,7 +1167,6 @@ static void
pixman_renderer_output_destroy(struct weston_output *output) pixman_renderer_output_destroy(struct weston_output *output)
{ {
struct pixman_output_state *po = get_output_state(output); struct pixman_output_state *po = get_output_state(output);
struct pixman_renderbuffer *renderbuffer, *tmp;
if (po->shadow_image) if (po->shadow_image)
pixman_image_unref(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->shadow_image = NULL;
po->hw_buffer = NULL; po->hw_buffer = NULL;
wl_list_for_each_safe(renderbuffer, tmp, &po->renderbuffer_list, link) { pixman_renderer_discard_renderbuffers(po, true);
wl_list_remove(&renderbuffer->link);
weston_renderbuffer_unref(&renderbuffer->base);
}
free(po); free(po);
} }
static void static weston_renderbuffer_t
pixman_renderer_renderbuffer_destroy(struct weston_renderbuffer *renderbuffer);
static struct weston_renderbuffer *
pixman_renderer_create_image_from_ptr(struct weston_output *output, pixman_renderer_create_image_from_ptr(struct weston_output *output,
const struct pixel_format_info *format, const struct pixel_format_info *format,
int width, int height, uint32_t *ptr, 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_init(&renderbuffer->damage);
pixman_region32_copy(&renderbuffer->damage, &output->region); 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); 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, pixman_renderer_create_image(struct weston_output *output,
const struct pixel_format_info *format, int width, const struct pixel_format_info *format, int width,
int height) int height)
@ -1207,21 +1232,9 @@ pixman_renderer_create_image(struct weston_output *output,
pixman_region32_init(&renderbuffer->damage); pixman_region32_init(&renderbuffer->damage);
pixman_region32_copy(&renderbuffer->damage, &output->region); 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); wl_list_insert(&po->renderbuffer_list, &renderbuffer->link);
return &renderbuffer->base; return (weston_renderbuffer_t) renderbuffer;
}
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);
} }
static struct pixman_renderer_interface pixman_renderer_interface = { static struct pixman_renderer_interface pixman_renderer_interface = {

View file

@ -47,14 +47,14 @@ struct pixman_renderer_interface {
const struct pixman_renderer_output_options *options); const struct pixman_renderer_output_options *options);
void (*output_destroy)(struct weston_output *output); void (*output_destroy)(struct weston_output *output);
struct weston_renderbuffer *(*create_image_from_ptr)(struct weston_output *output, weston_renderbuffer_t (*create_image_from_ptr)(struct weston_output *output,
const struct pixel_format_info *format, const struct pixel_format_info *format,
int width, int width,
int height, int height,
uint32_t *ptr, uint32_t *ptr,
int stride); int stride);
struct weston_renderbuffer *(*create_image)(struct weston_output *output, weston_renderbuffer_t (*create_image)(struct weston_output *output,
const struct pixel_format_info *format, const struct pixel_format_info *format,
int width, int height); int width, int height);
pixman_image_t *(*renderbuffer_get_image)(struct weston_renderbuffer *renderbuffer); pixman_image_t *(*renderbuffer_get_image)(weston_renderbuffer_t renderbuffer);
}; };

View file

@ -90,6 +90,12 @@ enum gl_border_status {
BORDER_SIZE_CHANGED = 0x10 BORDER_SIZE_CHANGED = 0x10
}; };
enum gl_renderbuffer_type {
RENDERBUFFER_DUMMY = 0,
RENDERBUFFER_FBO,
RENDERBUFFER_DMABUF,
};
struct gl_border_image { struct gl_border_image {
GLuint tex; GLuint tex;
int32_t width, height; int32_t width, height;
@ -103,9 +109,10 @@ struct gl_fbo_texture {
}; };
struct gl_renderbuffer { struct gl_renderbuffer {
struct weston_renderbuffer base; enum gl_renderbuffer_type type;
pixman_region32_t damage; pixman_region32_t damage;
enum gl_border_status border_damage; enum gl_border_status border_damage;
bool stale;
/* The fbo value zero represents the default surface framebuffer. */ /* The fbo value zero represents the default surface framebuffer. */
GLuint fbo; GLuint fbo;
GLuint rb; GLuint rb;
@ -677,12 +684,6 @@ gl_fbo_texture_fini(struct gl_fbo_texture *fbotex)
fbotex->tex = 0; 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 * static inline struct dmabuf_renderbuffer *
to_dmabuf_renderbuffer(struct gl_renderbuffer *renderbuffer) to_dmabuf_renderbuffer(struct gl_renderbuffer *renderbuffer)
{ {
@ -690,14 +691,61 @@ to_dmabuf_renderbuffer(struct gl_renderbuffer *renderbuffer)
} }
static void 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); assert(!renderbuffer->stale);
glDeleteRenderbuffers(1, &rb->rb);
pixman_region32_fini(&rb->damage); pixman_region32_fini(&renderbuffer->damage);
free(rb); 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 * static struct gl_renderbuffer *
@ -708,23 +756,18 @@ gl_renderer_create_dummy_renderbuffer(struct weston_output *output)
renderbuffer = xzalloc(sizeof(*renderbuffer)); renderbuffer = xzalloc(sizeof(*renderbuffer));
renderbuffer->type = RENDERBUFFER_DUMMY;
renderbuffer->fbo = 0; renderbuffer->fbo = 0;
pixman_region32_init(&renderbuffer->damage); pixman_region32_init(&renderbuffer->damage);
pixman_region32_copy(&renderbuffer->damage, &output->region); pixman_region32_copy(&renderbuffer->damage, &output->region);
renderbuffer->border_damage = BORDER_ALL_DIRTY; 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); wl_list_insert(&go->renderbuffer_list, &renderbuffer->link);
return renderbuffer; return renderbuffer;
} }
static struct weston_renderbuffer * static weston_renderbuffer_t
gl_renderer_create_fbo(struct weston_output *output, gl_renderer_create_fbo(struct weston_output *output,
const struct pixel_format_info *format, const struct pixel_format_info *format,
int width, int height, uint32_t *pixels) int width, int height, uint32_t *pixels)
@ -775,18 +818,13 @@ gl_renderer_create_fbo(struct weston_output *output,
} }
renderbuffer->pixels = pixels; renderbuffer->pixels = pixels;
renderbuffer->type = RENDERBUFFER_FBO;
pixman_region32_init(&renderbuffer->damage); pixman_region32_init(&renderbuffer->damage);
pixman_region32_copy(&renderbuffer->damage, &output->region); 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); wl_list_insert(&go->renderbuffer_list, &renderbuffer->link);
return &renderbuffer->base; return (weston_renderbuffer_t) renderbuffer;
} }
static bool static bool
@ -2337,7 +2375,7 @@ blit_shadow_to_output(struct weston_output *output,
static void static void
gl_renderer_repaint_output(struct weston_output *output, gl_renderer_repaint_output(struct weston_output *output,
pixman_region32_t *output_damage, pixman_region32_t *output_damage,
struct weston_renderbuffer *renderbuffer) weston_renderbuffer_t renderbuffer)
{ {
struct gl_output_state *go = get_output_state(output); struct gl_output_state *go = get_output_state(output);
struct weston_compositor *compositor = output->compositor; struct weston_compositor *compositor = output->compositor;
@ -2362,7 +2400,7 @@ gl_renderer_repaint_output(struct weston_output *output,
} }
if (renderbuffer) if (renderbuffer)
rb = to_gl_renderbuffer(renderbuffer); rb = (struct gl_renderbuffer *) renderbuffer;
else else
rb = output_get_dummy_renderbuffer(output); rb = output_get_dummy_renderbuffer(output);
@ -4020,22 +4058,6 @@ gl_renderer_output_set_border(struct weston_output *output,
go->border_status |= 1 << side; 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 static bool
gl_renderer_resize_output(struct weston_output *output, gl_renderer_resize_output(struct weston_output *output,
const struct weston_size *fb_size, const struct weston_size *fb_size,
@ -4048,7 +4070,7 @@ gl_renderer_resize_output(struct weston_output *output,
check_compositing_area(fb_size, area); check_compositing_area(fb_size, area);
gl_renderer_remove_renderbuffers(go); gl_renderer_discard_renderbuffers(go, false);
go->fb_size = *fb_size; go->fb_size = *fb_size;
go->area = *area; go->area = *area;
@ -4199,26 +4221,7 @@ gl_renderer_output_fbo_create(struct weston_output *output,
&options->fb_size, &options->area); &options->fb_size, &options->area);
} }
static void static weston_renderbuffer_t
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 *
gl_renderer_create_renderbuffer_dmabuf(struct weston_output *output, gl_renderer_create_renderbuffer_dmabuf(struct weston_output *output,
struct linux_dmabuf_memory *dmabuf) struct linux_dmabuf_memory *dmabuf)
{ {
@ -4272,26 +4275,12 @@ gl_renderer_create_renderbuffer_dmabuf(struct weston_output *output,
rb->gr = gr; rb->gr = gr;
rb->dmabuf = dmabuf; rb->dmabuf = dmabuf;
renderbuffer->type = RENDERBUFFER_DMABUF;
pixman_region32_init(&renderbuffer->damage); pixman_region32_init(&renderbuffer->damage);
pixman_region32_copy(&renderbuffer->damage, &output->region); pixman_region32_copy(&renderbuffer->damage, &output->region);
/* wl_list_insert(&go->renderbuffer_list, &renderbuffer->link);
* 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);
return &rb->base.base; return (weston_renderbuffer_t) rb;
}
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);
} }
#ifdef HAVE_GBM #ifdef HAVE_GBM
@ -4403,7 +4392,7 @@ gl_renderer_output_destroy(struct weston_output *output)
if (go->render_sync != EGL_NO_SYNC_KHR) if (go->render_sync != EGL_NO_SYNC_KHR)
gr->destroy_sync(gr->egl_display, go->render_sync); gr->destroy_sync(gr->egl_display, go->render_sync);
gl_renderer_remove_renderbuffers(go); gl_renderer_discard_renderbuffers(go, true);
free(go); free(go);
} }
@ -4581,6 +4570,7 @@ gl_renderer_display_create(struct weston_compositor *ec,
gr->base.read_pixels = gl_renderer_read_pixels; gr->base.read_pixels = gl_renderer_read_pixels;
gr->base.repaint_output = gl_renderer_repaint_output; gr->base.repaint_output = gl_renderer_repaint_output;
gr->base.resize_output = gl_renderer_resize_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.flush_damage = gl_renderer_flush_damage;
gr->base.attach = gl_renderer_attach; gr->base.attach = gl_renderer_attach;
gr->base.destroy = gl_renderer_destroy; 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.import_dmabuf = gl_renderer_import_dmabuf;
gr->base.get_supported_formats = gl_renderer_get_supported_formats; gr->base.get_supported_formats = gl_renderer_get_supported_formats;
gr->base.create_renderbuffer_dmabuf = gl_renderer_create_renderbuffer_dmabuf; 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); ret = populate_supported_formats(ec, &gr->supported_formats);
if (ret < 0) if (ret < 0)
goto fail_terminate; goto fail_terminate;

View file

@ -230,8 +230,8 @@ struct gl_renderer_interface {
* glReadPixels to download pixel data into the provided buffer after * glReadPixels to download pixel data into the provided buffer after
* repaint. * repaint.
*/ */
struct weston_renderbuffer *(*create_fbo)(struct weston_output *output, weston_renderbuffer_t (*create_fbo)(struct weston_output *output,
const struct pixel_format_info *format, const struct pixel_format_info *format,
int width, int height, int width, int height,
uint32_t *pixels); uint32_t *pixels);
}; };