diff --git a/daemon/gamemode-gpu.c b/daemon/gamemode-gpu.c new file mode 100644 index 0000000..bfd4fa9 --- /dev/null +++ b/daemon/gamemode-gpu.c @@ -0,0 +1,139 @@ + +/* + +Copyright (c) 2017-2018, 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. + + */ + +#define _GNU_SOURCE + +#include "gamemode.h" +#include "helpers.h" +#include "logging.h" + +// TODO +// Gather GPU type and information +// Allow configuration file specifying of gpu info +// Apply Nvidia GPU settings (CoolBits will be needed) +// Apply AMD GPU settings (Will need user changing pwm1_enable) +// Intel? +// Provide documentation on optimisations + +/* Enums for GPU vendors */ +enum GPUVendor { + Vendor_Invalid = 0, + Vendor_NVIDIA = 0x10de, + Vendor_AMD = 0x1002, + Vendor_Intel = 0x8086 +}; + +/* Storage for static GPU info gathered at start */ +struct GameModeGPUInfo { + enum GPUVendor vendor; + int device; /* path to device, ie. /sys/class/drm/card#/ */ +}; + +/** + * Applies or removes Nvidia optimisations + */ +static int apply_gpu_nvidia(bool apply) +{ + // Running these commands: + // nvidia-settings -a '[gpu:0]/GPUMemoryTransferRateOffset[3]=1400' + // nvidia-settings -a '[gpu:0]/GPUGraphicsClockOffset[3]=50' + if (apply) { + } else { + } + + return 0; +} + +/** + * Applies or removes AMD optimisations + */ +static int apply_gpu_amd(bool apply) +{ + // We'll want to set both the following: + // core: device/pp_sclk_od (0%+ additional) + // mem: device/pp_mclk_od (0%+ additional) + // Guide from https://www.maketecheasier.com/overclock-amd-gpu-linux/ + if (apply) { + } else { + } + + return 0; +} + +/** + * Attempts to identify the current in use GPU information + */ +int game_mode_identify_gpu(GameModeGPUInfo **info) +{ + int status = 0; + + /* Verify input, this is programmer error */ + if (!info || *info) + FATAL_ERROR("Invalid GameModeGPUInfo passed to %s", __func__); + + /* Create the context */ + GameModeGPUInfo *new_info = malloc(sizeof(GameModeGPUInfo)); + memset(new_info, 0, sizeof(GameModeGPUInfo)); + + // TODO: Fill in the GPU info + + /* Give back the new gpu info */ + *info = new_info; + + return status; +} + +/* Simply used to free the GPU info object */ +void game_mode_free_gpu(GameModeGPUInfo **info) +{ + /* Simply free the object */ + free(*info); + *info = NULL; +} + +/** + * Applies GPU optimisations when gamemode is active and removes them after + */ +int game_mode_apply_gpu(const GameModeGPUInfo *info, bool apply) +{ + switch (info->vendor) { + case Vendor_NVIDIA: + return apply_gpu_nvidia(apply); + case Vendor_AMD: + return apply_gpu_amd(apply); + default: + break; + } + + /* Unsupported GPU vendor, do nothing */ + return 0; +} diff --git a/daemon/gamemode.c b/daemon/gamemode.c index 8c0f3a4..f1479dc 100644 --- a/daemon/gamemode.c +++ b/daemon/gamemode.c @@ -63,6 +63,8 @@ struct GameModeContext { char initial_cpu_mode[64]; /**config = config_create(); config_init(self->config); + /* Grab the current GPU */ + game_mode_identify_gpu(&self->gpu_info); + pthread_rwlock_init(&self->rwlock, NULL); pthread_mutex_init(&self->reaper.mutex, NULL); pthread_cond_init(&self->reaper.condition, NULL); @@ -144,6 +149,9 @@ void game_mode_context_destroy(GameModeContext *self) pthread_cond_destroy(&self->reaper.condition); pthread_mutex_destroy(&self->reaper.mutex); + /* Destroy the gpu object */ + game_mode_free_gpu(&self->gpu_info); + /* Destroy the config object */ config_destroy(self->config); @@ -200,6 +208,9 @@ static void game_mode_context_enter(GameModeContext *self) /* Inhibit the screensaver */ if (config_get_inhibit_screensaver(self->config)) game_mode_inhibit_screensaver(true); + + /* Apply GPU optimisations */ + game_mode_apply_gpu(self->gpu_info, true); } /** @@ -213,6 +224,9 @@ static void game_mode_context_leave(GameModeContext *self) LOG_MSG("Leaving Game Mode...\n"); sd_notifyf(0, "STATUS=%sGameMode is currently deactivated.%s\n", "\x1B[1;36m", "\x1B[0m"); + /* Remove GPU optimisations */ + game_mode_apply_gpu(self->gpu_info, false); + /* UnInhibit the screensaver */ if (config_get_inhibit_screensaver(self->config)) game_mode_inhibit_screensaver(false); diff --git a/daemon/gamemode.h b/daemon/gamemode.h index 337c95f..6304e2f 100644 --- a/daemon/gamemode.h +++ b/daemon/gamemode.h @@ -136,3 +136,11 @@ char *game_mode_resolve_wine_preloader(const pid_t pid); * Provides a test suite to verify gamemode behaviour */ int game_mode_run_client_tests(void); + +/** gamemode-gpu.c + * Provides internal APU functions to apply optimisations to gpus + */ +typedef struct GameModeGPUInfo GameModeGPUInfo; +int game_mode_identify_gpu(GameModeGPUInfo **info); +void game_mode_free_gpu(GameModeGPUInfo **info); +int game_mode_apply_gpu(const GameModeGPUInfo *info, bool apply); diff --git a/daemon/meson.build b/daemon/meson.build index 02a4519..f5b054a 100644 --- a/daemon/meson.build +++ b/daemon/meson.build @@ -24,6 +24,7 @@ daemon_sources = [ 'gamemode-sched.c', 'gamemode-wine.c', 'gamemode-tests.c', + 'gamemode-gpu.c', 'daemonize.c', 'dbus_messaging.c', 'governors.c',