diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e95967b0a..9238a40924 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -320,7 +320,6 @@ endif() if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX)) set(HAS_NCE 1) add_compile_definitions(HAS_NCE=1) - find_package(oaknut 2.0.1) endif() if (YUZU_ROOM) @@ -546,10 +545,6 @@ else() find_package(Catch2 3.0.1 REQUIRED) endif() - if (PLATFORM_LINUX OR ANDROID) - find_package(gamemode 1.7 MODULE) - endif() - if (ENABLE_OPENSSL) find_package(OpenSSL 1.1.1 REQUIRED) endif() @@ -673,6 +668,7 @@ add_subdirectory(externals) # pass targets from externals find_package(libusb) find_package(VulkanMemoryAllocator) +find_package(gamemode) if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) find_package(xbyak) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 4c11104de2..2d0d5a7401 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -140,9 +140,11 @@ if (ANDROID AND ARCHITECTURE_arm64) AddJsonPackage(libadrenotools) endif() -if (NOT TARGET gamemode::headers) +AddJsonPackage(gamemode) + +if (gamemode_ADDED) add_library(gamemode INTERFACE) - target_include_directories(gamemode INTERFACE gamemode) + target_include_directories(gamemode INTERFACE ${gamemode_SOURCE_DIR}) add_library(gamemode::headers ALIAS gamemode) endif() diff --git a/externals/cpmfile.json b/externals/cpmfile.json index dcafc8f97d..6758957550 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -70,5 +70,12 @@ "sha": "73f3cbb237", "hash": "c08c03063938339d61392b687562909c1a92615b6ef39ec8df19ea472aa6b6478e70d7d5e33d4a27b5d23f7806daf57fe1bacb8124c8a945c918c7663a9e8532", "find_args": "CONFIG" + }, + "gamemode": { + "repo": "FeralInteractive/gamemode", + "sha": "ce6fe122f3", + "hash": "ff62f3c8638528e7afb7336f7c8f9940453d2871446c36f639e3114cc8b5c7f9a817ed209c45e0e061793fc3ee9ba35a4b05140d39f5175c2aacfa0703fddfc4", + "version": "1.7", + "find_args": "MODULE" } } diff --git a/externals/gamemode/gamemode_client.h b/externals/gamemode/gamemode_client.h deleted file mode 100644 index bfbf61c0c2..0000000000 --- a/externals/gamemode/gamemode_client.h +++ /dev/null @@ -1,402 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -/* - -Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Feral Interactive nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - - */ -#ifndef CLIENT_GAMEMODE_H -#define CLIENT_GAMEMODE_H -/* - * GameMode supports the following client functions - * Requests are refcounted in the daemon - * - * int gamemode_request_start() - Request gamemode starts - * 0 if the request was sent successfully - * -1 if the request failed - * - * int gamemode_request_end() - Request gamemode ends - * 0 if the request was sent successfully - * -1 if the request failed - * - * GAMEMODE_AUTO can be defined to make the above two functions apply during static init and - * destruction, as appropriate. In this configuration, errors will be printed to stderr - * - * int gamemode_query_status() - Query the current status of gamemode - * 0 if gamemode is inactive - * 1 if gamemode is active - * 2 if gamemode is active and this client is registered - * -1 if the query failed - * - * int gamemode_request_start_for(pid_t pid) - Request gamemode starts for another process - * 0 if the request was sent successfully - * -1 if the request failed - * -2 if the request was rejected - * - * int gamemode_request_end_for(pid_t pid) - Request gamemode ends for another process - * 0 if the request was sent successfully - * -1 if the request failed - * -2 if the request was rejected - * - * int gamemode_query_status_for(pid_t pid) - Query status of gamemode for another process - * 0 if gamemode is inactive - * 1 if gamemode is active - * 2 if gamemode is active and this client is registered - * -1 if the query failed - * - * const char* gamemode_error_string() - Get an error string - * returns a string describing any of the above errors - * - * Note: All the above requests can be blocking - dbus requests can and will block while the daemon - * handles the request. It is not recommended to make these calls in performance critical code - */ - -#include -#include - -#include -#include - -#include - -#include - -static char internal_gamemode_client_error_string[512] = { 0 }; - -/** - * Load libgamemode dynamically to dislodge us from most dependencies. - * This allows clients to link and/or use this regardless of runtime. - * See SDL2 for an example of the reasoning behind this in terms of - * dynamic versioning as well. - */ -static volatile int internal_libgamemode_loaded = 1; - -/* Typedefs for the functions to load */ -typedef int (*api_call_return_int)(void); -typedef const char *(*api_call_return_cstring)(void); -typedef int (*api_call_pid_return_int)(pid_t); - -/* Storage for functors */ -static api_call_return_int REAL_internal_gamemode_request_start = NULL; -static api_call_return_int REAL_internal_gamemode_request_end = NULL; -static api_call_return_int REAL_internal_gamemode_query_status = NULL; -static api_call_return_int REAL_internal_gamemode_request_restart = NULL; -static api_call_return_cstring REAL_internal_gamemode_error_string = NULL; -static api_call_pid_return_int REAL_internal_gamemode_request_start_for = NULL; -static api_call_pid_return_int REAL_internal_gamemode_request_end_for = NULL; -static api_call_pid_return_int REAL_internal_gamemode_query_status_for = NULL; - -/** - * Internal helper to perform the symbol binding safely. - * - * Returns 0 on success and -1 on failure - */ -__attribute__((always_inline)) static inline int internal_bind_libgamemode_symbol( - void *handle, const char *name, void **out_func, size_t func_size, bool required) -{ - void *symbol_lookup = NULL; - char *dl_error = NULL; - - /* Safely look up the symbol */ - symbol_lookup = dlsym(handle, name); - dl_error = dlerror(); - if (required && (dl_error || !symbol_lookup)) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "dlsym failed - %s", - dl_error); - return -1; - } - - /* Have the symbol correctly, copy it to make it usable */ - memcpy(out_func, &symbol_lookup, func_size); - return 0; -} - -/** - * Loads libgamemode and needed functions - * - * Returns 0 on success and -1 on failure - */ -__attribute__((always_inline)) static inline int internal_load_libgamemode(void) -{ - /* We start at 1, 0 is a success and -1 is a fail */ - if (internal_libgamemode_loaded != 1) { - return internal_libgamemode_loaded; - } - - /* Anonymous struct type to define our bindings */ - struct binding { - const char *name; - void **functor; - size_t func_size; - bool required; - } bindings[] = { - { "real_gamemode_request_start", - (void **)&REAL_internal_gamemode_request_start, - sizeof(REAL_internal_gamemode_request_start), - true }, - { "real_gamemode_request_end", - (void **)&REAL_internal_gamemode_request_end, - sizeof(REAL_internal_gamemode_request_end), - true }, - { "real_gamemode_query_status", - (void **)&REAL_internal_gamemode_query_status, - sizeof(REAL_internal_gamemode_query_status), - false }, - { "real_gamemode_request_restart", - (void **)&REAL_internal_gamemode_request_restart, - sizeof(REAL_internal_gamemode_request_restart), - false }, - { "real_gamemode_error_string", - (void **)&REAL_internal_gamemode_error_string, - sizeof(REAL_internal_gamemode_error_string), - true }, - { "real_gamemode_request_start_for", - (void **)&REAL_internal_gamemode_request_start_for, - sizeof(REAL_internal_gamemode_request_start_for), - false }, - { "real_gamemode_request_end_for", - (void **)&REAL_internal_gamemode_request_end_for, - sizeof(REAL_internal_gamemode_request_end_for), - false }, - { "real_gamemode_query_status_for", - (void **)&REAL_internal_gamemode_query_status_for, - sizeof(REAL_internal_gamemode_query_status_for), - false }, - }; - - void *libgamemode = NULL; - - /* Try and load libgamemode */ - libgamemode = dlopen("libgamemode.so.0", RTLD_NOW); - if (!libgamemode) { - /* Attempt to load unversioned library for compatibility with older - * versions (as of writing, there are no ABI changes between the two - - * this may need to change if ever ABI-breaking changes are made) */ - libgamemode = dlopen("libgamemode.so", RTLD_NOW); - if (!libgamemode) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "dlopen failed - %s", - dlerror()); - internal_libgamemode_loaded = -1; - return -1; - } - } - - /* Attempt to bind all symbols */ - for (size_t i = 0; i < sizeof(bindings) / sizeof(bindings[0]); i++) { - struct binding *binder = &bindings[i]; - - if (internal_bind_libgamemode_symbol(libgamemode, - binder->name, - binder->functor, - binder->func_size, - binder->required)) { - internal_libgamemode_loaded = -1; - return -1; - }; - } - - /* Success */ - internal_libgamemode_loaded = 0; - return 0; -} - -/** - * Redirect to the real libgamemode - */ -__attribute__((always_inline)) static inline const char *gamemode_error_string(void) -{ - /* If we fail to load the system gamemode, or we have an error string already, return our error - * string instead of diverting to the system version */ - if (internal_load_libgamemode() < 0 || internal_gamemode_client_error_string[0] != '\0') { - return internal_gamemode_client_error_string; - } - - /* Assert for static analyser that the function is not NULL */ - assert(REAL_internal_gamemode_error_string != NULL); - - return REAL_internal_gamemode_error_string(); -} - -/** - * Redirect to the real libgamemode - * Allow automatically requesting game mode - * Also prints errors as they happen. - */ -#ifdef GAMEMODE_AUTO -__attribute__((constructor)) -#else -__attribute__((always_inline)) static inline -#endif -int gamemode_request_start(void) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { -#ifdef GAMEMODE_AUTO - fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); -#endif - return -1; - } - - /* Assert for static analyser that the function is not NULL */ - assert(REAL_internal_gamemode_request_start != NULL); - - if (REAL_internal_gamemode_request_start() < 0) { -#ifdef GAMEMODE_AUTO - fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); -#endif - return -1; - } - - return 0; -} - -/* Redirect to the real libgamemode */ -#ifdef GAMEMODE_AUTO -__attribute__((destructor)) -#else -__attribute__((always_inline)) static inline -#endif -int gamemode_request_end(void) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { -#ifdef GAMEMODE_AUTO - fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); -#endif - return -1; - } - - /* Assert for static analyser that the function is not NULL */ - assert(REAL_internal_gamemode_request_end != NULL); - - if (REAL_internal_gamemode_request_end() < 0) { -#ifdef GAMEMODE_AUTO - fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); -#endif - return -1; - } - - return 0; -} - -/* Redirect to the real libgamemode */ -__attribute__((always_inline)) static inline int gamemode_query_status(void) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { - return -1; - } - - if (REAL_internal_gamemode_query_status == NULL) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "gamemode_query_status missing (older host?)"); - return -1; - } - - return REAL_internal_gamemode_query_status(); -} - -/* Redirect to the real libgamemode */ -__attribute__((always_inline)) static inline int gamemode_request_restart(void) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { - return -1; - } - - if (REAL_internal_gamemode_request_restart == NULL) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "gamemode_request_restart missing (older host?)"); - return -1; - } - - return REAL_internal_gamemode_request_restart(); -} - -/* Redirect to the real libgamemode */ -__attribute__((always_inline)) static inline int gamemode_request_start_for(pid_t pid) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { - return -1; - } - - if (REAL_internal_gamemode_request_start_for == NULL) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "gamemode_request_start_for missing (older host?)"); - return -1; - } - - return REAL_internal_gamemode_request_start_for(pid); -} - -/* Redirect to the real libgamemode */ -__attribute__((always_inline)) static inline int gamemode_request_end_for(pid_t pid) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { - return -1; - } - - if (REAL_internal_gamemode_request_end_for == NULL) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "gamemode_request_end_for missing (older host?)"); - return -1; - } - - return REAL_internal_gamemode_request_end_for(pid); -} - -/* Redirect to the real libgamemode */ -__attribute__((always_inline)) static inline int gamemode_query_status_for(pid_t pid) -{ - /* Need to load gamemode */ - if (internal_load_libgamemode() < 0) { - return -1; - } - - if (REAL_internal_gamemode_query_status_for == NULL) { - snprintf(internal_gamemode_client_error_string, - sizeof(internal_gamemode_client_error_string), - "gamemode_query_status_for missing (older host?)"); - return -1; - } - - return REAL_internal_gamemode_query_status_for(pid); -} - -#endif // CLIENT_GAMEMODE_H