From 2aa4791ba052bf207e6740a5402dc2c7b4523ac3 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Thu, 15 Dec 2022 08:02:41 +0000 Subject: [PATCH] layer, wlserver: Implement swapchain feedback --- layer/VkLayer_FROG_gamescope_wsi.cpp | 24 +++++++++++++++++++-- meson.build | 2 +- protocol/gamescope-xwayland.xml | 31 +++++++++++++++++++++++++++- src/wlserver.cpp | 29 +++++++++++++++++++++++++- src/wlserver.hpp | 15 ++++++++++++++ 5 files changed, 96 insertions(+), 5 deletions(-) diff --git a/layer/VkLayer_FROG_gamescope_wsi.cpp b/layer/VkLayer_FROG_gamescope_wsi.cpp index 6ed0162..b9dd7b0 100644 --- a/layer/VkLayer_FROG_gamescope_wsi.cpp +++ b/layer/VkLayer_FROG_gamescope_wsi.cpp @@ -25,6 +25,7 @@ namespace GamescopeWSILayer { VKROOTS_DEFINE_SYNCHRONIZED_MAP_TYPE(GamescopeInstance, VkInstance); struct GamescopeSurfaceData { + VkInstance instance; wl_surface* surface; }; VKROOTS_DEFINE_SYNCHRONIZED_MAP_TYPE(GamescopeSurface, VkSurfaceKHR); @@ -258,6 +259,7 @@ namespace GamescopeWSILayer { printf("Made gamescope surface for xid: 0x%x\n", window_xid); GamescopeSurface::create(*pSurface, GamescopeSurfaceData { + .instance = instance, .surface = waylandSurface, }); @@ -311,7 +313,7 @@ namespace GamescopeWSILayer { wl_registry_bind(registry, name, &wl_compositor_interface, version)); } else if (!std::strcmp(interface, gamescope_xwayland_interface.name)) { instance->gamescope = reinterpret_cast( - wl_registry_bind(registry, name, &gamescope_xwayland_interface, 1)); + wl_registry_bind(registry, name, &gamescope_xwayland_interface, version)); } }, .global_remove = [](void* data, wl_registry* registry, uint32_t name) { @@ -351,6 +353,23 @@ namespace GamescopeWSILayer { GamescopeSwapchain::create(*pSwapchain, GamescopeSwapchainData{ .surface = pCreateInfo->surface, }); + + auto gamescopeInstance = GamescopeInstance::get((*gamescopeSurface)->instance); + if (gamescopeInstance) { + uint32_t imageCount = 0; + pDispatch->GetSwapchainImagesKHR(device, *pSwapchain, &imageCount, nullptr); + + gamescope_xwayland_swapchain_feedback( + (*gamescopeInstance)->gamescope, + (*gamescopeSurface)->surface, + imageCount, + uint32_t(pCreateInfo->imageFormat), + uint32_t(pCreateInfo->imageColorSpace), + uint32_t(pCreateInfo->compositeAlpha), + uint32_t(pCreateInfo->preTransform), + uint32_t(pCreateInfo->presentMode), + uint32_t(pCreateInfo->clipped)); + } } return res; } @@ -369,7 +388,8 @@ namespace GamescopeWSILayer { VKROOTS_DEFINE_LAYER_INTERFACES(GamescopeWSILayer::VkInstanceOverrides, vkroots::NoOverrides, - vkroots::NoOverrides); + GamescopeWSILayer::VkDeviceOverrides); VKROOTS_IMPLEMENT_SYNCHRONIZED_MAP_TYPE(GamescopeWSILayer::GamescopeInstance); VKROOTS_IMPLEMENT_SYNCHRONIZED_MAP_TYPE(GamescopeWSILayer::GamescopeSurface); +VKROOTS_IMPLEMENT_SYNCHRONIZED_MAP_TYPE(GamescopeWSILayer::GamescopeSwapchain); diff --git a/meson.build b/meson.build index d8f8615..b24b42c 100644 --- a/meson.build +++ b/meson.build @@ -4,7 +4,7 @@ project( 'cpp', meson_version: '>=0.58.0', default_options: [ - 'cpp_std=c++14', + 'cpp_std=c++17', 'warning_level=2', 'force_fallback_for=wlroots,libliftoff', ], diff --git a/protocol/gamescope-xwayland.xml b/protocol/gamescope-xwayland.xml index d0bbfcc..4b73e05 100644 --- a/protocol/gamescope-xwayland.xml +++ b/protocol/gamescope-xwayland.xml @@ -29,7 +29,7 @@ it. - + @@ -46,5 +46,34 @@ + + + + Provide swapchain feedback to the compositor. + + This is what the useless tearing protocol should have been. + Absolutely not enough information in the final protocol to do what we want for SteamOS -- + which is have the Allow Tearing toggle apply to *both* Mailbox + Immediate and NOT fifo, + essentially acting as an override for tearing on/off for games. + The upstream protocol is very useless for our usecase here. + + Provides image count ahead of time instead of needing to try and calculate it from + an initial stall if we are doing low latency. + + Provides colorspace info for us to do HDR for both HDR10 PQ and scRGB. + The upstream HDR efforts seem to have no interest in supporting scRGB but we *need* that so /shrug + We can do it here now! Yipee! + + Swapchain feedback solves so many problems! :D + + + + + + + + + + diff --git a/src/wlserver.cpp b/src/wlserver.cpp index d1abd35..bfa54a0 100644 --- a/src/wlserver.cpp +++ b/src/wlserver.cpp @@ -515,6 +515,32 @@ static void gamescope_xwayland_handle_override_window_content( struct wl_client server->handle_override_window_content(client, resource, surface_resource, x11_window); } +static void gamescope_xwayland_handle_swapchain_feedback( struct wl_client *client, struct wl_resource *resource, + struct wl_resource *surface_resource, + uint32_t image_count, + uint32_t vk_format, + uint32_t vk_colorspace, + uint32_t vk_composite_alpha, + uint32_t vk_pre_transform, + uint32_t vk_present_mode, + uint32_t vk_clipped) +{ + struct wlr_surface *surface = wlr_surface_from_resource( surface_resource ); + wlserver_wl_surface_info *wl_info = get_wl_surface_info( surface ); + if ( wl_info ) + { + wl_info->swapchain_feedback = wlserver_vk_swapchain_feedback { + .image_count = image_count, + .vk_format = VkFormat(vk_format), + .vk_colorspace = VkColorSpaceKHR(vk_colorspace), + .vk_composite_alpha = VkCompositeAlphaFlagBitsKHR(vk_composite_alpha), + .vk_pre_transform = VkSurfaceTransformFlagBitsKHR(vk_pre_transform), + .vk_present_mode = VkPresentModeKHR(vk_present_mode), + .vk_clipped = VkBool32(vk_clipped), + }; + } +} + static void gamescope_xwayland_handle_destroy( struct wl_client *client, struct wl_resource *resource ) { wl_resource_destroy( resource ); @@ -523,6 +549,7 @@ static void gamescope_xwayland_handle_destroy( struct wl_client *client, struct static const struct gamescope_xwayland_interface gamescope_xwayland_impl = { .destroy = gamescope_xwayland_handle_destroy, .override_window_content = gamescope_xwayland_handle_override_window_content, + .swapchain_feedback = gamescope_xwayland_handle_swapchain_feedback, }; static void gamescope_xwayland_bind( struct wl_client *client, void *data, uint32_t version, uint32_t id ) @@ -533,7 +560,7 @@ static void gamescope_xwayland_bind( struct wl_client *client, void *data, uint3 static void create_gamescope_xwayland( void ) { - uint32_t version = 1; + uint32_t version = 2; wl_global_create( wlserver.display, &gamescope_xwayland_interface, version, NULL, gamescope_xwayland_bind ); } diff --git a/src/wlserver.hpp b/src/wlserver.hpp index af69aca..7e768d1 100644 --- a/src/wlserver.hpp +++ b/src/wlserver.hpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #define WLSERVER_BUTTON_COUNT 4 @@ -199,6 +201,17 @@ struct wlserver_x11_surface_info gamescope_xwayland_server_t *xwayland_server; }; +struct wlserver_vk_swapchain_feedback +{ + uint32_t image_count; + VkFormat vk_format; + VkColorSpaceKHR vk_colorspace; + VkCompositeAlphaFlagBitsKHR vk_composite_alpha; + VkSurfaceTransformFlagBitsKHR vk_pre_transform; + VkPresentModeKHR vk_present_mode; + VkBool32 vk_clipped; +}; + struct wlserver_wl_surface_info { wlserver_x11_surface_info *x11_surface = nullptr; @@ -207,6 +220,8 @@ struct wlserver_wl_surface_info struct wl_listener destroy; uint32_t presentation_hint = 0; + + std::optional swapchain_feedback = std::nullopt; }; void wlserver_x11_surface_info_init( struct wlserver_x11_surface_info *surf, gamescope_xwayland_server_t *server, uint32_t x11_id );