-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
79632f0
commit fc91389
Showing
2 changed files
with
240 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
From ab115896be1a448bde0eb7673c26300ea4ca5040 Mon Sep 17 00:00:00 2001 | ||
From: sharkautarch <[email protected]> | ||
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 <xcb/composite.h> | ||
#include <cstdio> | ||
#include <optional> | ||
+#include <pthread.h> | ||
|
||
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<xcb_get_geometry_cookie_t, xcb_query_tree_cookie_t> cached_cookies; | ||
+ std::tuple<xcb_get_geometry_reply_t*, xcb_query_tree_reply_t*> 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 <typename T> | ||
void operator()(T* ptr) const { | ||
- free(const_cast<std::remove_const_t<T>*>(ptr)); | ||
+ if (m_bOwning) | ||
+ free(const_cast<std::remove_const_t<T>*>(ptr)); | ||
} | ||
}; | ||
|
||
template <typename T> | ||
using Reply = std::unique_ptr<T, ReplyDeleter>; | ||
+ | ||
+ template <typename Cookie_RetType, typename Reply_RetType, typename XcbConn=xcb_connection_t*, typename... Args> | ||
+ 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<Reply_RetType> operator()(XcbConn conn, auto... args) { //have to use auto for argsTwo, since otherwise there'd be a type deduction conflict | ||
+ return Reply<Reply_RetType> { m_replyFunc(conn, m_cookieFunc(conn, args...), nullptr) }; | ||
+ } | ||
+ }; | ||
+ | ||
+ template <typename CookieType> | ||
+ concept CacheableCookie = std::is_same<CookieType, xcb_get_geometry_cookie_t>::value | ||
+ || std::is_same<CookieType, xcb_query_tree_cookie_t>::value; | ||
+ | ||
+ template <CacheableCookie Cookie_RetType, typename Reply_RetType> | ||
+ class XcbFetch<Cookie_RetType, Reply_RetType, xcb_connection_t*, xcb_window_t> { | ||
+ 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<Reply_RetType> getCachedReply(xcb_connection_t* connection) { | ||
+ if (std::get<Reply_RetType*>(g_cache.cached_replies) == nullptr) { | ||
+ std::get<Reply_RetType*>(g_cache.cached_replies) = m_replyFunc(connection, std::get<Cookie_RetType>(g_cache.cached_cookies), nullptr); | ||
+ } | ||
|
||
+ return Reply<Reply_RetType>{std::get<Reply_RetType*>(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<Reply_RetType> 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<Reply_RetType> { 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<xcb_atom_t> 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_t>{ 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_t>{ 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<xcb_window_t> 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_t>{ 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<VkRect2D> 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_t>{ 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<VkExtent2D> 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_t>{ 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_t>{ 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 <[email protected]> | ||
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<Prefetcher> GetPrefetcherIf(bool bCond, xcb_connection_t* connection, const xcb_window_t window) { | ||
+ if (bCond) | ||
+ return std::optional<Prefetcher>(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<Reply_RetType> 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<Reply_RetType> { m_replyFunc(conn, m_cookieFunc(conn, window), nullptr) }; | ||
|
||
auto ret = getCachedReply(conn); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters