diff --git a/common/common-gpu.h b/common/common-gpu.h index f61b96a..21d5790 100644 --- a/common/common-gpu.h +++ b/common/common-gpu.h @@ -51,6 +51,7 @@ struct GameModeGPUInfo { long nv_core; /* Nvidia core clock */ long nv_mem; /* Nvidia mem clock */ long nv_powermizer_mode; /* NV Powermizer Mode */ + long nv_per_profile_editable; /* Allows per profile editable offsets */ char amd_performance_level[GPU_VALUE_MAX]; /* The AMD performance level set to */ }; diff --git a/daemon/gamemode-config.c b/daemon/gamemode-config.c index 483de6f..1c07d5d 100644 --- a/daemon/gamemode-config.c +++ b/daemon/gamemode-config.c @@ -110,6 +110,7 @@ struct GameModeConfig { long nv_core_clock_mhz_offset; long nv_mem_clock_mhz_offset; long nv_powermizer_mode; + long nv_per_profile_editable; char amd_performance_level[CONFIG_VALUE_MAX]; char cpu_park_cores[CONFIG_VALUE_MAX]; @@ -308,6 +309,8 @@ static int inih_handler(void *user, const char *section, const char *name, const valid = get_long_value(name, value, &self->values.nv_mem_clock_mhz_offset); } else if (strcmp(name, "nv_powermizer_mode") == 0) { valid = get_long_value(name, value, &self->values.nv_powermizer_mode); + } else if (strcmp(name, "nv_per_profile_editable") == 0) { + valid = get_long_value(name, value, &self->values.nv_per_profile_editable); } else if (strcmp(name, "amd_performance_level") == 0) { valid = get_string_value(value, self->values.amd_performance_level); } @@ -387,6 +390,7 @@ static void load_config_files(GameModeConfig *self) self->values.reaper_frequency = DEFAULT_REAPER_FREQ; self->values.gpu_device = 0; self->values.nv_powermizer_mode = -1; + self->values.nv_per_profile_editable = 1; /* Defaults to editable profiles */ self->values.nv_core_clock_mhz_offset = -1; self->values.nv_mem_clock_mhz_offset = -1; self->values.script_timeout = 10; /* Default to 10 seconds for scripts */ @@ -479,7 +483,7 @@ GameModeConfig *config_create(void) } /* - * Initialise the config + * Initialize the config */ void config_init(GameModeConfig *self) { @@ -827,6 +831,7 @@ DEFINE_CONFIG_GET(gpu_device) DEFINE_CONFIG_GET(nv_core_clock_mhz_offset) DEFINE_CONFIG_GET(nv_mem_clock_mhz_offset) DEFINE_CONFIG_GET(nv_powermizer_mode) +DEFINE_CONFIG_GET(nv_per_profile_editable) void config_get_amd_performance_level(GameModeConfig *self, char value[CONFIG_VALUE_MAX]) { diff --git a/daemon/gamemode-config.h b/daemon/gamemode-config.h index a134beb..e0d93fd 100644 --- a/daemon/gamemode-config.h +++ b/daemon/gamemode-config.h @@ -119,6 +119,7 @@ long config_get_gpu_device(GameModeConfig *self); long config_get_nv_core_clock_mhz_offset(GameModeConfig *self); long config_get_nv_mem_clock_mhz_offset(GameModeConfig *self); long config_get_nv_powermizer_mode(GameModeConfig *self); +long config_get_nv_per_profile_editable(GameModeConfig *self); void config_get_amd_performance_level(GameModeConfig *self, char value[CONFIG_VALUE_MAX]); /* diff --git a/daemon/gamemode-gpu.c b/daemon/gamemode-gpu.c index 2e15149..6b3e3a9 100644 --- a/daemon/gamemode-gpu.c +++ b/daemon/gamemode-gpu.c @@ -96,6 +96,7 @@ int game_mode_initialise_gpu(GameModeConfig *config, GameModeGPUInfo **info) new_info->nv_core = config_get_nv_core_clock_mhz_offset(config); new_info->nv_mem = config_get_nv_mem_clock_mhz_offset(config); new_info->nv_powermizer_mode = config_get_nv_powermizer_mode(config); + new_info->nv_per_profile_editable = config_get_nv_per_profile_editable(config); /* Reject values over some guessed values * If a user wants to go into very unsafe levels they can recompile @@ -164,6 +165,8 @@ int game_mode_apply_gpu(const GameModeGPUInfo *info) snprintf(nv_mem, 8, "%ld", info->nv_mem); char nv_powermizer_mode[4]; snprintf(nv_powermizer_mode, 4, "%ld", info->nv_powermizer_mode); + char nv_per_profile_editable[4]; + snprintf(nv_per_profile_editable, 4, "%ld", info->nv_per_profile_editable); // Set up our command line to pass to gpuclockctl const char *const exec_args[] = { @@ -174,6 +177,7 @@ int game_mode_apply_gpu(const GameModeGPUInfo *info) info->vendor == Vendor_NVIDIA ? nv_core : info->amd_performance_level, info->vendor == Vendor_NVIDIA ? nv_mem : NULL, /* Only use this if Nvidia */ info->vendor == Vendor_NVIDIA ? nv_powermizer_mode : NULL, /* Only use this if Nvidia */ + info->vendor == Vendor_NVIDIA ? nv_per_profile_editable : NULL, /* Only use this if Nvidia */ NULL, }; @@ -192,7 +196,9 @@ int game_mode_get_gpu(GameModeGPUInfo *info) /* Generate the input strings */ char device[4]; + char profile_editable[4]; snprintf(device, 4, "%ld", info->device); + snprintf(profile_editable, 4, "%ld", info->nv_per_profile_editable); // Set up our command line to pass to gpuclockctl // This doesn't need pkexec as get does not need elevated perms @@ -200,6 +206,7 @@ int game_mode_get_gpu(GameModeGPUInfo *info) LIBEXECDIR "/gpuclockctl", device, "get", + profile_editable, //TODO:refactor NULL, }; @@ -228,4 +235,4 @@ int game_mode_get_gpu(GameModeGPUInfo *info) } return 0; -} +} \ No newline at end of file diff --git a/example/gamemode.ini b/example/gamemode.ini index 45365bd..cdd98ee 100644 --- a/example/gamemode.ini +++ b/example/gamemode.ini @@ -79,6 +79,10 @@ disable_splitlock=1 ;nv_core_clock_mhz_offset=0 ;nv_mem_clock_mhz_offset=0 +; Whether the GPU supports per-profile editable options for core and memory clock offsets. +; NOTE: if thi is set to 0 (AllPerformanceLevels) then nv_powermizer_mode must be set to 0 +;nv_per_profile_editable = 1 + ; AMD specific settings ; Requires a relatively up to date AMDGPU kernel module ; See: https://dri.freedesktop.org/docs/drm/gpu/amdgpu.html#gpu-power-thermal-controls-and-monitoring diff --git a/util/gpuclockctl.c b/util/gpuclockctl.c index 6935204..2a8a57c 100644 --- a/util/gpuclockctl.c +++ b/util/gpuclockctl.c @@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE. #define NV_PCIDEVICE_ATTRIBUTE "PCIDevice" #define NV_ATTRIBUTE_FORMAT "[gpu:%ld]/%s" #define NV_PERF_LEVEL_FORMAT "[%ld]" +#define NV_ALL_PERF_LEVELS "AllPerformanceLevels" #define NV_ARG_MAX 128 /* AMD constants */ @@ -183,49 +184,98 @@ static int get_gpu_state_nv(struct GameModeGPUInfo *info) const char *attr; char *end; - /* Get the GPUGraphicsClockOffset parameter */ - snprintf(arg, - NV_ARG_MAX, - NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT, - info->device, - NV_CORE_OFFSET_ATTRIBUTE, - perf_level); - if ((attr = get_nv_attr(arg)) == NULL) { - return -1; + if (info->nv_per_profile_editable == 1) { + /* Get the GPUGraphicsClockOffset parameter */ + snprintf(arg, + NV_ARG_MAX, + NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT, + info->device, + NV_CORE_OFFSET_ATTRIBUTE, + perf_level); + + attr = get_nv_attr(arg); // Should declaration be joined with assigment? :S + if (attr == NULL || attr[0] == '\0') { + return -1; + } + + info->nv_core = strtol(attr, &end, 10); + if (end == attr) { + LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, attr); + return -1; + } + + /* Get the GPUMemoryTransferRateOffset parameter */ + snprintf(arg, + NV_ARG_MAX, + NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT, + info->device, + NV_MEM_OFFSET_ATTRIBUTE, + perf_level); + + attr = get_nv_attr(arg); // Should declaration be joined with assigment? :S + if (attr == NULL || attr[0] == '\0') { + return -1; + } + + info->nv_mem = strtol(attr, &end, 10); + if (end == attr) { + LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, attr); + return -1; + } + + /* Get the GPUPowerMizerMode parameter */ + snprintf(arg, NV_ARG_MAX, NV_ATTRIBUTE_FORMAT, info->device, NV_POWERMIZER_MODE_ATTRIBUTE); + if ((attr = get_nv_attr(arg)) == NULL) { + return -1; + } + + info->nv_powermizer_mode = strtol(attr, &end, 10); + if (end == attr) { + LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, attr); + return -1; + } } - info->nv_core = strtol(attr, &end, 10); - if (end == attr) { - LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, attr); - return -1; + else if (info->nv_per_profile_editable == 0) { + /* Get the GPUGraphicsClockOffset parameter */ + snprintf(arg, + NV_ARG_MAX, + NV_ATTRIBUTE_FORMAT NV_ALL_PERF_LEVELS, + info->device, + NV_CORE_OFFSET_ATTRIBUTE); + + attr = get_nv_attr(arg); // Should declaration be joined with assigment? :S + if (attr == NULL || attr[0] == '\0') { + return -1; + } + + info->nv_core = strtol(attr, &end, 10); + if (end == attr) { + LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, attr); + return -1; + } + + /* Get the GPUMemoryTransferRateOffset parameter */ + snprintf(arg, + NV_ARG_MAX, + NV_ATTRIBUTE_FORMAT NV_ALL_PERF_LEVELS, + info->device, + NV_MEM_OFFSET_ATTRIBUTE); + + attr = get_nv_attr(arg); // Should declaration be joined with assigment? :S + if (attr == NULL || attr[0] == '\0') { + return -1; + } + + info->nv_mem = strtol(attr, &end, 10); + if (end == attr) { + LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, attr); + return -1; + } } - /* Get the GPUMemoryTransferRateOffset parameter */ - snprintf(arg, - NV_ARG_MAX, - NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT, - info->device, - NV_MEM_OFFSET_ATTRIBUTE, - perf_level); - if ((attr = get_nv_attr(arg)) == NULL) { - return -1; - } - - info->nv_mem = strtol(attr, &end, 10); - if (end == attr) { - LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, attr); - return -1; - } - - /* Get the GPUPowerMizerMode parameter */ - snprintf(arg, NV_ARG_MAX, NV_ATTRIBUTE_FORMAT, info->device, NV_POWERMIZER_MODE_ATTRIBUTE); - if ((attr = get_nv_attr(arg)) == NULL) { - return -1; - } - - info->nv_powermizer_mode = strtol(attr, &end, 10); - if (end == attr) { - LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, attr); + else { + LOG_ERROR("nv_per_profile_editable should be 0 or 1!"); return -1; } @@ -251,44 +301,74 @@ static int set_gpu_state_nv(struct GameModeGPUInfo *info) char arg[NV_ARG_MAX] = { 0 }; - /* Set the GPUGraphicsClockOffset parameter */ - if (info->nv_core != -1) { - snprintf(arg, - NV_ARG_MAX, - NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT "=%ld", - info->device, - NV_CORE_OFFSET_ATTRIBUTE, - perf_level, - info->nv_core); - if (set_nv_attr(arg) != 0) { - status = -1; + if (info->nv_per_profile_editable == 1) { + /* Set the GPUGraphicsClockOffset parameter */ + if (info->nv_core != -1) { + snprintf(arg, + NV_ARG_MAX, + NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT "=%ld", + info->device, + NV_CORE_OFFSET_ATTRIBUTE, + perf_level, + info->nv_core); + if (set_nv_attr(arg) != 0) { + status = -1; + } + } + + /* Set the GPUMemoryTransferRateOffset parameter */ + if (info->nv_mem != -1) { + snprintf(arg, + NV_ARG_MAX, + NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT "=%ld", + info->device, + NV_MEM_OFFSET_ATTRIBUTE, + perf_level, + info->nv_mem); + if (set_nv_attr(arg) != 0) { + status = -1; + } + } + + /* Set the GPUPowerMizerMode parameter if requested */ + if (info->nv_powermizer_mode != -1) { + snprintf(arg, + NV_ARG_MAX, + NV_ATTRIBUTE_FORMAT "=%ld", + info->device, + NV_POWERMIZER_MODE_ATTRIBUTE, + info->nv_powermizer_mode); + if (set_nv_attr(arg) != 0) { + status = -1; + } } } - /* Set the GPUMemoryTransferRateOffset parameter */ - if (info->nv_mem != -1) { - snprintf(arg, - NV_ARG_MAX, - NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT "=%ld", - info->device, - NV_MEM_OFFSET_ATTRIBUTE, - perf_level, - info->nv_mem); - if (set_nv_attr(arg) != 0) { - status = -1; + else if (info->nv_per_profile_editable == 0) { + /* Set the GPUGraphicsClockOffset parameter */ + if (info->nv_core != -1) { + snprintf(arg, + NV_ARG_MAX, + NV_ATTRIBUTE_FORMAT NV_ALL_PERF_LEVELS "=%ld", + info->device, + NV_CORE_OFFSET_ATTRIBUTE, + info->nv_core); + if (set_nv_attr(arg) != 0) { + status = -1; + } } - } - /* Set the GPUPowerMizerMode parameter if requested */ - if (info->nv_powermizer_mode != -1) { - snprintf(arg, - NV_ARG_MAX, - NV_ATTRIBUTE_FORMAT "=%ld", - info->device, - NV_POWERMIZER_MODE_ATTRIBUTE, - info->nv_powermizer_mode); - if (set_nv_attr(arg) != 0) { - status = -1; + /* Set the GPUMemoryTransferRateOffset parameter */ + if (info->nv_mem != -1) { + snprintf(arg, + NV_ARG_MAX, + NV_ATTRIBUTE_FORMAT NV_ALL_PERF_LEVELS "=%ld", + info->device, + NV_MEM_OFFSET_ATTRIBUTE, + info->nv_mem); + if (set_nv_attr(arg) != 0) { + status = -1; + } } } @@ -425,11 +505,18 @@ int main(int argc, char *argv[]) struct GameModeGPUInfo info; memset(&info, 0, sizeof(info)); - if (argc == 3 && strncmp(argv[2], "get", 3) == 0) { + if (argc >= 3 && strncmp(argv[2], "get", 3) == 0) { /* Get and verify the vendor and device */ info.device = get_device(argv[1]); info.vendor = gamemode_get_gpu_vendor(info.device); + /* Check for editable profiles argument */ + if (argc == 3) { + info.nv_per_profile_editable = 1; /* If not specified, default to editable profiles */ + } else if (argc == 4) { + info.nv_per_profile_editable = get_generic_value(argv[3]); + } + /* Fetch the state and print it out */ switch (info.vendor) { case Vendor_NVIDIA: @@ -469,9 +556,15 @@ int main(int argc, char *argv[]) info.device = get_gpu_index_id_nv(&info); /* Optional */ + /* If no per profile editable is defined, default to 1 */ info.nv_powermizer_mode = -1; - if (argc >= 6) + info.nv_per_profile_editable = 1; + if (argc >= 6) { info.nv_powermizer_mode = get_generic_value(argv[5]); + if (argc == 7) { + info.nv_per_profile_editable = get_generic_value(argv[6]); + } + } return set_gpu_state_nv(&info); break; @@ -495,4 +588,4 @@ int main(int argc, char *argv[]) } return EXIT_SUCCESS; -} +} \ No newline at end of file