xwayland: Implement linux_dmabuf_feedback event handlers
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com> [ Michel Dänzer: * Sort protocol #includes lexically. * memcpy to &xwl_feedback->main_dev directly in xwl_dmabuf_feedback_main_device. ]
This commit is contained in:
parent
2930eb113b
commit
bddfe190de
|
@ -44,6 +44,8 @@
|
|||
#include "xwayland-screen.h"
|
||||
#include "xwayland-window.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
static void
|
||||
glamor_egl_make_current(struct glamor_context *glamor_ctx)
|
||||
{
|
||||
|
@ -266,15 +268,228 @@ static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = {
|
|||
.modifier = xwl_dmabuf_handle_modifier
|
||||
};
|
||||
|
||||
/*
|
||||
* We need to check if the compositor is resending all of the tranche
|
||||
* information. Each tranche event will call this method to see
|
||||
* if the existing format info should be cleared before refilling.
|
||||
*/
|
||||
static void
|
||||
xwl_check_reset_tranche_info(struct xwl_dmabuf_feedback *xwl_feedback)
|
||||
{
|
||||
if (!xwl_feedback->feedback_done)
|
||||
return;
|
||||
|
||||
xwl_feedback->feedback_done = false;
|
||||
|
||||
xwl_dmabuf_feedback_clear_dev_formats(xwl_feedback);
|
||||
}
|
||||
|
||||
static void
|
||||
xwl_dmabuf_feedback_main_device(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
|
||||
struct wl_array *dev)
|
||||
{
|
||||
struct xwl_dmabuf_feedback *xwl_feedback = data;
|
||||
|
||||
xwl_check_reset_tranche_info(xwl_feedback);
|
||||
|
||||
assert(dev->size == sizeof(dev_t));
|
||||
memcpy(&xwl_feedback->main_dev, dev->data, sizeof(dev_t));
|
||||
}
|
||||
|
||||
static void
|
||||
xwl_dmabuf_feedback_tranche_target_device(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
|
||||
struct wl_array *dev)
|
||||
{
|
||||
struct xwl_dmabuf_feedback *xwl_feedback = data;
|
||||
|
||||
xwl_check_reset_tranche_info(xwl_feedback);
|
||||
|
||||
assert(dev->size == sizeof(dev_t));
|
||||
memcpy(&xwl_feedback->tmp_tranche.drm_dev, dev->data, sizeof(dev_t));
|
||||
}
|
||||
|
||||
static void
|
||||
xwl_dmabuf_feedback_tranche_flags(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct xwl_dmabuf_feedback *xwl_feedback = data;
|
||||
|
||||
xwl_check_reset_tranche_info(xwl_feedback);
|
||||
|
||||
if (flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT)
|
||||
xwl_feedback->tmp_tranche.supports_scanout = true;
|
||||
}
|
||||
|
||||
static void
|
||||
xwl_dmabuf_feedback_tranche_formats(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback,
|
||||
struct wl_array *indices)
|
||||
{
|
||||
struct xwl_dmabuf_feedback *xwl_feedback = data;
|
||||
struct xwl_device_formats *tranche = &xwl_feedback->tmp_tranche;
|
||||
uint16_t *index;
|
||||
|
||||
xwl_check_reset_tranche_info(xwl_feedback);
|
||||
|
||||
wl_array_for_each(index, indices) {
|
||||
if (*index >= xwl_feedback->format_table.len) {
|
||||
ErrorF("linux_dmabuf_feedback.tranche_formats: Index given to us by the compositor"
|
||||
" is too large to fit in the format table\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Look up this format/mod in the format table */
|
||||
struct xwl_format_table_entry *entry = &xwl_feedback->format_table.entry[*index];
|
||||
|
||||
/* Add it to the in-progress tranche */
|
||||
xwl_add_format_and_mod_to_list(&tranche->formats, &tranche->num_formats,
|
||||
entry->format,
|
||||
entry->modifier);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xwl_append_to_tranche(struct xwl_device_formats *dst, struct xwl_device_formats *src)
|
||||
{
|
||||
struct xwl_format *format;
|
||||
|
||||
for (int i = 0; i < src->num_formats; i++) {
|
||||
format = &src->formats[i];
|
||||
|
||||
for (int j = 0; j < format->num_modifiers; j++)
|
||||
xwl_add_format_and_mod_to_list(&dst->formats, &dst->num_formats,
|
||||
format->format,
|
||||
format->modifiers[j]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xwl_dmabuf_feedback_tranche_done(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
|
||||
{
|
||||
struct xwl_dmabuf_feedback *xwl_feedback = data;
|
||||
struct xwl_device_formats *tranche;
|
||||
int appended = false;
|
||||
|
||||
/*
|
||||
* No need to call xwl_check_reset_tranche_info, the other events should have been
|
||||
* triggered first
|
||||
*/
|
||||
|
||||
/*
|
||||
* First check if there is an existing tranche for this device+flags combo. We
|
||||
* will combine it with this tranche, since we can only send one modifier list
|
||||
* in DRI3 but the compositor may report multiple tranches per device (KDE
|
||||
* does this)
|
||||
*/
|
||||
for (int i = 0; i < xwl_feedback->dev_formats_len; i++) {
|
||||
tranche = &xwl_feedback->dev_formats[i];
|
||||
if (tranche->drm_dev == xwl_feedback->tmp_tranche.drm_dev &&
|
||||
tranche->supports_scanout == xwl_feedback->tmp_tranche.supports_scanout) {
|
||||
appended = true;
|
||||
|
||||
/* Add all format/mods to this tranche */
|
||||
xwl_append_to_tranche(tranche, &xwl_feedback->tmp_tranche);
|
||||
|
||||
/* Now free our temp tranche's allocations */
|
||||
xwl_device_formats_destroy(&xwl_feedback->tmp_tranche);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!appended) {
|
||||
xwl_feedback->dev_formats_len++;
|
||||
xwl_feedback->dev_formats = xnfrealloc(xwl_feedback->dev_formats,
|
||||
sizeof(struct xwl_device_formats) *
|
||||
xwl_feedback->dev_formats_len);
|
||||
|
||||
/* copy the temporary tranche into the official array */
|
||||
memcpy(&xwl_feedback->dev_formats[xwl_feedback->dev_formats_len - 1],
|
||||
&xwl_feedback->tmp_tranche,
|
||||
sizeof(struct xwl_device_formats));
|
||||
}
|
||||
|
||||
/* reset the tranche */
|
||||
memset(&xwl_feedback->tmp_tranche, 0, sizeof(struct xwl_device_formats));
|
||||
}
|
||||
|
||||
static void
|
||||
xwl_dmabuf_feedback_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback)
|
||||
{
|
||||
struct xwl_dmabuf_feedback *xwl_feedback = data;
|
||||
|
||||
xwl_feedback->feedback_done = true;
|
||||
}
|
||||
|
||||
static void
|
||||
xwl_dmabuf_feedback_format_table(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||
int32_t fd, uint32_t size)
|
||||
{
|
||||
struct xwl_dmabuf_feedback *xwl_feedback = data;
|
||||
/* Unmap the old table */
|
||||
if (xwl_feedback->format_table.entry) {
|
||||
munmap(xwl_feedback->format_table.entry,
|
||||
xwl_feedback->format_table.len * sizeof(struct xwl_format_table_entry));
|
||||
}
|
||||
|
||||
assert(size % sizeof(struct xwl_format_table_entry) == 0);
|
||||
xwl_feedback->format_table.len = size / sizeof(struct xwl_format_table_entry);
|
||||
xwl_feedback->format_table.entry = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
|
||||
if (xwl_feedback->format_table.entry == MAP_FAILED) {
|
||||
ErrorF("linux_dmabuf_feedback.format_table: Could not map the format"
|
||||
" table: Compositor bug or out of resources\n");
|
||||
xwl_feedback->format_table.len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct zwp_linux_dmabuf_feedback_v1_listener xwl_dmabuf_feedback_listener = {
|
||||
.done = xwl_dmabuf_feedback_done,
|
||||
.format_table = xwl_dmabuf_feedback_format_table,
|
||||
.main_device = xwl_dmabuf_feedback_main_device,
|
||||
.tranche_done = xwl_dmabuf_feedback_tranche_done,
|
||||
.tranche_target_device = xwl_dmabuf_feedback_tranche_target_device,
|
||||
.tranche_formats = xwl_dmabuf_feedback_tranche_formats,
|
||||
.tranche_flags = xwl_dmabuf_feedback_tranche_flags,
|
||||
};
|
||||
|
||||
Bool
|
||||
xwl_dmabuf_setup_feedback_for_window(struct xwl_window *xwl_window)
|
||||
{
|
||||
struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
|
||||
|
||||
xwl_window->feedback.dmabuf_feedback =
|
||||
zwp_linux_dmabuf_v1_get_surface_feedback(xwl_screen->dmabuf, xwl_window->surface);
|
||||
|
||||
if (!xwl_window->feedback.dmabuf_feedback)
|
||||
return FALSE;
|
||||
|
||||
zwp_linux_dmabuf_feedback_v1_add_listener(xwl_window->feedback.dmabuf_feedback,
|
||||
&xwl_dmabuf_feedback_listener,
|
||||
&xwl_window->feedback);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool
|
||||
xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
|
||||
uint32_t id, uint32_t version)
|
||||
{
|
||||
/* We either support versions 3 or 4. 4 is needed for dmabuf feedback */
|
||||
int supported_version = version >= 4 ? 4 : 3;
|
||||
|
||||
if (version < 3)
|
||||
return FALSE;
|
||||
|
||||
xwl_screen->dmabuf =
|
||||
wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3);
|
||||
wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, supported_version);
|
||||
xwl_screen->dmabuf_protocol_version = supported_version;
|
||||
zwp_linux_dmabuf_v1_add_listener(xwl_screen->dmabuf, &xwl_dmabuf_listener, xwl_screen);
|
||||
|
||||
return TRUE;
|
||||
|
|
|
@ -108,6 +108,7 @@ Bool xwl_glamor_init(struct xwl_screen *xwl_screen);
|
|||
|
||||
Bool xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen,
|
||||
uint32_t id, uint32_t version);
|
||||
Bool xwl_dmabuf_setup_feedback_for_window(struct xwl_window *xwl_window);
|
||||
Bool xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen,
|
||||
uint32_t id, uint32_t version);
|
||||
struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap);
|
||||
|
|
|
@ -185,6 +185,8 @@ xwl_close_screen(ScreenPtr screen)
|
|||
struct xwl_seat *xwl_seat, *next_xwl_seat;
|
||||
struct xwl_wl_surface *xwl_wl_surface, *xwl_wl_surface_next;
|
||||
|
||||
xwl_dmabuf_feedback_destroy(&xwl_screen->default_feedback);
|
||||
|
||||
DeleteCallback(&PropertyStateCallback, xwl_property_callback, screen);
|
||||
|
||||
xorg_list_for_each_entry_safe(xwl_output, next_xwl_output,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <dix.h>
|
||||
|
||||
#include "xwayland-types.h"
|
||||
#include "xwayland-window.h"
|
||||
#include "xwayland-output.h"
|
||||
#include "xwayland-glamor.h"
|
||||
#include "xwayland-drm-lease.h"
|
||||
|
@ -101,6 +102,8 @@ struct xwl_screen {
|
|||
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *shortcuts_inhibit_manager;
|
||||
struct zwp_keyboard_shortcuts_inhibitor_v1 *shortcuts_inhibit;
|
||||
struct zwp_linux_dmabuf_v1 *dmabuf;
|
||||
int dmabuf_protocol_version;
|
||||
struct xwl_dmabuf_feedback default_feedback;
|
||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
||||
struct wp_viewporter *viewporter;
|
||||
struct xwayland_shell_v1 *xwayland_shell;
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
|
@ -43,6 +45,7 @@
|
|||
#include "xwayland-window-buffers.h"
|
||||
#include "xwayland-shm.h"
|
||||
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
#include "viewporter-client-protocol.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
#include "xwayland-shell-v1-client-protocol.h"
|
||||
|
@ -835,6 +838,13 @@ ensure_surface_for_window(WindowPtr window)
|
|||
if (!xwl_screen->rootless && !xwl_create_root_surface(xwl_window))
|
||||
goto err;
|
||||
|
||||
#ifdef XWL_HAS_GLAMOR
|
||||
if (xwl_screen->dmabuf_protocol_version >= 4)
|
||||
xwl_dmabuf_setup_feedback_for_window(xwl_window);
|
||||
#endif
|
||||
|
||||
wl_display_flush(xwl_screen->display);
|
||||
|
||||
send_surface_id_event(xwl_window);
|
||||
|
||||
wl_surface_set_user_data(xwl_window->surface, xwl_window);
|
||||
|
@ -990,6 +1000,42 @@ release_wl_surface_for_window(struct xwl_window *xwl_window)
|
|||
release_wl_surface_for_window_legacy_delay(xwl_window);
|
||||
}
|
||||
|
||||
void
|
||||
xwl_device_formats_destroy(struct xwl_device_formats *dev_formats)
|
||||
{
|
||||
for (int j = 0; j < dev_formats->num_formats; j++)
|
||||
free(dev_formats->formats[j].modifiers);
|
||||
free(dev_formats->formats);
|
||||
}
|
||||
|
||||
void
|
||||
xwl_dmabuf_feedback_clear_dev_formats(struct xwl_dmabuf_feedback *xwl_feedback)
|
||||
{
|
||||
if (xwl_feedback->dev_formats_len == 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < xwl_feedback->dev_formats_len; i++) {
|
||||
struct xwl_device_formats *dev_format = &xwl_feedback->dev_formats[i];
|
||||
xwl_device_formats_destroy(dev_format);
|
||||
}
|
||||
free(xwl_feedback->dev_formats);
|
||||
xwl_feedback->dev_formats = NULL;
|
||||
xwl_feedback->dev_formats_len = 0;
|
||||
}
|
||||
|
||||
void
|
||||
xwl_dmabuf_feedback_destroy(struct xwl_dmabuf_feedback *xwl_feedback)
|
||||
{
|
||||
munmap(xwl_feedback->format_table.entry,
|
||||
xwl_feedback->format_table.len * sizeof(struct xwl_format_table_entry));
|
||||
xwl_dmabuf_feedback_clear_dev_formats(xwl_feedback);
|
||||
|
||||
if (xwl_feedback->dmabuf_feedback)
|
||||
zwp_linux_dmabuf_feedback_v1_destroy(xwl_feedback->dmabuf_feedback);
|
||||
|
||||
xwl_feedback->dmabuf_feedback = NULL;
|
||||
}
|
||||
|
||||
Bool
|
||||
xwl_unrealize_window(WindowPtr window)
|
||||
{
|
||||
|
@ -1032,6 +1078,8 @@ xwl_unrealize_window(WindowPtr window)
|
|||
if (xwl_window_has_viewport_enabled(xwl_window))
|
||||
xwl_window_disable_viewport(xwl_window);
|
||||
|
||||
xwl_dmabuf_feedback_destroy(&xwl_window->feedback);
|
||||
|
||||
#ifdef GLAMOR_HAS_GBM
|
||||
if (xwl_screen->present) {
|
||||
struct xwl_present_window *xwl_present_window, *tmp;
|
||||
|
|
|
@ -43,6 +43,44 @@ struct xwl_wl_surface {
|
|||
struct xorg_list link;
|
||||
};
|
||||
|
||||
struct xwl_format_table_entry {
|
||||
uint32_t format;
|
||||
uint32_t pad;
|
||||
uint64_t modifier;
|
||||
};
|
||||
|
||||
struct xwl_device_formats {
|
||||
dev_t drm_dev;
|
||||
int supports_scanout;
|
||||
uint32_t num_formats;
|
||||
struct xwl_format *formats;
|
||||
};
|
||||
|
||||
struct xwl_format_table {
|
||||
/* This is mmapped from the fd given to us by the compositor */
|
||||
int len;
|
||||
struct xwl_format_table_entry *entry;
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper struct for sharing dmabuf feedback logic between
|
||||
* a screen and a window. The screen will get the default
|
||||
* feedback, and a window will get a per-surface feedback.
|
||||
*/
|
||||
struct xwl_dmabuf_feedback {
|
||||
struct zwp_linux_dmabuf_feedback_v1 *dmabuf_feedback;
|
||||
struct xwl_format_table format_table;
|
||||
dev_t main_dev;
|
||||
/*
|
||||
* This will be filled in during wl events and copied to
|
||||
* dev_formats on dmabuf_feedback.tranche_done
|
||||
*/
|
||||
struct xwl_device_formats tmp_tranche;
|
||||
int feedback_done;
|
||||
int dev_formats_len;
|
||||
struct xwl_device_formats *dev_formats;
|
||||
};
|
||||
|
||||
struct xwl_window {
|
||||
struct xwl_screen *xwl_screen;
|
||||
struct wl_surface *surface;
|
||||
|
@ -68,6 +106,7 @@ struct xwl_window {
|
|||
struct libdecor_frame *libdecor_frame;
|
||||
#endif
|
||||
struct xwayland_surface_v1 *xwayland_surface;
|
||||
struct xwl_dmabuf_feedback feedback;
|
||||
};
|
||||
|
||||
struct xwl_window *xwl_window_get(WindowPtr window);
|
||||
|
@ -102,4 +141,8 @@ void xwl_window_surface_do_destroy(struct xwl_wl_surface *xwl_wl_surface);
|
|||
|
||||
Bool xwl_window_init(void);
|
||||
|
||||
void xwl_dmabuf_feedback_destroy(struct xwl_dmabuf_feedback *xwl_feedback);
|
||||
void xwl_dmabuf_feedback_clear_dev_formats(struct xwl_dmabuf_feedback *xwl_feedback);
|
||||
void xwl_device_formats_destroy(struct xwl_device_formats *dev_formats);
|
||||
|
||||
#endif /* XWAYLAND_WINDOW_H */
|
||||
|
|
Loading…
Reference in New Issue