mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-26 11:04:18 +01:00
Linux: Add Vulkan support for wayland (#553)
This commit is contained in:
parent
2c81d240a5
commit
fca7f5dfe4
@ -27,6 +27,7 @@ elseif(UNIX)
|
|||||||
add_compile_definitions(
|
add_compile_definitions(
|
||||||
VK_USE_PLATFORM_XLIB_KHR # legacy. Do we need to support XLIB surfaces?
|
VK_USE_PLATFORM_XLIB_KHR # legacy. Do we need to support XLIB surfaces?
|
||||||
VK_USE_PLATFORM_XCB_KHR
|
VK_USE_PLATFORM_XCB_KHR
|
||||||
|
VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
add_compile_options(-maes)
|
add_compile_options(-maes)
|
||||||
|
@ -129,6 +129,7 @@ VKFUNC_DEVICE(vkCmdBindPipeline);
|
|||||||
#if BOOST_OS_LINUX
|
#if BOOST_OS_LINUX
|
||||||
VKFUNC_INSTANCE(vkCreateXlibSurfaceKHR);
|
VKFUNC_INSTANCE(vkCreateXlibSurfaceKHR);
|
||||||
VKFUNC_INSTANCE(vkCreateXcbSurfaceKHR);
|
VKFUNC_INSTANCE(vkCreateXcbSurfaceKHR);
|
||||||
|
VKFUNC_INSTANCE(vkCreateWaylandSurfaceKHR);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
|
@ -107,7 +107,11 @@ std::vector<VulkanRenderer::DeviceInfo> VulkanRenderer::GetDevices()
|
|||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
requiredExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
requiredExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#elif BOOST_OS_LINUX
|
#elif BOOST_OS_LINUX
|
||||||
requiredExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
auto backend = gui_getWindowInfo().window_main.backend;
|
||||||
|
if(backend == WindowHandleInfo::Backend::X11)
|
||||||
|
requiredExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
else if (backend == WindowHandleInfo::Backend::WAYLAND)
|
||||||
|
requiredExtensions.emplace_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||||
#elif BOOST_OS_MACOS
|
#elif BOOST_OS_MACOS
|
||||||
requiredExtensions.emplace_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
|
requiredExtensions.emplace_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
|
||||||
#endif
|
#endif
|
||||||
@ -1149,7 +1153,11 @@ std::vector<const char*> VulkanRenderer::CheckInstanceExtensionSupport(FeatureCo
|
|||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
requiredInstanceExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
requiredInstanceExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
#elif BOOST_OS_LINUX
|
#elif BOOST_OS_LINUX
|
||||||
requiredInstanceExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
auto backend = gui_getWindowInfo().window_main.backend;
|
||||||
|
if(backend == WindowHandleInfo::Backend::X11)
|
||||||
|
requiredInstanceExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
else if (backend == WindowHandleInfo::Backend::WAYLAND)
|
||||||
|
requiredInstanceExtensions.emplace_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
|
||||||
#elif BOOST_OS_MACOS
|
#elif BOOST_OS_MACOS
|
||||||
requiredInstanceExtensions.emplace_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
|
requiredInstanceExtensions.emplace_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
|
||||||
#endif
|
#endif
|
||||||
@ -1267,6 +1275,25 @@ VkSurfaceKHR VulkanRenderer::CreateXcbSurface(VkInstance instance, xcb_connectio
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkSurfaceKHR VulkanRenderer::CreateWaylandSurface(VkInstance instance, wl_display* display, wl_surface* surface)
|
||||||
|
{
|
||||||
|
VkWaylandSurfaceCreateInfoKHR sci{};
|
||||||
|
sci.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
|
||||||
|
sci.flags = 0;
|
||||||
|
sci.display = display;
|
||||||
|
sci.surface = surface;
|
||||||
|
|
||||||
|
VkSurfaceKHR result;
|
||||||
|
VkResult err;
|
||||||
|
if ((err = vkCreateWaylandSurfaceKHR(instance, &sci, nullptr, &result)) != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
forceLog_printf("Cannot create a Wayland Vulkan surface: %d", (sint32)err);
|
||||||
|
throw std::runtime_error(fmt::format("Cannot create a Wayland Vulkan surface: {}", err));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, struct WindowHandleInfo& windowInfo)
|
VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, struct WindowHandleInfo& windowInfo)
|
||||||
@ -1274,7 +1301,11 @@ VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, struc
|
|||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
return CreateWinSurface(instance, windowInfo.hwnd);
|
return CreateWinSurface(instance, windowInfo.hwnd);
|
||||||
#elif BOOST_OS_LINUX
|
#elif BOOST_OS_LINUX
|
||||||
return CreateXlibSurface(instance, windowInfo.xlib_display, windowInfo.xlib_window);
|
if(windowInfo.backend == WindowHandleInfo::Backend::X11)
|
||||||
|
return CreateXlibSurface(instance, windowInfo.xlib_display, windowInfo.xlib_window);
|
||||||
|
if(windowInfo.backend == WindowHandleInfo::Backend::WAYLAND)
|
||||||
|
return CreateWaylandSurface(instance, windowInfo.display, windowInfo.surface);
|
||||||
|
return {};
|
||||||
#elif BOOST_OS_MACOS
|
#elif BOOST_OS_MACOS
|
||||||
return CreateCocoaSurface(instance, windowInfo.handle);
|
return CreateCocoaSurface(instance, windowInfo.handle);
|
||||||
#endif
|
#endif
|
||||||
@ -2596,6 +2627,15 @@ bool VulkanRenderer::UpdateSwapchainProperties(bool mainWindow)
|
|||||||
if (chainInfo.m_usesSRGB != latteBufferUsesSRGB)
|
if (chainInfo.m_usesSRGB != latteBufferUsesSRGB)
|
||||||
stateChanged = true;
|
stateChanged = true;
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
if (mainWindow)
|
||||||
|
gui_getWindowSize(width, height);
|
||||||
|
else
|
||||||
|
gui_getPadWindowSize(width, height);
|
||||||
|
auto extent = chainInfo.getExtent();
|
||||||
|
if (width != extent.width || height != extent.height)
|
||||||
|
stateChanged = true;
|
||||||
|
|
||||||
if(stateChanged)
|
if(stateChanged)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -201,6 +201,7 @@ public:
|
|||||||
#if BOOST_OS_LINUX
|
#if BOOST_OS_LINUX
|
||||||
static VkSurfaceKHR CreateXlibSurface(VkInstance instance, Display* dpy, Window window);
|
static VkSurfaceKHR CreateXlibSurface(VkInstance instance, Display* dpy, Window window);
|
||||||
static VkSurfaceKHR CreateXcbSurface(VkInstance instance, xcb_connection_t* connection, xcb_window_t window);
|
static VkSurfaceKHR CreateXcbSurface(VkInstance instance, xcb_connection_t* connection, xcb_window_t window);
|
||||||
|
static VkSurfaceKHR CreateWaylandSurface(VkInstance instance, wl_display* display, wl_surface* surface);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static VkSurfaceKHR CreateFramebufferSurface(VkInstance instance, struct WindowHandleInfo& windowInfo);
|
static VkSurfaceKHR CreateFramebufferSurface(VkInstance instance, struct WindowHandleInfo& windowInfo);
|
||||||
|
@ -87,6 +87,7 @@ void PadViewFrame::InitializeRenderCanvas()
|
|||||||
m_render_canvas->Bind(wxEVT_GESTURE_PAN, &PadViewFrame::OnGesturePan, this);
|
m_render_canvas->Bind(wxEVT_GESTURE_PAN, &PadViewFrame::OnGesturePan, this);
|
||||||
|
|
||||||
m_render_canvas->SetFocus();
|
m_render_canvas->SetFocus();
|
||||||
|
SendSizeEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PadViewFrame::OnSizeEvent(wxSizeEvent& event)
|
void PadViewFrame::OnSizeEvent(wxSizeEvent& event)
|
||||||
|
@ -11,7 +11,17 @@ VulkanCanvas::VulkanCanvas(wxWindow* parent, const wxSize& size, bool is_main_wi
|
|||||||
Bind(wxEVT_SIZE, &VulkanCanvas::OnResize, this);
|
Bind(wxEVT_SIZE, &VulkanCanvas::OnResize, this);
|
||||||
|
|
||||||
if(is_main_window)
|
if(is_main_window)
|
||||||
gui_initHandleContextFromWxWidgetsWindow(gui_getWindowInfo().canvas_main, this);
|
{
|
||||||
|
WindowHandleInfo& canvasMain = gui_getWindowInfo().canvas_main;
|
||||||
|
gui_initHandleContextFromWxWidgetsWindow(canvasMain, this);
|
||||||
|
#if BOOST_OS_LINUX
|
||||||
|
if(canvasMain.backend == WindowHandleInfo::Backend::WAYLAND)
|
||||||
|
{
|
||||||
|
m_subsurface = std::make_unique<wxWlSubsurface>(this);
|
||||||
|
canvasMain.surface = m_subsurface->getSurface();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
else
|
else
|
||||||
gui_initHandleContextFromWxWidgetsWindow(gui_getWindowInfo().canvas_pad, this);
|
gui_initHandleContextFromWxWidgetsWindow(gui_getWindowInfo().canvas_pad, this);
|
||||||
|
|
||||||
@ -55,6 +65,14 @@ void VulkanCanvas::OnPaint(wxPaintEvent& event)
|
|||||||
|
|
||||||
void VulkanCanvas::OnResize(wxSizeEvent& event)
|
void VulkanCanvas::OnResize(wxSizeEvent& event)
|
||||||
{
|
{
|
||||||
|
#if BOOST_OS_LINUX
|
||||||
|
if(m_subsurface)
|
||||||
|
{
|
||||||
|
int32_t x,y;
|
||||||
|
GetScreenPosition(&x,&y);
|
||||||
|
m_subsurface->setPosition(x, y);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
const wxSize size = GetSize();
|
const wxSize size = GetSize();
|
||||||
if (size.GetWidth() == 0 || size.GetHeight() == 0)
|
if (size.GetWidth() == 0 || size.GetHeight() == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -6,11 +6,15 @@
|
|||||||
|
|
||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#if BOOST_OS_LINUX
|
||||||
|
#include "gui/helpers/wxWayland.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
class VulkanCanvas : public IRenderCanvas, public wxWindow
|
class VulkanCanvas : public IRenderCanvas, public wxWindow
|
||||||
{
|
{
|
||||||
|
#if BOOST_OS_LINUX
|
||||||
|
std::unique_ptr<wxWlSubsurface> m_subsurface;
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
VulkanCanvas(wxWindow* parent, const wxSize& size, bool is_main_window);
|
VulkanCanvas(wxWindow* parent, const wxSize& size, bool is_main_window);
|
||||||
~VulkanCanvas();
|
~VulkanCanvas();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <gdk/gdk.h>
|
#include <gdk/gdk.h>
|
||||||
#include <gdk/gdkwindow.h>
|
#include <gdk/gdkwindow.h>
|
||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
|
#include <gdk/gdkwayland.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gui/wxgui.h"
|
#include "gui/wxgui.h"
|
||||||
@ -204,19 +205,31 @@ void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, c
|
|||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
handleInfoOut.hwnd = wxw->GetHWND();
|
handleInfoOut.hwnd = wxw->GetHWND();
|
||||||
#elif BOOST_OS_LINUX
|
#elif BOOST_OS_LINUX
|
||||||
// get window
|
|
||||||
GtkWidget* gtkWidget = (GtkWidget*)wxw->GetHandle(); // returns GtkWidget
|
GtkWidget* gtkWidget = (GtkWidget*)wxw->GetHandle(); // returns GtkWidget
|
||||||
gtk_widget_realize(gtkWidget);
|
gtk_widget_realize(gtkWidget);
|
||||||
GdkWindow* gdkWindow = gtk_widget_get_window(gtkWidget);
|
GdkWindow* gdkWindow = gtk_widget_get_window(gtkWidget);
|
||||||
handleInfoOut.xlib_window = gdk_x11_window_get_xid(gdkWindow);
|
GdkDisplay* gdkDisplay = gdk_window_get_display(gdkWindow);
|
||||||
|
if(GDK_IS_X11_WINDOW(gdkWindow))
|
||||||
|
{
|
||||||
|
handleInfoOut.backend = WindowHandleInfo::Backend::X11;
|
||||||
|
handleInfoOut.xlib_window = gdk_x11_window_get_xid(gdkWindow);
|
||||||
|
handleInfoOut.xlib_display = gdk_x11_display_get_xdisplay(gdkDisplay);
|
||||||
|
if(!handleInfoOut.xlib_display)
|
||||||
|
{
|
||||||
|
cemuLog_log(LogType::Force, "Unable to get xlib display");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(GDK_IS_WAYLAND_WINDOW(gdkWindow))
|
||||||
|
{
|
||||||
|
handleInfoOut.backend = WindowHandleInfo::Backend::WAYLAND;
|
||||||
|
handleInfoOut.surface = gdk_wayland_window_get_wl_surface(gdkWindow);
|
||||||
|
handleInfoOut.display = gdk_wayland_display_get_wl_display(gdkDisplay);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cemuLog_log(LogType::Force, "Unsuported GTK backend");
|
||||||
|
|
||||||
// get display
|
}
|
||||||
GdkDisplay* gdkDisplay = gdk_window_get_display(gdkWindow);
|
|
||||||
handleInfoOut.xlib_display = gdk_x11_display_get_xdisplay(gdkDisplay);
|
|
||||||
if(!handleInfoOut.xlib_display)
|
|
||||||
{
|
|
||||||
cemuLog_log(LogType::Force, "Unable to get xlib display");
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
handleInfoOut.handle = wxw->GetHandle();
|
handleInfoOut.handle = wxw->GetHandle();
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#if BOOST_OS_LINUX
|
#if BOOST_OS_LINUX
|
||||||
#include "xcb/xproto.h"
|
#include "xcb/xproto.h"
|
||||||
#include <gdk/gdkkeysyms.h>
|
#include <gdk/gdkkeysyms.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if BOOST_OS_MACOS
|
#if BOOST_OS_MACOS
|
||||||
@ -16,6 +17,11 @@ struct WindowHandleInfo
|
|||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
std::atomic<HWND> hwnd;
|
std::atomic<HWND> hwnd;
|
||||||
#elif BOOST_OS_LINUX
|
#elif BOOST_OS_LINUX
|
||||||
|
enum class Backend
|
||||||
|
{
|
||||||
|
X11,
|
||||||
|
WAYLAND,
|
||||||
|
} backend;
|
||||||
// XLIB
|
// XLIB
|
||||||
Display* xlib_display{};
|
Display* xlib_display{};
|
||||||
Window xlib_window{};
|
Window xlib_window{};
|
||||||
@ -24,7 +30,8 @@ struct WindowHandleInfo
|
|||||||
//xcb_connection_t* xcb_con{};
|
//xcb_connection_t* xcb_con{};
|
||||||
//xcb_window_t xcb_window{};
|
//xcb_window_t xcb_window{};
|
||||||
// Wayland
|
// Wayland
|
||||||
// todo
|
wl_display* display;
|
||||||
|
wl_surface* surface;
|
||||||
#else
|
#else
|
||||||
void* handle;
|
void* handle;
|
||||||
#endif
|
#endif
|
||||||
|
75
src/gui/helpers/wxWayland.h
Normal file
75
src/gui/helpers/wxWayland.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if BOOST_OS_LINUX
|
||||||
|
|
||||||
|
#include <gdk/gdk.h>
|
||||||
|
#include <gdk/gdkwayland.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <wx/wx.h>
|
||||||
|
|
||||||
|
class wxWlSubsurface
|
||||||
|
{
|
||||||
|
static void registry_add_object(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)
|
||||||
|
{
|
||||||
|
if (!strcmp(interface, wl_subcompositor_interface.name))
|
||||||
|
{
|
||||||
|
auto wlSubsurface = static_cast<wxWlSubsurface*>(data);
|
||||||
|
wlSubsurface->m_subcompositor = static_cast<wl_subcompositor*>(wl_registry_bind(registry, name, &wl_subcompositor_interface, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void registry_remove_object(void* /*data*/, struct wl_registry* /*registry*/, uint32_t /*name*/) {}
|
||||||
|
|
||||||
|
wl_registry_listener m_registry_listener = {®istry_add_object, ®istry_remove_object};
|
||||||
|
wl_subcompositor* m_subcompositor;
|
||||||
|
wl_surface* m_surface;
|
||||||
|
wl_subsurface* m_subsurface;
|
||||||
|
int32_t m_xPos = 0;
|
||||||
|
int32_t m_yPos = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
wxWlSubsurface(wxWindow* window)
|
||||||
|
{
|
||||||
|
GtkWidget* widget = static_cast<GtkWidget*>(window->GetHandle());
|
||||||
|
gtk_widget_realize(widget);
|
||||||
|
GdkWindow* gdkWindow = gtk_widget_get_window(widget);
|
||||||
|
GdkDisplay* gdkDisplay = gdk_window_get_display(gdkWindow);
|
||||||
|
wl_display* display = gdk_wayland_display_get_wl_display(gdkDisplay);
|
||||||
|
wl_surface* surface = gdk_wayland_window_get_wl_surface(gdkWindow);
|
||||||
|
wl_compositor* compositor = gdk_wayland_display_get_wl_compositor(gdkDisplay);
|
||||||
|
wl_registry* registry = wl_display_get_registry(display);
|
||||||
|
wl_registry_add_listener(registry, &m_registry_listener, this);
|
||||||
|
wl_display_roundtrip(display);
|
||||||
|
m_surface = wl_compositor_create_surface(compositor);
|
||||||
|
wl_region* region = wl_compositor_create_region(compositor);
|
||||||
|
wl_surface_set_input_region(m_surface, region);
|
||||||
|
m_subsurface = wl_subcompositor_get_subsurface(m_subcompositor, m_surface, surface);
|
||||||
|
wl_subsurface_set_desync(m_subsurface);
|
||||||
|
window->GetScreenPosition(&m_xPos, &m_yPos);
|
||||||
|
wl_subsurface_set_position(m_subsurface, m_xPos, m_yPos);
|
||||||
|
wl_surface_commit(m_surface);
|
||||||
|
wl_region_destroy(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_surface* getSurface() const { return m_surface; }
|
||||||
|
|
||||||
|
void setPosition(int32_t xPos, int32_t yPos)
|
||||||
|
{
|
||||||
|
if (xPos != m_xPos || m_yPos != yPos)
|
||||||
|
{
|
||||||
|
m_xPos = xPos;
|
||||||
|
m_yPos = yPos;
|
||||||
|
wl_subsurface_set_position(m_subsurface, m_xPos, m_yPos);
|
||||||
|
wl_surface_commit(m_surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~wxWlSubsurface()
|
||||||
|
{
|
||||||
|
wl_subsurface_destroy(m_subsurface);
|
||||||
|
wl_surface_destroy(m_surface);
|
||||||
|
wl_subcompositor_destroy(m_subcompositor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BOOST_OS_LINUX
|
Loading…
Reference in New Issue
Block a user