mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-14 08:22:25 -04:00
wlr_raster: Add surface helper
This commit is contained in:
parent
d9f6ec080f
commit
46b0ba0da6
2 changed files with 150 additions and 0 deletions
|
|
@ -17,6 +17,7 @@ struct wlr_buffer;
|
|||
struct wlr_texture;
|
||||
struct wlr_renderer;
|
||||
struct wlr_drm_syncobj_timeline;
|
||||
struct wlr_surface;
|
||||
|
||||
struct wlr_raster {
|
||||
// May be NULL
|
||||
|
|
@ -83,4 +84,12 @@ void wlr_raster_unlock(struct wlr_raster *raster);
|
|||
struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster,
|
||||
struct wlr_renderer *renderer);
|
||||
|
||||
/**
|
||||
* Creates a wlr_raster from a surface. This will automatically deduplicate
|
||||
* rasters if multiple are consumed from the same surface so that redundant
|
||||
* uploads are not performed. The raster returned will automatically be locked.
|
||||
* Users are required to call wlr_raster_unlock() after invoking this function.
|
||||
*/
|
||||
struct wlr_raster *wlr_raster_from_surface(struct wlr_surface *surface);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
#include <assert.h>
|
||||
#include <pixman.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_linux_drm_syncobj_v1.h>
|
||||
#include <wlr/types/wlr_raster.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/util/addon.h>
|
||||
#include "types/wlr_buffer.h"
|
||||
|
||||
static void raster_handle_buffer_release(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -120,3 +123,141 @@ struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster,
|
|||
|
||||
return texture;
|
||||
}
|
||||
|
||||
struct surface_raster {
|
||||
struct wlr_raster *raster;
|
||||
struct wlr_surface *surface;
|
||||
|
||||
struct wlr_addon addon;
|
||||
|
||||
struct wl_listener buffer_prerelease;
|
||||
|
||||
bool locking_buffer;
|
||||
};
|
||||
|
||||
static void surface_raster_drop_raster(struct surface_raster *surface_raster) {
|
||||
if (surface_raster->locking_buffer) {
|
||||
wlr_buffer_unlock(surface_raster->raster->buffer);
|
||||
surface_raster->locking_buffer = false;
|
||||
}
|
||||
|
||||
wlr_raster_unlock(surface_raster->raster);
|
||||
surface_raster->raster = NULL;
|
||||
}
|
||||
|
||||
static void surface_raster_destroy(struct surface_raster *surface_raster) {
|
||||
surface_raster_drop_raster(surface_raster);
|
||||
|
||||
wl_list_remove(&surface_raster->buffer_prerelease.link);
|
||||
wlr_addon_finish(&surface_raster->addon);
|
||||
free(surface_raster);
|
||||
}
|
||||
|
||||
static void surface_raster_handle_addon_destroy(struct wlr_addon *addon) {
|
||||
struct surface_raster *surface_raster = wl_container_of(addon, surface_raster, addon);
|
||||
surface_raster_destroy(surface_raster);
|
||||
}
|
||||
|
||||
static void surface_raster_handle_buffer_prerelease(struct wl_listener *listener, void *data) {
|
||||
struct surface_raster *surface_raster =
|
||||
wl_container_of(listener, surface_raster, buffer_prerelease);
|
||||
struct wlr_raster *raster = surface_raster->raster;
|
||||
|
||||
struct wlr_surface_output *output;
|
||||
wl_list_for_each(output, &surface_raster->surface->current_outputs, link) {
|
||||
wlr_raster_obtain_texture(raster, output->output->renderer);
|
||||
}
|
||||
|
||||
// if there was a failed texture upload, keep on locking the buffer
|
||||
if (!raster->texture) {
|
||||
wlr_buffer_lock(raster->buffer);
|
||||
surface_raster->locking_buffer = true;
|
||||
}
|
||||
|
||||
wl_list_remove(&surface_raster->buffer_prerelease.link);
|
||||
wl_list_init(&surface_raster->buffer_prerelease.link);
|
||||
}
|
||||
|
||||
const struct wlr_addon_interface surface_raster_addon_impl = {
|
||||
.name = "wlr_raster_surface",
|
||||
.destroy = surface_raster_handle_addon_destroy,
|
||||
};
|
||||
|
||||
static struct surface_raster *get_surface_raster(struct wlr_surface *surface) {
|
||||
struct wlr_addon *addon = wlr_addon_find(&surface->addons, NULL,
|
||||
&surface_raster_addon_impl);
|
||||
if (!addon) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct surface_raster *surface_raster = wl_container_of(addon, surface_raster, addon);
|
||||
return surface_raster;
|
||||
}
|
||||
|
||||
struct wlr_raster *wlr_raster_from_surface(struct wlr_surface *surface) {
|
||||
struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
|
||||
wlr_linux_drm_syncobj_v1_get_surface_state(surface);
|
||||
|
||||
struct wlr_raster_create_options options = {0};
|
||||
if (syncobj_surface_state) {
|
||||
options.wait_timeline = syncobj_surface_state->acquire_timeline;
|
||||
options.wait_point = syncobj_surface_state->acquire_point;
|
||||
}
|
||||
|
||||
struct surface_raster *surface_raster = get_surface_raster(surface);
|
||||
if (!surface_raster) {
|
||||
surface_raster = calloc(1, sizeof(*surface_raster));
|
||||
if (!surface_raster) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface_raster->surface = surface;
|
||||
|
||||
wlr_addon_init(&surface_raster->addon, &surface->addons, NULL,
|
||||
&surface_raster_addon_impl);
|
||||
|
||||
surface_raster->buffer_prerelease.notify = surface_raster_handle_buffer_prerelease;
|
||||
wl_list_init(&surface_raster->buffer_prerelease.link);
|
||||
}
|
||||
|
||||
if (!surface->current.buffer) {
|
||||
// surface is mapped but it hasn't committed a new buffer. We need to keep
|
||||
// using the old one
|
||||
if (wlr_surface_has_buffer(surface)) {
|
||||
if (surface_raster->raster) {
|
||||
return wlr_raster_lock(surface_raster->raster);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wl_list_remove(&surface_raster->buffer_prerelease.link);
|
||||
wl_list_init(&surface_raster->buffer_prerelease.link);
|
||||
|
||||
surface_raster_drop_raster(surface_raster);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_raster *raster;
|
||||
if (surface_raster->raster) {
|
||||
// make sure we haven't already seen this buffer
|
||||
if (surface_raster->raster->buffer == surface->current.buffer) {
|
||||
return wlr_raster_lock(surface_raster->raster);
|
||||
}
|
||||
}
|
||||
|
||||
raster = wlr_raster_create(surface->current.buffer, &options);
|
||||
|
||||
if (!raster) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface_raster_drop_raster(surface_raster);
|
||||
surface_raster->raster = wlr_raster_lock(raster);
|
||||
|
||||
wl_list_remove(&surface_raster->buffer_prerelease.link);
|
||||
wl_signal_add(&surface->current.buffer->events.prerelease, &surface_raster->buffer_prerelease);
|
||||
|
||||
return raster;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue