Remove deprecated overclocking option

This commit is contained in:
dec05eba
2026-05-02 01:44:25 +02:00
parent e48be50cd8
commit 2f23dcf29a
15 changed files with 15 additions and 450 deletions

View File

@@ -89,7 +89,6 @@ There are also additional dependencies needed at runtime depending on your GPU v
* cuda runtime (libcuda.so.1) (libnvidia-compute) * cuda runtime (libcuda.so.1) (libnvidia-compute)
* nvenc (libnvidia-encode) * nvenc (libnvidia-encode)
* nvfbc (libnvidia-fbc1, when recording the screen on x11) * nvfbc (libnvidia-fbc1, when recording the screen on x11)
* xnvctrl (libxnvctrl0, when using the `-oc` option)
# How to use # How to use
Run `gpu-screen-recorder --help` to see all options and run `man gpu-screen-recorder` to see more detailed explanations for the options and also examples.\ Run `gpu-screen-recorder --help` to see all options and run `man gpu-screen-recorder` to see more detailed explanations for the options and also examples.\

View File

@@ -329,9 +329,6 @@ Clear buffer after saving replay (default: no).
Organize replays in date-based folders (default: no). Organize replays in date-based folders (default: no).
.SS Advanced Options .SS Advanced Options
.TP .TP
.BI \-oc " yes|no"
Overclock NVIDIA memory (X11 only). Requires Coolbits=12. Use at own risk.
.TP
.BI \-p " plugin.so" .BI \-p " plugin.so"
Load plugin (.so file). Can be specified multiple times. Load plugin (.so file). Can be specified multiple times.
.TP .TP

View File

@@ -97,7 +97,6 @@ typedef struct {
bool date_folders; bool date_folders;
bool restore_portal_session; bool restore_portal_session;
bool restart_replay_on_save; bool restart_replay_on_save;
bool overclock;
bool write_first_frame_ts; bool write_first_frame_ts;
bool is_livestream; bool is_livestream;
bool is_output_piped; bool is_output_piped;

View File

@@ -1,7 +1,6 @@
#ifndef GSR_CUDA_H #ifndef GSR_CUDA_H
#define GSR_CUDA_H #define GSR_CUDA_H
#include "overclock.h"
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
@@ -75,9 +74,6 @@ typedef struct CUgraphicsResource_st *CUgraphicsResource;
typedef struct gsr_cuda gsr_cuda; typedef struct gsr_cuda gsr_cuda;
struct gsr_cuda { struct gsr_cuda {
gsr_overclock overclock;
bool do_overclock;
void *library; void *library;
CUcontext cu_ctx; CUcontext cu_ctx;
@@ -102,7 +98,7 @@ struct gsr_cuda {
CUresult (*cuGraphicsSubResourceGetMappedArray)(CUarray *pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel); CUresult (*cuGraphicsSubResourceGetMappedArray)(CUarray *pArray, CUgraphicsResource resource, unsigned int arrayIndex, unsigned int mipLevel);
}; };
bool gsr_cuda_load(gsr_cuda *self, Display *display, bool overclock); bool gsr_cuda_load(gsr_cuda *self);
void gsr_cuda_unload(gsr_cuda *self); void gsr_cuda_unload(gsr_cuda *self);
#endif /* GSR_CUDA_H */ #endif /* GSR_CUDA_H */

View File

@@ -7,7 +7,6 @@ typedef struct gsr_egl gsr_egl;
typedef struct { typedef struct {
gsr_egl *egl; gsr_egl *egl;
bool overclock;
gsr_color_depth color_depth; gsr_color_depth color_depth;
} gsr_video_encoder_nvenc_params; } gsr_video_encoder_nvenc_params;

View File

@@ -1,17 +0,0 @@
#ifndef GSR_OVERCLOCK_H
#define GSR_OVERCLOCK_H
#include "xnvctrl.h"
typedef struct {
gsr_xnvctrl xnvctrl;
int num_performance_levels;
} gsr_overclock;
bool gsr_overclock_load(gsr_overclock *self, Display *display);
void gsr_overclock_unload(gsr_overclock *self);
bool gsr_overclock_start(gsr_overclock *self);
void gsr_overclock_stop(gsr_overclock *self);
#endif /* GSR_OVERCLOCK_H */

View File

@@ -1,45 +0,0 @@
#ifndef GSR_XNVCTRL_H
#define GSR_XNVCTRL_H
#include <stdbool.h>
#include <stdint.h>
#define NV_CTRL_GPU_NVCLOCK_OFFSET 409
#define NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET 410
#define NV_CTRL_GPU_NVCLOCK_OFFSET_ALL_PERFORMANCE_LEVELS 424
#define NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS 425
#define NV_CTRL_TARGET_TYPE_GPU 1
#define NV_CTRL_STRING_PERFORMANCE_MODES 29
typedef struct _XDisplay Display;
typedef struct {
int type;
union {
struct {
int64_t min;
int64_t max;
} range;
struct {
unsigned int ints;
} bits;
} u;
unsigned int permissions;
} NVCTRLAttributeValidValuesRec;
typedef struct {
Display *display;
void *library;
int (*XNVCTRLQueryExtension)(Display *dpy, int *event_basep, int *error_basep);
int (*XNVCTRLSetTargetAttributeAndGetStatus)(Display *dpy, int target_type, int target_id, unsigned int display_mask, unsigned int attribute, int value);
int (*XNVCTRLQueryValidTargetAttributeValues)(Display *dpy, int target_type, int target_id, unsigned int display_mask, unsigned int attribute, NVCTRLAttributeValidValuesRec *values);
int (*XNVCTRLQueryTargetStringAttribute)(Display *dpy, int target_type, int target_id, unsigned int display_mask, unsigned int attribute, char **ptr);
} gsr_xnvctrl;
bool gsr_xnvctrl_load(gsr_xnvctrl *self, Display *display);
void gsr_xnvctrl_unload(gsr_xnvctrl *self);
#endif /* GSR_XNVCTRL_H */

View File

@@ -32,8 +32,6 @@ src = [
'src/replay_buffer/replay_buffer_disk.c', 'src/replay_buffer/replay_buffer_disk.c',
'src/egl.c', 'src/egl.c',
'src/cuda.c', 'src/cuda.c',
'src/xnvctrl.c',
'src/overclock.c',
'src/window_texture.c', 'src/window_texture.c',
'src/shader.c', 'src/shader.c',
'src/color_conversion.c', 'src/color_conversion.c',

View File

@@ -199,7 +199,7 @@ static void usage_header(void) {
const char *program_name = inside_flatpak ? "flatpak run --command=gpu-screen-recorder com.dec05eba.gpu_screen_recorder" : "gpu-screen-recorder"; const char *program_name = inside_flatpak ? "flatpak run --command=gpu-screen-recorder com.dec05eba.gpu_screen_recorder" : "gpu-screen-recorder";
printf("usage: %s -w <window_id|monitor|focused|portal|region|v4l2_device_path> [-c <container_format>] [-s WxH] [-region WxH+X+Y] [-f <fps>] [-a <audio_input>] " printf("usage: %s -w <window_id|monitor|focused|portal|region|v4l2_device_path> [-c <container_format>] [-s WxH] [-region WxH+X+Y] [-f <fps>] [-a <audio_input>] "
"[-q <quality>] [-r <replay_buffer_size_sec>] [-replay-storage ram|disk] [-restart-replay-on-save yes|no] " "[-q <quality>] [-r <replay_buffer_size_sec>] [-replay-storage ram|disk] [-restart-replay-on-save yes|no] "
"[-k h264|hevc|av1|vp8|vp9|hevc_hdr|av1_hdr|hevc_10bit|av1_10bit] [-ac aac|opus|flac] [-ab <bitrate>] [-oc yes|no] [-fm cfr|vfr|content] " "[-k h264|hevc|av1|vp8|vp9|hevc_hdr|av1_hdr|hevc_10bit|av1_10bit] [-ac aac|opus|flac] [-ab <bitrate>] [-fm cfr|vfr|content] "
"[-bm auto|qp|vbr|cbr] [-cr limited|full] [-tune performance|quality] [-df yes|no] [-sc <script_path>] [-p <plugin_path>] " "[-bm auto|qp|vbr|cbr] [-cr limited|full] [-tune performance|quality] [-df yes|no] [-sc <script_path>] [-p <plugin_path>] "
"[-cursor yes|no] [-keyint <value>] [-restore-portal-session yes|no] [-portal-session-token-filepath filepath] [-encoder gpu|cpu] " "[-cursor yes|no] [-keyint <value>] [-restore-portal-session yes|no] [-portal-session-token-filepath filepath] [-encoder gpu|cpu] "
"[-fallback-cpu-encoding yes|no] [-o <output_file>] [-ro <output_directory>] [-ffmpeg-opts <options>] [--list-capture-options [card_path]] " "[-fallback-cpu-encoding yes|no] [-o <output_file>] [-ro <output_directory>] [-ffmpeg-opts <options>] [--list-capture-options [card_path]] "
@@ -261,7 +261,7 @@ static bool args_parser_set_values(args_parser *self) {
self->date_folders = args_get_boolean_by_key(self->args, NUM_ARGS, "-df", false); self->date_folders = args_get_boolean_by_key(self->args, NUM_ARGS, "-df", false);
self->restore_portal_session = args_get_boolean_by_key(self->args, NUM_ARGS, "-restore-portal-session", false); self->restore_portal_session = args_get_boolean_by_key(self->args, NUM_ARGS, "-restore-portal-session", false);
self->restart_replay_on_save = args_get_boolean_by_key(self->args, NUM_ARGS, "-restart-replay-on-save", false); self->restart_replay_on_save = args_get_boolean_by_key(self->args, NUM_ARGS, "-restart-replay-on-save", false);
self->overclock = args_get_boolean_by_key(self->args, NUM_ARGS, "-oc", false); const bool overclock = args_get_boolean_by_key(self->args, NUM_ARGS, "-oc", false);
self->fallback_cpu_encoding = args_get_boolean_by_key(self->args, NUM_ARGS, "-fallback-cpu-encoding", false); self->fallback_cpu_encoding = args_get_boolean_by_key(self->args, NUM_ARGS, "-fallback-cpu-encoding", false);
self->write_first_frame_ts = args_get_boolean_by_key(self->args, NUM_ARGS, "-write-first-frame-ts", false); self->write_first_frame_ts = args_get_boolean_by_key(self->args, NUM_ARGS, "-write-first-frame-ts", false);
self->low_power = args_get_boolean_by_key(self->args, NUM_ARGS, "-low-power", false); self->low_power = args_get_boolean_by_key(self->args, NUM_ARGS, "-low-power", false);
@@ -271,6 +271,10 @@ static bool args_parser_set_values(args_parser *self) {
self->keyint = args_get_double_by_key(self->args, NUM_ARGS, "-keyint", 2.0); self->keyint = args_get_double_by_key(self->args, NUM_ARGS, "-keyint", 2.0);
if(overclock) {
fprintf(stderr, "gsr info: the overclock option (-oc) is deprecated and no longer has any effect as it's no longer needed (on GPUs that are 12 years old or younger)\n");
}
if(self->audio_codec == GSR_AUDIO_CODEC_FLAC) { if(self->audio_codec == GSR_AUDIO_CODEC_FLAC) {
fprintf(stderr, "gsr warning: flac audio codec is temporary disabled, using opus audio codec instead\n"); fprintf(stderr, "gsr warning: flac audio codec is temporary disabled, using opus audio codec instead\n");
self->audio_codec = GSR_AUDIO_CODEC_OPUS; self->audio_codec = GSR_AUDIO_CODEC_OPUS;
@@ -690,16 +694,6 @@ bool args_parser_validate_with_gl_info(args_parser *self, gsr_egl *egl) {
self->bitrate_mode = GSR_BITRATE_MODE_QP; self->bitrate_mode = GSR_BITRATE_MODE_QP;
} }
if(egl->gpu_info.vendor != GSR_GPU_VENDOR_NVIDIA && self->overclock) {
fprintf(stderr, "gsr info: overclock option has no effect on amd/intel, ignoring option\n");
self->overclock = false;
}
if(egl->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA && self->overclock && wayland) {
fprintf(stderr, "gsr info: overclocking is not possible on nvidia on wayland, ignoring option\n");
self->overclock = false;
}
if(egl->gpu_info.is_steam_deck) { if(egl->gpu_info.is_steam_deck) {
fprintf(stderr, "gsr warning: steam deck has multiple driver issues. One of them has been reported here: https://github.com/ValveSoftware/SteamOS/issues/1609\n" fprintf(stderr, "gsr warning: steam deck has multiple driver issues. One of them has been reported here: https://github.com/ValveSoftware/SteamOS/issues/1609\n"
"If you have issues with GPU Screen Recorder on steam deck that you don't have on a desktop computer then report the issue to Valve and/or AMD.\n"); "If you have issues with GPU Screen Recorder on steam deck that you don't have on a desktop computer then report the issue to Valve and/or AMD.\n");

View File

@@ -197,7 +197,7 @@ bool gsr_get_supported_video_codecs_nvenc(gsr_supported_video_codecs *video_code
gsr_cuda cuda; gsr_cuda cuda;
memset(&cuda, 0, sizeof(cuda)); memset(&cuda, 0, sizeof(cuda));
if(!gsr_cuda_load(&cuda, NULL, false)) { if(!gsr_cuda_load(&cuda)) {
fprintf(stderr, "gsr error: gsr_get_supported_video_codecs_nvenc: failed to load cuda\n"); fprintf(stderr, "gsr error: gsr_get_supported_video_codecs_nvenc: failed to load cuda\n");
goto done; goto done;
} }

View File

@@ -5,9 +5,8 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <assert.h> #include <assert.h>
bool gsr_cuda_load(gsr_cuda *self, Display *display, bool do_overclock) { bool gsr_cuda_load(gsr_cuda *self) {
memset(self, 0, sizeof(gsr_cuda)); memset(self, 0, sizeof(gsr_cuda));
self->do_overclock = do_overclock;
dlerror(); /* clear */ dlerror(); /* clear */
void *lib = dlopen("libcuda.so.1", RTLD_LAZY); void *lib = dlopen("libcuda.so.1", RTLD_LAZY);
@@ -83,15 +82,6 @@ bool gsr_cuda_load(gsr_cuda *self, Display *display, bool do_overclock) {
goto fail; goto fail;
} }
if(self->do_overclock && display) {
if(gsr_overclock_load(&self->overclock, display))
gsr_overclock_start(&self->overclock);
else
fprintf(stderr, "gsr warning: gsr_cuda_load: failed to load xnvctrl, failed to overclock memory transfer rate\n");
} else if(self->do_overclock && !display) {
fprintf(stderr, "gsr warning: gsr_cuda_load: overclocking enabled but no X server is running. Overclocking has been disabled\n");
}
self->library = lib; self->library = lib;
return true; return true;
@@ -102,11 +92,6 @@ bool gsr_cuda_load(gsr_cuda *self, Display *display, bool do_overclock) {
} }
void gsr_cuda_unload(gsr_cuda *self) { void gsr_cuda_unload(gsr_cuda *self) {
if(self->do_overclock && self->overclock.xnvctrl.library) {
gsr_overclock_stop(&self->overclock);
gsr_overclock_unload(&self->overclock);
}
if(self->library) { if(self->library) {
if(self->cu_ctx) { if(self->cu_ctx) {
self->cuCtxDestroy_v2(self->cu_ctx); self->cuCtxDestroy_v2(self->cu_ctx);

View File

@@ -1,7 +1,7 @@
#include "../../../include/encoder/video/nvenc.h" #include "../../../include/encoder/video/nvenc.h"
#include "../../../include/egl.h" #include "../../../include/egl.h"
#include "../../../include/cuda.h" #include "../../../include/cuda.h"
#include "../../../include/window/window.h" #include "../../../include/utils.h"
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavutil/hwcontext_cuda.h> #include <libavutil/hwcontext_cuda.h>
@@ -116,10 +116,7 @@ static void gsr_video_encoder_nvenc_stop(gsr_video_encoder_nvenc *self, AVCodecC
static bool gsr_video_encoder_nvenc_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) { static bool gsr_video_encoder_nvenc_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) {
gsr_video_encoder_nvenc *self = encoder->priv; gsr_video_encoder_nvenc *self = encoder->priv;
const bool is_x11 = gsr_window_get_display_server(self->params.egl->window) == GSR_DISPLAY_SERVER_X11; if(!gsr_cuda_load(&self->cuda)) {
const bool overclock = is_x11 ? self->params.overclock : false;
Display *display = is_x11 ? gsr_window_get_display(self->params.egl->window) : NULL;
if(!gsr_cuda_load(&self->cuda, display, overclock)) {
fprintf(stderr, "gsr error: gsr_video_encoder_nvenc_start: failed to load cuda\n"); fprintf(stderr, "gsr error: gsr_video_encoder_nvenc_start: failed to load cuda\n");
gsr_video_encoder_nvenc_stop(self, video_codec_context); gsr_video_encoder_nvenc_stop(self, video_codec_context);
return false; return false;

View File

@@ -1551,7 +1551,6 @@ static gsr_video_encoder* create_video_encoder(gsr_egl *egl, const args_parser &
case GSR_GPU_VENDOR_NVIDIA: { case GSR_GPU_VENDOR_NVIDIA: {
gsr_video_encoder_nvenc_params params; gsr_video_encoder_nvenc_params params;
params.egl = egl; params.egl = egl;
params.overclock = arg_parser.overclock;
params.color_depth = color_depth; params.color_depth = color_depth;
video_encoder = gsr_video_encoder_nvenc_create(&params); video_encoder = gsr_video_encoder_nvenc_create(&params);
break; break;
@@ -3571,6 +3570,10 @@ static void validate_args_with_capture_sources(args_parser &arg_parser, const st
fprintf(stderr, "gsr info: option '-w portal' was used without '-restore-portal-session yes'. The previous screencast session will be ignored\n"); fprintf(stderr, "gsr info: option '-w portal' was used without '-restore-portal-session yes'. The previous screencast session will be ignored\n");
} }
static void install_cuda_no_stable_perf_limit() {
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
setlocale(LC_ALL, "C"); // Sigh... stupid C setlocale(LC_ALL, "C"); // Sigh... stupid C
#ifdef __GLIBC__ #ifdef __GLIBC__
@@ -3645,21 +3648,6 @@ int main(int argc, char **argv) {
} }
validate_args_with_capture_sources(arg_parser, capture_sources); validate_args_with_capture_sources(arg_parser, capture_sources);
// TODO: Remove, this isn't true
if(arg_parser.overclock) {
int driver_major_version = 0;
int driver_minor_version = 0;
if(get_nvidia_driver_version(&driver_major_version, &driver_minor_version) && (driver_major_version > 580 || (driver_major_version == 580 && driver_minor_version >= 105))) {
fprintf(stderr, "gsr info: overclocking was set but has been forcefully disabled since your gpu supports CUDA_DISABLE_PERF_BOOST to workaround driver issue (overclocking is not needed)\n");
arg_parser.overclock = false;
}
}
if(arg_parser.overclock && video_codec_is_vulkan(arg_parser.video_codec)) {
fprintf(stderr, "gsr info: overclocking was set but has been forcefully disabled since you're using vulkan video encoder which doesn't suffer from cuda p2 power level issues\n");
arg_parser.overclock = false;
}
//av_log_set_level(AV_LOG_TRACE); //av_log_set_level(AV_LOG_TRACE);
const Arg *audio_input_arg = args_parser_get_arg(&arg_parser, "-a"); const Arg *audio_input_arg = args_parser_get_arg(&arg_parser, "-a");

View File

@@ -1,279 +0,0 @@
#include "../include/overclock.h"
#include <X11/Xlib.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// HACK!!!: When a program uses cuda (including nvenc) then the nvidia driver drops to max performance level - 1 (memory transfer rate is dropped and possibly graphics clock).
// Nvidia does this because in some very extreme cases of cuda there can be memory corruption when running at max memory transfer rate.
// So to get around this we overclock memory transfer rate (maybe this should also be done for graphics clock?) to the best performance level while GPU Screen Recorder is running.
static int min_int(int a, int b) {
return a < b ? a : b;
}
// Fields are 0 if not set
typedef struct {
int perf;
int nv_clock;
int nv_clock_min;
int nv_clock_max;
int mem_clock;
int mem_clock_min;
int mem_clock_max;
int mem_transfer_rate;
int mem_transfer_rate_min;
int mem_transfer_rate_max;
} NVCTRLPerformanceLevel;
#define MAX_PERFORMANCE_LEVELS 12
typedef struct {
NVCTRLPerformanceLevel performance_level[MAX_PERFORMANCE_LEVELS];
int num_performance_levels;
} NVCTRLPerformanceLevelQuery;
typedef void (*split_callback)(const char *str, size_t size, void *userdata);
static void split_by_delimiter(const char *str, size_t size, char delimiter, split_callback callback, void *userdata) {
const char *it = str;
while(it < str + size) {
const char *prev_it = it;
it = memchr(it, delimiter, (str + size) - it);
if(!it)
it = str + size;
callback(prev_it, it - prev_it, userdata);
it += 1; // skip delimiter
}
}
typedef enum {
NVCTRL_GPU_NVCLOCK,
NVCTRL_ATTRIB_GPU_MEM_TRANSFER_RATE,
} NvCTRLAttributeType;
static unsigned int attribute_type_to_attribute_param(NvCTRLAttributeType attribute_type) {
switch(attribute_type) {
case NVCTRL_GPU_NVCLOCK:
return NV_CTRL_GPU_NVCLOCK_OFFSET;
case NVCTRL_ATTRIB_GPU_MEM_TRANSFER_RATE:
return NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET;
}
return 0;
}
static unsigned int attribute_type_to_attribute_param_all_levels(NvCTRLAttributeType attribute_type) {
switch(attribute_type) {
case NVCTRL_GPU_NVCLOCK:
return NV_CTRL_GPU_NVCLOCK_OFFSET_ALL_PERFORMANCE_LEVELS;
case NVCTRL_ATTRIB_GPU_MEM_TRANSFER_RATE:
return NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS;
}
return 0;
}
// Returns 0 on error
static int xnvctrl_get_attribute_max_value(gsr_xnvctrl *xnvctrl, int num_performance_levels, NvCTRLAttributeType attribute_type) {
NVCTRLAttributeValidValuesRec valid;
if(xnvctrl->XNVCTRLQueryValidTargetAttributeValues(xnvctrl->display, NV_CTRL_TARGET_TYPE_GPU, 0, 0, attribute_type_to_attribute_param_all_levels(attribute_type), &valid)) {
return valid.u.range.max;
}
if(num_performance_levels > 0 && xnvctrl->XNVCTRLQueryValidTargetAttributeValues(xnvctrl->display, NV_CTRL_TARGET_TYPE_GPU, 0, num_performance_levels - 1, attribute_type_to_attribute_param(attribute_type), &valid)) {
return valid.u.range.max;
}
return 0;
}
static bool xnvctrl_set_attribute_offset(gsr_xnvctrl *xnvctrl, int num_performance_levels, int offset, NvCTRLAttributeType attribute_type) {
bool success = false;
// NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS works (or at least used to?) without Xorg running as root
// so we try that first. NV_CTRL_GPU_MEM_TRANSFER_RATE_OFFSET_ALL_PERFORMANCE_LEVELS also only works with GTX 1000+.
// TODO: Reverse engineer NVIDIA Xorg driver so we can set this always without root access.
if(xnvctrl->XNVCTRLSetTargetAttributeAndGetStatus(xnvctrl->display, NV_CTRL_TARGET_TYPE_GPU, 0, 0, attribute_type_to_attribute_param_all_levels(attribute_type), offset))
success = true;
for(int i = 0; i < num_performance_levels; ++i) {
success |= xnvctrl->XNVCTRLSetTargetAttributeAndGetStatus(xnvctrl->display, NV_CTRL_TARGET_TYPE_GPU, 0, i, attribute_type_to_attribute_param(attribute_type), offset);
}
return success;
}
static void strip(const char **str, int *size) {
const char *str_d = *str;
int s_d = *size;
const char *start = str_d;
const char *end = start + s_d;
while(str_d < end) {
char c = *str_d;
if(c != ' ' && c != '\t' && c != '\n')
break;
++str_d;
}
int start_offset = str_d - start;
while(s_d > start_offset) {
char c = start[s_d];
if(c != ' ' && c != '\t' && c != '\n')
break;
--s_d;
}
*str = str_d;
*size = s_d;
}
static void attribute_callback(const char *str, size_t size, void *userdata) {
if(size > 255 - 1)
return;
int size_i = size;
strip(&str, &size_i);
char attribute[255];
memcpy(attribute, str, size_i);
attribute[size_i] = '\0';
const char *sep = strchr(attribute, '=');
if(!sep)
return;
const char *attribute_name = attribute;
size_t attribute_name_len = sep - attribute_name;
const char *attribute_value_str = sep + 1;
int attribute_value = 0;
if(sscanf(attribute_value_str, "%d", &attribute_value) != 1)
return;
NVCTRLPerformanceLevel *performance_level = userdata;
if(attribute_name_len == 4 && memcmp(attribute_name, "perf", 4) == 0)
performance_level->perf = attribute_value;
else if(attribute_name_len == 7 && memcmp(attribute_name, "nvclock", 7) == 0)
performance_level->nv_clock = attribute_value;
else if(attribute_name_len == 10 && memcmp(attribute_name, "nvclockmin", 10) == 0)
performance_level->nv_clock_min = attribute_value;
else if(attribute_name_len == 10 && memcmp(attribute_name, "nvclockmax", 10) == 0)
performance_level->nv_clock_max = attribute_value;
else if(attribute_name_len == 8 && memcmp(attribute_name, "memclock", 8) == 0)
performance_level->mem_clock = attribute_value;
else if(attribute_name_len == 11 && memcmp(attribute_name, "memclockmin", 11) == 0)
performance_level->mem_clock_min = attribute_value;
else if(attribute_name_len == 11 && memcmp(attribute_name, "memclockmax", 11) == 0)
performance_level->mem_clock_max = attribute_value;
else if(attribute_name_len == 15 && memcmp(attribute_name, "memTransferRate", 15) == 0)
performance_level->mem_transfer_rate = attribute_value;
else if(attribute_name_len == 18 && memcmp(attribute_name, "memTransferRatemin", 18) == 0)
performance_level->mem_transfer_rate_min = attribute_value;
else if(attribute_name_len == 18 && memcmp(attribute_name, "memTransferRatemax", 18) == 0)
performance_level->mem_transfer_rate_max = attribute_value;
}
static void attribute_line_callback(const char *str, size_t size, void *userdata) {
NVCTRLPerformanceLevelQuery *query = userdata;
if(query->num_performance_levels >= MAX_PERFORMANCE_LEVELS)
return;
NVCTRLPerformanceLevel *current_performance_level = &query->performance_level[query->num_performance_levels];
memset(current_performance_level, 0, sizeof(NVCTRLPerformanceLevel));
++query->num_performance_levels;
split_by_delimiter(str, size, ',', attribute_callback, current_performance_level);
}
static bool xnvctrl_get_performance_levels(gsr_xnvctrl *xnvctrl, NVCTRLPerformanceLevelQuery *query) {
bool success = false;
memset(query, 0, sizeof(NVCTRLPerformanceLevelQuery));
char *attributes = NULL;
if(!xnvctrl->XNVCTRLQueryTargetStringAttribute(xnvctrl->display, NV_CTRL_TARGET_TYPE_GPU, 0, 0, NV_CTRL_STRING_PERFORMANCE_MODES, &attributes)) {
success = false;
goto done;
}
split_by_delimiter(attributes, strlen(attributes), ';', attribute_line_callback, query);
success = true;
done:
if(attributes)
XFree(attributes);
return success;
}
static int compare_mem_transfer_rate_max_asc(const void *a, const void *b) {
const NVCTRLPerformanceLevel *perf_a = a;
const NVCTRLPerformanceLevel *perf_b = b;
return perf_a->mem_transfer_rate_max - perf_b->mem_transfer_rate_max;
}
bool gsr_overclock_load(gsr_overclock *self, Display *display) {
memset(self, 0, sizeof(gsr_overclock));
self->num_performance_levels = 0;
return gsr_xnvctrl_load(&self->xnvctrl, display);
}
void gsr_overclock_unload(gsr_overclock *self) {
gsr_xnvctrl_unload(&self->xnvctrl);
}
bool gsr_overclock_start(gsr_overclock *self) {
int basep = 0;
int errorp = 0;
if(!self->xnvctrl.XNVCTRLQueryExtension(self->xnvctrl.display, &basep, &errorp)) {
fprintf(stderr, "gsr warning: gsr_overclock_start: xnvctrl is not supported on your system, failed to overclock memory transfer rate\n");
return false;
}
NVCTRLPerformanceLevelQuery query;
if(!xnvctrl_get_performance_levels(&self->xnvctrl, &query) || query.num_performance_levels == 0) {
fprintf(stderr, "gsr warning: gsr_overclock_start: failed to get performance levels for overclocking\n");
return false;
}
self->num_performance_levels = query.num_performance_levels;
qsort(query.performance_level, query.num_performance_levels, sizeof(NVCTRLPerformanceLevel), compare_mem_transfer_rate_max_asc);
int target_transfer_rate_offset = xnvctrl_get_attribute_max_value(&self->xnvctrl, query.num_performance_levels, NVCTRL_ATTRIB_GPU_MEM_TRANSFER_RATE);
if(query.num_performance_levels > 1) {
const int transfer_rate_max_diff = query.performance_level[query.num_performance_levels - 1].mem_transfer_rate_max - query.performance_level[query.num_performance_levels - 2].mem_transfer_rate_max;
target_transfer_rate_offset = min_int(target_transfer_rate_offset, transfer_rate_max_diff);
if(target_transfer_rate_offset >= 0 && xnvctrl_set_attribute_offset(&self->xnvctrl, self->num_performance_levels, target_transfer_rate_offset, NVCTRL_ATTRIB_GPU_MEM_TRANSFER_RATE)) {
fprintf(stderr, "gsr info: gsr_overclock_start: successfully set memory transfer rate offset to %d\n", target_transfer_rate_offset);
} else {
fprintf(stderr, "gsr info: gsr_overclock_start: failed to overclock memory transfer rate offset to %d\n", target_transfer_rate_offset);
}
}
// TODO: Sort by nv_clock_max
// TODO: Enable. Crashes on my system (gtx 1080) so it's disabled for now. Seems to crash even if graphics clock is increasd by 1, let alone 1200
/*
int target_nv_clock_offset = xnvctrl_get_attribute_max_value(&self->xnvctrl, query.num_performance_levels, NVCTRL_GPU_NVCLOCK);
if(query.num_performance_levels > 1) {
const int nv_clock_max_diff = query.performance_level[query.num_performance_levels - 1].nv_clock_max - query.performance_level[query.num_performance_levels - 2].nv_clock_max;
target_nv_clock_offset = min_int(target_nv_clock_offset, nv_clock_max_diff);
if(target_nv_clock_offset >= 0 && xnvctrl_set_attribute_offset(&self->xnvctrl, self->num_performance_levels, target_nv_clock_offset, NVCTRL_GPU_NVCLOCK)) {
fprintf(stderr, "gsr info: gsr_overclock_start: successfully set nv clock offset to %d\n", target_nv_clock_offset);
} else {
fprintf(stderr, "gsr info: gsr_overclock_start: failed to overclock nv clock offset to %d\n", target_nv_clock_offset);
}
}
*/
XSync(self->xnvctrl.display, False);
return true;
}
void gsr_overclock_stop(gsr_overclock *self) {
xnvctrl_set_attribute_offset(&self->xnvctrl, self->num_performance_levels, 0, NVCTRL_ATTRIB_GPU_MEM_TRANSFER_RATE);
//xnvctrl_set_attribute_offset(&self->xnvctrl, self->num_performance_levels, 0, NVCTRL_GPU_NVCLOCK);
XSync(self->xnvctrl.display, False);
}

View File

@@ -1,46 +0,0 @@
#include "../include/xnvctrl.h"
#include "../include/library_loader.h"
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>
bool gsr_xnvctrl_load(gsr_xnvctrl *self, Display *display) {
memset(self, 0, sizeof(gsr_xnvctrl));
self->display = display;
dlerror(); /* clear */
void *lib = dlopen("libXNVCtrl.so.0", RTLD_LAZY);
if(!lib) {
fprintf(stderr, "gsr error: gsr_xnvctrl_load failed: failed to load libXNVCtrl.so.0, error: %s\n", dlerror());
return false;
}
const dlsym_assign required_dlsym[] = {
{ (void**)&self->XNVCTRLQueryExtension, "XNVCTRLQueryExtension" },
{ (void**)&self->XNVCTRLSetTargetAttributeAndGetStatus, "XNVCTRLSetTargetAttributeAndGetStatus" },
{ (void**)&self->XNVCTRLQueryValidTargetAttributeValues, "XNVCTRLQueryValidTargetAttributeValues" },
{ (void**)&self->XNVCTRLQueryTargetStringAttribute, "XNVCTRLQueryTargetStringAttribute" },
{ NULL, NULL }
};
if(!dlsym_load_list(lib, required_dlsym)) {
fprintf(stderr, "gsr error: gsr_xnvctrl_load failed: missing required symbols in libXNVCtrl.so.0\n");
goto fail;
}
self->library = lib;
return true;
fail:
dlclose(lib);
memset(self, 0, sizeof(gsr_xnvctrl));
return false;
}
void gsr_xnvctrl_unload(gsr_xnvctrl *self) {
if(self->library) {
dlclose(self->library);
memset(self, 0, sizeof(gsr_xnvctrl));
}
}