Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DolphinQt: Add support for Vulkan on Wayland #8727

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions CMake/FindWayland.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Try to find Wayland on a Unix system
#
# This will define:
#
# WAYLAND_FOUND - True if Wayland is found
# WAYLAND_LIBRARIES - Link these to use Wayland
# WAYLAND_INCLUDE_DIR - Include directory for Wayland
# WAYLAND_DEFINITIONS - Compiler flags for using Wayland
#
# In addition the following more fine grained variables will be defined:
#
# WAYLAND_CLIENT_FOUND WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
# WAYLAND_SERVER_FOUND WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
# WAYLAND_EGL_FOUND WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
#
# Copyright (c) 2013 Martin Gräßlin <[email protected]>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.

IF (NOT WIN32)
IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES)
# In the cache already
SET(WAYLAND_FIND_QUIETLY TRUE)
ENDIF ()

# Use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor)

SET(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS})

FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})

FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS})

set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR} ${WAYLAND_CURSOR_INCLUDE_DIR})

set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES})

list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR)

include(FindPackageHandleStandardArgs)

FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CLIENT DEFAULT_MSG WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_SERVER DEFAULT_MSG WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_EGL DEFAULT_MSG WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CURSOR DEFAULT_MSG WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIR)

MARK_AS_ADVANCED(
WAYLAND_INCLUDE_DIR WAYLAND_LIBRARIES
WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES
)

ENDIF ()
12 changes: 12 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ set(DISTRIBUTOR "None" CACHE STRING "Name of the distributor.")

if(UNIX AND NOT APPLE AND NOT ANDROID)
option(ENABLE_X11 "Enables X11 Support" ON)
option(ENABLE_WAYLAND "Enables Wayland Support" OFF)
endif()
if(NOT WIN32 AND NOT APPLE)
option(ENABLE_EGL "Enables EGL OpenGL Interface" ON)
Expand Down Expand Up @@ -448,6 +449,17 @@ if(ENABLE_X11)
endif()
endif()

if(ENABLE_WAYLAND)
find_package(Wayland)
if(WAYLAND_FOUND)
add_definitions(-DHAVE_WAYLAND=1)
message(STATUS "Wayland support enabled")
else()
message(WARNING "Wayland support enabled but not found. This build will not support Wayland.")
endif()
endif()


if(ENABLE_EGL)
find_package(EGL)
if(EGL_FOUND)
Expand Down
10 changes: 8 additions & 2 deletions Source/Core/Common/WindowSystemInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ struct WindowSystemInfo
{
WindowSystemInfo() = default;
WindowSystemInfo(WindowSystemType type_, void* display_connection_, void* render_window_,
void* render_surface_)
void* render_surface_, int width_, int height_)
: type(type_), display_connection(display_connection_), render_window(render_window_),
render_surface(render_surface_)
render_surface(render_surface_), width(width_), height(height_)
{
}

Expand All @@ -41,6 +41,12 @@ struct WindowSystemInfo
// during video backend startup the surface pointer may change (MoltenVK).
void* render_surface = nullptr;

// Width and height of the render surface. This is necessary on Wayland as
// vkGetPhysicalDeviceSurfaceCapabilitiesKHR does not return the size of
// the VkSurfaceKHR created with vkCreateWaylandSurfaceKHR
int width = -1;
int height = -1;

// Scale of the render surface. For hidpi systems, this will be >1.
float render_surface_scale = 1.0f;
};
2 changes: 1 addition & 1 deletion Source/Core/DolphinQt/Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void Host::SetRenderFullscreen(bool fullscreen)
void Host::ResizeSurface(int new_width, int new_height)
{
if (g_renderer)
g_renderer->ResizeSurface();
g_renderer->ResizeSurface(new_width, new_height);
}

void Host_Message(HostMessageID id)
Expand Down
11 changes: 10 additions & 1 deletion Source/Core/DolphinQt/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,12 @@ static WindowSystemInfo GetWindowSystemInfo(QWindow* window)
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
wsi.display_connection = pni->nativeResourceForWindow("display", window);
if (wsi.type == WindowSystemType::Wayland)
{
wsi.render_window = window ? pni->nativeResourceForWindow("surface", window) : nullptr;
QSize size = window->size();
wsi.width = size.width();
wsi.height = size.height();
}
else
wsi.render_window = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
wsi.render_surface = wsi.render_window;
Expand Down Expand Up @@ -1137,8 +1142,12 @@ void MainWindow::ShowGraphicsWindow()
static_cast<Display*>(QGuiApplication::platformNativeInterface()->nativeResourceForWindow(
"display", windowHandle())),
winId());
m_graphics_window = new GraphicsWindow(m_xrr_config.get(), this);
}
else
{
m_graphics_window = new GraphicsWindow(nullptr, this);
}
m_graphics_window = new GraphicsWindow(m_xrr_config.get(), this);
#else
m_graphics_window = new GraphicsWindow(nullptr, this);
#endif
Expand Down
1 change: 1 addition & 0 deletions Source/Core/VideoBackends/OGL/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ PUBLIC

PRIVATE
${X11_LIBRARIES}
${WAYLAND_LIBRARIES}
)
1 change: 1 addition & 0 deletions Source/Core/VideoBackends/Vulkan/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ void Renderer::CheckForSurfaceResize()
g_command_buffer_mgr->CheckLastPresentFail();

// Resize the swap chain.
m_swap_chain->UpdateSize(m_new_width, m_new_height);
m_swap_chain->RecreateSwapChain();
OnSwapChainResized();
}
Expand Down
34 changes: 33 additions & 1 deletion Source/Core/VideoBackends/Vulkan/SwapChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
#include <X11/Xlib.h>
#endif

#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
#include <wayland-client.h>
#endif

namespace Vulkan
{
SwapChain::SwapChain(const WindowSystemInfo& wsi, VkSurfaceKHR surface, bool vsync)
Expand Down Expand Up @@ -85,6 +89,29 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, const WindowSys
}
#endif

#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
if (wsi.type == WindowSystemType::Wayland)
{
VkWaylandSurfaceCreateInfoKHR surface_create_info = {
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
nullptr, // const void* pNext
0, // VkWaylandSurfaceCreateFlagsKHR flags
static_cast<struct wl_display*>(wsi.display_connection), // struct wl_display* display
static_cast<struct wl_surface*>(wsi.render_surface) // struct wl_surface* surface
};

VkSurfaceKHR surface;
VkResult res = vkCreateWaylandSurfaceKHR(instance, &surface_create_info, nullptr, &surface);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateWaylandSurfaceKHR failed: ");
return VK_NULL_HANDLE;
}

return surface;
}
#endif

#if defined(VK_USE_PLATFORM_ANDROID_KHR)
if (wsi.type == WindowSystemType::Android)
{
Expand Down Expand Up @@ -263,7 +290,12 @@ bool SwapChain::CreateSwapChain()
// Determine the dimensions of the swap chain. Values of -1 indicate the size we specify here
// determines window size?
VkExtent2D size = surface_capabilities.currentExtent;
if (size.width == UINT32_MAX)
if (size.width == UINT32_MAX && m_wsi.type == WindowSystemType::Wayland)
{
size.width = m_wsi.width;
size.height = m_wsi.height;
}
else if (size.width == UINT32_MAX)
{
size.width = std::max(g_renderer->GetBackbufferWidth(), 1);
size.height = std::max(g_renderer->GetBackbufferHeight(), 1);
Expand Down
6 changes: 6 additions & 0 deletions Source/Core/VideoBackends/Vulkan/SwapChain.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ class SwapChain
}
VkResult AcquireNextImage();

void UpdateSize(int width, int height)
{
m_wsi.width = width;
m_wsi.height = height;
}

bool RecreateSurface(void* native_handle);
bool ResizeSwapChain();
bool RecreateSwapChain();
Expand Down
7 changes: 7 additions & 0 deletions Source/Core/VideoBackends/Vulkan/VulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,13 @@ bool VulkanContext::SelectInstanceExtensions(std::vector<const char*>* extension
return false;
}
#endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
if (wstype == WindowSystemType::Wayland &&
!AddExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true))
{
return false;
}
#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
if (wstype == WindowSystemType::Android &&
!AddExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true))
Expand Down
5 changes: 5 additions & 0 deletions Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ VULKAN_INSTANCE_ENTRY_POINT(vkCreateXlibSurfaceKHR, false)
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceXlibPresentationSupportKHR, false)
#endif

#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
VULKAN_INSTANCE_ENTRY_POINT(vkCreateWaylandSurfaceKHR, false)
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceWaylandPresentationSupportKHR, false)
#endif

#if defined(VK_USE_PLATFORM_ANDROID_KHR)
VULKAN_INSTANCE_ENTRY_POINT(vkCreateAndroidSurfaceKHR, false)
#endif
Expand Down
4 changes: 4 additions & 0 deletions Source/Core/VideoBackends/Vulkan/VulkanLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
#define VK_USE_PLATFORM_XLIB_KHR
#endif

#if defined(HAVE_WAYLAND)
#define VK_USE_PLATFORM_WAYLAND_KHR
#endif

#if defined(ANDROID)
#define VK_USE_PLATFORM_ANDROID_KHR
#endif
Expand Down
4 changes: 3 additions & 1 deletion Source/Core/VideoCommon/RenderBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,9 +625,11 @@ void Renderer::ChangeSurface(void* new_surface_handle)
m_surface_changed.Set();
}

void Renderer::ResizeSurface()
void Renderer::ResizeSurface(int width, int height)
{
std::lock_guard<std::mutex> lock(m_swap_mutex);
m_new_width = width;
m_new_height = height;
m_surface_resized.Set();
}

Expand Down
7 changes: 6 additions & 1 deletion Source/Core/VideoCommon/RenderBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ class Renderer
// Final surface changing
// This is called when the surface is resized (WX) or the window changes (Android).
void ChangeSurface(void* new_surface_handle);
void ResizeSurface();
void ResizeSurface(int width, int height);
void ResizeSurface() { ResizeSurface(-1, -1); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just default the parameters to -1 and avoid the overload altogether?

bool UseVertexDepthRange() const;
void DoState(PointerWrap& p);

Expand Down Expand Up @@ -330,6 +331,10 @@ class Renderer
std::mutex m_imgui_mutex;
u64 m_imgui_last_frame_time;

// Set when we receive a window resize event. Useful on Wayland
int m_new_width = -1;
int m_new_height = -1;

private:
void RunFrameDumps();
std::tuple<int, int> CalculateOutputDimensions(int width, int height) const;
Expand Down