From fc9138926fd86862f633743971a457a5f0be8f2b Mon Sep 17 00:00:00 2001 From: Jack Greiner Date: Sat, 5 Oct 2024 09:47:12 -0400 Subject: [PATCH] Add patch for PR 1231 See: https://github.com/ValveSoftware/gamescope/pull/1231 --- 002-pr-1231.patch | 239 ++++++++++++++++++++++++++++++++++++++++++++++ gamescope.spec | 1 + 2 files changed, 240 insertions(+) create mode 100644 002-pr-1231.patch diff --git a/002-pr-1231.patch b/002-pr-1231.patch new file mode 100644 index 0000000..e21cb0a --- /dev/null +++ b/002-pr-1231.patch @@ -0,0 +1,239 @@ +From ab115896be1a448bde0eb7673c26300ea4ca5040 Mon Sep 17 00:00:00 2001 +From: sharkautarch <128002472+sharkautarch@users.noreply.github.com> +Date: Sun, 19 May 2024 20:15:36 -0400 +Subject: [PATCH 1/2] QueuePresent: canBypassXWayland(): fetch multiple xcb + cookies initially before waiting on any of them + +--- + layer/VkLayer_FROG_gamescope_wsi.cpp | 1 + + layer/xcb_helpers.hpp | 105 +++++++++++++++++++++++---- + 2 files changed, 93 insertions(+), 13 deletions(-) + +diff --git a/layer/VkLayer_FROG_gamescope_wsi.cpp b/layer/VkLayer_FROG_gamescope_wsi.cpp +index 5844c2a63..ca44849f2 100644 +--- a/layer/VkLayer_FROG_gamescope_wsi.cpp ++++ b/layer/VkLayer_FROG_gamescope_wsi.cpp +@@ -975,6 +975,7 @@ namespace GamescopeWSILayer { + continue; + } + ++ xcb::Prefetcher prefetcher(gamescopeSurface->connection, gamescopeSurface->window); + const bool canBypass = gamescopeSurface->canBypassXWayland(); + if (canBypass != gamescopeSwapchain->isBypassingXWayland) + UpdateSwapchainResult(canBypass ? VK_SUBOPTIMAL_KHR : VK_ERROR_OUT_OF_DATE_KHR); +diff --git a/layer/xcb_helpers.hpp b/layer/xcb_helpers.hpp +index 8fac5635b..72d0ec092 100644 +--- a/layer/xcb_helpers.hpp ++++ b/layer/xcb_helpers.hpp +@@ -4,22 +4,106 @@ + #include + #include + #include ++#include + + namespace xcb { ++ inline static constinit pthread_t g_cache_tid; //incase g_cache could otherwise be accessed by one thread, while it is being deleted by another thread ++ inline static constinit struct cookie_cache_t { ++ xcb_window_t window; ++ std::tuple cached_cookies; ++ std::tuple cached_replies; ++ } g_cache = {}; ++ ++ //Note: this class is currently only meant to be used within GamescopeWSILayer::VkDeviceOverrides::QueuePresentKHR: ++ struct Prefetcher { ++ explicit Prefetcher(xcb_connection_t* connection, const xcb_window_t window) { ++ g_cache = { ++ .window = window, ++ .cached_cookies = { ++ xcb_get_geometry(connection, window), ++ xcb_query_tree(connection, window) ++ } ++ }; ++ g_cache_tid = pthread_self(); ++ } + ++ ~Prefetcher() { ++ g_cache_tid = {}; ++ free(std::get<0>(g_cache.cached_replies)); ++ free(std::get<1>(g_cache.cached_replies)); ++ g_cache.cached_replies = {nullptr,nullptr}; ++ } ++ }; ++ + struct ReplyDeleter { ++ const bool m_bOwning = true; ++ consteval ReplyDeleter(bool bOwning = true) : m_bOwning{bOwning} {} + template + void operator()(T* ptr) const { +- free(const_cast*>(ptr)); ++ if (m_bOwning) ++ free(const_cast*>(ptr)); + } + }; + + template + using Reply = std::unique_ptr; ++ ++ template ++ class XcbFetch { ++ using cookie_f_ptr_t = Cookie_RetType (*)(XcbConn, Args...); ++ using reply_f_ptr_t = Reply_RetType* (*)(XcbConn, Cookie_RetType, xcb_generic_error_t**); ++ ++ const cookie_f_ptr_t m_cookieFunc; ++ const reply_f_ptr_t m_replyFunc; ++ ++ public: ++ consteval XcbFetch(cookie_f_ptr_t cookieFunc, reply_f_ptr_t replyFunc) : m_cookieFunc{cookieFunc}, m_replyFunc{replyFunc} {} ++ ++ inline Reply operator()(XcbConn conn, auto... args) { //have to use auto for argsTwo, since otherwise there'd be a type deduction conflict ++ return Reply { m_replyFunc(conn, m_cookieFunc(conn, args...), nullptr) }; ++ } ++ }; ++ ++ template ++ concept CacheableCookie = std::is_same::value ++ || std::is_same::value; ++ ++ template ++ class XcbFetch { ++ using cookie_f_ptr_t = Cookie_RetType (*)(xcb_connection_t*, xcb_window_t); ++ using reply_f_ptr_t = Reply_RetType* (*)(xcb_connection_t*, Cookie_RetType, xcb_generic_error_t**); ++ ++ const cookie_f_ptr_t m_cookieFunc; ++ const reply_f_ptr_t m_replyFunc; ++ ++ inline Reply getCachedReply(xcb_connection_t* connection) { ++ if (std::get(g_cache.cached_replies) == nullptr) { ++ std::get(g_cache.cached_replies) = m_replyFunc(connection, std::get(g_cache.cached_cookies), nullptr); ++ } + ++ return Reply{std::get(g_cache.cached_replies), ReplyDeleter{false}}; // return 'non-owning' unique_ptr ++ } ++ ++ public: ++ consteval XcbFetch(cookie_f_ptr_t cookieFunc, reply_f_ptr_t replyFunc) : m_cookieFunc{cookieFunc}, m_replyFunc{replyFunc} {} ++ ++ inline Reply operator()(xcb_connection_t* conn, xcb_window_t window) { ++ const bool tryCached = pthread_equal(g_cache_tid, pthread_self()) ++ && g_cache.window == window; ++ if (!tryCached) [[unlikely]] ++ return Reply { m_replyFunc(conn, m_cookieFunc(conn, window), nullptr) }; ++ ++ auto ret = getCachedReply(conn); ++ #if !defined(NDEBUG) || NDEBUG == 0 ++ if (!ret) ++ fprintf(stderr, "[Gamescope WSI] getCachedReply() failed.\n"); ++ #endif ++ return ret; ++ } ++ }; ++ + static std::optional getAtom(xcb_connection_t* connection, std::string_view name) { +- xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, false, name.length(), name.data()); +- auto reply = Reply{ xcb_intern_atom_reply(connection, cookie, nullptr) }; ++ auto reply = XcbFetch{xcb_intern_atom, xcb_intern_atom_reply}(connection, false, name.length(), name.data()); + if (!reply) { + fprintf(stderr, "[Gamescope WSI] Failed to get xcb atom.\n"); + return std::nullopt; +@@ -34,8 +118,7 @@ namespace xcb { + + xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data; + +- xcb_get_property_cookie_t cookie = xcb_get_property(connection, false, screen->root, atom, XCB_ATOM_CARDINAL, 0, sizeof(T) / sizeof(uint32_t)); +- auto reply = Reply{ xcb_get_property_reply(connection, cookie, nullptr) }; ++ auto reply = XcbFetch{xcb_get_property, xcb_get_property_reply}(connection, false, screen->root, atom, XCB_ATOM_CARDINAL, 0, sizeof(T) / sizeof(uint32_t)); + if (!reply) { + fprintf(stderr, "[Gamescope WSI] Failed to read T root window property.\n"); + return std::nullopt; +@@ -61,8 +144,7 @@ namespace xcb { + + static std::optional getToplevelWindow(xcb_connection_t* connection, xcb_window_t window) { + for (;;) { +- xcb_query_tree_cookie_t cookie = xcb_query_tree(connection, window); +- auto reply = Reply{ xcb_query_tree_reply(connection, cookie, nullptr) }; ++ auto reply = XcbFetch{xcb_query_tree, xcb_query_tree_reply}(connection, window); + + if (!reply) { + fprintf(stderr, "[Gamescope WSI] getToplevelWindow: xcb_query_tree failed for window 0x%x.\n", window); +@@ -77,8 +159,7 @@ namespace xcb { + } + + static std::optional getWindowRect(xcb_connection_t* connection, xcb_window_t window) { +- xcb_get_geometry_cookie_t cookie = xcb_get_geometry(connection, window); +- auto reply = Reply{ xcb_get_geometry_reply(connection, cookie, nullptr) }; ++ auto reply = XcbFetch{xcb_get_geometry, xcb_get_geometry_reply}(connection, window); + if (!reply) { + fprintf(stderr, "[Gamescope WSI] getWindowRect: xcb_get_geometry failed for window 0x%x.\n", window); + return std::nullopt; +@@ -112,8 +193,7 @@ namespace xcb { + static std::optional getLargestObscuringChildWindowSize(xcb_connection_t* connection, xcb_window_t window) { + VkExtent2D largestExtent = {}; + +- xcb_query_tree_cookie_t cookie = xcb_query_tree(connection, window); +- auto reply = Reply{ xcb_query_tree_reply(connection, cookie, nullptr) }; ++ auto reply = XcbFetch{xcb_query_tree, xcb_query_tree_reply}(connection, window); + + if (!reply) { + fprintf(stderr, "[Gamescope WSI] getLargestObscuringWindowSize: xcb_query_tree failed for window 0x%x.\n", window); +@@ -130,8 +210,7 @@ namespace xcb { + for (uint32_t i = 0; i < reply->children_len; i++) { + xcb_window_t child = children[i]; + +- xcb_get_window_attributes_cookie_t attributeCookie = xcb_get_window_attributes(connection, child); +- auto attributeReply = Reply{ xcb_get_window_attributes_reply(connection, attributeCookie, nullptr) }; ++ auto attributeReply = XcbFetch{xcb_get_window_attributes, xcb_get_window_attributes_reply}(connection, child); + + const bool obscuring = + attributeReply && + +From 1b59621f4de5c05096d1f279cba2e04264124154 Mon Sep 17 00:00:00 2001 +From: sharkautarch <128002472+sharkautarch@users.noreply.github.com> +Date: Tue, 18 Jun 2024 22:21:23 -0400 +Subject: [PATCH 2/2] WSI: prefetcher: fix issue w/ attempting to prefetch xcb + stuff for pure wayland surfaces + +--- + layer/VkLayer_FROG_gamescope_wsi.cpp | 2 +- + layer/xcb_helpers.hpp | 9 ++++++++- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/layer/VkLayer_FROG_gamescope_wsi.cpp b/layer/VkLayer_FROG_gamescope_wsi.cpp +index f26819a60..ce011dcd7 100644 +--- a/layer/VkLayer_FROG_gamescope_wsi.cpp ++++ b/layer/VkLayer_FROG_gamescope_wsi.cpp +@@ -1234,7 +1234,7 @@ namespace GamescopeWSILayer { + continue; + } + +- xcb::Prefetcher prefetcher(gamescopeSurface->connection, gamescopeSurface->window); ++ auto prefetcher = xcb::Prefetcher::GetPrefetcherIf(!gamescopeSurface->isWayland(), gamescopeSurface->connection, gamescopeSurface->window); + const bool canBypass = gamescopeSurface->canBypassXWayland(); + if (canBypass != gamescopeSwapchain->isBypassingXWayland) + UpdateSwapchainResult(canBypass ? VK_SUBOPTIMAL_KHR : VK_ERROR_OUT_OF_DATE_KHR); +diff --git a/layer/xcb_helpers.hpp b/layer/xcb_helpers.hpp +index 72d0ec092..f26aef38b 100644 +--- a/layer/xcb_helpers.hpp ++++ b/layer/xcb_helpers.hpp +@@ -16,6 +16,13 @@ namespace xcb { + + //Note: this class is currently only meant to be used within GamescopeWSILayer::VkDeviceOverrides::QueuePresentKHR: + struct Prefetcher { ++ static std::optional GetPrefetcherIf(bool bCond, xcb_connection_t* connection, const xcb_window_t window) { ++ if (bCond) ++ return std::optional(std::in_place_t{}, connection, window); ++ ++ return std::nullopt; ++ } ++ + explicit Prefetcher(xcb_connection_t* connection, const xcb_window_t window) { + g_cache = { + .window = window, +@@ -90,7 +97,7 @@ namespace xcb { + inline Reply operator()(xcb_connection_t* conn, xcb_window_t window) { + const bool tryCached = pthread_equal(g_cache_tid, pthread_self()) + && g_cache.window == window; +- if (!tryCached) [[unlikely]] ++ if (!tryCached) + return Reply { m_replyFunc(conn, m_cookieFunc(conn, window), nullptr) }; + + auto ret = getCachedReply(conn); diff --git a/gamescope.spec b/gamescope.spec index fb103ec..aa5d516 100644 --- a/gamescope.spec +++ b/gamescope.spec @@ -14,6 +14,7 @@ URL: https://github.com/ValveSoftware/gamescope # Create stb.pc to satisfy dependency('stb') Source0: stb.pc Patch0: 001-fix-sdl-backend-on-rx580.patch +Patch1: 002-pr-1231.patch BuildRequires: meson >= 0.54.0 BuildRequires: ninja-build