#include #include #include #include #include #include #include #include "nv/api.h" #include "nv/module.h" #include "util/fs.h" #include "util/mem.h" #include "util/str.h" #define NV_DRS_SETTINGS_FOLDER "C:\\ProgramData\\NVIDIA Corporation\\Drs" #define printf_out(fmt, ...) \ fprintf(stdout, fmt, ##__VA_ARGS__) #define printf_err(fmt, ...) \ fprintf(stderr, fmt, ##__VA_ARGS__) #define printfln_out(fmt, ...) \ fprintf(stdout, fmt "\n", ##__VA_ARGS__) #define printfln_err(fmt, ...) \ fprintf(stderr, fmt "\n", ##__VA_ARGS__) #define PRINT_ERR_WITH_NVAPI_MESSAGE(status, fmt, ...) \ NvAPI_ShortString error_str; \ nv_api->NvAPI_GetErrorMessage(status, error_str); \ fprintf(stderr, fmt ", reason: %s\n", ##__VA_ARGS__, error_str); typedef struct displayconfig_path_info { NvU32 path_info_count; NV_DISPLAYCONFIG_PATH_INFO *path_info; } displayconfig_path_info_t; static bool _session_destroy(const nv_api_t *nv_api, NvDRSSessionHandle session) { assert(nv_api); assert(session); NvAPI_Status status; status = nv_api->NvAPI_DRS_DestroySession(session); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Destroying driver settings session"); return false; } return true; } static bool _session_create_and_settings_load(const nv_api_t *nv_api, NvDRSSessionHandle *session) { assert(nv_api); assert(session); NvAPI_Status status; status = nv_api->NvAPI_DRS_CreateSession(session); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Creating driver settings session"); return false; } status = nv_api->NvAPI_DRS_LoadSettings(*session); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Loading driver settings"); return _session_destroy(nv_api, *session); } return true; } static bool _settings_save_and_session_destroy(const nv_api_t *nv_api, NvDRSSessionHandle session) { assert(nv_api); assert(session); NvAPI_Status status; printfln_err("Saving ..."); status = nv_api->NvAPI_DRS_SaveSettings(session); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Saving driver settings"); return _session_destroy(nv_api, session); } return _session_destroy(nv_api, session); } static bool _profile_get( const nv_api_t *nv_api, const char *profile_name, NvDRSSessionHandle session, NvDRSProfileHandle *profile) { NvAPI_UnicodeString nv_profile_name; NvAPI_Status status; wchar_t *profile_name_wstr; assert(nv_api); assert(session); assert(profile); profile_name_wstr = str_widen(profile_name); wstr_cpy(nv_profile_name, sizeof(nv_profile_name), profile_name_wstr); status = nv_api->NvAPI_DRS_FindProfileByName(session, nv_profile_name, profile); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Finding driver profile %s", profile_name); return false; } return true; } static bool _profile_setting_set( const nv_api_t *nv_api, NvDRSSessionHandle session, NvDRSProfileHandle profile, NVDRS_SETTING *setting) { NvAPI_Status status; assert(nv_api); assert(setting); status = nv_api->NvAPI_DRS_SetSetting(session, profile, setting); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "Error setting driver settings"); return false; } return true; } static void _display_config_free(displayconfig_path_info_t *displayconfig_path_info) { assert(displayconfig_path_info); assert(displayconfig_path_info->path_info); for (NvU32 i = 0; i < displayconfig_path_info->path_info_count; i++) { assert(displayconfig_path_info->path_info[i].sourceModeInfo); assert(displayconfig_path_info->path_info[i].targetInfo); for (NvU32 j = 0; j < displayconfig_path_info->path_info[i].targetInfoCount; j++) { assert(displayconfig_path_info->path_info[i].targetInfo[i].details); free(displayconfig_path_info->path_info[i].targetInfo[i].details); } free(displayconfig_path_info->path_info[i].targetInfo); free(displayconfig_path_info->path_info[i].sourceModeInfo); } free(displayconfig_path_info->path_info); } static bool _display_config_get(const nv_api_t *nv_api, displayconfig_path_info_t *displayconfig_path_info) { NvAPI_Status status; assert(nv_api); assert(displayconfig_path_info); status = nv_api->NvAPI_DISP_GetDisplayConfig(&displayconfig_path_info->path_info_count , NULL); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Getting display config path info count"); return false; } displayconfig_path_info->path_info = (NV_DISPLAYCONFIG_PATH_INFO*) xmalloc(sizeof(NV_DISPLAYCONFIG_PATH_INFO) * displayconfig_path_info->path_info_count); memset(displayconfig_path_info->path_info, 0, sizeof(NV_DISPLAYCONFIG_PATH_INFO) * displayconfig_path_info->path_info_count); for (NvU32 i = 0; i < displayconfig_path_info->path_info_count; i++) { displayconfig_path_info->path_info[i].version = NV_DISPLAYCONFIG_PATH_INFO_VER; } status = nv_api->NvAPI_DISP_GetDisplayConfig(&displayconfig_path_info->path_info_count, displayconfig_path_info->path_info); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Getting display config target info counts"); free(displayconfig_path_info->path_info); return false; } for (NvU32 i = 0; i < displayconfig_path_info->path_info_count; i++) { if (displayconfig_path_info->path_info[i].version == NV_DISPLAYCONFIG_PATH_INFO_VER1 || displayconfig_path_info->path_info[i].version == NV_DISPLAYCONFIG_PATH_INFO_VER2) { displayconfig_path_info->path_info[i].sourceModeInfo = (NV_DISPLAYCONFIG_SOURCE_MODE_INFO*) xmalloc(sizeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO)); } else { #ifdef NV_DISPLAYCONFIG_PATH_INFO_VER3 displayconfig_path_info->path_info[i].sourceModeInfo =(NV_DISPLAYCONFIG_SOURCE_MODE_INFO*) malloc( displayconfig_path_info->path_info[i].sourceModeInfoCount * sizeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO)); #endif } memset(displayconfig_path_info->path_info[i].sourceModeInfo, 0, sizeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO)); displayconfig_path_info->path_info[i].targetInfo = (NV_DISPLAYCONFIG_PATH_TARGET_INFO*) xmalloc( displayconfig_path_info->path_info[i].targetInfoCount * sizeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO)); memset(displayconfig_path_info->path_info[i].targetInfo, 0, displayconfig_path_info->path_info[i].targetInfoCount * sizeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO)); for (NvU32 j = 0 ; j < displayconfig_path_info->path_info[i].targetInfoCount ; j++) { displayconfig_path_info->path_info[i].targetInfo[j].details = (NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO*) xmalloc(sizeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO)); memset(displayconfig_path_info->path_info[i].targetInfo[j].details, 0, sizeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO)); displayconfig_path_info->path_info[i].targetInfo[j].details->version = NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_VER; } } status = nv_api->NvAPI_DISP_GetDisplayConfig(&displayconfig_path_info->path_info_count, displayconfig_path_info->path_info); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Getting display config"); _display_config_free(displayconfig_path_info); return false; } return true; } static bool _display_config_set(const nv_api_t *nv_api, displayconfig_path_info_t *displayconfig_path_info) { NvAPI_Status status; assert(nv_api); assert(displayconfig_path_info); printfln_err("Validating display config..."); status = nv_api->NvAPI_DISP_SetDisplayConfig(displayconfig_path_info->path_info_count, displayconfig_path_info->path_info, NV_DISPLAYCONFIG_VALIDATE_ONLY); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Validating display config"); return false; } printfln_err("Saving display config..."); status = nv_api->NvAPI_DISP_SetDisplayConfig(displayconfig_path_info->path_info_count, displayconfig_path_info->path_info, NV_DISPLAYCONFIG_SAVE_TO_PERSISTENCE | NV_DISPLAYCONFIG_DRIVER_RELOAD_ALLOWED); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Saving display config"); return false; } return true; } static bool _display_config_visit(displayconfig_path_info_t *displayconfig_path_info, NvU32 display_id, bool (*display_config_filter)(NV_DISPLAYCONFIG_PATH_TARGET_INFO *target_info)) { NV_DISPLAYCONFIG_PATH_TARGET_INFO *target_info; for (NvU32 i = 0; i < displayconfig_path_info->path_info_count; i++) { target_info = &displayconfig_path_info->path_info[i].targetInfo[i]; if (display_id != 0 && target_info->displayId != display_id) { continue; } return display_config_filter(target_info); } return false; } static void _ensure_drs_settings_folder_exists() { // Even on a fresh install, this might not exist which result // in NVAPI_ACCESS_DENIED errors on many (or even all?) nvapi DRS functions if (!path_exists(NV_DRS_SETTINGS_FOLDER)) { printfln_err("NOTE: DRS settings folder to store profiles does not exist, creating..."); path_mkdir(NV_DRS_SETTINGS_FOLDER); } } // ------------------------------------------------------------------------------------------------- static bool _nv_info(const nv_api_t *nv_api) { NvAPI_ShortString interface_version; NvAPI_ShortString driver_version; NvU32 driver_version_number; NvAPI_Status status; printfln_err("Getting interface version..."); status = nv_api->NvAPI_GetInterfaceVersionStringEx(interface_version); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Getting interface version string"); return false; } printfln_err("Getting driver and branch version..."); status = nv_api->NvAPI_SYS_GetDriverAndBranchVersion(&driver_version_number, driver_version); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Getting driver and branch version"); return false; } printfln_out("Interface version: %s", interface_version); printfln_out("Driver version: %s", driver_version); printfln_out("Driver version number: %lu", driver_version_number); return true; } static bool _profile_create(const nv_api_t *nv_api, const char *profile_name) { NvDRSSessionHandle session; NVDRS_PROFILE profile; wchar_t *profile_name_wstr; NvAPI_Status status; NvDRSProfileHandle profile_handle; assert(nv_api); assert(profile_name); if (!_session_create_and_settings_load(nv_api, &session)) { return false; } profile.version = NVDRS_PROFILE_VER; profile_name_wstr = str_widen(profile_name); wstr_cpy(profile.profileName, sizeof(profile.profileName), profile_name_wstr); free(profile_name_wstr); printfln_err("Creating profile %s...", profile_name); status = nv_api->NvAPI_DRS_CreateProfile(session, &profile, &profile_handle); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Creating driver profile"); _session_destroy(nv_api, session); return false; } return _settings_save_and_session_destroy(nv_api, session); } static bool _profile_delete(const nv_api_t *nv_api, const char *profile_name) { NvDRSSessionHandle session; NvDRSProfileHandle profile; NvAPI_Status status; assert(nv_api); assert(profile_name); if (!_session_create_and_settings_load(nv_api, &session)) { return false; } if (!_profile_get(nv_api, profile_name, session, &profile)) { _session_destroy(nv_api, session); return false; } printfln_err("Deleting profile %s...", profile_name); status = nv_api->NvAPI_DRS_DeleteProfile(session, profile); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Deleting driver profile %s", profile_name); _session_destroy(nv_api, session); return false; } return _settings_save_and_session_destroy(nv_api, session); } static bool _profile_application_add(const nv_api_t *nv_api, const char *profile_name, const char *application_name) { NvDRSSessionHandle session; NvDRSProfileHandle profile; NvAPI_Status status; NVDRS_APPLICATION application; wchar_t *application_name_wstr; assert(nv_api); assert(profile_name); assert(application_name); if (!_session_create_and_settings_load(nv_api, &session)) { return false; } if (!_profile_get(nv_api, profile_name, session, &profile)) { _session_destroy(nv_api, session); return false; } application.version = NVDRS_APPLICATION_VER; application_name_wstr = str_widen(application_name); wstr_cpy(application.appName, sizeof(application.appName), application_name_wstr); free(application_name_wstr); printfln_err("Adding application %s to profile %s...", application_name, profile_name); status = nv_api->NvAPI_DRS_CreateApplication(session, profile, &application); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Adding application %s to profile %s", application_name, profile_name); _session_destroy(nv_api, session); return false; } return _settings_save_and_session_destroy(nv_api, session); } static bool _profile_gsync_disable(const nv_api_t *nv_api, const char *profile_name) { NvDRSSessionHandle session; NvDRSProfileHandle profile; NVDRS_SETTING setting; assert(nv_api); assert(profile_name); if (!_session_create_and_settings_load(nv_api, &session)) { return false; } if (!_profile_get(nv_api, profile_name, session, &profile)) { _session_destroy(nv_api, session); return false; } setting.version = NVDRS_SETTING_VER; setting.settingId = VRR_APP_OVERRIDE_ID; setting.settingType = NVDRS_DWORD_TYPE; setting.u32PredefinedValue = VRR_APP_OVERRIDE_FIXED_REFRESH; setting.u32CurrentValue = VRR_APP_OVERRIDE_FIXED_REFRESH; printfln_err("Disabling G-SYNC for profile %s...", profile_name); if (!_profile_setting_set(nv_api, session, profile, &setting)) { _session_destroy(nv_api, session); return false; } return _settings_save_and_session_destroy(nv_api, session); } static bool _profile_gpu_power_state_max(const nv_api_t *nv_api, const char *profile_name) { NvDRSSessionHandle session; NvDRSProfileHandle profile; NVDRS_SETTING setting; assert(nv_api); assert(profile_name); if (!_session_create_and_settings_load(nv_api, &session)) { return false; } if (!_profile_get(nv_api, profile_name, session, &profile)) { _session_destroy(nv_api, session); return false; } setting.version = NVDRS_SETTING_VER; setting.settingId = PREFERRED_PSTATE_ID; setting.settingType = NVDRS_DWORD_TYPE; setting.u32PredefinedValue = PREFERRED_PSTATE_PREFER_MAX; setting.u32CurrentValue = PREFERRED_PSTATE_PREFER_MAX; printfln_err("Setting GPU power state to maximum for profile %s...", profile_name); if (!_profile_setting_set(nv_api, session, profile, &setting)) { _session_destroy(nv_api, session); return false; } return _settings_save_and_session_destroy(nv_api, session); } static bool _display_primary_display_id(const nv_api_t *nv_api) { NvAPI_Status status; NvPhysicalGpuHandle gpu_handle[NVAPI_MAX_PHYSICAL_GPUS]; NvU32 gpu_count; NvU32 display_id_count; NV_GPU_DISPLAYIDS *display_ids; assert(nv_api); status = nv_api->NvAPI_EnumPhysicalGPUs(gpu_handle, &gpu_count); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Enumerating physical GPUs"); return false; } // Assuming first physical GPU, first display = primary display if (gpu_count > 0) { status = nv_api->NvAPI_GPU_GetConnectedDisplayIds(gpu_handle[0], NULL, &display_id_count, 0); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Getting connected display count of GPU"); return false; } if (display_id_count > 0) { display_ids = (NV_GPU_DISPLAYIDS*) xmalloc(sizeof(NV_GPU_DISPLAYIDS) * display_id_count); for (NvU32 j = 0; j < display_id_count; j++) { display_ids[j].version = NV_GPU_DISPLAYIDS_VER; } status = nv_api->NvAPI_GPU_GetConnectedDisplayIds(gpu_handle[0], display_ids, &display_id_count, 0); if (status != NVAPI_OK) { free(display_ids); PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Getting connected display ids of GPU"); return false; } printfln_out("0x%lX", display_ids[0].displayId); free(display_ids); return true; } } return false; } static bool _displays_list(const nv_api_t *nv_api) { NvAPI_Status status; NvPhysicalGpuHandle gpu_handle[NVAPI_MAX_PHYSICAL_GPUS]; NvU32 gpu_count; NvU32 display_id_count; NV_GPU_DISPLAYIDS *display_ids; const char *connector_type; assert(nv_api); status = nv_api->NvAPI_EnumPhysicalGPUs(gpu_handle, &gpu_count); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Enumerating physical GPUs"); return false; } printfln_err("Display ID, Connector Type, Active, Connected, Physically Connected"); for (NvU32 i = 0; i < gpu_count; i++) { // Get display count per GPU display_id_count = 0; status = nv_api->NvAPI_GPU_GetConnectedDisplayIds(gpu_handle[i], NULL, &display_id_count, 0); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Getting connected display count of GPU"); return false; } if (display_id_count > 0) { display_ids = (NV_GPU_DISPLAYIDS*) xmalloc(sizeof(NV_GPU_DISPLAYIDS) * display_id_count); for (NvU32 j = 0; j < display_id_count; j++) { display_ids[j].version = NV_GPU_DISPLAYIDS_VER; } status = nv_api->NvAPI_GPU_GetConnectedDisplayIds(gpu_handle[i], display_ids, &display_id_count, 0); if (status != NVAPI_OK) { free(display_ids); PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Getting connected display ids of GPU"); return false; } for (NvU32 j = 0; j < display_id_count; j++) { switch (display_ids[j].connectorType) { case NV_MONITOR_CONN_TYPE_VGA: connector_type = "VGA"; break; case NV_MONITOR_CONN_TYPE_COMPONENT: connector_type = "Component"; break; case NV_MONITOR_CONN_TYPE_SVIDEO: connector_type = "S-Video"; break; case NV_MONITOR_CONN_TYPE_HDMI: connector_type = "HDMI"; break; case NV_MONITOR_CONN_TYPE_DVI: connector_type = "DVI"; break; case NV_MONITOR_CONN_TYPE_LVDS: connector_type = "LVDS"; break; case NV_MONITOR_CONN_TYPE_DP: connector_type = "DP"; break; case NV_MONITOR_CONN_TYPE_COMPOSITE: connector_type = "Composite"; break; default: connector_type = "unknown"; break; } printfln_out("0x%lX, %s, %s, %s, %s", display_ids[j].displayId, connector_type, display_ids[j].isActive ? "active" : "inactive", display_ids[j].isConnected ? "connected" : "disconnected", display_ids[j].isPhysicallyConnected ? "connected" : "disconnected"); } free(display_ids); } } return true; } static bool _display_config_print(const nv_api_t *nv_api, NvU32 display_id) { displayconfig_path_info_t displayconfig_path_info; NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 *target_info; NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 *source_mode_info; assert(nv_api); if (!_display_config_get(nv_api, &displayconfig_path_info)) { return false; } if (display_id != 0) { printfln_err("Applying display ID filter: %lX", display_id); } printfln_err("Num total adapters in config: %ld", displayconfig_path_info.path_info_count); for (NvU32 i = 0; i < displayconfig_path_info.path_info_count; i++) { printfln_err("Num total displays in adapter: %ld", displayconfig_path_info.path_info[i].targetInfoCount); for (NvU32 j = 0; j < displayconfig_path_info.path_info[i].targetInfoCount; j++) { target_info = &displayconfig_path_info.path_info[i].targetInfo[j]; source_mode_info = &displayconfig_path_info.path_info[i].sourceModeInfo[j]; if (display_id != 0 && target_info->displayId != display_id) { continue; } printfln_out("--------------------------------"); printfln_out("Adapter source ID %ld", displayconfig_path_info.path_info[i].sourceId); printfln_out("Display ID: %lX", target_info->displayId); printfln_out("Resolution width: %ld", source_mode_info->resolution.width); printfln_out("Resolution height: %ld", source_mode_info->resolution.height); printfln_out("Color depth: %d", source_mode_info->colorFormat); printfln_out("Position x: %d", source_mode_info->position.x); printfln_out("Position y: %d", source_mode_info->position.y); printfln_out("Spanning orientation: %d", source_mode_info->spanningOrientation); printfln_out("GDI primary: %d", source_mode_info->bGDIPrimary); printfln_out("SLI focus: %d", source_mode_info->bSLIFocus); if (target_info->details) { switch (target_info->details->rotation) { case NV_ROTATE_0: printfln_out("Rotation: 0 degrees"); break; case NV_ROTATE_90: printfln_out("Rotation: 90 degrees"); break; case NV_ROTATE_180: printfln_out("Rotation: 180 degrees"); break; case NV_ROTATE_270: printfln_out("Rotation: 270 degrees"); break; case NV_ROTATE_IGNORED: printfln_out("Rotation: ignored"); break; default: printfln_out("Rotation: unknown (%d)", target_info->details->rotation); break; } switch (target_info->details->scaling) { case NV_SCALING_DEFAULT: printfln_out("Scaling: default"); break; case NV_SCALING_GPU_SCALING_TO_CLOSEST: printfln_out("Scaling: GPU scaling to closest"); break; case NV_SCALING_GPU_SCALING_TO_NATIVE: printfln_out("Scaling: GPU scaling to native"); break; case NV_SCALING_GPU_SCANOUT_TO_NATIVE: printfln_out("Scaling: GPU scanout to native"); break; case NV_SCALING_GPU_SCALING_TO_ASPECT_SCANOUT_TO_NATIVE: printfln_out("Scaling: GPU scaling to aspect scanout to native"); break; case NV_SCALING_GPU_SCALING_TO_ASPECT_SCANOUT_TO_CLOSEST: printfln_out("Scaling: GPU scaling to aspect scanout to closest"); break; case NV_SCALING_GPU_SCANOUT_TO_CLOSEST: printfln_out("Scaling: GPU scanout to closest"); break; case NV_SCALING_GPU_INTEGER_ASPECT_SCALING: printfln_out("Scaling: GPU integer aspect scaling"); break; default: printfln_out("Scaling: unknown (%d)", target_info->details->scaling); break; } printfln_out("Refresh rate (non interlaced): %ld", target_info->details->refreshRate1K * 1000); printfln_out("Interlaced: %d", target_info->details->interlaced); printfln_out("Primary: %d", target_info->details->primary); printfln_out("Disable virtual mode support: %d", target_info->details->disableVirtualModeSupport); printfln_out("Is preferred unscaled target: %d", target_info->details->isPreferredUnscaledTarget); switch (target_info->details->connector) { case NVAPI_GPU_CONNECTOR_VGA_15_PIN: printfln_out("Connector: VGA 15 Pin"); break; case NVAPI_GPU_CONNECTOR_TV_COMPOSITE: printfln_out("Connector: TV Composite"); break; case NVAPI_GPU_CONNECTOR_TV_SVIDEO: printfln_out("Connector: TV S-Video"); break; case NVAPI_GPU_CONNECTOR_TV_HDTV_COMPONENT: printfln_out("Connector: TV HDTV Component"); break; case NVAPI_GPU_CONNECTOR_TV_SCART: printfln_out("Connector: TV SCART"); break; case NVAPI_GPU_CONNECTOR_TV_COMPOSITE_SCART_ON_EIAJ4120: printfln_out("Connector: TV Composite SCART on EIAJ4120"); break; case NVAPI_GPU_CONNECTOR_TV_HDTV_EIAJ4120: printfln_out("Connector: TV HDTV EIAJ4120"); break; case NVAPI_GPU_CONNECTOR_PC_POD_HDTV_YPRPB: printfln_out("Connector: PC POD HDTV YPRPB"); break; case NVAPI_GPU_CONNECTOR_PC_POD_SVIDEO: printfln_out("Connector: PC POD S-Video"); break; case NVAPI_GPU_CONNECTOR_PC_POD_COMPOSITE: printfln_out("Connector: PC POD Composite"); break; case NVAPI_GPU_CONNECTOR_DVI_I_TV_SVIDEO: printfln_out("Connector: DVI-I TV S-Video"); break; case NVAPI_GPU_CONNECTOR_DVI_I_TV_COMPOSITE: printfln_out("Connector: DVI-I TV Composite"); break; case NVAPI_GPU_CONNECTOR_DVI_I: printfln_out("Connector: DVI-I"); break; case NVAPI_GPU_CONNECTOR_DVI_D: printfln_out("Connector: DVI-D"); break; case NVAPI_GPU_CONNECTOR_ADC: printfln_out("Connector: ADC"); break; case NVAPI_GPU_CONNECTOR_LFH_DVI_I_1: printfln_out("Connector: LFH DVI-I 1"); break; case NVAPI_GPU_CONNECTOR_LFH_DVI_I_2: printfln_out("Connector: LFH DVI-I 2"); break; case NVAPI_GPU_CONNECTOR_SPWG: printfln_out("Connector: SPWG"); break; case NVAPI_GPU_CONNECTOR_OEM: printfln_out("Connector: OEM"); break; case NVAPI_GPU_CONNECTOR_DISPLAYPORT_EXTERNAL: printfln_out("Connector: DisplayPort External"); break; case NVAPI_GPU_CONNECTOR_DISPLAYPORT_INTERNAL: printfln_out("Connector: DisplayPort Internal"); break; case NVAPI_GPU_CONNECTOR_DISPLAYPORT_MINI_EXT: printfln_out("Connector: DisplayPort Mini External"); break; case NVAPI_GPU_CONNECTOR_HDMI_A: printfln_out("Connector: HDMI A"); break; case NVAPI_GPU_CONNECTOR_HDMI_C_MINI: printfln_out("Connector: HDMI C Mini"); break; case NVAPI_GPU_CONNECTOR_LFH_DISPLAYPORT_1: printfln_out("Connector: LFH DisplayPort 1"); break; case NVAPI_GPU_CONNECTOR_LFH_DISPLAYPORT_2: printfln_out("Connector: LFH DisplayPort 2"); break; case NVAPI_GPU_CONNECTOR_VIRTUAL_WFD: printfln_out("Connector: Virtual WFD"); break; case NVAPI_GPU_CONNECTOR_USB_C: printfln_out("Connector: USB C"); break; default: printfln_out("Connector: unknown (%d)", target_info->details->connector); break; } switch (target_info->details->tvFormat) { case NV_DISPLAY_TV_FORMAT_NONE: printfln_out("TV format: none"); break; case NV_DISPLAY_TV_FORMAT_SD_NTSCM: printfln_out("TV format: SD NTSC-M"); break; case NV_DISPLAY_TV_FORMAT_SD_NTSCJ: printfln_out("TV format: SD NTSC-J"); break; case NV_DISPLAY_TV_FORMAT_SD_PALM: printfln_out("TV format: SD PAL-M"); break; case NV_DISPLAY_TV_FORMAT_SD_PALBDGH: printfln_out("TV format: SD PAL-BDGH"); break; case NV_DISPLAY_TV_FORMAT_SD_PALN: printfln_out("TV format: SD PAL-N"); break; case NV_DISPLAY_TV_FORMAT_SD_PALNC: printfln_out("TV format: SD PAL-NC"); break; case NV_DISPLAY_TV_FORMAT_SD_576i: printfln_out("TV format: SD 576i"); break; case NV_DISPLAY_TV_FORMAT_SD_480i: printfln_out("TV format: SD 480i"); break; case NV_DISPLAY_TV_FORMAT_ED_480p: printfln_out("TV format: ED 480p"); break; case NV_DISPLAY_TV_FORMAT_ED_576p: printfln_out("TV format: ED 576p"); break; case NV_DISPLAY_TV_FORMAT_HD_720p: printfln_out("TV format: HD 720p"); break; case NV_DISPLAY_TV_FORMAT_HD_1080i: printfln_out("TV format: HD 1080i"); break; case NV_DISPLAY_TV_FORMAT_HD_1080p: printfln_out("TV format: HD 1080p"); break; case NV_DISPLAY_TV_FORMAT_HD_720p50: printfln_out("TV format: HD 720p50"); break; case NV_DISPLAY_TV_FORMAT_HD_1080p24: printfln_out("TV format: HD 1080p24"); break; case NV_DISPLAY_TV_FORMAT_HD_1080i50: printfln_out("TV format: HD 1080i50"); break; case NV_DISPLAY_TV_FORMAT_HD_1080p50: printfln_out("TV format: HD 1080p50"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp30_3840: printfln_out("TV format: UHD 4Kp30 3840"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp25_3840: printfln_out("TV format: UHD 4Kp25 3840"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp24_3840: printfln_out("TV format: UHD 4Kp24 3840"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp24_SMPTE: printfln_out("TV format: UHD 4Kp24 SMPTE"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp50_3840: printfln_out("TV format: UHD 4Kp50 3840"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp60_3840: printfln_out("TV format: UHD 4Kp60 3840"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp30_4096: printfln_out("TV format: UHD 4Kp30 4096"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp25_4096: printfln_out("TV format: UHD 4Kp25 4096"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp24_4096: printfln_out("TV format: UHD 4Kp24 4096"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp50_4096: printfln_out("TV format: UHD 4Kp50 4096"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp60_4096: printfln_out("TV format: UHD 4Kp60 4096"); break; case NV_DISPLAY_TV_FORMAT_UHD_8Kp24_7680: printfln_out("TV format: UHD 8Kp24 7680"); break; case NV_DISPLAY_TV_FORMAT_UHD_8Kp25_7680: printfln_out("TV format: UHD 8Kp25 7680"); break; case NV_DISPLAY_TV_FORMAT_UHD_8Kp30_7680: printfln_out("TV format: UHD 8Kp30 7680"); break; case NV_DISPLAY_TV_FORMAT_UHD_8Kp48_7680: printfln_out("TV format: UHD 8Kp48 7680"); break; case NV_DISPLAY_TV_FORMAT_UHD_8Kp50_7680: printfln_out("TV format: UHD 8Kp50 7680"); break; case NV_DISPLAY_TV_FORMAT_UHD_8Kp60_7680: printfln_out("TV format: UHD 8Kp60 7680"); break; case NV_DISPLAY_TV_FORMAT_UHD_8Kp100_7680: printfln_out("TV format: UHD 8Kp100 7680"); break; case NV_DISPLAY_TV_FORMAT_UHD_8Kp120_7680: printfln_out("TV format: UHD 8Kp120 7680"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp48_3840: printfln_out("TV format: UHD 4Kp48 3840"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp48_4096: printfln_out("TV format: UHD 4Kp48 4096"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp100_3840: printfln_out("TV format: UHD 4Kp100 3840"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp100_4096: printfln_out("TV format: UHD 4Kp100 4096"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp120_4096: printfln_out("TV format: UHD 4Kp120 4096"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp120_3840: printfln_out("TV format: UHD 4Kp120 3840"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp100_5120: printfln_out("TV format: UHD 4Kp100 5120"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp120_5120: printfln_out("TV format: UHD 4Kp120 5120"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp24_5120: printfln_out("TV format: UHD 4Kp24 5120"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp25_5120: printfln_out("TV format: UHD 4Kp25 5120"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp30_5120: printfln_out("TV format: UHD 4Kp30 5120"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp48_5120: printfln_out("TV format: UHD 4Kp48 5120"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp50_5120: printfln_out("TV format: UHD 4Kp50 5120"); break; case NV_DISPLAY_TV_FORMAT_UHD_4Kp60_5120: printfln_out("TV format: UHD 4Kp60 5120"); break; case NV_DISPLAY_TV_FORMAT_UHD_10Kp24_10240: printfln_out("TV format: UHD 10Kp24 10240"); break; case NV_DISPLAY_TV_FORMAT_UHD_10Kp25_10240: printfln_out("TV format: UHD 10Kp25 10240"); break; case NV_DISPLAY_TV_FORMAT_UHD_10Kp30_10240: printfln_out("TV format: UHD 10Kp30 10240"); break; case NV_DISPLAY_TV_FORMAT_UHD_10Kp48_10240: printfln_out("TV format: UHD 10Kp48 10240"); break; case NV_DISPLAY_TV_FORMAT_UHD_10Kp50_10240: printfln_out("TV format: UHD 10Kp50 10240"); break; case NV_DISPLAY_TV_FORMAT_UHD_10Kp60_10240: printfln_out("TV format: UHD 10Kp60 10240"); break; case NV_DISPLAY_TV_FORMAT_UHD_10Kp100_10240: printfln_out("TV format: UHD 10Kp100 10240"); break; case NV_DISPLAY_TV_FORMAT_UHD_10Kp120_10240: printfln_out("TV format: UHD 10Kp120 10240"); break; case NV_DISPLAY_TV_FORMAT_SD_OTHER: printfln_out("TV format: SD Other"); break; case NV_DISPLAY_TV_FORMAT_ED_OTHER: printfln_out("TV format: ED Other"); break; case NV_DISPLAY_TV_FORMAT_HD_OTHER: printfln_out("TV format: HD Other"); break; case NV_DISPLAY_TV_FORMAT_ANY: printfln_out("TV format: Any"); break; default: printfln_out("TV format: unknown (%d)", target_info->details->tvFormat); break; } switch (target_info->details->timingOverride) { case NV_TIMING_OVERRIDE_CURRENT: printfln_out("Timing override: current"); break; case NV_TIMING_OVERRIDE_AUTO: printfln_out("Timing override: auto"); break; case NV_TIMING_OVERRIDE_EDID: printfln_out("Timing override: EDID"); break; case NV_TIMING_OVERRIDE_DMT: printfln_out("Timing override: VESA DMT"); break; case NV_TIMING_OVERRIDE_DMT_RB: printfln_out("Timing override: VESA DMT RB"); break; case NV_TIMING_OVERRIDE_CVT: printfln_out("Timing override: VESA CVT"); break; case NV_TIMING_OVERRIDE_CVT_RB: printfln_out("Timing override: VESA CVT RB"); break; case NV_TIMING_OVERRIDE_GTF: printfln_out("Timing override: VESA GTF"); break; case NV_TIMING_OVERRIDE_EIA861: printfln_out("Timing override: EIA 861x pre-defined timing"); break; case NV_TIMING_OVERRIDE_ANALOG_TV: printfln_out("Timing override: analog SD/HDTV timing"); break; case NV_TIMING_OVERRIDE_CUST: printfln_out("Timing override: NV custom timings"); break; case NV_TIMING_OVERRIDE_NV_PREDEFINED: printfln_out("Timing override: NV pre-defined timing (basically the PsF timings)"); break; case NV_TIMING_OVERRIDE_NV_ASPR: printfln_out("Timing override: NV ASPR"); break; case NV_TIMING_OVERRIDE_SDI: printfln_out("Timing override: SDI"); break; case NV_TIMING_OVRRIDE_MAX: printfln_out("Timing override: max"); break; default: printfln_out("Timing override: unknown (%d)", target_info->details->timingOverride); break; } printfln_out("Override custom (backend raster) timing"); printfln_out("Horizontal visible: %d", target_info->details->timing.HVisible); printfln_out("Horizontal border: %d", target_info->details->timing.HBorder); printfln_out("Horizontal front porch: %d", target_info->details->timing.HFrontPorch); printfln_out("Horizontal sync width: %d", target_info->details->timing.HSyncWidth); printfln_out("Horizontal total: %d", target_info->details->timing.HTotal); printfln_out("Horizontal sync polarity: %s", target_info->details->timing.HSyncPol == 1 ? "negative" : "positive"); printfln_out("Vertical visible: %d", target_info->details->timing.VVisible); printfln_out("Vertical border: %d", target_info->details->timing.VBorder); printfln_out("Vertical front porch: %d", target_info->details->timing.VFrontPorch); printfln_out("Vertical sync width: %d", target_info->details->timing.VSyncWidth); printfln_out("Vertical total: %d", target_info->details->timing.VTotal); printfln_out("Vertical sync polarity: %s", target_info->details->timing.VSyncPol == 1 ? "negative" : "positive"); printfln_out("Interlaced: %s", target_info->details->timing.interlaced == 1 ? "interlaced" : "progressive"); printfln_out("Pixel clock: %lu kHz", target_info->details->timing.pclk * 10); printfln_out("Flag: 0x%lX", target_info->details->timing.etc.flag); printfln_out("Logical refresh rate to present: %d", target_info->details->timing.etc.rr); printfln_out("Physical vertical refresh rate: %f Hz", target_info->details->timing.etc.rrx1k * 0.001); printfln_out("Display aspect ratio: %lu:%lu", target_info->details->timing.etc.aspect >> 16, target_info->details->timing.etc.aspect & 0xFFFF); printfln_out("Bit-wise pixel repetition factor (1 = no pixel repetition, 2 = each pixel repeats twice horizontally, etc.): %d", target_info->details->timing.etc.rep); printfln_out("Timing status: 0x%lX", target_info->details->timing.etc.status); printfln_out("Timing name: %s", target_info->details->timing.etc.name); } printfln_out("--------------------------------"); } } _display_config_free(&displayconfig_path_info); return true; } static bool _custom_resolution_set( const nv_api_t *nv_api, NvU32 display_id, uint16_t screen_width, uint16_t screen_height, float screen_refresh_rate, uint8_t test_only_timeout_sec) { NV_CUSTOM_DISPLAY custom_display; NV_TIMING_FLAG flag; NV_TIMING_INPUT timing; NvAPI_Status status; assert(nv_api); memset(&custom_display, 0, sizeof(NV_CUSTOM_DISPLAY)); memset(&flag, 0, sizeof(NV_TIMING_FLAG)); memset(&timing, 0, sizeof(NV_TIMING_INPUT)); custom_display.version = NV_CUSTOM_DISPLAY_VER; custom_display.width = screen_width; custom_display.height = screen_height; custom_display.depth = 32; custom_display.colorFormat = NV_FORMAT_A8R8G8B8; custom_display.srcPartition.x = 0; custom_display.srcPartition.y = 0; custom_display.srcPartition.w = 1; custom_display.srcPartition.h = 1; custom_display.xRatio = 1; custom_display.yRatio = 1; timing.version = NV_TIMING_INPUT_VER; timing.height = screen_height; timing.width = screen_width; timing.rr = screen_refresh_rate; timing.flag = flag; timing.type = NV_TIMING_OVERRIDE_CVT_RB; printfln_err("Calculating custom display timing for display ID 0x%lX", display_id); status = nv_api->NvAPI_DISP_GetTiming(display_id, &timing, &custom_display.timing); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Calculating custom display timing"); return false; } status = nv_api->NvAPI_DISP_TryCustomDisplay(&display_id, 1, &custom_display); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Trying custom display configuration"); return false; } if (test_only_timeout_sec == 0) { printfln_err("Persisting custom display configuration"); status = nv_api->NvAPI_DISP_SaveCustomDisplay(&display_id, 1, true, true); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Saving custom display configuration"); return false; } printfln_err("Custom display configuration persisted"); } else { printfln_err("Trying custom display configuration for %d seconds...", test_only_timeout_sec); Sleep(test_only_timeout_sec * 1000); printfln_err("Reverting custom display configuration, not persisting"); status = nv_api->NvAPI_DISP_RevertCustomDisplayTrial(&display_id, 1); if (status != NVAPI_OK) { PRINT_ERR_WITH_NVAPI_MESSAGE(status, "ERROR: Reverting custom display configuration"); return false; } } return true; } static bool _display_config_gpu_scaling_enable_filter(NV_DISPLAYCONFIG_PATH_TARGET_INFO *target_info) { if (target_info->details == NULL) { printfln_err("ERROR: No details found for target info"); return false; } if (target_info->details->scaling == NV_SCALING_GPU_SCALING_TO_NATIVE) { printfln_err("GPU scaling to native resolution is already enabled"); return false; } else { target_info->details->scaling = NV_SCALING_GPU_SCALING_TO_NATIVE; printfln_err("Enabling GPU scaling to native resolution"); return true; } } static bool _display_config_gpu_scaling_to_native_resolution_enable(const nv_api_t *nv_api, NvU32 display_id) { displayconfig_path_info_t displayconfig_path_info; bool changes_to_save; assert(nv_api); if (!_display_config_get(nv_api, &displayconfig_path_info)) { return false; } changes_to_save = _display_config_visit(&displayconfig_path_info, display_id, _display_config_gpu_scaling_enable_filter); if (changes_to_save) { if (!_display_config_set(nv_api, &displayconfig_path_info)) { _display_config_free(&displayconfig_path_info); return false; } } _display_config_free(&displayconfig_path_info); return true; } // ------------------------------------------------------------------------------------------------- static void _print_synopsis() { printfln_err("Usage: nvgpu "); printfln_err("Commands:"); printfln_err(" nv"); printfln_err(" info Print information about the NVAPI module and driver"); printfln_err(""); printfln_err(" profile"); printfln_err(" create Create a new driver profile with the given name"); printfln_err(" delete Delete an existing driver profile"); printfln_err(" application-add "); printfln_err(" Add an application to the driver profile. This will apply the profile to the application when the driver detects a process being launched, e.g. MyApplication.exe"); printfln_err(" gsync-disable Disable G-SYNC for the driver profile"); printfln_err(" gpu-power-state-max Set GPU power state to maximum for the driver profile"); printfln_err(""); printfln_err(" display"); printfln_err(" primary-display-id Print the ID of the primary display"); printfln_err(" list List all connected displays and their display IDs"); printfln_err(" config [display_id] Print the current display configurations. Optionally, specify a display ID to get the configuration of that display only"); printfln_err(" custom-resolution-set "); printfln_err(" Set a custom display mode with the given parameters for the given display ID. The settings are persisted immediately. Ensure you tested these before with the custom-display-test command."); printfln_err(" custom-resolution-test [--test-timeout-secs n]"); printfln_err(" Test a custom display mode for a limited amount of time. This will revert the display mode after the given amount of seconds and not persist the changes."); printfln_err(" test-timeout-secs: Optional. Number of seconds to test the custom display mode for. Default is 10 seconds."); printfln_err(" gpu-scaling-to-native-resolution-enable Enable GPU scaling to native resolution for the given display ID"); } static bool _cmd_nv_info(const nv_api_t *nv_api) { return _nv_info(nv_api); } static bool _cmd_profile_create(const nv_api_t *nv_api, int argc, char **argv) { const char *profile_name; if (argc < 1) { _print_synopsis(); printfln_err("ERROR: Insufficient arguments"); return false; } profile_name = argv[0]; return _profile_create(nv_api, profile_name); } static bool _cmd_profile_delete(const nv_api_t *nv_api, int argc, char **argv) { const char *profile_name; if (argc < 1) { _print_synopsis(); printfln_err("ERROR: Insufficient arguments"); return false; } profile_name = argv[0]; return _profile_delete(nv_api, profile_name); } static bool _cmd_profile_application_add(const nv_api_t *nv_api, int argc, char **argv) { const char *profile_name; const char *application_name; if (argc < 2) { _print_synopsis(); printfln_err("ERROR: Insufficient arguments"); return false; } profile_name = argv[0]; application_name = argv[1]; return _profile_application_add(nv_api, profile_name, application_name); } static bool _cmd_profile_gsync_disable(const nv_api_t *nv_api, int argc, char **argv) { const char *profile_name; if (argc < 1) { _print_synopsis(); printfln_err("ERROR: Insufficient arguments"); return false; } profile_name = argv[0]; return _profile_gsync_disable(nv_api, profile_name); } static bool _cmd_profile_gpu_power_state_max(const nv_api_t *nv_api, int argc, char **argv) { const char *profile_name; if (argc < 1) { _print_synopsis(); printfln_err("ERROR: Insufficient arguments"); return false; } profile_name = argv[0]; return _profile_gpu_power_state_max(nv_api, profile_name); } static bool _cmd_display_primary_display_id(const nv_api_t *nv_api) { return _display_primary_display_id(nv_api); } static bool _cmd_display_list(const nv_api_t *nv_api) { return _displays_list(nv_api); } static bool _cmd_display_config(const nv_api_t *nv_api, int argc, char **argv) { uint32_t display_id; if (argc > 0) { if (argv[0][0] == '0' && argv[0][1] == 'x') { display_id = strtoul(argv[0] + 2, NULL, 16); } else { display_id = strtoul(argv[0], NULL, 10); } } else { display_id = 0; } return _display_config_print(nv_api, display_id); } static bool _cmd_custom_resolution_set(const nv_api_t *nv_api, int argc, char **argv) { uint32_t display_id; uint16_t screen_width; uint16_t screen_height; float screen_refresh_rate; if (argc < 4) { _print_synopsis(); printfln_err("ERROR: Insufficient arguments"); return false; } if (argv[0][0] == '0' && argv[0][1] == 'x') { display_id = strtoul(argv[0] + 2, NULL, 16); } else { display_id = strtoul(argv[0], NULL, 10); } screen_width = atoi(argv[1]); screen_height = atoi(argv[2]); screen_refresh_rate = atof(argv[3]); printf_err("Setting custom resolution for display ID 0x%X: %dx%d@%f\n", display_id, screen_width, screen_height, screen_refresh_rate); return _custom_resolution_set( nv_api, display_id, screen_width, screen_height, screen_refresh_rate, 0); } static bool _cmd_custom_resolution_test(const nv_api_t *nv_api, int argc, char **argv) { uint32_t display_id; uint16_t screen_width; uint16_t screen_height; float screen_refresh_rate; uint8_t test_only_timeout_sec; if (argc < 5) { _print_synopsis(); printfln_err("ERROR: Insufficient arguments"); return false; } if (argv[0][0] == '0' && argv[0][1] == 'x') { display_id = strtoul(argv[0] + 2, NULL, 16); } else { display_id = strtoul(argv[0], NULL, 10); } screen_width = atoi(argv[1]); screen_height = atoi(argv[2]); screen_refresh_rate = atof(argv[3]); // Sane defaults for optional parameters test_only_timeout_sec = 10; for (int i = 4; i < argc; i++) { if (!strcmp(argv[i], "--test-timeout-secs")) { if (i + 1 < argc) { test_only_timeout_sec = atoi(argv[++i]); if (test_only_timeout_sec == 0) { printfln_err("ERROR: Time out parameter must be greater than 0"); return false; } } else { printfln_err("ERROR: Missing argument for --test-timeout-secs"); return false; } } } printf_err("Testing custom resolution for display ID %u: %dx%d@%f, timeout %d seconds\n", display_id, screen_width, screen_height, screen_refresh_rate, test_only_timeout_sec); return _custom_resolution_set( nv_api, display_id, screen_width, screen_height, screen_refresh_rate, test_only_timeout_sec); } static bool _cmd_display_gpu_scaling_to_native_resolution_enable(const nv_api_t *nv_api, int argc, char **argv) { uint32_t display_id; if (argc < 1) { _print_synopsis(); printfln_err("ERROR: Insufficient arguments"); return false; } if (argv[0][0] == '0' && argv[0][1] == 'x') { display_id = strtoul(argv[0] + 2, NULL, 16); } else { display_id = strtoul(argv[0], NULL, 10); } return _display_config_gpu_scaling_to_native_resolution_enable(nv_api, display_id); } // ------------------------------------------------------------------------------------------------- int main(int argc, char **argv) { const char *command; const char *sub_command; nv_module_t *nv_module; nv_api_t nv_api; NvAPI_Status status; bool result; if (argc < 3) { _print_synopsis(); printfln_err("ERROR: Insufficient arguments"); exit(1); } command = argv[1]; sub_command = argv[2]; printfln_err("Loading NVAPI module..."); nv_module_load(&nv_module); nv_module_api_get(nv_module, &nv_api); printfln_err("Initializing NVAPI..."); status = nv_api.NvAPI_Initialize(); if (status != NVAPI_OK) { NvAPI_ShortString error_str; nv_api.NvAPI_GetErrorMessage(status, error_str); fprintf(stderr, "ERROR: Initializing NVAPI, reason: %s\n", error_str); nv_module_free(&nv_module); exit(1); } printfln_err("Running command: %s %s", command, sub_command); if (!strcmp(command, "nv")) { if (!strcmp(sub_command, "info")) { result = _cmd_nv_info(&nv_api); } else { printfln_err("ERROR: Unknown sub-command: %s", sub_command); _print_synopsis(); result = false; } } else if (!strcmp(command, "profile")) { _ensure_drs_settings_folder_exists(); if (!strcmp(sub_command, "create")) { result = _cmd_profile_create(&nv_api, argc - 3, argv + 3); } else if (!strcmp(sub_command, "delete")) { result = _cmd_profile_delete(&nv_api, argc - 3, argv + 3); } else if (!strcmp(sub_command, "application-add")) { result = _cmd_profile_application_add(&nv_api, argc - 3, argv + 3); } else if (!strcmp(sub_command, "gsync-disable")) { result = _cmd_profile_gsync_disable(&nv_api, argc - 3, argv + 3); } else if (!strcmp(sub_command, "gpu-power-state-max")) { result = _cmd_profile_gpu_power_state_max(&nv_api, argc - 3, argv + 3); } else { printfln_err("ERROR: Unknown sub-command: %s", sub_command); _print_synopsis(); result = false; } } else if (!strcmp(command, "display")) { if (!strcmp(sub_command, "primary-display-id")) { result = _cmd_display_primary_display_id(&nv_api); } else if (!strcmp(sub_command, "list")) { result = _cmd_display_list(&nv_api); } else if (!strcmp(sub_command, "config")) { result = _cmd_display_config(&nv_api, argc - 3, argv + 3); } else if (!strcmp(sub_command, "custom-resolution-set")) { result = _cmd_custom_resolution_set(&nv_api, argc - 3, argv + 3); } else if (!strcmp(sub_command, "custom-resolution-test")) { result = _cmd_custom_resolution_test(&nv_api, argc - 3, argv + 3); } else if (!strcmp(sub_command, "gpu-scaling-to-native-resolution-enable")) { result = _cmd_display_gpu_scaling_to_native_resolution_enable(&nv_api, argc - 3, argv + 3); } else { printfln_err("ERROR: Unknown sub-command: %s", sub_command); _print_synopsis(); result = false; } } else { printfln_err("ERROR: Unknown command: %s", command); _print_synopsis(); result = false; } status = nv_api.NvAPI_Unload(); if (status != NVAPI_OK) { NvAPI_ShortString error_str; nv_api.NvAPI_GetErrorMessage(status, error_str); printfln_err("ERROR: Unloading NVAPI, reason: %s", error_str); } nv_module_free(&nv_module); if (result) { printfln_err("Command completed successfully"); exit(0); } else { printfln_err("Command failed"); exit(1); } }