From 987489b34aa0d9adc6b758960132148eb783c5b4 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 13 Aug 2023 21:22:07 +1000 Subject: [PATCH] 3rdparty: Add WinPixEventRuntime --- .../WinPixEventRuntime.props | 37 + .../bin/WinPixEventRuntime.dll | Bin 0 -> 57040 bytes .../include/WinPixEventRuntime/PIXEvents.h | 661 ++++++++++++++++++ .../WinPixEventRuntime/PIXEventsCommon.h | 605 ++++++++++++++++ .../include/WinPixEventRuntime/pix3.h | 175 +++++ .../include/WinPixEventRuntime/pix3_win.h | 439 ++++++++++++ .../lib/WinPixEventRuntime.lib | Bin 0 -> 6230 bytes 7 files changed, 1917 insertions(+) create mode 100644 3rdparty/winpixeventruntime/WinPixEventRuntime.props create mode 100644 3rdparty/winpixeventruntime/bin/WinPixEventRuntime.dll create mode 100644 3rdparty/winpixeventruntime/include/WinPixEventRuntime/PIXEvents.h create mode 100644 3rdparty/winpixeventruntime/include/WinPixEventRuntime/PIXEventsCommon.h create mode 100644 3rdparty/winpixeventruntime/include/WinPixEventRuntime/pix3.h create mode 100644 3rdparty/winpixeventruntime/include/WinPixEventRuntime/pix3_win.h create mode 100644 3rdparty/winpixeventruntime/lib/WinPixEventRuntime.lib diff --git a/3rdparty/winpixeventruntime/WinPixEventRuntime.props b/3rdparty/winpixeventruntime/WinPixEventRuntime.props new file mode 100644 index 0000000000..8f5272bcfe --- /dev/null +++ b/3rdparty/winpixeventruntime/WinPixEventRuntime.props @@ -0,0 +1,37 @@ + + + + $(SolutionDir)bin\ + $(SolutionDir)3rdparty\winpixeventruntime\ + + + + $(WinPixEventRuntimeDir)include;%(AdditionalIncludeDirectories) + + + $(WinPixEventRuntimeDir)lib;%(AdditionalLibraryDirectories) + WinPixEventRuntime.lib;%(AdditionalDependencies) + + + $(WinPixEventRuntimeDir)lib;%(AdditionalLibraryDirectories) + WinPixEventRuntime.lib;%(AdditionalDependencies) + + + + + + + + + + + + diff --git a/3rdparty/winpixeventruntime/bin/WinPixEventRuntime.dll b/3rdparty/winpixeventruntime/bin/WinPixEventRuntime.dll new file mode 100644 index 0000000000000000000000000000000000000000..0e2f75c51cb3215b0ac27efdb5bab73908d18a55 GIT binary patch literal 57040 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
  • 0QHAck0f+h7TO9B%V9hpJOfW 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 p6+0Kr7PX1>6opTad(EJ_#cku8dy + struct PIXEventTypeInferer + { + static constexpr PIXEventType Begin() { return PIXEvent_BeginEvent_VarArgs; } + static constexpr PIXEventType SetMarker() { return PIXEvent_SetMarker_VarArgs; } + static constexpr PIXEventType BeginOnContext() { return PIXEvent_BeginEvent_OnContext_VarArgs; } + static constexpr PIXEventType SetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_VarArgs; } + + // Xbox and Windows store different types of events for context events. + // On Xbox these include a context argument, while on Windows they do + // not. It is important not to change the event types used on the + // Windows version as there are OS components (eg debug layer & DRED) + // that decode event structs. +#ifdef PIX_XBOX + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_OnContext_VarArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_VarArgs; } +#else + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_VarArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_VarArgs; } +#endif + }; + + template<> + struct PIXEventTypeInferer<> + { + static constexpr PIXEventType Begin() { return PIXEvent_BeginEvent_NoArgs; } + static constexpr PIXEventType SetMarker() { return PIXEvent_SetMarker_NoArgs; } + static constexpr PIXEventType BeginOnContext() { return PIXEvent_BeginEvent_OnContext_NoArgs; } + static constexpr PIXEventType SetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_NoArgs; } + +#ifdef PIX_XBOX + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_OnContext_NoArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_NoArgs; } +#else + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_NoArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_NoArgs; } +#endif + }; + + inline void PIXCopyEventArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit) + { + // nothing + UNREFERENCED_PARAMETER(destination); + UNREFERENCED_PARAMETER(limit); + } + + template + void PIXCopyEventArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, ARG const& arg, ARGS const&... args) + { + PIXCopyEventArgument(destination, limit, arg); + PIXCopyEventArguments(destination, limit, args...); + } + + template + __declspec(noinline) void PIXBeginEventAllocate(PIXEventsThreadInfo* threadInfo, UINT64 color, STR formatString, ARGS... args) + { +#ifdef PIX_XBOX + UINT64 time = PIXEventsReplaceBlock(false); +#else + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); +#endif + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + *destination++ = PIXEncodeEventInfo(time, PIXEventTypeInferer::Begin()); + *destination++ = color; + + PIXCopyEventArguments(destination, limit, formatString, args...); + + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + + template + void PIXBeginEvent(UINT64 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + *destination++ = PIXEncodeEventInfo(time, PIXEventTypeInferer::Begin()); + *destination++ = color; + + PIXCopyEventArguments(destination, limit, formatString, args...); + + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + else + { + PIXBeginEventAllocate(threadInfo, color, formatString, args...); + } + } + } + + template + __declspec(noinline) void PIXSetMarkerAllocate(PIXEventsThreadInfo* threadInfo, UINT64 color, STR formatString, ARGS... args) + { +#ifdef PIX_XBOX + UINT64 time = PIXEventsReplaceBlock(false); +#else + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); +#endif + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + *destination++ = PIXEncodeEventInfo(time, PIXEventTypeInferer::SetMarker()); + *destination++ = color; + + PIXCopyEventArguments(destination, limit, formatString, args...); + + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + + template + void PIXSetMarker(UINT64 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + *destination++ = PIXEncodeEventInfo(time, PIXEventTypeInferer::SetMarker()); + *destination++ = color; + + PIXCopyEventArguments(destination, limit, formatString, args...); + + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + else + { + PIXSetMarkerAllocate(threadInfo, color, formatString, args...); + } + } + } + + template + __declspec(noinline) void PIXBeginEventOnContextCpuAllocate(PIXEventsThreadInfo* threadInfo, void* context, UINT64 color, STR formatString, ARGS... args) + { +#ifdef PIX_XBOX + UINT64 time = PIXEventsReplaceBlock(false); +#else + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); +#endif + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + *destination++ = PIXEncodeEventInfo(time, PIXEventTypeInferer::BeginOnContext()); + *destination++ = color; + +#ifdef PIX_XBOX + UNREFERENCED_PARAMETER(context); + PIXCopyEventArguments(destination, limit, formatString, args...); +#else + PIXCopyEventArguments(destination, limit, context, formatString, args...); +#endif + + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + + template + void PIXBeginEventOnContextCpu(void* context, UINT64 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + *destination++ = PIXEncodeEventInfo(time, PIXEventTypeInferer::BeginOnContext()); + *destination++ = color; + +#ifdef PIX_XBOX + PIXCopyEventArguments(destination, limit, formatString, args...); +#else + PIXCopyEventArguments(destination, limit, context, formatString, args...); +#endif + + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + else + { + PIXBeginEventOnContextCpuAllocate(threadInfo, context, color, formatString, args...); + } + } + } + + template + void PIXBeginEvent(CONTEXT* context, UINT64 color, STR formatString, ARGS... args) + { +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXBeginEventOnContextCpu(context, color, formatString, args...); +#endif + + // TODO: we've already encoded this once for the CPU event - figure out way to avoid doing it again + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + UINT64* destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + *destination++ = PIXEncodeEventInfo(0, PIXEventTypeInferer::GpuBeginOnContext()); + *destination++ = color; + + PIXCopyEventArguments(destination, limit, formatString, args...); + *destination = 0ull; + + PIXBeginGPUEventOnContext(context, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); + } + + template + __declspec(noinline) void PIXSetMarkerOnContextCpuAllocate(PIXEventsThreadInfo* threadInfo, void* context, UINT64 color, STR formatString, ARGS... args) + { +#ifdef PIX_XBOX + UINT64 time = PIXEventsReplaceBlock(false); +#else + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); +#endif + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + *destination++ = PIXEncodeEventInfo(time, PIXEventTypeInferer::SetMarkerOnContext()); + *destination++ = color; + +#ifdef PIX_XBOX + UNREFERENCED_PARAMETER(context); + PIXCopyEventArguments(destination, limit, formatString, args...); +#else + PIXCopyEventArguments(destination, limit, context, formatString, args...); +#endif + + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + + template + void PIXSetMarkerOnContextCpu(void* context, UINT64 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + *destination++ = PIXEncodeEventInfo(time, PIXEventTypeInferer::SetMarkerOnContext()); + *destination++ = color; + +#ifdef PIX_XBOX + PIXCopyEventArguments(destination, limit, formatString, args...); +#else + PIXCopyEventArguments(destination, limit, context, formatString, args...); +#endif + + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + else + { + PIXSetMarkerOnContextCpuAllocate(threadInfo, context, color, formatString, args...); + } + } + } + + template + void PIXSetMarker(CONTEXT* context, UINT64 color, STR formatString, ARGS... args) + { +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXSetMarkerOnContextCpu(context, color, formatString, args...); +#endif + + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + UINT64* destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + *destination++ = PIXEncodeEventInfo(0, PIXEventTypeInferer::GpuSetMarkerOnContext()); + *destination++ = color; + + PIXCopyEventArguments(destination, limit, formatString, args...); + *destination = 0ull; + + PIXSetGPUMarkerOnContext(context, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); + } + + __declspec(noinline) inline void PIXEndEventAllocate(PIXEventsThreadInfo* threadInfo) + { +#ifdef PIX_XBOX + UINT64 time = PIXEventsReplaceBlock(true); +#else + UINT64 time = PIXEventsReplaceBlock(threadInfo, true); +#endif + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + *destination++ = PIXEncodeEventInfo(time, PIXEvent_EndEvent); + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + + inline void PIXEndEvent() + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + *destination++ = PIXEncodeEventInfo(time, PIXEvent_EndEvent); + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + else + { + PIXEndEventAllocate(threadInfo); + } + } + } + + __declspec(noinline) inline void PIXEndEventOnContextCpuAllocate(PIXEventsThreadInfo* threadInfo, void* context) + { +#ifdef PIX_XBOX + UINT64 time = PIXEventsReplaceBlock(true); +#else + UINT64 time = PIXEventsReplaceBlock(threadInfo, true); +#endif + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + *destination++ = PIXEncodeEventInfo(time, PIXEvent_EndEvent_OnContext); +#ifdef PIX_XBOX + UNREFERENCED_PARAMETER(context); +#else + PIXCopyEventArgument(destination, limit, context); +#endif + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + + inline void PIXEndEventOnContextCpu(void* context) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + *destination++ = PIXEncodeEventInfo(time, PIXEvent_EndEvent_OnContext); +#ifndef PIX_XBOX + PIXCopyEventArgument(destination, limit, context); +#endif + *destination = PIXEventsBlockEndMarker; + threadInfo->destination = destination; + } + else + { + PIXEndEventOnContextCpuAllocate(threadInfo, context); + } + } + } + + template + void PIXEndEvent(CONTEXT* context) + { +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXEndEventOnContextCpu(context); +#endif + PIXEndGPUEventOnContext(context); + } +} + +#if defined(USE_PIX) + +template +void PIXBeginEvent(UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(color, formatString, args...); +} + +template +void PIXBeginEvent(UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(color, formatString, args...); +} + +template +void PIXSetMarker(UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(color, formatString, args...); +} + +template +void PIXSetMarker(UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(color, formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +inline void PIXEndEvent() +{ + PIXEventsDetail::PIXEndEvent(); +} + +template +void PIXEndEvent(CONTEXT* context) +{ + PIXEventsDetail::PIXEndEvent(context); +} + +#else // USE_PIX_RETAIL + +inline void PIXBeginEvent(UINT64, _In_ PCSTR, ...) {} +inline void PIXBeginEvent(UINT64, _In_ PCWSTR, ...) {} +inline void PIXBeginEvent(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXBeginEvent(void*, UINT64, _In_ PCWSTR, ...) {} +inline void PIXEndEvent() {} +inline void PIXEndEvent(void*) {} +inline void PIXSetMarker(UINT64, _In_ PCSTR, ...) {} +inline void PIXSetMarker(UINT64, _In_ PCWSTR, ...) {} +inline void PIXSetMarker(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXSetMarker(void*, UINT64, _In_ PCWSTR, ...) {} + +#endif // USE_PIX + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXEndRetailEvent(CONTEXT* context) +{ + PIXEventsDetail::PIXEndEvent(context); +} + +template +class PIXScopedEventObject +{ + CONTEXT* m_context; + +public: + template + PIXScopedEventObject(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + ~PIXScopedEventObject() + { + PIXEndEvent(m_context); + } +}; + +template +class PIXScopedRetailEventObject +{ + CONTEXT* m_context; + +public: + template + PIXScopedRetailEventObject(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + ~PIXScopedRetailEventObject() + { + PIXEndRetailEvent(m_context); + } +}; + +template<> +class PIXScopedEventObject +{ +public: + template + PIXScopedEventObject(UINT64 color, PCWSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(UINT64 color, PCSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + ~PIXScopedEventObject() + { + PIXEndEvent(); + } +}; + +#define PIXConcatenate(a, b) a ## b +#define PIXGetScopedEventVariableName(a, b) PIXConcatenate(a, b) +#define PIXScopedEvent(context, ...) PIXScopedEventObject::Type> PIXGetScopedEventVariableName(pixEvent, __LINE__)(context, __VA_ARGS__) + +#ifdef PIX3__DEFINED_CONSTEXPR +#undef constexpr +#undef PIX3__DEFINED_CONSTEXPR +#endif + +#endif // _PIXEvents_H__ diff --git a/3rdparty/winpixeventruntime/include/WinPixEventRuntime/PIXEventsCommon.h b/3rdparty/winpixeventruntime/include/WinPixEventRuntime/PIXEventsCommon.h new file mode 100644 index 0000000000..a9c21d97fe --- /dev/null +++ b/3rdparty/winpixeventruntime/include/WinPixEventRuntime/PIXEventsCommon.h @@ -0,0 +1,605 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +/*==========================================================================; +* +* Copyright (C) Microsoft Corporation. All Rights Reserved. +* +* File: PIXEventsCommon.h +* Content: PIX include file +* Don't include this file directly - use pix3.h +* +****************************************************************************/ +#pragma once + +#ifndef _PIXEventsCommon_H_ +#define _PIXEventsCommon_H_ + +#if defined(XBOX) || defined(_XBOX_ONE) || defined(_DURANGO) || defined(_GAMING_XBOX) || defined(_GAMING_XBOX_SCARLETT) +#define PIX_XBOX +#endif + +#include + +#if defined(_M_X64) || defined(_M_IX86) +#include +#endif + +// +// The PIXBeginEvent and PIXSetMarker functions have an optimized path for +// copying strings that work by copying 128-bit or 64-bits at a time. In some +// circumstances this may result in PIX logging the remaining memory after the +// null terminator. +// +// By default this optimization is enabled unless Address Sanitizer is enabled, +// since this optimization can trigger a global-buffer-overflow when copying +// string literals. +// +// The PIX_ENABLE_BLOCK_ARGUMENT_COPY controls whether or not this optimization +// is enabled. Applications may also explicitly set this macro to 0 to disable +// the optimization if necessary. +// + +// Check for Address Sanitizer on either Clang or MSVC + +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define PIX_ASAN_ENABLED +#endif +#elif defined(__SANITIZE_ADDRESS__) +#define PIX_ASAN_ENABLED +#endif + +#if defined(PIX_ENABLE_BLOCK_ARGUMENT_COPY) +// Previously set values override everything +# define PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET 0 +#elif defined(PIX_ASAN_ENABLED) +// Disable block argument copy when address sanitizer is enabled +#define PIX_ENABLE_BLOCK_ARGUMENT_COPY 0 +#define PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET 1 +#endif + +#if !defined(PIX_ENABLE_BLOCK_ARGUMENT_COPY) +// Default to enabled. +#define PIX_ENABLE_BLOCK_ARGUMENT_COPY 1 +#define PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET 1 +#endif + +struct PIXEventsBlockInfo; + +struct PIXEventsThreadInfo +{ + PIXEventsBlockInfo* block; + UINT64* biasedLimit; + UINT64* destination; +}; + +#ifdef PIX_XBOX +extern "C" UINT64 WINAPI PIXEventsReplaceBlock(bool getEarliestTime) noexcept; +#else +extern "C" UINT64 WINAPI PIXEventsReplaceBlock(PIXEventsThreadInfo * threadInfo, bool getEarliestTime) noexcept; +#endif + +enum PIXEventType +{ + PIXEvent_EndEvent = 0x000, + PIXEvent_BeginEvent_VarArgs = 0x001, + PIXEvent_BeginEvent_NoArgs = 0x002, + PIXEvent_SetMarker_VarArgs = 0x007, + PIXEvent_SetMarker_NoArgs = 0x008, + + PIXEvent_EndEvent_OnContext = 0x010, + PIXEvent_BeginEvent_OnContext_VarArgs = 0x011, + PIXEvent_BeginEvent_OnContext_NoArgs = 0x012, + PIXEvent_SetMarker_OnContext_VarArgs = 0x017, + PIXEvent_SetMarker_OnContext_NoArgs = 0x018, +}; + +static const UINT64 PIXEventsReservedRecordSpaceQwords = 64; +//this is used to make sure SSE string copy always will end 16-byte write in the current block +//this way only a check if destination < limit can be performed, instead of destination < limit - 1 +//since both these are UINT64* and SSE writes in 16 byte chunks, 8 bytes are kept in reserve +//so even if SSE overwrites 8 extra bytes, those will still belong to the correct block +//on next iteration check destination will be greater than limit +//this is used as well for fixed size UMD events and PIXEndEvent since these require less space +//than other variable length user events and do not need big reserved space +static const UINT64 PIXEventsReservedTailSpaceQwords = 2; +static const UINT64 PIXEventsSafeFastCopySpaceQwords = PIXEventsReservedRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; +static const UINT64 PIXEventsGraphicsRecordSpaceQwords = 64; + +//Bits 7-19 (13 bits) +static const UINT64 PIXEventsBlockEndMarker = 0x00000000000FFF80; + +//Bits 10-19 (10 bits) +static const UINT64 PIXEventsTypeReadMask = 0x00000000000FFC00; +static const UINT64 PIXEventsTypeWriteMask = 0x00000000000003FF; +static const UINT64 PIXEventsTypeBitShift = 10; + +//Bits 20-63 (44 bits) +static const UINT64 PIXEventsTimestampReadMask = 0xFFFFFFFFFFF00000; +static const UINT64 PIXEventsTimestampWriteMask = 0x00000FFFFFFFFFFF; +static const UINT64 PIXEventsTimestampBitShift = 20; + +inline UINT64 PIXEncodeEventInfo(UINT64 timestamp, PIXEventType eventType) +{ + return ((timestamp & PIXEventsTimestampWriteMask) << PIXEventsTimestampBitShift) | + (((UINT64)eventType & PIXEventsTypeWriteMask) << PIXEventsTypeBitShift); +} + +//Bits 60-63 (4) +static const UINT64 PIXEventsStringAlignmentWriteMask = 0x000000000000000F; +static const UINT64 PIXEventsStringAlignmentReadMask = 0xF000000000000000; +static const UINT64 PIXEventsStringAlignmentBitShift = 60; + +//Bits 55-59 (5) +static const UINT64 PIXEventsStringCopyChunkSizeWriteMask = 0x000000000000001F; +static const UINT64 PIXEventsStringCopyChunkSizeReadMask = 0x0F80000000000000; +static const UINT64 PIXEventsStringCopyChunkSizeBitShift = 55; + +//Bit 54 +static const UINT64 PIXEventsStringIsANSIWriteMask = 0x0000000000000001; +static const UINT64 PIXEventsStringIsANSIReadMask = 0x0040000000000000; +static const UINT64 PIXEventsStringIsANSIBitShift = 54; + +//Bit 53 +static const UINT64 PIXEventsStringIsShortcutWriteMask = 0x0000000000000001; +static const UINT64 PIXEventsStringIsShortcutReadMask = 0x0020000000000000; +static const UINT64 PIXEventsStringIsShortcutBitShift = 53; + +inline UINT64 PIXEncodeStringInfo(UINT64 alignment, UINT64 copyChunkSize, BOOL isANSI, BOOL isShortcut) +{ + return ((alignment & PIXEventsStringAlignmentWriteMask) << PIXEventsStringAlignmentBitShift) | + ((copyChunkSize & PIXEventsStringCopyChunkSizeWriteMask) << PIXEventsStringCopyChunkSizeBitShift) | + (((UINT64)isANSI & PIXEventsStringIsANSIWriteMask) << PIXEventsStringIsANSIBitShift) | + (((UINT64)isShortcut & PIXEventsStringIsShortcutWriteMask) << PIXEventsStringIsShortcutBitShift); +} + +template +inline bool PIXIsPointerAligned(T* pointer) +{ + return !(((UINT64)pointer) & (alignment - 1)); +} + +// Generic template version slower because of the additional clear write +template +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, T argument) +{ + if (destination < limit) + { + *destination = 0ull; + *((T*)destination) = argument; + ++destination; + } +} + +// int32 specialization to avoid slower double memory writes +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT32 argument) +{ + if (destination < limit) + { + *reinterpret_cast(destination) = static_cast(argument); + ++destination; + } +} + +// unsigned int32 specialization to avoid slower double memory writes +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT32 argument) +{ + if (destination < limit) + { + *destination = static_cast(argument); + ++destination; + } +} + +// int64 specialization to avoid slower double memory writes +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT64 argument) +{ + if (destination < limit) + { + *reinterpret_cast(destination) = argument; + ++destination; + } +} + +// unsigned int64 specialization to avoid slower double memory writes +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT64 argument) +{ + if (destination < limit) + { + *destination = argument; + ++destination; + } +} + +//floats must be cast to double during writing the data to be properly printed later when reading the data +//this is needed because when float is passed to varargs function it's cast to double +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, float argument) +{ + if (destination < limit) + { + *reinterpret_cast(destination) = static_cast(argument); + ++destination; + } +} + +//char has to be cast to a longer signed integer type +//this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, char argument) +{ + if (destination < limit) + { + *reinterpret_cast(destination) = static_cast(argument); + ++destination; + } +} + +//unsigned char has to be cast to a longer unsigned integer type +//this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, unsigned char argument) +{ + if (destination < limit) + { + *destination = static_cast(argument); + ++destination; + } +} + +//bool has to be cast to an integer since it's not explicitly supported by string format routines +//there's no format specifier for bool type, but it should work with integer format specifiers +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, bool argument) +{ + if (destination < limit) + { + *destination = static_cast(argument); + ++destination; + } +} + +inline void PIXCopyEventArgumentSlowest(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + *destination++ = PIXEncodeStringInfo(0, 8, TRUE, FALSE); + while (destination < limit) + { + UINT64 c = static_cast(argument[0]); + if (!c) + { + *destination++ = 0; + return; + } + UINT64 x = c; + c = static_cast(argument[1]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 8; + c = static_cast(argument[2]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 16; + c = static_cast(argument[3]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 24; + c = static_cast(argument[4]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 32; + c = static_cast(argument[5]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 40; + c = static_cast(argument[6]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 48; + c = static_cast(argument[7]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 56; + *destination++ = x; + argument += 8; + } +} + +inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ +#if PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<8>(argument)) + { + *destination++ = PIXEncodeStringInfo(0, 8, TRUE, FALSE); + UINT64* source = (UINT64*)argument; + while (destination < limit) + { + UINT64 qword = *source++; + *destination++ = qword; + //check if any of the characters is a terminating zero + if (!((qword & 0xFF00000000000000) && + (qword & 0xFF000000000000) && + (qword & 0xFF0000000000) && + (qword & 0xFF00000000) && + (qword & 0xFF000000) && + (qword & 0xFF0000) && + (qword & 0xFF00) && + (qword & 0xFF))) + { + break; + } + } + } + else +#endif // PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlowest(destination, limit, argument); + } +} + +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + if (destination < limit) + { + if (argument != nullptr) + { +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<16>(argument)) + { + *destination++ = PIXEncodeStringInfo(0, 16, TRUE, FALSE); + __m128i zero = _mm_setzero_si128(); + if (PIXIsPointerAligned<16>(destination)) + { + while (destination < limit) + { + __m128i mem = _mm_load_si128((__m128i*)argument); + _mm_store_si128((__m128i*)destination, mem); + //check if any of the characters is a terminating zero + __m128i res = _mm_cmpeq_epi8(mem, zero); + destination += 2; + if (_mm_movemask_epi8(res)) + break; + argument += 16; + } + } + else + { + while (destination < limit) + { + __m128i mem = _mm_load_si128((__m128i*)argument); + _mm_storeu_si128((__m128i*)destination, mem); + //check if any of the characters is a terminating zero + __m128i res = _mm_cmpeq_epi8(mem, zero); + destination += 2; + if (_mm_movemask_epi8(res)) + break; + argument += 16; + } + } + } + else +#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlow(destination, limit, argument); + } + } + else + { + *destination++ = 0ull; + } + } +} + +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PSTR argument) +{ + PIXCopyEventArgument(destination, limit, (PCSTR)argument); +} + +inline void PIXCopyEventArgumentSlowest(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + *destination++ = PIXEncodeStringInfo(0, 8, FALSE, FALSE); + while (destination < limit) + { + UINT64 c = static_cast(argument[0]); + if (!c) + { + *destination++ = 0; + return; + } + UINT64 x = c; + c = static_cast(argument[1]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 16; + c = static_cast(argument[2]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 32; + c = static_cast(argument[3]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 48; + *destination++ = x; + argument += 4; + } +} + +inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ +#if PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<8>(argument)) + { + *destination++ = PIXEncodeStringInfo(0, 8, FALSE, FALSE); + UINT64* source = (UINT64*)argument; + while (destination < limit) + { + UINT64 qword = *source++; + *destination++ = qword; + //check if any of the characters is a terminating zero + //TODO: check if reversed condition is faster + if (!((qword & 0xFFFF000000000000) && + (qword & 0xFFFF00000000) && + (qword & 0xFFFF0000) && + (qword & 0xFFFF))) + { + break; + } + } + } + else +#endif // PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlowest(destination, limit, argument); + } +} + +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + if (destination < limit) + { + if (argument != nullptr) + { +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<16>(argument)) + { + *destination++ = PIXEncodeStringInfo(0, 16, FALSE, FALSE); + __m128i zero = _mm_setzero_si128(); + if (PIXIsPointerAligned<16>(destination)) + { + while (destination < limit) + { + __m128i mem = _mm_load_si128((__m128i*)argument); + _mm_store_si128((__m128i*)destination, mem); + //check if any of the characters is a terminating zero + __m128i res = _mm_cmpeq_epi16(mem, zero); + destination += 2; + if (_mm_movemask_epi8(res)) + break; + argument += 8; + } + } + else + { + while (destination < limit) + { + __m128i mem = _mm_load_si128((__m128i*)argument); + _mm_storeu_si128((__m128i*)destination, mem); + //check if any of the characters is a terminating zero + __m128i res = _mm_cmpeq_epi16(mem, zero); + destination += 2; + if (_mm_movemask_epi8(res)) + break; + argument += 8; + } + } + } + else +#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlow(destination, limit, argument); + } + } + else + { + *destination++ = 0ull; + } + } +} + +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PWSTR argument) +{ + PIXCopyEventArgument(destination, limit, (PCWSTR)argument); +}; + +#if defined(__d3d12_x_h__) || defined(__d3d12_xs_h__) || defined(__d3d12_h__) + +inline void PIXSetGPUMarkerOnContext(_In_ ID3D12GraphicsCommandList* commandList, _In_reads_bytes_(size) void* data, UINT size) +{ + commandList->SetMarker(D3D12_EVENT_METADATA, data, size); +} + +inline void PIXSetGPUMarkerOnContext(_In_ ID3D12CommandQueue* commandQueue, _In_reads_bytes_(size) void* data, UINT size) +{ + commandQueue->SetMarker(D3D12_EVENT_METADATA, data, size); +} + +inline void PIXBeginGPUEventOnContext(_In_ ID3D12GraphicsCommandList* commandList, _In_reads_bytes_(size) void* data, UINT size) +{ + commandList->BeginEvent(D3D12_EVENT_METADATA, data, size); +} + +inline void PIXBeginGPUEventOnContext(_In_ ID3D12CommandQueue* commandQueue, _In_reads_bytes_(size) void* data, UINT size) +{ + commandQueue->BeginEvent(D3D12_EVENT_METADATA, data, size); +} + +inline void PIXEndGPUEventOnContext(_In_ ID3D12GraphicsCommandList* commandList) +{ + commandList->EndEvent(); +} + +inline void PIXEndGPUEventOnContext(_In_ ID3D12CommandQueue* commandQueue) +{ + commandQueue->EndEvent(); +} + +#endif //__d3d12_h__ + +template struct PIXInferScopedEventType { typedef T Type; }; +template struct PIXInferScopedEventType { typedef T Type; }; +template struct PIXInferScopedEventType { typedef T Type; }; +template struct PIXInferScopedEventType { typedef T Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; + + +#if PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET +#undef PIX_ENABLE_BLOCK_ARGUMENT_COPY +#endif + +#undef PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET + +#endif //_PIXEventsCommon_H_ diff --git a/3rdparty/winpixeventruntime/include/WinPixEventRuntime/pix3.h b/3rdparty/winpixeventruntime/include/WinPixEventRuntime/pix3.h new file mode 100644 index 0000000000..9007765e4a --- /dev/null +++ b/3rdparty/winpixeventruntime/include/WinPixEventRuntime/pix3.h @@ -0,0 +1,175 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +/*==========================================================================; + * + * Copyright (C) Microsoft Corporation. All Rights Reserved. + * + * File: pix3.h + * Content: PIX include file + * + ****************************************************************************/ +#pragma once + +#ifndef _PIX3_H_ +#define _PIX3_H_ + +#include + +#ifndef __cplusplus +#error "Only C++ files can include pix3.h. C is not supported." +#endif + +#if !defined(USE_PIX_SUPPORTED_ARCHITECTURE) +#if defined(_M_X64) || defined(USE_PIX_ON_ALL_ARCHITECTURES) || defined(_M_ARM64) +#define USE_PIX_SUPPORTED_ARCHITECTURE +#endif +#endif + +#if !defined(USE_PIX) +#if defined(USE_PIX_SUPPORTED_ARCHITECTURE) && (defined(_DEBUG) || DBG || defined(PROFILE) || defined(PROFILE_BUILD)) && !defined(_PREFAST_) +#define USE_PIX +#endif +#endif + +#if defined(USE_PIX) && !defined(USE_PIX_SUPPORTED_ARCHITECTURE) +#pragma message("Warning: Pix markers are only supported on AMD64 and ARM64") +#endif + + +// These flags are used by both PIXBeginCapture and PIXGetCaptureState +#define PIX_CAPTURE_TIMING (1 << 0) +#define PIX_CAPTURE_GPU (1 << 1) +#define PIX_CAPTURE_FUNCTION_SUMMARY (1 << 2) +#define PIX_CAPTURE_FUNCTION_DETAILS (1 << 3) +#define PIX_CAPTURE_CALLGRAPH (1 << 4) +#define PIX_CAPTURE_INSTRUCTION_TRACE (1 << 5) +#define PIX_CAPTURE_SYSTEM_MONITOR_COUNTERS (1 << 6) +#define PIX_CAPTURE_VIDEO (1 << 7) +#define PIX_CAPTURE_AUDIO (1 << 8) +#define PIX_CAPTURE_RESERVED (1 << 15) + +union PIXCaptureParameters +{ + enum PIXCaptureStorage + { + Memory = 0, + }; + + struct GpuCaptureParameters + { + PCWSTR FileName; + } GpuCaptureParameters; + + struct TimingCaptureParameters + { + PCWSTR FileName; + UINT32 MaximumToolingMemorySizeMb; + PIXCaptureStorage CaptureStorage; + + BOOL CaptureGpuTiming; + + BOOL CaptureCallstacks; + BOOL CaptureCpuSamples; + UINT32 CpuSamplesPerSecond; + + BOOL CaptureFileIO; + + BOOL CaptureVirtualAllocEvents; + BOOL CaptureHeapAllocEvents; + BOOL CaptureXMemEvents; // Xbox only + BOOL CapturePixMemEvents; // Xbox only + } TimingCaptureParameters; +}; + +typedef PIXCaptureParameters* PPIXCaptureParameters; + +#if defined(XBOX) || defined(_XBOX_ONE) || defined(_DURANGO) || defined(_GAMING_XBOX) || defined(_GAMING_XBOX_SCARLETT) +#include "pix3_xbox.h" +#else +#include "pix3_win.h" +#endif + +#if defined(USE_PIX_SUPPORTED_ARCHITECTURE) && (defined(USE_PIX) || defined(USE_PIX_RETAIL)) + +#define PIX_EVENTS_ARE_TURNED_ON + +#include "PIXEventsCommon.h" +#include "PIXEvents.h" + +#ifdef USE_PIX +// Starts a programmatically controlled capture. +// captureFlags uses the PIX_CAPTURE_* family of flags to specify the type of capture to take +extern "C" HRESULT WINAPI PIXBeginCapture2(DWORD captureFlags, _In_opt_ const PPIXCaptureParameters captureParameters); +inline HRESULT PIXBeginCapture(DWORD captureFlags, _In_opt_ const PPIXCaptureParameters captureParameters) { return PIXBeginCapture2(captureFlags, captureParameters); } + +// Stops a programmatically controlled capture +// If discard == TRUE, the captured data is discarded +// If discard == FALSE, the captured data is saved +// discard parameter is not supported on Windows +extern "C" HRESULT WINAPI PIXEndCapture(BOOL discard); + +extern "C" DWORD WINAPI PIXGetCaptureState(); + +extern "C" void WINAPI PIXReportCounter(_In_ PCWSTR name, float value); + +#endif // USE_PIX + +#endif // (USE_PIX_SUPPORTED_ARCHITECTURE) && (USE_PIX || USE_PIX_RETAIL) + +#if !defined(USE_PIX_SUPPORTED_ARCHITECTURE) || !defined(USE_PIX) + +// Eliminate these APIs when not using PIX +inline HRESULT PIXBeginCapture2(DWORD, _In_opt_ const PIXCaptureParameters*) { return S_OK; } +inline HRESULT PIXBeginCapture(DWORD, _In_opt_ const PIXCaptureParameters*) { return S_OK; } +inline HRESULT PIXEndCapture(BOOL) { return S_OK; } +inline HRESULT PIXGpuCaptureNextFrames(PCWSTR, UINT32) { return S_OK; } +inline HRESULT PIXSetTargetWindow(HWND) { return S_OK; } +inline HRESULT PIXForceD3D11On12() { return S_OK; } +inline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions) { return S_OK; } +inline bool WINAPI PIXIsAttachedForGpuCapture() { return false; } +inline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR) { return 0; } +inline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary() { return nullptr; } +inline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary() { return nullptr; } +inline DWORD PIXGetCaptureState() { return 0; } +inline void PIXReportCounter(_In_ PCWSTR, float) {} +inline void PIXNotifyWakeFromFenceSignal(_In_ HANDLE) {} + +#if !defined(USE_PIX_RETAIL) + +inline void PIXBeginEvent(UINT64, _In_ PCSTR, ...) {} +inline void PIXBeginEvent(UINT64, _In_ PCWSTR, ...) {} +inline void PIXBeginEvent(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXBeginEvent(void*, UINT64, _In_ PCWSTR, ...) {} +inline void PIXEndEvent() {} +inline void PIXEndEvent(void*) {} +inline void PIXSetMarker(UINT64, _In_ PCSTR, ...) {} +inline void PIXSetMarker(UINT64, _In_ PCWSTR, ...) {} +inline void PIXSetMarker(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXSetMarker(void*, UINT64, _In_ PCWSTR, ...) {} +inline void PIXBeginRetailEvent(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXBeginRetailEvent(void*, UINT64, _In_ PCWSTR, ...) {} +inline void PIXEndRetailEvent(void*) {} +inline void PIXSetRetailMarker(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXSetRetailMarker(void*, UINT64, _In_ PCWSTR, ...) {} +inline void PIXScopedEvent(UINT64, _In_ PCSTR, ...) {} +inline void PIXScopedEvent(UINT64, _In_ PCWSTR, ...) {} +inline void PIXScopedEvent(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXScopedEvent(void*, UINT64, _In_ PCWSTR, ...) {} + +#endif // !USE_PIX_RETAIL + +// don't show warnings about expressions with no effect +#pragma warning(disable:4548) +#pragma warning(disable:4555) + +#endif // !USE_PIX_SUPPORTED_ARCHITECTURE || !USE_PIX + +// Use these functions to specify colors to pass as metadata to a PIX event/marker API. +// Use PIX_COLOR() to specify a particular color for an event. +// Or, use PIX_COLOR_INDEX() to specify a set of unique event categories, and let PIX choose +// the colors to represent each category. +inline UINT PIX_COLOR(BYTE r, BYTE g, BYTE b) { return 0xff000000 | (r << 16) | (g << 8) | b; } +inline UINT PIX_COLOR_INDEX(BYTE i) { return i; } +const UINT PIX_COLOR_DEFAULT = PIX_COLOR_INDEX(0); + +#endif // _PIX3_H_ diff --git a/3rdparty/winpixeventruntime/include/WinPixEventRuntime/pix3_win.h b/3rdparty/winpixeventruntime/include/WinPixEventRuntime/pix3_win.h new file mode 100644 index 0000000000..2c7d0a537b --- /dev/null +++ b/3rdparty/winpixeventruntime/include/WinPixEventRuntime/pix3_win.h @@ -0,0 +1,439 @@ +// 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_ diff --git a/3rdparty/winpixeventruntime/lib/WinPixEventRuntime.lib b/3rdparty/winpixeventruntime/lib/WinPixEventRuntime.lib new file mode 100644 index 0000000000000000000000000000000000000000..d5628599e9171ed3608f56d89afdb6c49c843d75 GIT binary patch literal 6230 zcmcIo%}*Og6n{1$1Ve%F*+U~ygcSM_u+2w^gjxeOsf7W@7(v=9X0aF8VtdiDv zxovq@;umF3Cj5lLcE)A`hZMm(DSkW8W%;SRnBCIJZRRMG^rpmfxp;A1)QM53VHoL< zrzpwOB5sP8bUO1e(#?yquzq8i+u~;=u`t6Iv;3m4QRMRa8fOwkPF9q1b9_ORZcOHJ z2b?U3MFqRgA;mirmGGF6c)rYPefo7=7%S!!+J)k@SSWDCTte89Bay3IP3&?i1ni$fOI#&eJt0o9c>3V#s#-J0G?v|_E~@lq{ZtWnxPe%paq_T zHmHYFa2n1)BLtuUeBduLTL%v3S*`DDr|Q7R#c>c07MrXV2U@o6`pWXvl^!{zl}%*? znhuEqNboerFdQw7f^^6nqyBebL1xB~q6Yo@`I-gpsuMC&U zSWNe_)r6{b0?m+gFji)j(Uh=3GqABrDuNoKV}@q1P>tT%PBjvvIaZYh={9TNVYJ+8 zvdy8Ai@Z`69v)_S`D(zL%ns)Ac?b-#lwBpQ#B+3bT%}wM~db<{cnZBv6nj+43mFq^_K0hsCort->HhrbaB?yGcT>M%TyjR4AH zbYwgNz59Nw&tXI%U$^~c&qGIB15V#ni10ZAFTex2eNMP^JwXVrOA z)r>uYi4?&2MOq{_)+;T0frue8yhW9&gmtjZ4uD?j}8t%8`~ z2C%cL9G%jB4OTVG28mVOVI8$5R&~Dn)cgJ!?{^qsE{enSb=3hXsl z#xF;i(uiLZzchXkh%mn#VdI4ESJqK$LU)pyu13oPh~*?KHWV7w?m+D zpgbSuvkuv&>pO?W1KxdP+rF zOCIDMPW{ee7VzESM?YRcob^sPE9(<8Ezb~!Ml72A