Skip to content

Commit ae3c15b

Browse files
committed
GPU (Windows): support VMEM type detection via nvapi
Ref #993
1 parent 8dafd8f commit ae3c15b

File tree

2 files changed

+149
-0
lines changed

2 files changed

+149
-0
lines changed

src/detection/gpu/gpu_nvidia.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,105 @@ struct FFNvmlData {
2121
bool inited;
2222
} nvmlData;
2323

24+
#if defined(_WIN32) && !defined(FF_DISABLE_DLOPEN)
25+
26+
#include "nvapi.h"
27+
28+
struct FFNvapiData {
29+
FF_LIBRARY_SYMBOL(nvapi_Unload)
30+
FF_LIBRARY_SYMBOL(nvapi_EnumPhysicalGPUs)
31+
FF_LIBRARY_SYMBOL(nvapi_GPU_GetRamType)
32+
33+
bool inited;
34+
} nvapiData;
35+
36+
const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
37+
{
38+
if (!nvapiData.inited)
39+
{
40+
nvapiData.inited = true;
41+
42+
FF_LIBRARY_LOAD(libnvapi, "dlopen nvapi failed",
43+
#ifdef _WIN64
44+
"nvapi64.dll"
45+
#else
46+
"nvapi.dll"
47+
#endif
48+
, 1);
49+
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libnvapi, nvapi_QueryInterface)
50+
#define FF_NVAPI_INTERFACE(iName, iOffset) \
51+
__typeof__(&iName) ff ## iName = ffnvapi_QueryInterface(iOffset); \
52+
if (ff ## iName == NULL) return "nvapi_QueryInterface " #iName " failed";
53+
54+
FF_NVAPI_INTERFACE(nvapi_Initialize, NVAPI_INTERFACE_OFFSET_INITIALIZE)
55+
FF_NVAPI_INTERFACE(nvapi_Unload, NVAPI_INTERFACE_OFFSET_UNLOAD)
56+
FF_NVAPI_INTERFACE(nvapi_EnumPhysicalGPUs, NVAPI_INTERFACE_OFFSET_ENUM_PHYSICAL_GPUS)
57+
FF_NVAPI_INTERFACE(nvapi_GPU_GetRamType, NVAPI_INTERFACE_OFFSET_GPU_GET_RAM_TYPE)
58+
#undef FF_NVAPI_INTERFACE
59+
60+
if (ffnvapi_Initialize() < 0)
61+
return "NvAPI_Initialize() failed";
62+
63+
nvapiData.ffnvapi_EnumPhysicalGPUs = ffnvapi_EnumPhysicalGPUs;
64+
nvapiData.ffnvapi_GPU_GetRamType = ffnvapi_GPU_GetRamType;
65+
nvapiData.ffnvapi_Unload = ffnvapi_Unload;
66+
67+
atexit((void*) ffnvapi_Unload);
68+
libnvapi = NULL; // don't close nvapi
69+
}
70+
71+
if (nvapiData.ffnvapi_EnumPhysicalGPUs == NULL)
72+
return "loading nvapi library failed";
73+
74+
NvPhysicalGpuHandle handles[32];
75+
int gpuCount = 0;
76+
77+
if (nvapiData.ffnvapi_EnumPhysicalGPUs(handles, &gpuCount) < 0)
78+
return "NvAPI_EnumPhysicalGPUs() failed";
79+
80+
uint32_t gpuIndex = *result->index;
81+
82+
if ((uint32_t) gpuCount < gpuIndex)
83+
return "GPU index out of range";
84+
85+
NvApiGPUMemoryType memType;
86+
if (nvapiData.ffnvapi_GPU_GetRamType(handles[gpuIndex], &memType) < 0)
87+
return "NvAPI_GPU_GetRamType() failed";
88+
89+
switch (memType)
90+
{
91+
#define FF_NVAPI_MEMORY_TYPE(type) \
92+
case NVAPI_GPU_MEMORY_TYPE_##type: \
93+
ffStrbufSetStatic(result->memoryType, #type); \
94+
break;
95+
FF_NVAPI_MEMORY_TYPE(UNKNOWN)
96+
FF_NVAPI_MEMORY_TYPE(SDRAM)
97+
FF_NVAPI_MEMORY_TYPE(DDR1)
98+
FF_NVAPI_MEMORY_TYPE(DDR2)
99+
FF_NVAPI_MEMORY_TYPE(GDDR2)
100+
FF_NVAPI_MEMORY_TYPE(GDDR3)
101+
FF_NVAPI_MEMORY_TYPE(GDDR4)
102+
FF_NVAPI_MEMORY_TYPE(DDR3)
103+
FF_NVAPI_MEMORY_TYPE(GDDR5)
104+
FF_NVAPI_MEMORY_TYPE(LPDDR2)
105+
FF_NVAPI_MEMORY_TYPE(GDDR5X)
106+
FF_NVAPI_MEMORY_TYPE(LPDDR3)
107+
FF_NVAPI_MEMORY_TYPE(LPDDR4)
108+
FF_NVAPI_MEMORY_TYPE(LPDDR5)
109+
FF_NVAPI_MEMORY_TYPE(GDDR6)
110+
FF_NVAPI_MEMORY_TYPE(GDDR6X)
111+
FF_NVAPI_MEMORY_TYPE(GDDR7)
112+
#undef FF_NVAPI_MEMORY_TYPE
113+
default:
114+
ffStrbufSetF(result->memoryType, "Unknown (%d)", memType);
115+
break;
116+
}
117+
118+
return NULL;
119+
}
120+
121+
#endif
122+
24123
const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName)
25124
{
26125
#ifndef FF_DISABLE_DLOPEN
@@ -113,7 +212,13 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
113212
{
114213
unsigned int value;
115214
if (nvmlData.ffnvmlDeviceGetIndex(device, &value) == NVML_SUCCESS)
215+
{
116216
*result.index = value;
217+
#ifdef _WIN32
218+
if (result.memoryType)
219+
detectMemTypeByNvapi(&result);
220+
#endif
221+
}
117222
}
118223

119224

src/detection/gpu/nvapi.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// References:
2+
// https://github.com/NVIDIA/nvapi (MIT License)
3+
// https://github.com/deathcamp/NVOC/blob/master/nvoc.c (Public Domain)
4+
5+
typedef enum NvApiGPUMemoryType
6+
{
7+
NVAPI_GPU_MEMORY_TYPE_UNKNOWN = 0,
8+
NVAPI_GPU_MEMORY_TYPE_SDRAM,
9+
NVAPI_GPU_MEMORY_TYPE_DDR1,
10+
NVAPI_GPU_MEMORY_TYPE_DDR2,
11+
NVAPI_GPU_MEMORY_TYPE_GDDR2,
12+
NVAPI_GPU_MEMORY_TYPE_GDDR3,
13+
NVAPI_GPU_MEMORY_TYPE_GDDR4,
14+
NVAPI_GPU_MEMORY_TYPE_DDR3,
15+
NVAPI_GPU_MEMORY_TYPE_GDDR5,
16+
NVAPI_GPU_MEMORY_TYPE_LPDDR2,
17+
NVAPI_GPU_MEMORY_TYPE_GDDR5X,
18+
NVAPI_GPU_MEMORY_TYPE_LPDDR3,
19+
NVAPI_GPU_MEMORY_TYPE_LPDDR4,
20+
NVAPI_GPU_MEMORY_TYPE_LPDDR5,
21+
NVAPI_GPU_MEMORY_TYPE_GDDR6,
22+
NVAPI_GPU_MEMORY_TYPE_GDDR6X,
23+
NVAPI_GPU_MEMORY_TYPE_GDDR7,
24+
} NvApiGPUMemoryType;
25+
26+
typedef int NvAPI_Status; // 0 = success; < 0 = error
27+
typedef struct NvPhysicalGpuHandle* NvPhysicalGpuHandle;
28+
29+
typedef enum
30+
{
31+
NVAPI_INTERFACE_OFFSET_INITIALIZE = 0x0150E828,
32+
NVAPI_INTERFACE_OFFSET_UNLOAD = 0xD22BDD7E,
33+
NVAPI_INTERFACE_OFFSET_ENUM_PHYSICAL_GPUS = 0xE5AC921F,
34+
NVAPI_INTERFACE_OFFSET_GPU_GET_RAM_TYPE = 0x57F7CAAC,
35+
36+
NVAPI_INTERFACE_OFFSET_FORCE_UINT32 = 0xFFFFFFFF
37+
} NvApiInterfaceOffsets;
38+
39+
extern void* nvapi_QueryInterface(NvApiInterfaceOffsets offset);
40+
41+
extern NvAPI_Status nvapi_Initialize(void);
42+
extern NvAPI_Status nvapi_Unload(void);
43+
extern NvAPI_Status nvapi_EnumPhysicalGPUs(NvPhysicalGpuHandle* handles, int* count);
44+
extern NvAPI_Status nvapi_GPU_GetRamType(NvPhysicalGpuHandle handle, NvApiGPUMemoryType* memtype);

0 commit comments

Comments
 (0)