From ed345ffc2f3373743d74a5e0a1dc73c012389273 Mon Sep 17 00:00:00 2001 From: Rostislav Pehlivanov Date: Sat, 16 Sep 2017 03:46:38 +0100 Subject: vo_gpu: vulkan: add support for wayland --- video/out/gpu/context.c | 9 +++ video/out/vulkan/common.h | 3 + video/out/vulkan/context_wayland.c | 146 +++++++++++++++++++++++++++++++++++++ video/out/vulkan/context_xlib.c | 7 +- video/out/vulkan/utils.c | 9 +-- video/out/vulkan/utils.h | 3 +- 6 files changed, 168 insertions(+), 9 deletions(-) create mode 100644 video/out/vulkan/context_wayland.c (limited to 'video') diff --git a/video/out/gpu/context.c b/video/out/gpu/context.c index 69f322c422..22387077d5 100644 --- a/video/out/gpu/context.c +++ b/video/out/gpu/context.c @@ -33,6 +33,7 @@ #include "context.h" #include "spirv.h" +/* OpenGL */ extern const struct ra_ctx_fns ra_ctx_glx; extern const struct ra_ctx_fns ra_ctx_glx_probe; extern const struct ra_ctx_fns ra_ctx_x11_egl; @@ -45,6 +46,9 @@ extern const struct ra_ctx_fns ra_ctx_dxgl; extern const struct ra_ctx_fns ra_ctx_rpi; extern const struct ra_ctx_fns ra_ctx_mali; extern const struct ra_ctx_fns ra_ctx_vdpauglx; + +/* Vulkan */ +extern const struct ra_ctx_fns ra_ctx_vulkan_wayland; extern const struct ra_ctx_fns ra_ctx_vulkan_xlib; static const struct ra_ctx_fns *contexts[] = { @@ -88,9 +92,14 @@ static const struct ra_ctx_fns *contexts[] = { // Vulkan contexts: #if HAVE_VULKAN + +#if HAVE_WAYLAND + &ra_ctx_vulkan_wayland, +#endif #if HAVE_X11 &ra_ctx_vulkan_xlib, #endif + #endif }; diff --git a/video/out/vulkan/common.h b/video/out/vulkan/common.h index d0d14e28c2..8ea515e27b 100644 --- a/video/out/vulkan/common.h +++ b/video/out/vulkan/common.h @@ -13,6 +13,9 @@ // We need to define all platforms we want to support. Since we have // our own mechanism for checking this, we re-define the right symbols +#if HAVE_WAYLAND +#define VK_USE_PLATFORM_WAYLAND_KHR +#endif #if HAVE_X11 #define VK_USE_PLATFORM_XLIB_KHR #endif diff --git a/video/out/vulkan/context_wayland.c b/video/out/vulkan/context_wayland.c new file mode 100644 index 0000000000..a77f17a4f2 --- /dev/null +++ b/video/out/vulkan/context_wayland.c @@ -0,0 +1,146 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . + */ + +#include "video/out/gpu/context.h" +#include "video/out/wayland_common.h" + +#include "common.h" +#include "context.h" +#include "utils.h" + +struct priv { + struct mpvk_ctx vk; +}; + +static void wayland_uninit(struct ra_ctx *ctx) +{ + struct priv *p = ctx->priv; + + ra_vk_ctx_uninit(ctx); + mpvk_uninit(&p->vk); + vo_wayland_uninit(ctx->vo); +} + +static bool wayland_init(struct ra_ctx *ctx) +{ + struct priv *p = ctx->priv = talloc_zero(ctx, struct priv); + struct mpvk_ctx *vk = &p->vk; + int msgl = ctx->opts.probing ? MSGL_V : MSGL_ERR; + + if (!mpvk_instance_init(vk, ctx->log, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, + ctx->opts.debug)) + goto error; + + if (!vo_wayland_init(ctx->vo)) + goto error; + + if (!vo_wayland_config(ctx->vo)) + goto error; + + VkWaylandSurfaceCreateInfoKHR wlinfo = { + .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, + .display = ctx->vo->wayland->display.display, + .surface = ctx->vo->wayland->window.video_surface, + }; + + VkResult res = vkCreateWaylandSurfaceKHR(vk->inst, &wlinfo, MPVK_ALLOCATOR, + &vk->surf); + if (res != VK_SUCCESS) { + MP_MSG(ctx, msgl, "Failed creating Wayland surface: %s\n", vk_err(res)); + goto error; + } + + /* Because in Wayland clients render whenever they receive a callback from + * the compositor, and the fact that the compositor usually stops sending + * callbacks once the surface is no longer visible, using FIFO here would + * mean the entire player would block on acquiring swapchain images. Hence, + * use MAILBOX to guarantee that there'll always be a swapchain image and + * the player won't block waiting on those */ + if (!ra_vk_ctx_init(ctx, vk, VK_PRESENT_MODE_MAILBOX_KHR)) + goto error; + + return true; + +error: + wayland_uninit(ctx); + return false; +} + +static bool resize(struct ra_ctx *ctx) +{ + struct vo_wayland_state *wl = ctx->vo->wayland; + int32_t width = wl->window.sh_width; + int32_t height = wl->window.sh_height; + int32_t scale = 1; + + if (wl->display.current_output) + scale = wl->display.current_output->scale; + + MP_VERBOSE(wl, "resizing %dx%d -> %dx%d\n", wl->window.width, + wl->window.height, + width, + height); + + wl_surface_set_buffer_scale(wl->window.video_surface, scale); + int err = ra_vk_ctx_resize(ctx->swapchain, scale*width, scale*height); + + wl->window.width = width; + wl->window.height = height; + + wl->vo->dwidth = scale*wl->window.width; + wl->vo->dheight = scale*wl->window.height; + wl->vo->want_redraw = true; + + return err; +} + +static bool wayland_reconfig(struct ra_ctx *ctx) +{ + vo_wayland_config(ctx->vo); + return resize(ctx); +} + +static int wayland_control(struct ra_ctx *ctx, int *events, int request, void *arg) +{ + int ret = vo_wayland_control(ctx->vo, events, request, arg); + if (*events & VO_EVENT_RESIZE) { + if (!resize(ctx)) + return VO_ERROR; + } + return ret; +} + +static void wayland_wakeup(struct ra_ctx *ctx) +{ + vo_wayland_wakeup(ctx->vo); +} + +static void wayland_wait_events(struct ra_ctx *ctx, int64_t until_time_us) +{ + vo_wayland_wait_events(ctx->vo, until_time_us); +} + +const struct ra_ctx_fns ra_ctx_vulkan_wayland = { + .type = "vulkan", + .name = "wayland", + .reconfig = wayland_reconfig, + .control = wayland_control, + .wakeup = wayland_wakeup, + .wait_events = wayland_wait_events, + .init = wayland_init, + .uninit = wayland_uninit, +}; diff --git a/video/out/vulkan/context_xlib.c b/video/out/vulkan/context_xlib.c index 2611fbb706..26efd6f583 100644 --- a/video/out/vulkan/context_xlib.c +++ b/video/out/vulkan/context_xlib.c @@ -41,13 +41,14 @@ static bool xlib_init(struct ra_ctx *ctx) struct mpvk_ctx *vk = &p->vk; int msgl = ctx->opts.probing ? MSGL_V : MSGL_ERR; - if (!vo_x11_init(ctx->vo)) + if (!mpvk_instance_init(vk, ctx->log, VK_KHR_XLIB_SURFACE_EXTENSION_NAME, + ctx->opts.debug)) goto error; - if (!vo_x11_create_vo_window(ctx->vo, NULL, "mpvk")) + if (!vo_x11_init(ctx->vo)) goto error; - if (!mpvk_instance_init(vk, ctx->log, ctx->opts.debug)) + if (!vo_x11_create_vo_window(ctx->vo, NULL, "mpvk")) goto error; VkXlibSurfaceCreateInfoKHR xinfo = { diff --git a/video/out/vulkan/utils.c b/video/out/vulkan/utils.c index 659da9159a..3d11062939 100644 --- a/video/out/vulkan/utils.c +++ b/video/out/vulkan/utils.c @@ -167,7 +167,8 @@ void mpvk_uninit(struct mpvk_ctx *vk) *vk = (struct mpvk_ctx){0}; } -bool mpvk_instance_init(struct mpvk_ctx *vk, struct mp_log *log, bool debug) +bool mpvk_instance_init(struct mpvk_ctx *vk, struct mp_log *log, + const char *surf_ext_name, bool debug) { *vk = (struct mpvk_ctx) { .log = log, @@ -189,11 +190,9 @@ bool mpvk_instance_init(struct mpvk_ctx *vk, struct mp_log *log, bool debug) } // Enable whatever extensions were compiled in. - static const char *extensions[] = { + const char *extensions[] = { VK_KHR_SURFACE_EXTENSION_NAME, -#if HAVE_X11 - VK_KHR_XLIB_SURFACE_EXTENSION_NAME, -#endif + surf_ext_name, // Extra extensions only used for debugging. These are toggled by // decreasing the enabledExtensionCount, so the number needs to be diff --git a/video/out/vulkan/utils.h b/video/out/vulkan/utils.h index 5bde48089d..4b9d9b86e3 100644 --- a/video/out/vulkan/utils.h +++ b/video/out/vulkan/utils.h @@ -37,7 +37,8 @@ void mpvk_uninit(struct mpvk_ctx *vk); // finally followed by vk_swchain initialization. // Create a vulkan instance. Returns VK_NULL_HANDLE on failure -bool mpvk_instance_init(struct mpvk_ctx *vk, struct mp_log *log, bool debug); +bool mpvk_instance_init(struct mpvk_ctx *vk, struct mp_log *log, + const char *surf_ext_name, bool debug); // Generate a VkSurfaceKHR usable for video output. Returns VK_NULL_HANDLE on // failure. Must be called after mpvk_instance_init. -- cgit v1.2.3