diff --git a/layer/VkLayer_FROG_gamescope_wsi.cpp b/layer/VkLayer_FROG_gamescope_wsi.cpp index f0f614d..650d407 100644 --- a/layer/VkLayer_FROG_gamescope_wsi.cpp +++ b/layer/VkLayer_FROG_gamescope_wsi.cpp @@ -2,6 +2,7 @@ #define VK_USE_PLATFORM_XCB_KHR #define VK_USE_PLATFORM_XLIB_KHR #include "vkroots.h" +#include #include "gamescope-xwayland-client-protocol.h" #include @@ -27,7 +28,9 @@ namespace GamescopeWSILayer { struct GamescopeSurfaceData { VkInstance instance; wl_surface* surface; - uint32_t window_xid; + + xcb_connection_t* xcb_conn; + xcb_window_t window_xid; }; VKROOTS_DEFINE_SYNCHRONIZED_MAP_TYPE(GamescopeSurface, VkSurfaceKHR); @@ -130,7 +133,7 @@ namespace GamescopeWSILayer { if (!gamescopeInstance) return pDispatch->CreateXcbSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); - return CreateGamescopeSurface(pDispatch, *gamescopeInstance, instance, uint32_t(pCreateInfo->window), pAllocator, pSurface); + return CreateGamescopeSurface(pDispatch, *gamescopeInstance, instance, pCreateInfo->connection, uint32_t(pCreateInfo->window), pAllocator, pSurface); } static VkResult CreateXlibSurfaceKHR( @@ -143,7 +146,7 @@ namespace GamescopeWSILayer { if (!gamescopeInstance) return pDispatch->CreateXlibSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); - return CreateGamescopeSurface(pDispatch, *gamescopeInstance, instance, uint32_t(pCreateInfo->window), pAllocator, pSurface); + return CreateGamescopeSurface(pDispatch, *gamescopeInstance, instance, XGetXCBConnection(pCreateInfo->dpy), uint32_t(pCreateInfo->window), pAllocator, pSurface); } static VkResult GetPhysicalDeviceSurfaceFormatsKHR( @@ -184,6 +187,29 @@ namespace GamescopeWSILayer { pSurfaceInfo); } + static VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( + const vkroots::VkInstanceDispatch* pDispatch, + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) { + auto gamescopeSurface = GamescopeSurface::get(surface); + if (!gamescopeSurface) + return pDispatch->GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities); + + VkResult res = VK_SUCCESS; + if ((res = pDispatch->GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities)) != VK_SUCCESS) + return res; + + VkExtent2D currentExtent = {}; + if ((res = getCurrentExtent((*gamescopeSurface)->xcb_conn, (*gamescopeSurface)->window_xid, ¤tExtent)) != VK_SUCCESS) + return res; + + pSurfaceCapabilities->currentExtent = currentExtent; + pSurfaceCapabilities->minImageCount = getMinImageCount(); + + return VK_SUCCESS; + } + static void DestroySurfaceKHR( const vkroots::VkInstanceDispatch* pDispatch, VkInstance instance, @@ -229,6 +255,7 @@ namespace GamescopeWSILayer { const vkroots::VkInstanceDispatch* pDispatch, GamescopeInstance& gamescopeInstance, VkInstance instance, + xcb_connection_t* xcb_conn, uint32_t window_xid, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) { @@ -262,7 +289,8 @@ namespace GamescopeWSILayer { GamescopeSurface::create(*pSurface, GamescopeSurfaceData { .instance = instance, .surface = waylandSurface, - .window_xid = window_xid, + .xcb_conn = xcb_conn, + .window_xid = xcb_window_t(window_xid), }); return result; @@ -306,6 +334,29 @@ namespace GamescopeWSILayer { return s_isRunningUnderGamescope; } + static VkResult getCurrentExtent(xcb_connection_t* xcb_conn, xcb_window_t window_xid, VkExtent2D *pExtent) { + xcb_generic_error_t *err = nullptr; + xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(xcb_conn, window_xid); + xcb_get_geometry_reply_t* geom = xcb_get_geometry_reply(xcb_conn, geom_cookie, &err); + if (!geom) { + free(err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + *pExtent = VkExtent2D{ geom->width, geom->height }; + free(geom); + free(err); + return VK_SUCCESS; + } + + static uint32_t getMinImageCount() { + const char *overrideStr = std::getenv("GAMESCOPE_WSI_MIN_IMAGE_COUNT"); + if (overrideStr && *overrideStr) + return uint32_t(std::atoi(overrideStr)); + + return 3; + } + static constexpr wl_registry_listener s_registryListener = { .global = [](void* data, wl_registry* registry, uint32_t name, const char* interface, uint32_t version) { auto instance = reinterpret_cast(data); diff --git a/layer/meson.build b/layer/meson.build index ee8968a..963c374 100644 --- a/layer/meson.build +++ b/layer/meson.build @@ -1,6 +1,6 @@ gamescope_wsi_layer = shared_library('VkLayer_FROG_gamescope_wsi', 'VkLayer_FROG_gamescope_wsi.cpp', protocols_client_src, - dependencies : [ vkroots_dep, dep_xcb, dep_x11, wayland_client ], + dependencies : [ vkroots_dep, dep_xcb, dep_x11, dep_x11_xcb, wayland_client ], override_options : [ 'cpp_std=c++20' ], install : true ) diff --git a/meson.build b/meson.build index b24b42c..7c14f90 100644 --- a/meson.build +++ b/meson.build @@ -34,6 +34,7 @@ dep_xxf86vm = dependency('xxf86vm') dep_xtst = dependency('xtst') dep_xres = dependency('xres') dep_xcb = dependency('xcb') +dep_x11_xcb = dependency('x11-xcb') drm_dep = dependency('libdrm', version: '>= 2.4.113') vulkan_dep = dependency('vulkan')