void VulkanContext::ReinitSurface(int width, int height) { if (surface_ != VK_NULL_HANDLE) { ILOG("Destroying Vulkan surface (%d, %d)", width_, height_); vkDestroySurfaceKHR(instance_, surface_, nullptr); surface_ = VK_NULL_HANDLE; } ILOG("Creating Vulkan surface (%d, %d)", width, height); switch (winsys_) { #ifdef _WIN32 case WINDOWSYSTEM_WIN32: { HINSTANCE connection = (HINSTANCE)winsysData1_; HWND window = (HWND)winsysData2_; RECT rc; GetClientRect(window, &rc); width = rc.right - rc.left; height = rc.bottom - rc.top; VkWin32SurfaceCreateInfoKHR win32{ VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; win32.flags = 0; win32.hwnd = window; win32.hinstance = connection; VkResult res = vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_); assert(res == VK_SUCCESS); break; } #endif #if defined(__ANDROID__) case WINDOWSYSTEM_ANDROID: { ANativeWindow *wnd = (ANativeWindow *)winsysData1_; VkAndroidSurfaceCreateInfoKHR android{ VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR }; android.flags = 0; android.window = wnd; VkResult res = vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); assert(res == VK_SUCCESS); break; } #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) case WINDOWSYSTEM_XLIB: { VkXlibSurfaceCreateInfoKHR xlib = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR }; xlib.flags = 0; xlib.dpy = (Display *)winsysData1_; xlib.window = (Window)winsysData2_; VkResult res = vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_); assert(res == VK_SUCCESS); break; } #endif #if defined(VK_USE_PLATFORM_XCB_KHR) case WINDOWSYSTEM_XCB: { VkXCBSurfaceCreateInfoKHR xcb = { VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR }; xcb.flags = 0; xcb.connection = (Connection *)winsysData1_; xcb.window = (Window)(uintptr_t)winsysData2_; VkResult res = vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_); assert(res == VK_SUCCESS); break; } #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) case WINDOWSYSTEM_WAYLAND: { VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR }; wayland.flags = 0; wayland.display = (wl_display *)winsysData1_; wayland.surface = (wl_surface *)winsysData2_; VkResult res = vkCreateWaylandSurfaceKHR(instance_, &wayland, nullptr, &surface_); assert(res == VK_SUCCESS); break; } #endif default: _assert_msg_(G3D, false, "Vulkan support for chosen window system not implemented"); break; } width_ = width; height_ = height; }
static bool wayland_vk_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; VkWaylandSurfaceCreateInfoKHR wlinfo = { .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, .display = ctx->vo->wl->display, .surface = ctx->vo->wl->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_vk_uninit(ctx); return false; } static void resize(struct ra_ctx *ctx) { struct vo_wayland_state *wl = ctx->vo->wl; MP_VERBOSE(wl, "Handling resize on the vk side\n"); const int32_t width = wl->scaling*mp_rect_w(wl->geometry); const int32_t height = wl->scaling*mp_rect_h(wl->geometry); wl_surface_set_buffer_scale(wl->surface, wl->scaling); wl->vo->dwidth = width; wl->vo->dheight = height; } static bool wayland_vk_reconfig(struct ra_ctx *ctx) { if (!vo_wayland_reconfig(ctx->vo)) return false; return true; } static int wayland_vk_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) { resize(ctx); if (ra_vk_ctx_resize(ctx->swapchain, ctx->vo->dwidth, ctx->vo->dheight)) return VO_ERROR; } return ret; }