pix3_win.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. // Copyright (c) Microsoft Corporation.
  2. // Licensed under the MIT License.
  3. // Don't include this file directly - use pix3.h
  4. #pragma once
  5. #ifndef _PIX3_H_
  6. #error "Don't include this file directly - use pix3.h"
  7. #endif
  8. #ifndef _PIX3_WIN_H_
  9. #define _PIX3_WIN_H_
  10. // PIXEventsThreadInfo is defined in PIXEventsCommon.h
  11. struct PIXEventsThreadInfo;
  12. //extern "C" PIXEventsThreadInfo* WINAPI PIXGetThreadInfo() noexcept;
  13. //
  14. //#if defined(USE_PIX) && defined(USE_PIX_SUPPORTED_ARCHITECTURE)
  15. //// Notifies PIX that an event handle was set as a result of a D3D12 fence being signaled.
  16. //// The event specified must have the same handle value as the handle
  17. //// used in ID3D12Fence::SetEventOnCompletion.
  18. //extern "C" void WINAPI PIXNotifyWakeFromFenceSignal(_In_ HANDLE event);
  19. //
  20. //// Notifies PIX that a block of memory was allocated
  21. //extern "C" void WINAPI PIXRecordMemoryAllocationEvent(USHORT allocatorId, void* baseAddress, size_t size, UINT64 metadata);
  22. //
  23. //// Notifies PIX that a block of memory was freed
  24. //extern "C" void WINAPI PIXRecordMemoryFreeEvent(USHORT allocatorId, void* baseAddress, size_t size, UINT64 metadata);
  25. //
  26. //#else
  27. //
  28. //// Eliminate these APIs when not using PIX
  29. //inline void PIXRecordMemoryAllocationEvent(USHORT, void*, size_t, UINT64) {}
  30. //inline void PIXRecordMemoryFreeEvent(USHORT, void*, size_t, UINT64) {}
  31. //
  32. //#endif
  33. // The following WINPIX_EVENT_* defines denote the different metadata values that have
  34. // been used by tools to denote how to parse pix marker event data. The first two values
  35. // are legacy values used by pix.h in the Windows SDK.
  36. #define WINPIX_EVENT_UNICODE_VERSION 0
  37. #define WINPIX_EVENT_ANSI_VERSION 1
  38. // These values denote PIX marker event data that was created by the WinPixEventRuntime.
  39. // In early 2023 we revised the PIX marker format and defined a new version number.
  40. #define WINPIX_EVENT_PIX3BLOB_VERSION 2
  41. #define WINPIX_EVENT_PIX3BLOB_V2 6345127 // A number that other applications are unlikely to have used before
  42. // For backcompat reasons, the WinPixEventRuntime uses the older PIX3BLOB format when it passes data
  43. // into the D3D12 runtime. It will be updated to use the V2 format in the future.
  44. #define D3D12_EVENT_METADATA WINPIX_EVENT_PIX3BLOB_VERSION
  45. __forceinline UINT64 PIXGetTimestampCounter()
  46. {
  47. LARGE_INTEGER time = {};
  48. QueryPerformanceCounter(&time);
  49. return static_cast<UINT64>(time.QuadPart);
  50. }
  51. enum PIXHUDOptions
  52. {
  53. PIX_HUD_SHOW_ON_ALL_WINDOWS = 0x1,
  54. PIX_HUD_SHOW_ON_TARGET_WINDOW_ONLY = 0x2,
  55. PIX_HUD_SHOW_ON_NO_WINDOWS = 0x4
  56. };
  57. DEFINE_ENUM_FLAG_OPERATORS(PIXHUDOptions);
  58. #if defined(USE_PIX_SUPPORTED_ARCHITECTURE) && defined(USE_PIX)
  59. #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
  60. #include <shlobj.h>
  61. #include <strsafe.h>
  62. #include <knownfolders.h>
  63. #include <shellapi.h>
  64. #define PIXERRORCHECK(value) do { \
  65. if (FAILED(value)) \
  66. return nullptr; \
  67. } while(0)
  68. namespace PixImpl
  69. {
  70. #ifndef PIX3_WIN_UNIT_TEST
  71. __forceinline BOOL GetModuleHandleExW(
  72. DWORD dwFlags,
  73. LPCWSTR lpModuleName,
  74. HMODULE* phModule)
  75. {
  76. return ::GetModuleHandleExW(dwFlags, lpModuleName, phModule);
  77. }
  78. __forceinline HRESULT SHGetKnownFolderPath(
  79. REFKNOWNFOLDERID rfid,
  80. DWORD dwFlags,
  81. HANDLE hToken,
  82. PWSTR* ppszPath)
  83. {
  84. return ::SHGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath);
  85. }
  86. __forceinline void CoTaskMemFree(LPVOID pv)
  87. {
  88. return ::CoTaskMemFree(pv);
  89. }
  90. __forceinline HANDLE FindFirstFileW(
  91. LPCWSTR lpFileName,
  92. LPWIN32_FIND_DATAW lpFindFileData)
  93. {
  94. return ::FindFirstFileW(lpFileName, lpFindFileData);
  95. }
  96. __forceinline DWORD GetFileAttributesW(LPCWSTR lpFileName)
  97. {
  98. return ::GetFileAttributesW(lpFileName);
  99. }
  100. __forceinline BOOL FindNextFileW(
  101. HANDLE hFindFile,
  102. LPWIN32_FIND_DATAW lpFindFileData)
  103. {
  104. return ::FindNextFileW(hFindFile, lpFindFileData);
  105. }
  106. __forceinline BOOL FindClose(HANDLE hFindFile)
  107. {
  108. return ::FindClose(hFindFile);
  109. }
  110. __forceinline HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, DWORD flags)
  111. {
  112. return ::LoadLibraryExW(lpLibFileName, NULL, flags);
  113. }
  114. #endif // !PIX3_WIN_UNIT_TESTS
  115. __forceinline void * GetGpuCaptureFunctionPtr(LPCSTR fnName) noexcept
  116. {
  117. HMODULE module = GetModuleHandleW(L"WinPixGpuCapturer.dll");
  118. if (module == NULL)
  119. {
  120. return nullptr;
  121. }
  122. auto fn = (void*)GetProcAddress(module, fnName);
  123. if (fn == nullptr)
  124. {
  125. return nullptr;
  126. }
  127. return fn;
  128. }
  129. __forceinline void* GetTimingCaptureFunctionPtr(LPCSTR fnName) noexcept
  130. {
  131. HMODULE module = GetModuleHandleW(L"WinPixTimingCapturer.dll");
  132. if (module == NULL)
  133. {
  134. return nullptr;
  135. }
  136. auto fn = (void*)GetProcAddress(module, fnName);
  137. if (fn == nullptr)
  138. {
  139. return nullptr;
  140. }
  141. return fn;
  142. }
  143. __forceinline HMODULE PIXLoadLatestCapturerLibrary(wchar_t const* capturerDllName, DWORD flags)
  144. {
  145. HMODULE libHandle{};
  146. if (PixImpl::GetModuleHandleExW(0, capturerDllName, &libHandle))
  147. {
  148. return libHandle;
  149. }
  150. LPWSTR programFilesPath = nullptr;
  151. if (FAILED(PixImpl::SHGetKnownFolderPath(FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &programFilesPath)))
  152. {
  153. PixImpl::CoTaskMemFree(programFilesPath);
  154. return nullptr;
  155. }
  156. wchar_t pixSearchPath[MAX_PATH];
  157. if (FAILED(StringCchCopyW(pixSearchPath, MAX_PATH, programFilesPath)))
  158. {
  159. PixImpl::CoTaskMemFree(programFilesPath);
  160. return nullptr;
  161. }
  162. PixImpl::CoTaskMemFree(programFilesPath);
  163. PIXERRORCHECK(StringCchCatW(pixSearchPath, MAX_PATH, L"\\Microsoft PIX\\*"));
  164. WIN32_FIND_DATAW findData;
  165. bool foundPixInstallation = false;
  166. wchar_t newestVersionFound[MAX_PATH];
  167. wchar_t output[MAX_PATH];
  168. wchar_t possibleOutput[MAX_PATH];
  169. HANDLE hFind = PixImpl::FindFirstFileW(pixSearchPath, &findData);
  170. if (hFind != INVALID_HANDLE_VALUE)
  171. {
  172. do
  173. {
  174. if (((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) &&
  175. (findData.cFileName[0] != '.'))
  176. {
  177. if (!foundPixInstallation || wcscmp(newestVersionFound, findData.cFileName) <= 0)
  178. {
  179. // length - 1 to get rid of the wildcard character in the search path
  180. PIXERRORCHECK(StringCchCopyNW(possibleOutput, MAX_PATH, pixSearchPath, wcslen(pixSearchPath) - 1));
  181. PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, findData.cFileName));
  182. PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, L"\\"));
  183. PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, capturerDllName));
  184. DWORD result = PixImpl::GetFileAttributesW(possibleOutput);
  185. if (result != INVALID_FILE_ATTRIBUTES && !(result & FILE_ATTRIBUTE_DIRECTORY))
  186. {
  187. foundPixInstallation = true;
  188. PIXERRORCHECK(StringCchCopyW(newestVersionFound, _countof(newestVersionFound), findData.cFileName));
  189. PIXERRORCHECK(StringCchCopyW(output, _countof(possibleOutput), possibleOutput));
  190. }
  191. }
  192. }
  193. } while (PixImpl::FindNextFileW(hFind, &findData) != 0);
  194. }
  195. PixImpl::FindClose(hFind);
  196. if (!foundPixInstallation)
  197. {
  198. SetLastError(ERROR_FILE_NOT_FOUND);
  199. return nullptr;
  200. }
  201. return PixImpl::LoadLibraryExW(output, flags);
  202. }
  203. }
  204. #undef PIXERRORCHECK
  205. __forceinline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary()
  206. {
  207. return PixImpl::PIXLoadLatestCapturerLibrary(
  208. L"WinPixGpuCapturer.dll",
  209. LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
  210. }
  211. __forceinline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary()
  212. {
  213. return PixImpl::PIXLoadLatestCapturerLibrary(
  214. L"WinPixTimingCapturer.dll",
  215. LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
  216. }
  217. __forceinline HRESULT WINAPI PIXSetTargetWindow(HWND hwnd)
  218. {
  219. typedef void(WINAPI* SetGlobalTargetWindowFn)(HWND);
  220. auto fn = (SetGlobalTargetWindowFn)PixImpl::GetGpuCaptureFunctionPtr("SetGlobalTargetWindow");
  221. if (fn == nullptr)
  222. {
  223. return HRESULT_FROM_WIN32(GetLastError());
  224. }
  225. fn(hwnd);
  226. return S_OK;
  227. }
  228. __forceinline HRESULT WINAPI PIXGpuCaptureNextFrames(PCWSTR fileName, UINT32 numFrames)
  229. {
  230. typedef HRESULT(WINAPI* CaptureNextFrameFn)(PCWSTR, UINT32);
  231. auto fn = (CaptureNextFrameFn)PixImpl::GetGpuCaptureFunctionPtr("CaptureNextFrame");
  232. if (fn == nullptr)
  233. {
  234. return HRESULT_FROM_WIN32(GetLastError());
  235. }
  236. return fn(fileName, numFrames);
  237. }
  238. extern "C" __forceinline HRESULT WINAPI PIXBeginCapture2(DWORD captureFlags, _In_opt_ const PPIXCaptureParameters captureParameters)
  239. {
  240. if (captureFlags == PIX_CAPTURE_GPU)
  241. {
  242. typedef HRESULT(WINAPI* BeginProgrammaticGpuCaptureFn)(const PPIXCaptureParameters);
  243. auto fn = (BeginProgrammaticGpuCaptureFn)PixImpl::GetGpuCaptureFunctionPtr("BeginProgrammaticGpuCapture");
  244. if (fn == nullptr)
  245. {
  246. return HRESULT_FROM_WIN32(GetLastError());
  247. }
  248. return fn(captureParameters);
  249. }
  250. else if (captureFlags == PIX_CAPTURE_TIMING)
  251. {
  252. typedef HRESULT(WINAPI* BeginProgrammaticTimingCaptureFn)(void const*, UINT64);
  253. auto fn = (BeginProgrammaticTimingCaptureFn)PixImpl::GetTimingCaptureFunctionPtr("BeginProgrammaticTimingCapture");
  254. if (fn == nullptr)
  255. {
  256. return HRESULT_FROM_WIN32(GetLastError());
  257. }
  258. return fn(&captureParameters->TimingCaptureParameters, sizeof(captureParameters->TimingCaptureParameters));
  259. }
  260. else
  261. {
  262. return E_NOTIMPL;
  263. }
  264. }
  265. extern "C" __forceinline HRESULT WINAPI PIXEndCapture(BOOL discard)
  266. {
  267. // We can't tell if the user wants to end a GPU Capture or a Timing Capture.
  268. // The user shouldn't have both WinPixGpuCapturer and WinPixTimingCapturer loaded in the process though,
  269. // so we can just look for one of them and call it.
  270. typedef HRESULT(WINAPI* EndProgrammaticGpuCaptureFn)(void);
  271. auto gpuFn = (EndProgrammaticGpuCaptureFn)PixImpl::GetGpuCaptureFunctionPtr("EndProgrammaticGpuCapture");
  272. if (gpuFn != NULL)
  273. {
  274. return gpuFn();
  275. }
  276. typedef HRESULT(WINAPI* EndProgrammaticTimingCaptureFn)(BOOL);
  277. auto timingFn = (EndProgrammaticTimingCaptureFn)PixImpl::GetTimingCaptureFunctionPtr("EndProgrammaticTimingCapture");
  278. if (timingFn != NULL)
  279. {
  280. return timingFn(discard);
  281. }
  282. return HRESULT_FROM_WIN32(GetLastError());
  283. }
  284. __forceinline HRESULT WINAPI PIXForceD3D11On12()
  285. {
  286. typedef HRESULT (WINAPI* ForceD3D11On12Fn)(void);
  287. auto fn = (ForceD3D11On12Fn)PixImpl::GetGpuCaptureFunctionPtr("ForceD3D11On12");
  288. if (fn == NULL)
  289. {
  290. return HRESULT_FROM_WIN32(GetLastError());
  291. }
  292. return fn();
  293. }
  294. __forceinline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions hudOptions)
  295. {
  296. typedef HRESULT(WINAPI* SetHUDOptionsFn)(PIXHUDOptions);
  297. auto fn = (SetHUDOptionsFn)PixImpl::GetGpuCaptureFunctionPtr("SetHUDOptions");
  298. if (fn == NULL)
  299. {
  300. return HRESULT_FROM_WIN32(GetLastError());
  301. }
  302. return fn(hudOptions);
  303. }
  304. __forceinline bool WINAPI PIXIsAttachedForGpuCapture()
  305. {
  306. typedef bool(WINAPI* GetIsAttachedToPixFn)(void);
  307. auto fn = (GetIsAttachedToPixFn)PixImpl::GetGpuCaptureFunctionPtr("GetIsAttachedToPix");
  308. if (fn == NULL)
  309. {
  310. OutputDebugStringW(L"WinPixEventRuntime error: Mismatched header/dll. Please ensure that pix3.h and WinPixGpuCapturer.dll match");
  311. return false;
  312. }
  313. return fn();
  314. }
  315. __forceinline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR fileName)
  316. {
  317. return ShellExecuteW(0, 0, fileName, 0, 0, SW_SHOW);
  318. }
  319. #else
  320. __forceinline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary()
  321. {
  322. return nullptr;
  323. }
  324. __forceinline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary()
  325. {
  326. return nullptr;
  327. }
  328. __forceinline HRESULT WINAPI PIXSetTargetWindow(HWND)
  329. {
  330. return E_NOTIMPL;
  331. }
  332. __forceinline HRESULT WINAPI PIXGpuCaptureNextFrames(PCWSTR, UINT32)
  333. {
  334. return E_NOTIMPL;
  335. }
  336. extern "C" __forceinline HRESULT WINAPI PIXBeginCapture2(DWORD, _In_opt_ const PPIXCaptureParameters)
  337. {
  338. return E_NOTIMPL;
  339. }
  340. extern "C" __forceinline HRESULT WINAPI PIXEndCapture(BOOL)
  341. {
  342. return E_NOTIMPL;
  343. }
  344. __forceinline HRESULT WINAPI PIXForceD3D11On12()
  345. {
  346. return E_NOTIMPL;
  347. }
  348. __forceinline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions)
  349. {
  350. return E_NOTIMPL;
  351. }
  352. __forceinline bool WINAPI PIXIsAttachedForGpuCapture()
  353. {
  354. return false;
  355. }
  356. __forceinline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR)
  357. {
  358. return 0;
  359. }
  360. #endif // WINAPI_PARTITION
  361. #endif // USE_PIX_SUPPORTED_ARCHITECTURE || USE_PIX
  362. #if defined(__d3d12_h__)
  363. inline void PIXInsertTimingMarkerOnContextForBeginEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
  364. {
  365. UNREFERENCED_PARAMETER(eventType);
  366. commandList->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size);
  367. }
  368. inline void PIXInsertTimingMarkerOnContextForBeginEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
  369. {
  370. UNREFERENCED_PARAMETER(eventType);
  371. commandQueue->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size);
  372. }
  373. inline void PIXInsertTimingMarkerOnContextForSetMarker(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
  374. {
  375. UNREFERENCED_PARAMETER(eventType);
  376. commandList->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size);
  377. }
  378. inline void PIXInsertTimingMarkerOnContextForSetMarker(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
  379. {
  380. UNREFERENCED_PARAMETER(eventType);
  381. commandQueue->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size);
  382. }
  383. inline void PIXInsertTimingMarkerOnContextForEndEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType)
  384. {
  385. UNREFERENCED_PARAMETER(eventType);
  386. commandList->EndEvent();
  387. }
  388. inline void PIXInsertTimingMarkerOnContextForEndEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType)
  389. {
  390. UNREFERENCED_PARAMETER(eventType);
  391. commandQueue->EndEvent();
  392. }
  393. inline void PIXInsertGPUMarkerOnContextForBeginEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
  394. {
  395. UNREFERENCED_PARAMETER(eventType);
  396. commandList->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size);
  397. }
  398. inline void PIXInsertGPUMarkerOnContextForBeginEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
  399. {
  400. UNREFERENCED_PARAMETER(eventType);
  401. commandQueue->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size);
  402. }
  403. inline void PIXInsertGPUMarkerOnContextForSetMarker(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
  404. {
  405. UNREFERENCED_PARAMETER(eventType);
  406. commandList->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size);
  407. }
  408. inline void PIXInsertGPUMarkerOnContextForSetMarker(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
  409. {
  410. UNREFERENCED_PARAMETER(eventType);
  411. commandQueue->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size);
  412. }
  413. inline void PIXInsertGPUMarkerOnContextForEndEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8, void*, UINT)
  414. {
  415. commandList->EndEvent();
  416. }
  417. inline void PIXInsertGPUMarkerOnContextForEndEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8, void*, UINT)
  418. {
  419. commandQueue->EndEvent();
  420. }
  421. #endif
  422. #endif //_PIX3_WIN_H_