nvapi.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /*
  2. * Copyright 2011-2018 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:
  13. * http://docs.nvidia.com/gameworks/content/gameworkslibrary/coresdk/nvapi/index.html
  14. * 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:
  64. * 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. }
  132. char name[64];
  133. nvApiGpuGetFullName(m_nvGpu, name);
  134. BX_TRACE("%s", name);
  135. }
  136. initialized = NULL != m_nvGpu;
  137. if (!initialized)
  138. {
  139. nvApiUnload();
  140. }
  141. }
  142. if (!initialized)
  143. {
  144. bx::dlclose(m_nvApiDll);
  145. m_nvApiDll = NULL;
  146. }
  147. BX_WARN(!initialized, "NVAPI supported.");
  148. }
  149. }
  150. void NvApi::shutdown()
  151. {
  152. if (NULL != m_nvGpu)
  153. {
  154. nvApiUnload();
  155. m_nvGpu = NULL;
  156. }
  157. if (NULL != m_nvApiDll)
  158. {
  159. bx::dlclose(m_nvApiDll);
  160. m_nvApiDll = NULL;
  161. }
  162. shutdownAftermath();
  163. }
  164. void NvApi::getMemoryInfo(int64_t& _gpuMemoryUsed, int64_t& _gpuMemoryMax)
  165. {
  166. if (NULL != m_nvGpu)
  167. {
  168. NvMemoryInfoV2 memInfo;
  169. NvApiStatus status = nvApiGpuGetMemoryInfo(m_nvGpu, &memInfo);
  170. if (NVAPI_OK == status)
  171. {
  172. _gpuMemoryMax = 1024 * int64_t(memInfo.availableDedicatedVideoMemory);
  173. _gpuMemoryUsed = 1024 * int64_t(memInfo.availableDedicatedVideoMemory - memInfo.curAvailableDedicatedVideoMemory);
  174. // BX_TRACE(" dedicatedVideoMemory: %d KiB", memInfo.dedicatedVideoMemory);
  175. // BX_TRACE(" availableDedicatedVideoMemory: %d KiB", memInfo.availableDedicatedVideoMemory);
  176. // BX_TRACE(" systemVideoMemory: %d KiB", memInfo.systemVideoMemory);
  177. // BX_TRACE(" sharedSystemMemory: %d KiB", memInfo.sharedSystemMemory);
  178. // BX_TRACE("curAvailableDedicatedVideoMemory: %d KiB", memInfo.curAvailableDedicatedVideoMemory);
  179. }
  180. }
  181. else
  182. {
  183. _gpuMemoryMax = -INT64_MAX;
  184. _gpuMemoryUsed = -INT64_MAX;
  185. }
  186. }
  187. bool NvApi::loadAftermath()
  188. {
  189. m_nvAftermathDll = bx::dlopen(
  190. "GFSDK_Aftermath_Lib."
  191. #if BX_ARCH_32BIT
  192. "x86"
  193. #else
  194. "x64"
  195. #endif // BX_ARCH_32BIT
  196. ".dll"
  197. );
  198. if (NULL != m_nvAftermathDll)
  199. {
  200. nvAftermathDx11Initialize = (PFN_NVAFTERMATH_DX11_INITIALIZE )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_DX11_Initialize");
  201. nvAftermathDx11CreateContextHandle = (PFN_NVAFTERMATH_DX11_CREATECONTEXTHANDLE)bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_DX11_CreateContextHandle");
  202. nvAftermathDx12Initialize = (PFN_NVAFTERMATH_DX12_INITIALIZE )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_DX12_Initialize");
  203. nvAftermathDx12CreateContextHandle = (PFN_NVAFTERMATH_DX12_CREATECONTEXTHANDLE)bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_DX12_CreateContextHandle");
  204. nvAftermathReleaseContextHandle = (PFN_NVAFTERMATH_RELEASECONTEXTHANDLE )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_ReleaseContextHandle");
  205. nvAftermathSetEventMarker = (PFN_NVAFTERMATH_SETEVENTMARKER )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_SetEventMarker");
  206. nvAftermathGetData = (PFN_NVAFTERMATH_GETDATA )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_GetData");
  207. nvAftermathGetDeviceStatus = (PFN_NVAFTERMATH_GETDEVICESTATUS )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_GetDeviceStatus");
  208. nvAftermathGetPageFaultInformation = (PFN_NVAFTERMATH_GETPAGEFAULTINFORMATION )bx::dlsym(m_nvAftermathDll, "GFSDK_Aftermath_GetPageFaultInformation");
  209. bool initialized = true
  210. && NULL != nvAftermathDx11Initialize
  211. && NULL != nvAftermathDx11CreateContextHandle
  212. && NULL != nvAftermathDx12Initialize
  213. && NULL != nvAftermathDx12CreateContextHandle
  214. && NULL != nvAftermathReleaseContextHandle
  215. && NULL != nvAftermathSetEventMarker
  216. && NULL != nvAftermathGetData
  217. && NULL != nvAftermathGetDeviceStatus
  218. && NULL != nvAftermathGetPageFaultInformation
  219. ;
  220. if (initialized)
  221. {
  222. return true;
  223. }
  224. shutdownAftermath();
  225. }
  226. return false;
  227. }
  228. bool NvApi::initAftermath(const ID3D11Device* _device, const ID3D11DeviceContext* _deviceCtx)
  229. {
  230. if (loadAftermath() )
  231. {
  232. int32_t result;
  233. result = nvAftermathDx11Initialize(0x13, 1, _device);
  234. if (1 == result)
  235. {
  236. result = nvAftermathDx11CreateContextHandle(_deviceCtx, &m_aftermathHandle);
  237. BX_WARN(1 == result, "NV Aftermath: nvAftermathDx12CreateContextHandle failed %x", result);
  238. if (1 == result)
  239. {
  240. return true;
  241. }
  242. }
  243. else
  244. {
  245. switch (result)
  246. {
  247. case int32_t(0xbad0000a): BX_TRACE("NV Aftermath: Debug layer not compatible with Aftermath."); break;
  248. default: BX_TRACE("NV Aftermath: Failed to initialize."); break;
  249. }
  250. }
  251. shutdownAftermath();
  252. }
  253. return false;
  254. }
  255. bool NvApi::initAftermath(const ID3D12Device* _device, const ID3D12CommandList* _commandList)
  256. {
  257. if (loadAftermath() )
  258. {
  259. int32_t result;
  260. result = nvAftermathDx12Initialize(0x13, 1, _device);
  261. if (1 == result)
  262. {
  263. result = nvAftermathDx12CreateContextHandle(_commandList, &m_aftermathHandle);
  264. BX_WARN(1 == result, "NV Aftermath: nvAftermathDx12CreateContextHandle failed %x", result);
  265. if (1 == result)
  266. {
  267. return true;
  268. }
  269. }
  270. else
  271. {
  272. switch (result)
  273. {
  274. case int32_t(0xbad0000a): BX_TRACE("NV Aftermath: Debug layer not compatible with Aftermath."); break;
  275. default: BX_TRACE("NV Aftermath: Failed to initialize."); break;
  276. }
  277. }
  278. shutdownAftermath();
  279. }
  280. return false;
  281. }
  282. NvAftermathDeviceStatus::Enum NvApi::getDeviceStatus() const
  283. {
  284. if (NULL != m_aftermathHandle)
  285. {
  286. int32_t status;
  287. nvAftermathGetDeviceStatus(&status);
  288. return NvAftermathDeviceStatus::Enum(status);
  289. }
  290. return NvAftermathDeviceStatus::NotInitialized;
  291. }
  292. void NvApi::shutdownAftermath()
  293. {
  294. if (NULL != m_nvAftermathDll)
  295. {
  296. if (NULL != m_aftermathHandle)
  297. {
  298. nvAftermathReleaseContextHandle(m_aftermathHandle);
  299. m_aftermathHandle = NULL;
  300. }
  301. bx::dlclose(m_nvAftermathDll);
  302. m_nvAftermathDll = NULL;
  303. }
  304. }
  305. #define NVA_CHECK(_call) \
  306. BX_MACRO_BLOCK_BEGIN \
  307. int32_t __result__ = _call; \
  308. BX_CHECK(1 == __result__, #_call " FAILED 0x%08x\n", __result__); \
  309. BX_UNUSED(__result__); \
  310. BX_MACRO_BLOCK_END
  311. void NvApi::setMarker(const bx::StringView& _marker)
  312. {
  313. if (NULL != m_aftermathHandle)
  314. {
  315. NVA_CHECK(nvAftermathSetEventMarker(m_aftermathHandle, _marker.getPtr(), _marker.getLength() ) );
  316. }
  317. }
  318. } // namespace bgfx