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 0000000000..0e2f75c51c Binary files /dev/null and b/3rdparty/winpixeventruntime/bin/WinPixEventRuntime.dll differ diff --git a/3rdparty/winpixeventruntime/include/WinPixEventRuntime/PIXEvents.h b/3rdparty/winpixeventruntime/include/WinPixEventRuntime/PIXEvents.h new file mode 100644 index 0000000000..ec5f2ed573 --- /dev/null +++ b/3rdparty/winpixeventruntime/include/WinPixEventRuntime/PIXEvents.h @@ -0,0 +1,661 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. + +/*==========================================================================; + * + * Copyright (C) Microsoft Corporation. All Rights Reserved. + * + * File: PIXEvents.h + * Content: PIX include file + * Don't include this file directly - use pix3.h + * + ****************************************************************************/ +#pragma once + +#ifndef _PixEvents_H_ +#define _PixEvents_H_ + +#ifndef _PIX3_H_ +# error Do not include this file directly - use pix3.h +#endif + +#include "PIXEventsCommon.h" + +#if _MSC_VER < 1800 +# error This version of pix3.h is only supported on Visual Studio 2013 or higher +#elif _MSC_VER < 1900 +# ifndef constexpr // Visual Studio 2013 doesn't support constexpr +# define constexpr +# define PIX3__DEFINED_CONSTEXPR +# endif +#endif + +// Xbox does not support CPU events for retail scenarios +#if defined(USE_PIX) || !defined(PIX_XBOX) +#define PIX_CONTEXT_EMIT_CPU_EVENTS +#endif + +namespace PIXEventsDetail +{ + template + 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 0000000000..d5628599e9 Binary files /dev/null and b/3rdparty/winpixeventruntime/lib/WinPixEventRuntime.lib differ