diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c index 11bf647..ffa3a02 100644 --- a/src/loader/loader_dri3_helper.c +++ b/src/loader/loader_dri3_helper.c @@ -37,13 +37,14 @@ #include "loader_dri_helper.h" #include "loader_dri3_helper.h" #include "util/macros.h" +#include "util/simple_mtx.h" #include "drm-uapi/drm_fourcc.h" /** * A cached blit context. */ struct loader_dri3_blit_context { - mtx_t mtx; + simple_mtx_t mtx; __DRIcontext *ctx; __DRIscreen *cur_screen; const __DRIcoreExtension *core; @@ -51,7 +52,7 @@ struct loader_dri3_blit_context { /* For simplicity we maintain the cache only for a single screen at a time */ static struct loader_dri3_blit_context blit_context = { - _MTX_INITIALIZER_NP, NULL + SIMPLE_MTX_INITIALIZER, NULL }; static void @@ -162,7 +163,7 @@ static bool loader_dri3_have_image_blit(const struct loader_dri3_drawable *draw) static __DRIcontext * loader_dri3_blit_context_get(struct loader_dri3_drawable *draw) { - mtx_lock(&blit_context.mtx); + simple_mtx_lock(&blit_context.mtx); if (blit_context.ctx && blit_context.cur_screen != draw->dri_screen_render_gpu) { blit_context.core->destroyContext(blit_context.ctx); @@ -186,7 +187,7 @@ loader_dri3_blit_context_get(struct loader_dri3_drawable *draw) static void loader_dri3_blit_context_put(void) { - mtx_unlock(&blit_context.mtx); + simple_mtx_unlock(&blit_context.mtx); } /** @@ -288,6 +289,30 @@ dri3_update_max_num_back(struct loader_dri3_drawable *draw) } } +static unsigned +gamescope_swapchain_override() +{ + const char *path = getenv("GAMESCOPE_LIMITER_FILE"); + if (!path) + return 0; + + static simple_mtx_t mtx = SIMPLE_MTX_INITIALIZER; + static int fd = -1; + + simple_mtx_lock(&mtx); + if (fd < 0) { + fd = open(path, O_RDONLY); + } + simple_mtx_unlock(&mtx); + + if (fd < 0) + return 0; + + uint32_t override_value = 0; + pread(fd, &override_value, sizeof(override_value), 0); + return override_value; +} + void loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval) { @@ -302,10 +327,12 @@ loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval) * PS. changing from value A to B and A < B won't cause swap out of order but * may still gets wrong target_msc value at the beginning. */ - if (draw->swap_interval != interval) + if (draw->orig_swap_interval != interval) loader_dri3_swapbuffer_barrier(draw); - draw->swap_interval = interval; + draw->orig_swap_interval = interval; + if (gamescope_swapchain_override() != 1) + draw->swap_interval = interval; } static void @@ -434,6 +461,12 @@ loader_dri3_drawable_init(xcb_connection_t *conn, if (!draw->adaptive_sync) set_adaptive_sync_property(conn, draw->drawable, false); + draw->orig_swap_interval = draw->swap_interval; + + unsigned gamescope_override = gamescope_swapchain_override(); + if (gamescope_override == 1) + draw->swap_interval = 1; + draw->swap_interval = dri_get_initial_swap_interval(draw->dri_screen_render_gpu, draw->ext->config); @@ -1091,6 +1124,12 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw, if (draw->type == LOADER_DRI3_DRAWABLE_WINDOW) { dri3_fence_reset(draw->conn, back); + unsigned gamescope_override = gamescope_swapchain_override(); + if (gamescope_override == 1) + draw->swap_interval = 1; + else + draw->swap_interval = draw->orig_swap_interval; + /* Compute when we want the frame shown by taking the last known * successful MSC and adding in a swap interval for each outstanding swap * request. target_msc=divisor=remainder=0 means "Use glXSwapBuffers() @@ -2357,12 +2396,12 @@ loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw) void loader_dri3_close_screen(__DRIscreen *dri_screen) { - mtx_lock(&blit_context.mtx); + simple_mtx_lock(&blit_context.mtx); if (blit_context.ctx && blit_context.cur_screen == dri_screen) { blit_context.core->destroyContext(blit_context.ctx); blit_context.ctx = NULL; } - mtx_unlock(&blit_context.mtx); + simple_mtx_unlock(&blit_context.mtx); } /** diff --git a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h index 1fd340b..b8f5eaa 100644 --- a/src/loader/loader_dri3_helper.h +++ b/src/loader/loader_dri3_helper.h @@ -178,6 +178,7 @@ struct loader_dri3_drawable { bool block_on_depleted_buffers; bool queries_buffer_age; int swap_interval; + int orig_swap_interval; struct loader_dri3_extensions *ext; const struct loader_dri3_vtable *vtable; diff --git a/src/loader/meson.build b/src/loader/meson.build index 81779a3..18c9fd9 100644 --- a/src/loader/meson.build +++ b/src/loader/meson.build @@ -28,7 +28,7 @@ if with_platform_x11 and with_dri3 include_directories : [inc_include, inc_src], dependencies : [ dep_libdrm, dep_xcb_dri3, dep_xcb_present, dep_xcb_sync, dep_xshmfence, - dep_xcb_xfixes, + dep_xcb_xfixes, dep_xcb_xrandr, idep_mesautil ], build_by_default : false, ) diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c index a423559..5ed89cb 100644 --- a/src/vulkan/wsi/wsi_common_x11.c +++ b/src/vulkan/wsi/wsi_common_x11.c @@ -42,6 +42,7 @@ #include "util/hash_table.h" #include "util/os_file.h" #include "util/os_time.h" +#include "util/simple_mtx.h" #include "util/u_debug.h" #include "util/u_thread.h" #include "util/xmlconfig.h" @@ -198,6 +199,30 @@ wsi_x11_detect_xwayland(xcb_connection_t *conn, return is_xwayland; } +static unsigned +gamescope_swapchain_override() +{ + const char *path = getenv("GAMESCOPE_LIMITER_FILE"); + if (!path) + return 0; + + static simple_mtx_t mtx = SIMPLE_MTX_INITIALIZER; + static int fd = -1; + + simple_mtx_lock(&mtx); + if (fd < 0) { + fd = open(path, O_RDONLY); + } + simple_mtx_unlock(&mtx); + + if (fd < 0) + return 0; + + uint32_t override_value = 0; + pread(fd, &override_value, sizeof(override_value), 0); + return override_value; +} + static struct wsi_x11_connection * wsi_x11_connection_create(struct wsi_device *wsi_dev, xcb_connection_t *conn) @@ -1074,6 +1099,8 @@ struct x11_swapchain { /* Total number of images returned to application in AcquireNextImage. */ uint64_t present_poll_acquire_count; + VkPresentModeKHR orig_present_mode; + struct x11_image images[0]; }; VK_DEFINE_NONDISP_HANDLE_CASTS(x11_swapchain, base.base, VkSwapchainKHR, @@ -1802,6 +1829,12 @@ x11_queue_present(struct wsi_swapchain *anv_chain, if (chain->status < 0) return chain->status; + unsigned gamescope_override = gamescope_swapchain_override(); + if ((gamescope_override == 1 && chain->base.present_mode != VK_PRESENT_MODE_FIFO_KHR) || + (gamescope_override != 1 && chain->base.present_mode != chain->orig_present_mode)) { + return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR); + } + if (damage && damage->pRectangles && damage->rectangleCount > 0 && damage->rectangleCount <= MAX_DAMAGE_RECTS) { xcb_rectangle_t rects[MAX_DAMAGE_RECTS]; @@ -2554,6 +2587,10 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, xcb_void_cookie_t cookie; VkResult result; VkPresentModeKHR present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo); + VkPresentModeKHR orig_present_mode = present_mode; + + if (gamescope_swapchain_override() == 1) + present_mode = VK_PRESENT_MODE_FIFO_KHR; assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); @@ -2666,6 +2703,7 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, chain->base.wait_for_present = x11_wait_for_present; chain->base.release_images = x11_release_images; chain->base.present_mode = present_mode; + chain->orig_present_mode = orig_present_mode; chain->base.image_count = num_images; chain->conn = conn; chain->window = window;