forked from eden-emu/eden
		
	yuzu: integrate gamemode support on linux
This commit is contained in:
		
							parent
							
								
									5a182f4e7c
								
							
						
					
					
						commit
						dfa56765d6
					
				
					 11 changed files with 481 additions and 1 deletions
				
			
		
							
								
								
									
										6
									
								
								externals/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								externals/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							|  | @ -189,6 +189,12 @@ if (ANDROID) | ||||||
|    endif() |    endif() | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
|  | # Gamemode | ||||||
|  | if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") | ||||||
|  |     add_subdirectory(gamemode) | ||||||
|  |     target_include_directories(gamemode PUBLIC gamemode/include) | ||||||
|  | endif() | ||||||
|  | 
 | ||||||
| # Breakpad | # Breakpad | ||||||
| # https://github.com/microsoft/vcpkg/blob/master/ports/breakpad/CMakeLists.txt | # https://github.com/microsoft/vcpkg/blob/master/ports/breakpad/CMakeLists.txt | ||||||
| if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client) | if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client) | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								externals/gamemode/CMakeLists.txt
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								externals/gamemode/CMakeLists.txt
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | ||||||
|  | # SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||||||
|  | # SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  | 
 | ||||||
|  | project(gamemode) | ||||||
|  | 
 | ||||||
|  | add_library(gamemode include/gamemode_client.h) | ||||||
|  | set_target_properties(gamemode PROPERTIES LINKER_LANGUAGE C) | ||||||
							
								
								
									
										379
									
								
								externals/gamemode/include/gamemode_client.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										379
									
								
								externals/gamemode/include/gamemode_client.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,379 @@ | ||||||
|  | // SPDX-FileCopyrightText: Copyright 2017-2019 Feral Interactive
 | ||||||
|  | // SPDX-License-Identifier: BSD-3-Clause
 | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | 
 | ||||||
|  | Copyright (c) 2017-2019, Feral Interactive | ||||||
|  | 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 <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | 
 | ||||||
|  | #include <dlfcn.h> | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | #include <assert.h> | ||||||
|  | 
 | ||||||
|  | #include <sys/types.h> | ||||||
|  | 
 | ||||||
|  | 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_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_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_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
 | ||||||
|  | @ -178,6 +178,8 @@ struct Values { | ||||||
|                                              true, |                                              true, | ||||||
|                                              &use_speed_limit}; |                                              &use_speed_limit}; | ||||||
| 
 | 
 | ||||||
|  |     Setting<bool> enable_gamemode{linkage, false, "enable_gamemode", Category::Core}; | ||||||
|  | 
 | ||||||
|     // Cpu
 |     // Cpu
 | ||||||
|     SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage,           CpuAccuracy::Auto, |     SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage,           CpuAccuracy::Auto, | ||||||
|                                                       CpuAccuracy::Auto, CpuAccuracy::Paranoid, |                                                       CpuAccuracy::Auto, CpuAccuracy::Paranoid, | ||||||
|  |  | ||||||
|  | @ -386,7 +386,7 @@ if (NOT WIN32) | ||||||
|     target_include_directories(yuzu PRIVATE ${Qt${QT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS}) |     target_include_directories(yuzu PRIVATE ${Qt${QT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS}) | ||||||
| endif() | endif() | ||||||
| if (UNIX AND NOT APPLE) | if (UNIX AND NOT APPLE) | ||||||
|     target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::DBus) |     target_link_libraries(yuzu PRIVATE Qt${QT_MAJOR_VERSION}::DBus gamemode) | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| target_compile_definitions(yuzu PRIVATE | target_compile_definitions(yuzu PRIVATE | ||||||
|  |  | ||||||
|  | @ -29,6 +29,9 @@ ConfigureGeneral::ConfigureGeneral(const Core::System& system_, | ||||||
|     if (!Settings::IsConfiguringGlobal()) { |     if (!Settings::IsConfiguringGlobal()) { | ||||||
|         ui->button_reset_defaults->setVisible(false); |         ui->button_reset_defaults->setVisible(false); | ||||||
|     } |     } | ||||||
|  | #ifndef __linux__ | ||||||
|  |     ui->enable_gamemode->setVisible(false); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ConfigureGeneral::~ConfigureGeneral() = default; | ConfigureGeneral::~ConfigureGeneral() = default; | ||||||
|  |  | ||||||
|  | @ -175,6 +175,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { | ||||||
|     INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), QStringLiteral()); |     INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), QStringLiteral()); | ||||||
|     INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"), |     INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"), | ||||||
|            QStringLiteral()); |            QStringLiteral()); | ||||||
|  |     INSERT(UISettings, enable_gamemode, tr("Enable Gamemode"), QStringLiteral()); | ||||||
| 
 | 
 | ||||||
|     // Ui Debugging
 |     // Ui Debugging
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -185,6 +185,10 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef __linux__ | ||||||
|  | #include <gamemode_client.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| constexpr int default_mouse_hide_timeout = 2500; | constexpr int default_mouse_hide_timeout = 2500; | ||||||
| constexpr int default_mouse_center_timeout = 10; | constexpr int default_mouse_center_timeout = 10; | ||||||
| constexpr int default_input_update_timeout = 1; | constexpr int default_input_update_timeout = 1; | ||||||
|  | @ -2126,6 +2130,16 @@ void GMainWindow::OnEmulationStopped() { | ||||||
| 
 | 
 | ||||||
|     discord_rpc->Update(); |     discord_rpc->Update(); | ||||||
| 
 | 
 | ||||||
|  | #ifdef __linux__ | ||||||
|  |     if (UISettings::values.enable_gamemode) { | ||||||
|  |         if (gamemode_request_end() < 0) { | ||||||
|  |             LOG_WARNING(Frontend, "Failed to stop gamemode: {}", gamemode_error_string()); | ||||||
|  |         } else { | ||||||
|  |             LOG_INFO(Frontend, "Stopped gamemode"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     // The emulation is stopped, so closing the window or not does not matter anymore
 |     // The emulation is stopped, so closing the window or not does not matter anymore
 | ||||||
|     disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); |     disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); | ||||||
| 
 | 
 | ||||||
|  | @ -3504,6 +3518,16 @@ void GMainWindow::OnStartGame() { | ||||||
|     play_time_manager->Start(); |     play_time_manager->Start(); | ||||||
| 
 | 
 | ||||||
|     discord_rpc->Update(); |     discord_rpc->Update(); | ||||||
|  | 
 | ||||||
|  | #ifdef __linux__ | ||||||
|  |     if (UISettings::values.enable_gamemode) { | ||||||
|  |         if (gamemode_request_start() < 0) { | ||||||
|  |             LOG_WARNING(Frontend, "Failed to start gamemode: {}", gamemode_error_string()); | ||||||
|  |         } else { | ||||||
|  |             LOG_INFO(Frontend, "Started gamemode"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GMainWindow::OnRestartGame() { | void GMainWindow::OnRestartGame() { | ||||||
|  | @ -3524,6 +3548,16 @@ void GMainWindow::OnPauseGame() { | ||||||
|     play_time_manager->Stop(); |     play_time_manager->Stop(); | ||||||
|     UpdateMenuState(); |     UpdateMenuState(); | ||||||
|     AllowOSSleep(); |     AllowOSSleep(); | ||||||
|  | 
 | ||||||
|  | #ifdef __linux__ | ||||||
|  |     if (UISettings::values.enable_gamemode) { | ||||||
|  |         if (gamemode_request_end() < 0) { | ||||||
|  |             LOG_WARNING(Frontend, "Failed to stop gamemode: {}", gamemode_error_string()); | ||||||
|  |         } else { | ||||||
|  |             LOG_INFO(Frontend, "Stopped gamemode"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GMainWindow::OnPauseContinueGame() { | void GMainWindow::OnPauseContinueGame() { | ||||||
|  | @ -5181,6 +5215,26 @@ void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { | ||||||
|     discord_rpc->Update(); |     discord_rpc->Update(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void GMainWindow::SetGamemodeDisabled([[maybe_unused]] bool state) { | ||||||
|  | #ifdef __linux__ | ||||||
|  |     if (emulation_running) { | ||||||
|  |         if (state) { | ||||||
|  |             if (gamemode_request_end() < 0) { | ||||||
|  |                 LOG_WARNING(Frontend, "Failed to stop gamemode: {}", gamemode_error_string()); | ||||||
|  |             } else { | ||||||
|  |                 LOG_INFO(Frontend, "Stopped gamemode"); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if (gamemode_request_start() < 0) { | ||||||
|  |                 LOG_WARNING(Frontend, "Failed to start gamemode: {}", gamemode_error_string()); | ||||||
|  |             } else { | ||||||
|  |                 LOG_INFO(Frontend, "Started gamemode"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void GMainWindow::changeEvent(QEvent* event) { | void GMainWindow::changeEvent(QEvent* event) { | ||||||
| #ifdef __unix__ | #ifdef __unix__ | ||||||
|     // PaletteChange event appears to only reach so far into the GUI, explicitly asking to
 |     // PaletteChange event appears to only reach so far into the GUI, explicitly asking to
 | ||||||
|  |  | ||||||
|  | @ -140,6 +140,9 @@ struct Values { | ||||||
|                                       Settings::Specialization::Default, |                                       Settings::Specialization::Default, | ||||||
|                                       true, |                                       true, | ||||||
|                                       true}; |                                       true}; | ||||||
|  |     // Gamemode
 | ||||||
|  |     Setting<bool> enable_gamemode{linkage, false, "enable_gamemode", Category::UiGeneral}; | ||||||
|  | 
 | ||||||
|     Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Ui}; |     Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Ui}; | ||||||
| 
 | 
 | ||||||
|     // Discord RPC
 |     // Discord RPC
 | ||||||
|  |  | ||||||
|  | @ -44,6 +44,7 @@ target_link_libraries(yuzu-cmd PRIVATE SDL2::SDL2 Vulkan::Headers) | ||||||
| 
 | 
 | ||||||
| if(UNIX AND NOT APPLE) | if(UNIX AND NOT APPLE) | ||||||
|     install(TARGETS yuzu-cmd) |     install(TARGETS yuzu-cmd) | ||||||
|  |     target_link_libraries(yuzu-cmd PRIVATE gamemode) | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| if(WIN32) | if(WIN32) | ||||||
|  |  | ||||||
|  | @ -63,6 +63,10 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef __linux__ | ||||||
|  | #include <gamemode_client.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| static void PrintHelp(const char* argv0) { | static void PrintHelp(const char* argv0) { | ||||||
|     std::cout << "Usage: " << argv0 |     std::cout << "Usage: " << argv0 | ||||||
|               << " [options] <filename>\n" |               << " [options] <filename>\n" | ||||||
|  | @ -425,6 +429,16 @@ int main(int argc, char** argv) { | ||||||
|         exit(0); |         exit(0); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  | #ifdef __linux__ | ||||||
|  |     if (Settings::values.disable_gamemode) { | ||||||
|  |         if (gamemode_request_start() < 0) { | ||||||
|  |             LOG_WARNING(Frontend, "Failed to start gamemode: {}", gamemode_error_string()); | ||||||
|  |         } else { | ||||||
|  |             LOG_INFO(Frontend, "Started gamemode"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     void(system.Run()); |     void(system.Run()); | ||||||
|     if (system.DebuggerEnabled()) { |     if (system.DebuggerEnabled()) { | ||||||
|         system.InitializeDebugger(); |         system.InitializeDebugger(); | ||||||
|  | @ -436,6 +450,16 @@ int main(int argc, char** argv) { | ||||||
|     void(system.Pause()); |     void(system.Pause()); | ||||||
|     system.ShutdownMainProcess(); |     system.ShutdownMainProcess(); | ||||||
| 
 | 
 | ||||||
|  | #ifdef __linux__ | ||||||
|  |     if (Settings::values.disable_gamemode) { | ||||||
|  |         if (gamemode_request_end() < 0) { | ||||||
|  |             LOG_WARNING(Frontend, "Failed to stop gamemode: {}", gamemode_error_string()); | ||||||
|  |         } else { | ||||||
|  |             LOG_INFO(Frontend, "Stopped gamemode"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     detached_tasks.WaitForAllTasks(); |     detached_tasks.WaitForAllTasks(); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 xcfrg
						xcfrg