// Copyright (c) Microsoft Corporation. All rights reserved. /*==========================================================================; * * Copyright (C) Microsoft Corporation. All Rights Reserved. * * File: PIX3_win.h * Content: PIX include file * Don't include this file directly - use pix3.h * ****************************************************************************/ #pragma once #ifndef _PIX3_H_ #error Don't include this file directly - use pix3.h #endif #ifndef _PIX3_WIN_H_ #define _PIX3_WIN_H_ // PIXEventsThreadInfo is defined in PIXEventsCommon.h struct PIXEventsThreadInfo; extern "C" PIXEventsThreadInfo* WINAPI PIXGetThreadInfo() noexcept; #if defined(USE_PIX) && defined(USE_PIX_SUPPORTED_ARCHITECTURE) // Notifies PIX that an event handle was set as a result of a D3D12 fence being signaled. // The event specified must have the same handle value as the handle // used in ID3D12Fence::SetEventOnCompletion. extern "C" void WINAPI PIXNotifyWakeFromFenceSignal(_In_ HANDLE event); // Notifies PIX that a block of memory was allocated extern "C" void WINAPI PIXRecordMemoryAllocationEvent(USHORT allocatorId, void* baseAddress, size_t size, UINT64 metadata); // Notifies PIX that a block of memory was freed extern "C" void WINAPI PIXRecordMemoryFreeEvent(USHORT allocatorId, void* baseAddress, size_t size, UINT64 metadata); #else // Eliminate these APIs when not using PIX inline void PIXRecordMemoryAllocationEvent(USHORT, void*, size_t, UINT64) {} inline void PIXRecordMemoryFreeEvent(USHORT, void*, size_t, UINT64) {} #endif // The following defines denote the different metadata values that have been used // by tools to denote how to parse pix marker event data. The first two values // are legacy values. #define WINPIX_EVENT_UNICODE_VERSION 0 #define WINPIX_EVENT_ANSI_VERSION 1 #define WINPIX_EVENT_PIX3BLOB_VERSION 2 #define D3D12_EVENT_METADATA WINPIX_EVENT_PIX3BLOB_VERSION __forceinline UINT64 PIXGetTimestampCounter() { LARGE_INTEGER time = {}; QueryPerformanceCounter(&time); return static_cast(time.QuadPart); } enum PIXHUDOptions { PIX_HUD_SHOW_ON_ALL_WINDOWS = 0x1, PIX_HUD_SHOW_ON_TARGET_WINDOW_ONLY = 0x2, PIX_HUD_SHOW_ON_NO_WINDOWS = 0x4 }; DEFINE_ENUM_FLAG_OPERATORS(PIXHUDOptions); #if defined(USE_PIX_SUPPORTED_ARCHITECTURE) && defined(USE_PIX) #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) #include #include #include #include #define PIXERRORCHECK(value) do { \ if (FAILED(value)) \ return nullptr; \ } while(0) namespace PixImpl { #ifndef PIX3_WIN_UNIT_TEST __forceinline BOOL GetModuleHandleExW( DWORD dwFlags, LPCWSTR lpModuleName, HMODULE* phModule) { return ::GetModuleHandleExW(dwFlags, lpModuleName, phModule); } __forceinline HRESULT SHGetKnownFolderPath( REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR* ppszPath) { return ::SHGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath); } __forceinline void CoTaskMemFree(LPVOID pv) { return ::CoTaskMemFree(pv); } __forceinline HANDLE FindFirstFileW( LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) { return ::FindFirstFileW(lpFileName, lpFindFileData); } __forceinline DWORD GetFileAttributesW(LPCWSTR lpFileName) { return ::GetFileAttributesW(lpFileName); } __forceinline BOOL FindNextFileW( HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) { return ::FindNextFileW(hFindFile, lpFindFileData); } __forceinline BOOL FindClose(HANDLE hFindFile) { return ::FindClose(hFindFile); } __forceinline HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, DWORD flags) { return ::LoadLibraryExW(lpLibFileName, NULL, flags); } #endif // !PIX3_WIN_UNIT_TESTS __forceinline void * GetGpuCaptureFunctionPtr(LPCSTR fnName) noexcept { HMODULE module = GetModuleHandleW(L"WinPixGpuCapturer.dll"); if (module == NULL) { return nullptr; } auto fn = (void*)GetProcAddress(module, fnName); if (fn == nullptr) { return nullptr; } return fn; } __forceinline void* GetTimingCaptureFunctionPtr(LPCSTR fnName) noexcept { HMODULE module = GetModuleHandleW(L"WinPixTimingCapturer.dll"); if (module == NULL) { return nullptr; } auto fn = (void*)GetProcAddress(module, fnName); if (fn == nullptr) { return nullptr; } return fn; } __forceinline HMODULE PIXLoadLatestCapturerLibrary(wchar_t const* capturerDllName, DWORD flags) { HMODULE libHandle{}; if (PixImpl::GetModuleHandleExW(0, capturerDllName, &libHandle)) { return libHandle; } LPWSTR programFilesPath = nullptr; if (FAILED(PixImpl::SHGetKnownFolderPath(FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &programFilesPath))) { PixImpl::CoTaskMemFree(programFilesPath); return nullptr; } wchar_t pixSearchPath[MAX_PATH]; if (FAILED(StringCchCopyW(pixSearchPath, MAX_PATH, programFilesPath))) { PixImpl::CoTaskMemFree(programFilesPath); return nullptr; } PixImpl::CoTaskMemFree(programFilesPath); PIXERRORCHECK(StringCchCatW(pixSearchPath, MAX_PATH, L"\\Microsoft PIX\\*")); WIN32_FIND_DATAW findData; bool foundPixInstallation = false; wchar_t newestVersionFound[MAX_PATH]; wchar_t output[MAX_PATH]; wchar_t possibleOutput[MAX_PATH]; HANDLE hFind = PixImpl::FindFirstFileW(pixSearchPath, &findData); if (hFind != INVALID_HANDLE_VALUE) { do { if (((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) && (findData.cFileName[0] != '.')) { if (!foundPixInstallation || wcscmp(newestVersionFound, findData.cFileName) <= 0) { // length - 1 to get rid of the wildcard character in the search path PIXERRORCHECK(StringCchCopyNW(possibleOutput, MAX_PATH, pixSearchPath, wcslen(pixSearchPath) - 1)); PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, findData.cFileName)); PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, L"\\")); PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, capturerDllName)); DWORD result = PixImpl::GetFileAttributesW(possibleOutput); if (result != INVALID_FILE_ATTRIBUTES && !(result & FILE_ATTRIBUTE_DIRECTORY)) { foundPixInstallation = true; PIXERRORCHECK(StringCchCopyW(newestVersionFound, _countof(newestVersionFound), findData.cFileName)); PIXERRORCHECK(StringCchCopyW(output, _countof(possibleOutput), possibleOutput)); } } } } while (PixImpl::FindNextFileW(hFind, &findData) != 0); } PixImpl::FindClose(hFind); if (!foundPixInstallation) { SetLastError(ERROR_FILE_NOT_FOUND); return nullptr; } return PixImpl::LoadLibraryExW(output, flags); } } #undef PIXERRORCHECK __forceinline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary() { return PixImpl::PIXLoadLatestCapturerLibrary( L"WinPixGpuCapturer.dll", LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); } __forceinline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary() { return PixImpl::PIXLoadLatestCapturerLibrary( L"WinPixTimingCapturer.dll", LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); } __forceinline HRESULT WINAPI PIXSetTargetWindow(HWND hwnd) { typedef void(WINAPI* SetGlobalTargetWindowFn)(HWND); auto fn = (SetGlobalTargetWindowFn)PixImpl::GetGpuCaptureFunctionPtr("SetGlobalTargetWindow"); if (fn == nullptr) { return HRESULT_FROM_WIN32(GetLastError()); } fn(hwnd); return S_OK; } __forceinline HRESULT WINAPI PIXGpuCaptureNextFrames(PCWSTR fileName, UINT32 numFrames) { typedef HRESULT(WINAPI* CaptureNextFrameFn)(PCWSTR, UINT32); auto fn = (CaptureNextFrameFn)PixImpl::GetGpuCaptureFunctionPtr("CaptureNextFrame"); if (fn == nullptr) { return HRESULT_FROM_WIN32(GetLastError()); } return fn(fileName, numFrames); } extern "C" __forceinline HRESULT WINAPI PIXBeginCapture2(DWORD captureFlags, _In_opt_ const PPIXCaptureParameters captureParameters) { if (captureFlags == PIX_CAPTURE_GPU) { typedef HRESULT(WINAPI* BeginProgrammaticGpuCaptureFn)(const PPIXCaptureParameters); auto fn = (BeginProgrammaticGpuCaptureFn)PixImpl::GetGpuCaptureFunctionPtr("BeginProgrammaticGpuCapture"); if (fn == nullptr) { return HRESULT_FROM_WIN32(GetLastError()); } return fn(captureParameters); } else if (captureFlags == PIX_CAPTURE_TIMING) { typedef HRESULT(WINAPI* BeginProgrammaticTimingCaptureFn)(void const*, UINT64); auto fn = (BeginProgrammaticTimingCaptureFn)PixImpl::GetTimingCaptureFunctionPtr("BeginProgrammaticTimingCapture"); if (fn == nullptr) { return HRESULT_FROM_WIN32(GetLastError()); } return fn(&captureParameters->TimingCaptureParameters, sizeof(captureParameters->TimingCaptureParameters)); } else { return E_NOTIMPL; } } extern "C" __forceinline HRESULT WINAPI PIXEndCapture(BOOL discard) { UNREFERENCED_PARAMETER(discard); // We can't tell if the user wants to end a GPU Capture or a Timing Capture. // The user shouldn't have both WinPixGpuCapturer and WinPixTimingCapturer loaded in the process though, // so we can just look for one of them and call it. typedef HRESULT(WINAPI* EndProgrammaticGpuCaptureFn)(void); auto gpuFn = (EndProgrammaticGpuCaptureFn)PixImpl::GetGpuCaptureFunctionPtr("EndProgrammaticGpuCapture"); if (gpuFn != NULL) { return gpuFn(); } typedef HRESULT(WINAPI* EndProgrammaticTimingCaptureFn)(BOOL); auto timingFn = (EndProgrammaticTimingCaptureFn)PixImpl::GetTimingCaptureFunctionPtr("EndProgrammaticTimingCapture"); if (timingFn != NULL) { return timingFn(discard); } return HRESULT_FROM_WIN32(GetLastError()); } __forceinline HRESULT WINAPI PIXForceD3D11On12() { typedef HRESULT (WINAPI* ForceD3D11On12Fn)(void); auto fn = (ForceD3D11On12Fn)PixImpl::GetGpuCaptureFunctionPtr("ForceD3D11On12"); if (fn == NULL) { return HRESULT_FROM_WIN32(GetLastError()); } return fn(); } __forceinline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions hudOptions) { typedef HRESULT(WINAPI* SetHUDOptionsFn)(PIXHUDOptions); auto fn = (SetHUDOptionsFn)PixImpl::GetGpuCaptureFunctionPtr("SetHUDOptions"); if (fn == NULL) { return HRESULT_FROM_WIN32(GetLastError()); } return fn(hudOptions); } __forceinline bool WINAPI PIXIsAttachedForGpuCapture() { typedef bool(WINAPI* GetIsAttachedToPixFn)(void); auto fn = (GetIsAttachedToPixFn)PixImpl::GetGpuCaptureFunctionPtr("GetIsAttachedToPix"); if (fn == NULL) { OutputDebugStringW(L"WinPixEventRuntime error: Mismatched header/dll. Please ensure that pix3.h and WinPixGpuCapturer.dll match"); return false; } return fn(); } __forceinline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR fileName) { return ShellExecuteW(0, 0, fileName, 0, 0, SW_SHOW); } #else __forceinline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary() { return nullptr; } __forceinline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary() { return nullptr; } __forceinline HRESULT WINAPI PIXSetTargetWindow(HWND) { return E_NOTIMPL; } __forceinline HRESULT WINAPI PIXGpuCaptureNextFrames(PCWSTR, UINT32) { return E_NOTIMPL; } extern "C" __forceinline HRESULT WINAPI PIXBeginCapture2(DWORD, _In_opt_ const PPIXCaptureParameters) { return E_NOTIMPL; } extern "C" __forceinline HRESULT WINAPI PIXEndCapture(BOOL) { return E_NOTIMPL; } __forceinline HRESULT WINAPI PIXForceD3D11On12() { return E_NOTIMPL; } __forceinline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions) { return E_NOTIMPL; } __forceinline bool WINAPI PIXIsAttachedForGpuCapture() { return false; } __forceinline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR) { return 0; } #endif // WINAPI_PARTITION #endif // USE_PIX_SUPPORTED_ARCHITECTURE || USE_PIX #endif //_PIX3_WIN_H_