nvapi.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /*
  2. * Copyright 2011-2020 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. #include "bgfx_p.h"
  6. #include "nvapi.h"
  7. namespace bgfx
  8. {
  9. /*
  10. * NVAPI
  11. *
  12. * Reference(s):
  13. * - https://web.archive.org/web/20181126035649/https://docs.nvidia.com/gameworks/content/gameworkslibrary/coresdk/nvapi/index.html
  14. * - https://web.archive.org/web/20181126035710/https://github.com/jNizM/AHK_NVIDIA_NvAPI/blob/master/info/NvAPI_IDs.txt
  15. */
  16. struct NvPhysicalGpuHandle;
  17. #define NVAPI_MAX_PHYSICAL_GPUS 64
  18. #if BX_PLATFORM_WINDOWS
  19. # define NVAPICALL __cdecl
  20. #else
  21. # define NVAPICALL
  22. #endif // BX_PLATFORM_WINDOWS
  23. enum NvApiStatus
  24. {
  25. NVAPI_OK = 0,
  26. NVAPI_ERROR = -1,
  27. };
  28. struct NvMemoryInfoV2
  29. {
  30. NvMemoryInfoV2()
  31. : version(sizeof(NvMemoryInfoV2) | (2 << 16) )
  32. {
  33. }
  34. uint32_t version;
  35. uint32_t dedicatedVideoMemory;
  36. uint32_t availableDedicatedVideoMemory;
  37. uint32_t systemVideoMemory;
  38. uint32_t sharedSystemMemory;
  39. uint32_t curAvailableDedicatedVideoMemory;
  40. };
  41. typedef void* (NVAPICALL* PFN_NVAPI_QUERYINTERFACE)(uint32_t _functionOffset);
  42. typedef NvApiStatus (NVAPICALL* PFN_NVAPI_INITIALIZE)();
  43. typedef NvApiStatus (NVAPICALL* PFN_NVAPI_UNLOAD)();
  44. typedef NvApiStatus (NVAPICALL* PFN_NVAPI_ENUMPHYSICALGPUS)(NvPhysicalGpuHandle* _handle[NVAPI_MAX_PHYSICAL_GPUS], uint32_t* _gpuCount);
  45. typedef NvApiStatus (NVAPICALL* PFN_NVAPI_GPUGETMEMORYINFO)(NvPhysicalGpuHandle* _handle, NvMemoryInfoV2* _memoryInfo);
  46. typedef NvApiStatus (NVAPICALL* PFN_NVAPI_GPUGETFULLNAME)(NvPhysicalGpuHandle* _physicalGpu, char _name[64]);
  47. #define NVAPI_INITIALIZE UINT32_C(0x0150e828)
  48. #define NVAPI_UNLOAD UINT32_C(0xd22bdd7e)
  49. #define NVAPI_ENUMPHYSICALGPUS UINT32_C(0xe5ac921f)
  50. #define NVAPI_GPUGETMEMORYINFO UINT32_C(0x07f9b368)
  51. #define NVAPI_GPUGETFULLNAME UINT32_C(0xceee8e9f)
  52. #define NVAPI_MULTIDRAWINSTANCEDINDIRECT UINT32_C(0xd4e26bbf)
  53. #define NVAPI_MULTIDRAWINDEXEDINSTANCEDINDIRECT UINT32_C(0x59e890f9)
  54. static PFN_NVAPI_QUERYINTERFACE nvApiQueryInterface;
  55. static PFN_NVAPI_INITIALIZE nvApiInitialize;
  56. static PFN_NVAPI_UNLOAD nvApiUnload;
  57. static PFN_NVAPI_ENUMPHYSICALGPUS nvApiEnumPhysicalGPUs;
  58. static PFN_NVAPI_GPUGETMEMORYINFO nvApiGpuGetMemoryInfo;
  59. static PFN_NVAPI_GPUGETFULLNAME nvApiGpuGetFullName;
  60. /*
  61. * NVIDIA Aftermath
  62. *
  63. * Reference(s):
  64. * - https://web.archive.org/web/20181126035743/https://developer.nvidia.com/nvidia-aftermath
  65. */
  66. typedef int32_t (*PFN_NVAFTERMATH_DX11_INITIALIZE)(int32_t _version, int32_t _flags, const ID3D11Device* _device);
  67. typedef int32_t (*PFN_NVAFTERMATH_DX11_CREATECONTEXTHANDLE)(const ID3D11DeviceContext* _deviceCtx, NvAftermathContextHandle** _outContextHandle);
  68. typedef int32_t (*PFN_NVAFTERMATH_DX12_INITIALIZE)(int32_t _version, int32_t _flags, const ID3D12Device* _device);
  69. typedef int32_t (*PFN_NVAFTERMATH_DX12_CREATECONTEXTHANDLE)(const ID3D12CommandList* _commandList, NvAftermathContextHandle** _outContextHandle);
  70. typedef int32_t (*PFN_NVAFTERMATH_RELEASECONTEXTHANDLE)(const NvAftermathContextHandle* _contextHandle);
  71. typedef int32_t (*PFN_NVAFTERMATH_SETEVENTMARKER)(const NvAftermathContextHandle* _contextHandle, const void* _markerData, uint32_t _markerSize);
  72. typedef int32_t (*PFN_NVAFTERMATH_GETDATA)(uint32_t _numContexts, const NvAftermathContextHandle** _contextHandles, void* _outContextData);
  73. typedef int32_t (*PFN_NVAFTERMATH_GETDEVICESTATUS)(void* _outStatus);
  74. typedef int32_t (*PFN_NVAFTERMATH_GETPAGEFAULTINFORMATION)(void* _outPageFaultInformation);
  75. static PFN_NVAFTERMATH_DX11_INITIALIZE nvAftermathDx11Initialize;
  76. static PFN_NVAFTERMATH_DX11_CREATECONTEXTHANDLE nvAftermathDx11CreateContextHandle;
  77. static PFN_NVAFTERMATH_DX12_INITIALIZE nvAftermathDx12Initialize;
  78. static PFN_NVAFTERMATH_DX12_CREATECONTEXTHANDLE nvAftermathDx12CreateContextHandle;
  79. static PFN_NVAFTERMATH_RELEASECONTEXTHANDLE nvAftermathReleaseContextHandle;
  80. static PFN_NVAFTERMATH_SETEVENTMARKER nvAftermathSetEventMarker;
  81. static PFN_NVAFTERMATH_GETDATA nvAftermathGetData;
  82. static PFN_NVAFTERMATH_GETDEVICESTATUS nvAftermathGetDeviceStatus;
  83. static PFN_NVAFTERMATH_GETPAGEFAULTINFORMATION nvAftermathGetPageFaultInformation;
  84. NvApi::NvApi()
  85. : m_nvApiDll(NULL)
  86. , m_nvGpu(NULL)
  87. , m_nvAftermathDll(NULL)
  88. , m_aftermathHandle(NULL)
  89. {
  90. }
  91. void NvApi::init()
  92. {
  93. m_nvGpu = NULL;
  94. m_nvApiDll = bx::dlopen(
  95. "nvapi"
  96. #if BX_ARCH_64BIT
  97. "64"
  98. #endif // BX_ARCH_32BIT
  99. ".dll"
  100. );
  101. if (NULL != m_nvApiDll)
  102. {
  103. nvApiQueryInterface = (PFN_NVAPI_QUERYINTERFACE)bx::dlsym(m_nvApiDll, "nvapi_QueryInterface");
  104. bool initialized = NULL != nvApiQueryInterface;
  105. if (initialized)
  106. {
  107. nvApiInitialize = (PFN_NVAPI_INITIALIZE )nvApiQueryInterface(NVAPI_INITIALIZE);
  108. nvApiUnload = (PFN_NVAPI_UNLOAD )nvApiQueryInterface(NVAPI_UNLOAD);
  109. nvApiEnumPhysicalGPUs = (PFN_NVAPI_ENUMPHYSICALGPUS)nvApiQueryInterface(NVAPI_ENUMPHYSICALGPUS);
  110. nvApiGpuGetMemoryInfo = (PFN_NVAPI_GPUGETMEMORYINFO)nvApiQueryInterface(NVAPI_GPUGETMEMORYINFO);
  111. nvApiGpuGetFullName = (PFN_NVAPI_GPUGETFULLNAME )nvApiQueryInterface(NVAPI_GPUGETFULLNAME);
  112. nvApiD3D11MultiDrawInstancedIndirect = (PFN_NVAPI_MULTIDRAWINDIRECT)nvApiQueryInterface(NVAPI_MULTIDRAWINSTANCEDINDIRECT);
  113. nvApiD3D11MultiDrawIndexedInstancedIndirect = (PFN_NVAPI_MULTIDRAWINDIRECT)nvApiQueryInterface(NVAPI_MULTIDRAWINDEXEDINSTANCEDINDIRECT);
  114. initialized = true
  115. && NULL != nvApiInitialize
  116. && NULL != nvApiUnload
  117. && NULL != nvApiEnumPhysicalGPUs
  118. && NULL != nvApiGpuGetMemoryInfo
  119. && NULL != nvApiGpuGetFullName
  120. && NVAPI_OK == nvApiInitialize()
  121. ;
  122. if (initialized)
  123. {
  124. NvPhysicalGpuHandle* physicalGpus[NVAPI_MAX_PHYSICAL_GPUS];
  125. uint32_t numGpus = 0;
  126. nvApiEnumPhysicalGPUs(physicalGpus, &numGpus);
  127. initialized = 0 < numGpus;
  128. if (initialized)
  129. {
  130. m_nvGpu = physicalGpus[0];
  131. initialized = NULL != m_nvGpu;
  132. if (initialized)
  133. {
  134. char name[64];
  135. nvApiGpuGetFullName(m_nvGpu, name);
  136. BX_TRACE("%s", name);
  137. }
  138. else
  139. {
  140. nvApiUnload();
  141. }
  142. }
  143. }
  144. }
  145. if (!initialized)
  146. {
  147. bx::dlclose(m_nvApiDll);
  148. m_nvApiDll = NULL;
  149. }
  150. BX_WARN(!initialized, "NVAPI supported.");
  151. }
  152. }
  153. void NvApi::shutdown()
  154. {
  155. if (NULL != m_nvGpu)
  156. {
  157. nvApiUnload();
  158. m_nvGpu = NULL;
  159. }
  160. if (NULL != m_nvApiDll)
  161. {
  162. bx::dlclose(m_nvApiDll);
  163. m_nvApiDll = NULL;
  164. }
  165. shutdownAftermath();
  166. }
  167. void NvApi::getMemoryInfo(int64_t& _gpuMemoryUsed, int64_t& _gpuMemoryMax)
  168. {
  169. if (NULL != m_nvGpu)
  170. {
  171. NvMemoryInfoV2 memInfo;
  172. NvApiStatus status = nvApiGpuGetMemoryInfo(m_nvGpu, &memInfo);
  173. if (NVAPI_OK == status)
  174. {
  175. _gpuMemoryMax = 1024 * int64_t(memInfo.availableDedicatedVideoMemory);
  176. _gpuMemoryUsed = 1024 * int64_t(memInfo.availableDedicatedVideoMemory - memInfo.curAvailableDedicatedVideoMemory);
  177. // BX_TRACE(" dedicatedVideoMemory: %d KiB", memInfo.dedicatedVideoMemory);
  178. // BX_TRACE(" availableDedicatedVideoMemory: %d KiB", memInfo.availableDedicatedVideoMemory);
  179. // BX_TRACE(" systemVideoMemory: %d KiB", memInfo.systemVideoMemory);
  180. // BX_TRACE(" sharedSystemMemory: %d KiB", memInfo.sharedSystemMemory);
  181. // BX_TRACE("curAvailableDedicatedVideoMemory: %d KiB", memInfo.curAvailableDedicatedVideoMemory);
  182. }
  183. }
  184. else
  185. {
  186. _gpuMemoryMax = -INT64_MAX;
  187. _gpuMemoryUsed = -INT64_MAX;
  188. }
  189. }
  190. bool NvApi::loadAftermath()
  191. {
  192. m_nvAftermathDll = bx::dlopen(
  193. "GFSDK_Aftermath_Lib."
  194. #if BX_ARCH_32BIT
  195. "x86"
  196. #else
  197. "x64"
  198. #endif // BX_ARCH_32BIT
  199. ".dll"
  200. );
  201. if (NULL != m_nvAftermathDll)
  202. {
  203. nvAftermathDx11Initialize = (PFN_NVAFTERMATH_DX11_INITIALIZE )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_DX11_Initialize");
  204. nvAftermathDx11CreateContextHandle = (PFN_NVAFTERMATH_DX11_CREATECONTEXTHANDLE)bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_DX11_CreateContextHandle");
  205. nvAftermathDx12Initialize = (PFN_NVAFTERMATH_DX12_INITIALIZE )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_DX12_Initialize");
  206. nvAftermathDx12CreateContextHandle = (PFN_NVAFTERMATH_DX12_CREATECONTEXTHANDLE)bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_DX12_CreateContextHandle");
  207. nvAftermathReleaseContextHandle = (PFN_NVAFTERMATH_RELEASECONTEXTHANDLE )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_ReleaseContextHandle");
  208. nvAftermathSetEventMarker = (PFN_NVAFTERMATH_SETEVENTMARKER )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_SetEventMarker");
  209. nvAftermathGetData = (PFN_NVAFTERMATH_GETDATA )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_GetData");
  210. nvAftermathGetDeviceStatus = (PFN_NVAFTERMATH_GETDEVICESTATUS )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_GetDeviceStatus");
  211. nvAftermathGetPageFaultInformation = (PFN_NVAFTERMATH_GETPAGEFAULTINFORMATION )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_GetPageFaultInformation");
  212. bool initialized = true
  213. && NULL != nvAftermathDx11Initialize
  214. && NULL != nvAftermathDx11CreateContextHandle
  215. && NULL != nvAftermathDx12Initialize
  216. && NULL != nvAftermathDx12CreateContextHandle
  217. && NULL != nvAftermathReleaseContextHandle
  218. && NULL != nvAftermathSetEventMarker
  219. && NULL != nvAftermathGetData
  220. && NULL != nvAftermathGetDeviceStatus
  221. && NULL != nvAftermathGetPageFaultInformation
  222. ;
  223. if (initialized)
  224. {
  225. return true;
  226. }
  227. shutdownAftermath();
  228. }
  229. return false;
  230. }
  231. bool NvApi::initAftermath(const ID3D11Device* _device, const ID3D11DeviceContext* _deviceCtx)
  232. {
  233. if (loadAftermath() )
  234. {
  235. int32_t result;
  236. result = nvAftermathDx11Initialize(0x13, 1, _device);
  237. if (1 == result)
  238. {
  239. result = nvAftermathDx11CreateContextHandle(_deviceCtx, &m_aftermathHandle);
  240. BX_WARN(1 == result, "NV Aftermath: nvAftermathDx12CreateContextHandle failed %x", result);
  241. if (1 == result)
  242. {
  243. return true;
  244. }
  245. }
  246. else
  247. {
  248. switch (result)
  249. {
  250. case int32_t(0xbad0000a): BX_TRACE("NV Aftermath: Debug layer not compatible with Aftermath."); break;
  251. default: BX_TRACE("NV Aftermath: Failed to initialize."); break;
  252. }
  253. }
  254. shutdownAftermath();
  255. }
  256. return false;
  257. }
  258. bool NvApi::initAftermath(const ID3D12Device* _device, const ID3D12CommandList* _commandList)
  259. {
  260. if (loadAftermath() )
  261. {
  262. int32_t result;
  263. result = nvAftermathDx12Initialize(0x13, 1, _device);
  264. if (1 == result)
  265. {
  266. result = nvAftermathDx12CreateContextHandle(_commandList, &m_aftermathHandle);
  267. BX_WARN(1 == result, "NV Aftermath: nvAftermathDx12CreateContextHandle failed %x", result);
  268. if (1 == result)
  269. {
  270. return true;
  271. }
  272. }
  273. else
  274. {
  275. switch (result)
  276. {
  277. case int32_t(0xbad0000a): BX_TRACE("NV Aftermath: Debug layer not compatible with Aftermath."); break;
  278. default: BX_TRACE("NV Aftermath: Failed to initialize."); break;
  279. }
  280. }
  281. shutdownAftermath();
  282. }
  283. return false;
  284. }
  285. NvAftermathDeviceStatus::Enum NvApi::getDeviceStatus() const
  286. {
  287. if (NULL != m_aftermathHandle)
  288. {
  289. int32_t status;
  290. nvAftermathGetDeviceStatus(&status);
  291. return NvAftermathDeviceStatus::Enum(status);
  292. }
  293. return NvAftermathDeviceStatus::NotInitialized;
  294. }
  295. void NvApi::shutdownAftermath()
  296. {
  297. if (NULL != m_nvAftermathDll)
  298. {
  299. if (NULL != m_aftermathHandle)
  300. {
  301. nvAftermathReleaseContextHandle(m_aftermathHandle);
  302. m_aftermathHandle = NULL;
  303. }
  304. bx::dlclose(m_nvAftermathDll);
  305. m_nvAftermathDll = NULL;
  306. }
  307. }
  308. #define NVA_CHECK(_call) \
  309. BX_MACRO_BLOCK_BEGIN \
  310. int32_t __result__ = _call; \
  311. BX_CHECK(1 == __result__, #_call " FAILED 0x%08x\n", __result__); \
  312. BX_UNUSED(__result__); \
  313. BX_MACRO_BLOCK_END
  314. void NvApi::setMarker(const bx::StringView& _marker)
  315. {
  316. if (NULL != m_aftermathHandle)
  317. {
  318. NVA_CHECK(nvAftermathSetEventMarker(m_aftermathHandle, _marker.getPtr(), _marker.getLength() ) );
  319. }
  320. }
  321. } // namespace bgfx