Skip to content

Instantly share code, notes, and snippets.

@StefanoBelli
Last active April 26, 2021 07:03
Show Gist options
  • Save StefanoBelli/3fe285f4aa28b460241b85a0461faa14 to your computer and use it in GitHub Desktop.
Save StefanoBelli/3fe285f4aa28b460241b85a0461faa14 to your computer and use it in GitHub Desktop.
nvapi interface
#include <cstring>
#include <Windows.h>
#include <string>
#include <iostream>
#include <memory>
#include <vector>
#define MAKE_VERSION(stype, ver) static_cast<std::uint32_t>( sizeof(stype) | ((ver) << 16) )
//generic type for Nvapi handles
using NvHandle = int*;
enum class NvGpuPublicClockId {
GRAPHICS,
MEMORY,
PROCESSOR,
VIDEO,
UNDEFINED
};
enum class NvGpuPerfPstate20ClockTypeId {
SINGLE,
RANGE
};
enum class NvGpuPerfVoltageInfoDomainId {
CORE,
UNDEFINED
};
struct NvGpuPerfPstates20ParamDelta {
std::uint32_t value;
struct {
std::uint32_t max;
std::uint32_t min;
} range;
};
struct NvGpuPstate20ClockEntry {
NvGpuPublicClockId domainId;
NvGpuPerfPstate20ClockTypeId typeId;
std::uint32_t bIsEditable : 1;
std::uint32_t reserved : 31;
NvGpuPerfPstates20ParamDelta freqDeltaKHz;
union {
struct {
std::uint32_t freqKHz;
} single;
struct {
std::uint32_t minFreqKHz;
std::uint32_t maxFreqKHz;
NvGpuPerfVoltageInfoDomainId domainId;
std::uint32_t minVoltageuV;
std::uint32_t maxVoltageuV;
} range;
} data;
};
struct NvGpuPstate20BaseVoltageEntry {
NvGpuPerfVoltageInfoDomainId domainId;
std::uint32_t bIsEditable : 1;
std::uint32_t reserved : 31;
std::uint32_t voltuV;
NvGpuPerfPstates20ParamDelta paramDelta;
};
struct NvGpuPerfPstates20Info {
std::uint32_t version;
std::uint32_t bIsEditable : 1;
std::uint32_t reserved : 31;
std::uint32_t numPstates;
std::uint32_t numClocks;
std::uint32_t numBaseVoltages;
struct {
int pstateId; //0 - 16 pstate level
std::uint32_t bIsEditable : 1;
std::uint32_t reserved : 31;
NvGpuPstate20ClockEntry clocks[8];
NvGpuPstate20BaseVoltageEntry baseVoltages[4];
} pstates[16];
};
constexpr std::uint32_t PERF_PSTATES20_INFO_V1 = MAKE_VERSION(NvGpuPerfPstates20Info, 1);
class NvApiInterface {
public:
NvApiInterface(NvApiInterface const&) = delete;
NvApiInterface(NvApiInterface&&) = delete;
NvApiInterface& operator=(NvApiInterface&&) = delete;
NvApiInterface& operator=(NvApiInterface const&) = delete;
NvApiInterface(HMODULE rtHal) {
std::memset(rawGenericData, 0, sizeof(rawGenericData));
getVersionStringCallback =
callback_cast(GetProcAddress(rtHal,
"?GetVersionString@CNVAPIInterface@@QAE?AW4_NvAPI_Status@@PAD@Z"));
getPhysicalGPUHandles =
callback_cast(GetProcAddress(rtHal,
"?GetPhysicalGPUHandles@CNVAPIInterface@@QAE?AW4_NvAPI_Status@@PAPAUNvPhysicalGpuHandle__@@PAK@Z"));
gpuGetFullName =
callback_cast(GetProcAddress(rtHal,
"?GpuGetFullName@CNVAPIInterface@@QAE?AW4_NvAPI_Status@@PAUNvPhysicalGpuHandle__@@PAD@Z"));
gpuGetPstates20 =
callback_cast(GetProcAddress(rtHal,
"?GpuGetPstates20@CNVAPIInterface@@QAE?AW4_NvAPI_Status@@PAUNvPhysicalGpuHandle__@@PAUNV_GPU_PERF_PSTATES20_INFO_V1@@@Z"));
gpuSetPstates20 =
callback_cast(GetProcAddress(rtHal,
"?GpuSetPstates20@CNVAPIInterface@@QAE?AW4_NvAPI_Status@@PAUNvPhysicalGpuHandle__@@PAUNV_GPU_PERF_PSTATES20_INFO_V1@@@Z"));
Callback ctor = callback_cast(GetProcAddress(rtHal, "??0CNVAPIInterface@@QAE@XZ"));
Callback uninit = callback_cast(GetProcAddress(rtHal, "?Uninit@CNVAPIInterface@@QAEXXZ"));
Callback init = callback_cast(GetProcAddress(rtHal, "?Init@CNVAPIInterface@@QAE?AW4_NvAPI_Status@@XZ"));
__asm {
mov ecx, this
mov eax, ctor
call eax
mov eax, uninit
call eax
mov eax, init
call eax
}
__dtor = callback_cast(GetProcAddress(rtHal, "??1CNVAPIInterface@@UAE@XZ"));
}
~NvApiInterface() {
__asm {
mov ecx, this
mov eax, __dtor
add eax, this
call[eax]
}
}
std::string GetVersionString() const {
char buf[64]{ 0 };
__asm {
lea eax, buf
push eax
mov ecx, this
mov eax, getVersionStringCallback
add eax, this
call[eax]
}
return buf;
}
std::vector<NvHandle> GetPhysicalGPUHandles() const {
NvHandle addr[64];
unsigned len;
__asm {
lea eax, len
push eax
lea eax, addr
push eax
mov ecx, this
mov eax, getPhysicalGPUHandles
add eax, this
call[eax]
}
//we could also cache these values...
std::vector<NvHandle> handles;
for (unsigned hndIdx = 0; hndIdx < len; ++hndIdx)
handles.push_back(addr[hndIdx]);
return handles;
}
std::string GpuGetFullName(NvHandle gpuHandle) const {
char gpuFullName[64]{ 0 };
__asm {
lea eax, gpuFullName
push eax
mov eax, gpuHandle
push eax
mov ecx, this
mov eax, gpuGetFullName
add eax, this
call[eax]
}
return gpuFullName;
}
NvGpuPerfPstates20Info GpuGetPstates20(NvHandle gpuHandle) const {
NvGpuPerfPstates20Info info;
info.version = PERF_PSTATES20_INFO_V1;
__asm {
lea eax, info
push eax
mov eax, gpuHandle
push eax
mov ecx, this
mov eax, gpuGetPstates20
add eax, this
call[eax]
}
return info;
}
int GpuSetPstate20(NvHandle gpuHandle, NvGpuPerfPstates20Info info) {
__asm {
lea eax, info
push eax
mov eax, gpuHandle
push eax
mov ecx, this
mov eax, gpuSetPstates20
add eax, this
call[eax]
}
}
private:
typedef void(*Callback)();
constexpr Callback callback_cast(void* fptr) {
return reinterpret_cast<Callback>(fptr);
}
// data begin
int rawGenericData[100]; // 400 Bytes
// data end
Callback getVersionStringCallback;
Callback getPhysicalGPUHandles;
Callback gpuGetFullName;
Callback gpuGetPstates20;
Callback gpuSetPstates20;
Callback __dtor;
};
//
//example usage of the interface!
//
struct HmoduleDelete {
public:
void operator()(void* ptr) const {
FreeLibrary(static_cast<HMODULE>(ptr));
}
};
using ScopedHmodule = std::unique_ptr<void, HmoduleDelete>;
int main() {
SetDllDirectoryA("C:\\Windows\\Syswow64");
SetDllDirectoryA("D:\\ssynx\\Devel\\rthal_bin"); //replace with Afterburner or other piece of shit OC tool
ScopedHmodule nvapi(LoadLibraryA("nvapi.dll"));
if (nvapi == nullptr) {
std::cerr << "could not load nvapi.dll\n";
return 1;
}
ScopedHmodule hal(LoadLibraryA("rthal.dll"));
if (hal == nullptr) {
std::cerr << "could not load rthal.dll\n";
return 1;
}
NvApiInterface nvapiIntf(static_cast<HMODULE>(hal.get()));
std::vector<NvHandle> physicalGpus = nvapiIntf.GetPhysicalGPUHandles();
NvGpuPerfPstates20Info pstates =
nvapiIntf.GpuGetPstates20(physicalGpus[0]);
std::cout << "NvAPI version: " << nvapiIntf.GetVersionString() << '\n'
<< "Physical GPUs: " << physicalGpus.size() << '\n'
<< "First GPU name: " << nvapiIntf.GpuGetFullName(physicalGpus[0]) << '\n'
<< "===LISTING PSTATES===\n"
<< "Number of configured performance-states: " << pstates.numPstates;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment