From 6a989b9a690e9d15fad9a373a8a59985522b80e4 Mon Sep 17 00:00:00 2001 From: Robert Konrad Date: Sun, 29 Sep 2024 23:35:20 +0200 Subject: [PATCH] Use PIX to implement debug markers --- .../Sources/kope/direct3d12/commandlist.cpp | 20 +- .../Sources/kope/direct3d12/d3d12unit.h | 6 + .../Include/WinPixEventRuntime/PIXEvents.h | 1578 +++++++++++++++++ .../WinPixEventRuntime/PIXEventsCommon.h | 610 +++++++ .../WinPixEventRuntime/PIXEventsLegacy.h | 565 ++++++ .../pix/Include/WinPixEventRuntime/pix3.h | 195 ++ .../pix/Include/WinPixEventRuntime/pix3_win.h | 509 ++++++ .../Direct3D12/pix/ThirdPartyNotices.txt | 579 ++++++ .../pix/bin/x64/WinPixEventRuntime.dll | Bin 0 -> 58368 bytes .../pix/bin/x64/WinPixEventRuntime.lib | Bin 0 -> 6230 bytes Backends/Graphics5/Direct3D12/pix/license.txt | 21 + kfile.js | 6 + 12 files changed, 4086 insertions(+), 3 deletions(-) create mode 100644 Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEvents.h create mode 100644 Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEventsCommon.h create mode 100644 Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEventsLegacy.h create mode 100644 Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/pix3.h create mode 100644 Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/pix3_win.h create mode 100644 Backends/Graphics5/Direct3D12/pix/ThirdPartyNotices.txt create mode 100644 Backends/Graphics5/Direct3D12/pix/bin/x64/WinPixEventRuntime.dll create mode 100644 Backends/Graphics5/Direct3D12/pix/bin/x64/WinPixEventRuntime.lib create mode 100644 Backends/Graphics5/Direct3D12/pix/license.txt diff --git a/Backends/Graphics5/Direct3D12/Sources/kope/direct3d12/commandlist.cpp b/Backends/Graphics5/Direct3D12/Sources/kope/direct3d12/commandlist.cpp index 234c347c5..b86cf0665 100644 --- a/Backends/Graphics5/Direct3D12/Sources/kope/direct3d12/commandlist.cpp +++ b/Backends/Graphics5/Direct3D12/Sources/kope/direct3d12/commandlist.cpp @@ -13,6 +13,10 @@ #include +#ifdef KOPE_PIX +#include +#endif + void kope_d3d12_command_list_begin_render_pass(kope_g5_command_list *list, const kope_g5_render_pass_parameters *parameters) { list->d3d12.compute_pipeline_set = false; @@ -641,10 +645,20 @@ void kope_d3d12_command_list_set_name(kope_g5_command_list *list, const char *na list->d3d12.list->SetName(wstr); } -void kope_d3d12_command_list_push_debug_group(kope_g5_command_list *list, const char *name) {} +void kope_d3d12_command_list_push_debug_group(kope_g5_command_list *list, const char *name) { +#ifdef KOPE_PIX + PIXBeginEvent(list->d3d12.list, 0, "%s", name); +#endif +} -void kope_d3d12_command_list_pop_debug_group(kope_g5_command_list *list) {} +void kope_d3d12_command_list_pop_debug_group(kope_g5_command_list *list) { +#ifdef KOPE_PIX + PIXEndEvent(list->d3d12.list); +#endif +} void kope_d3d12_command_list_insert_debug_marker(kope_g5_command_list *list, const char *name) { - // PIXSetMarker(); +#ifdef KOPE_PIX + PIXSetMarker(list->d3d12.list, 0, "%s", name); +#endif } diff --git a/Backends/Graphics5/Direct3D12/Sources/kope/direct3d12/d3d12unit.h b/Backends/Graphics5/Direct3D12/Sources/kope/direct3d12/d3d12unit.h index de13c8893..ed1c6af87 100644 --- a/Backends/Graphics5/Direct3D12/Sources/kope/direct3d12/d3d12unit.h +++ b/Backends/Graphics5/Direct3D12/Sources/kope/direct3d12/d3d12unit.h @@ -12,7 +12,9 @@ #define NOCLIPBOARD #define NOCOLOR #define NOCOMM +#ifndef KOPE_PIX #define NOCTLMGR +#endif #define NODEFERWINDOWPOS #define NODRAWTEXT #define NOGDI @@ -34,7 +36,9 @@ #define NORASTEROPS #define NOSCROLL #define NOSERVICE +#ifndef KOPE_PIX #define NOSHOWWINDOW +#endif #define NOSOUND #define NOSYSCOMMANDS #define NOSYSMETRICS @@ -42,7 +46,9 @@ // #define NOUSER #define NOVIRTUALKEYCODES #define NOWH +#ifndef KOPE_PIX #define NOWINMESSAGES +#endif #define NOWINOFFSETS #define NOWINSTYLES #define WIN32_LEAN_AND_MEAN diff --git a/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEvents.h b/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEvents.h new file mode 100644 index 000000000..52dd8bcbd --- /dev/null +++ b/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEvents.h @@ -0,0 +1,1578 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// 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 +{ + 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 + void PIXCopyStringArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, ARG const& arg, ARGS const&... args) + { + PIXCopyStringArgument(destination, limit, arg); + PIXCopyEventArguments(destination, limit, args...); + } + + template + void PIXCopyStringArgumentsWithContext(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, void* context, ARG const& arg, ARGS const&... args) + { +#ifdef PIX_XBOX + UNREFERENCED_PARAMETER(context); + PIXCopyStringArgument(destination, limit, arg); + PIXCopyEventArguments(destination, limit, args...); +#else + PIXCopyEventArgument(destination, limit, context); + PIXCopyStringArgument(destination, limit, arg); + PIXCopyEventArguments(destination, limit, args...); +#endif + } + + inline UINT8 PIXGetEventSize(const UINT64* end, const UINT64* start) + { + const UINT64 actualEventSize = end - start; + + return static_cast(actualEventSize > PIXEventsSizeMax ? PIXEventsSizeMax : actualEventSize); + } + + template + inline UINT8 PIXEncodeStringIsAnsi() + { + return PIX_EVENT_METADATA_NONE; + } + + template<> + inline UINT8 PIXEncodeStringIsAnsi() + { + return PIX_EVENT_METADATA_STRING_IS_ANSI; + } + + template<> + inline UINT8 PIXEncodeStringIsAnsi() + { + return PIX_EVENT_METADATA_STRING_IS_ANSI; + } + + template + __declspec(noinline) void PIXBeginEventAllocate(PIXEventsThreadInfo* threadInfo, UINT64 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_HAS_COLOR | + PIXEncodeStringIsAnsi(); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + 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(); + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_HAS_COLOR | + PIXEncodeStringIsAnsi(); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXBeginEventAllocate(threadInfo, color, formatString, args...); + } + } + } + + template + __declspec(noinline) void PIXBeginEventAllocate(PIXEventsThreadInfo* threadInfo, UINT8 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64* eventDestination = destination++; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXBeginEvent(UINT8 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(); + UINT64* eventDestination = destination++; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXBeginEventAllocate(threadInfo, color, formatString, args...); + } + } + } + + template + __declspec(noinline) void PIXSetMarkerAllocate(PIXEventsThreadInfo* threadInfo, UINT64 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + 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(); + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXSetMarkerAllocate(threadInfo, color, formatString, args...); + } + } + } + + template + __declspec(noinline) void PIXSetMarkerAllocate(PIXEventsThreadInfo* threadInfo, UINT8 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64* eventDestination = destination++; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXSetMarker(UINT8 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(); + UINT64* eventDestination = destination++; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXSetMarkerAllocate(threadInfo, color, formatString, args...); + } + } + } + + template + __declspec(noinline) void PIXBeginEventOnContextCpuAllocate(UINT64*& eventDestination, UINT8& eventSize, PIXEventsThreadInfo* threadInfo, void* context, UINT64 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + { + eventDestination = nullptr; + return; + } + + limit += PIXEventsSafeFastCopySpaceQwords; + eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXBeginEventOnContextCpu(UINT64*& eventDestination, UINT8& eventSize, void* context, UINT64 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit == nullptr) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXBeginEventOnContextCpuAllocate(eventDestination, eventSize, threadInfo, context, color, formatString, args...); + } + } + + template + void PIXBeginEvent(CONTEXT* context, UINT64 color, STR formatString, ARGS... args) + { + UINT64* destination = nullptr; + UINT8 eventSize = 0u; + +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXBeginEventOnContextCpu(destination, eventSize, context, color, formatString, args...); +#endif + +#ifdef PIX_USE_GPU_MARKERS_V2 + if (destination != nullptr) + { + PIXInsertTimingMarkerOnContextForBeginEvent(context, PIXEvent_BeginEvent, static_cast(destination), eventSize * sizeof(UINT64)); + } + else +#endif + { + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + +#ifdef PIX_USE_GPU_MARKERS_V2 + destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = 0ull; + + eventSize = static_cast(destination - buffer); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(0, PIXEvent_BeginEvent, eventSize, eventMetadata); + PIXInsertGPUMarkerOnContextForBeginEvent(context, PIXEvent_BeginEvent, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#else + destination = PixEventsLegacy::EncodeBeginEventForContext(buffer, color, formatString, args...); + PIXBeginGPUEventOnContext(context, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#endif + } + } + + template + __declspec(noinline) void PIXBeginEventOnContextCpuAllocate(UINT64*& eventDestination, UINT8& eventSize, PIXEventsThreadInfo* threadInfo, void* context, UINT8 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + { + eventDestination = nullptr; + return; + } + + limit += PIXEventsSafeFastCopySpaceQwords; + eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXBeginEventOnContextCpu(UINT64*& eventDestination, UINT8& eventSize, void* context, UINT8 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit == nullptr) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXBeginEventOnContextCpuAllocate(eventDestination, eventSize, threadInfo, context, color, formatString, args...); + } + } + + template + void PIXBeginEvent(CONTEXT* context, UINT8 color, STR formatString, ARGS... args) + { + UINT64* destination = nullptr; + UINT8 eventSize = 0u; + +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXBeginEventOnContextCpu(destination, eventSize, context, color, formatString, args...); +#endif + +#ifdef PIX_USE_GPU_MARKERS_V2 + if (destination != nullptr) + { + PIXInsertTimingMarkerOnContextForBeginEvent(context, PIXEvent_BeginEvent, static_cast(destination), eventSize * sizeof(UINT64)); + } + else +#endif + { + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + +#ifdef PIX_USE_GPU_MARKERS_V2 + destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + UINT64* eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = 0ull; + + eventSize = static_cast(destination - buffer); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(0, PIXEvent_BeginEvent, eventSize, eventMetadata); + + PIXInsertGPUMarkerOnContextForBeginEvent(context, PIXEvent_BeginEvent, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#else + destination = PixEventsLegacy::EncodeBeginEventForContext(buffer, color, formatString, args...); + PIXBeginGPUEventOnContext(context, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#endif + } + } + + template + __declspec(noinline) void PIXSetMarkerOnContextCpuAllocate(UINT64*& eventDestination, UINT8& eventSize, PIXEventsThreadInfo* threadInfo, void* context, UINT64 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + { + eventDestination = nullptr; + return; + } + + limit += PIXEventsSafeFastCopySpaceQwords; + eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXSetMarkerOnContextCpu(UINT64*& eventDestination, UINT8& eventSize, void* context, UINT64 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit == nullptr) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXSetMarkerOnContextCpuAllocate(eventDestination, eventSize, threadInfo, context, color, formatString, args...); + } + } + + template + void PIXSetMarker(CONTEXT* context, UINT64 color, STR formatString, ARGS... args) + { + UINT64* destination = nullptr; + UINT8 eventSize = 0u; + +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXSetMarkerOnContextCpu(destination, eventSize, context, color, formatString, args...); +#endif + +#ifdef PIX_USE_GPU_MARKERS_V2 + if (destination != nullptr) + { + PIXInsertTimingMarkerOnContextForSetMarker(context, PIXEvent_SetMarker, static_cast(destination), eventSize * sizeof(UINT64)); + } + else +#endif + { + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + +#ifdef PIX_USE_GPU_MARKERS_V2 + destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = 0ull; + + eventSize = static_cast(destination - buffer); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(0, PIXEvent_SetMarker, eventSize, eventMetadata); + PIXInsertGPUMarkerOnContextForSetMarker(context, PIXEvent_SetMarker, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#else + destination = PixEventsLegacy::EncodeSetMarkerForContext(buffer, color, formatString, args...); + PIXSetGPUMarkerOnContext(context, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#endif + } + } + + template + __declspec(noinline) void PIXSetMarkerOnContextCpuAllocate(UINT64*& eventDestination, UINT8& eventSize, PIXEventsThreadInfo* threadInfo, void* context, UINT8 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + { + eventDestination = nullptr; + return; + } + + limit += PIXEventsSafeFastCopySpaceQwords; + eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXSetMarkerOnContextCpu(UINT64*& eventDestination, UINT8& eventSize, void* context, UINT8 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit == nullptr) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXSetMarkerOnContextCpuAllocate(eventDestination, eventSize, threadInfo, context, color, formatString, args...); + } + } + + template + void PIXSetMarker(CONTEXT* context, UINT8 color, STR formatString, ARGS... args) + { + UINT64* destination = nullptr; + UINT8 eventSize = 0u; + +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXSetMarkerOnContextCpu(destination, eventSize, context, color, formatString, args...); +#endif + +#ifdef PIX_USE_GPU_MARKERS_V2 + if (destination != nullptr) + { + PIXInsertTimingMarkerOnContextForSetMarker(context, PIXEvent_SetMarker, static_cast(destination), eventSize * sizeof(UINT64)); + } + else +#endif + { + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + +#ifdef PIX_USE_GPU_MARKERS_V2 + destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + UINT64* eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = 0ull; + + eventSize = static_cast(destination - buffer); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(0, PIXEvent_SetMarker, eventSize, eventMetadata); + PIXInsertGPUMarkerOnContextForSetMarker(context, PIXEvent_SetMarker, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#else + destination = PixEventsLegacy::EncodeSetMarkerForContext(buffer, color, formatString, args...); + PIXSetGPUMarkerOnContext(context, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#endif + } + } + + __declspec(noinline) inline void PIXEndEventAllocate(PIXEventsThreadInfo* threadInfo) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, true); + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + const UINT8 eventSize = 1; + const UINT8 eventMetadata = PIX_EVENT_METADATA_NONE; + *destination++ = PIXEncodeEventInfo(time, PIXEvent_EndEvent, eventSize, eventMetadata); + *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(); + const UINT8 eventSize = 1; + const UINT8 eventMetadata = PIX_EVENT_METADATA_NONE; + *destination++ = PIXEncodeEventInfo(time, PIXEvent_EndEvent, eventSize, eventMetadata); + *destination = PIXEventsBlockEndMarker; + + threadInfo->destination = destination; + } + else + { + PIXEndEventAllocate(threadInfo); + } + } + } + + __declspec(noinline) inline UINT64* PIXEndEventOnContextCpuAllocate(PIXEventsThreadInfo* threadInfo, void* context) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, true); + if (!time) + return nullptr; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return nullptr; + + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64* eventDestination = destination++; +#ifdef PIX_XBOX + UNREFERENCED_PARAMETER(context); +#else + PIXCopyEventArgument(destination, limit, context); +#endif + * destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = PIX_EVENT_METADATA_ON_CONTEXT; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_EndEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + + return eventDestination; + } + + inline UINT64* 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(); + UINT64* eventDestination = destination++; +#ifndef PIX_XBOX + PIXCopyEventArgument(destination, limit, context); +#endif + * destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = PIX_EVENT_METADATA_ON_CONTEXT; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_EndEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + + return eventDestination; + } + else + { + return PIXEndEventOnContextCpuAllocate(threadInfo, context); + } + } + + return nullptr; + } + + template + void PIXEndEvent(CONTEXT* context) + { + UINT64* destination = nullptr; +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + destination = PIXEndEventOnContextCpu(context); +#endif + +#ifdef PIX_USE_GPU_MARKERS_V2 + if (destination != nullptr) + { + PIXInsertTimingMarkerOnContextForEndEvent(context, PIXEvent_EndEvent); + } + else +#endif + { +#ifdef PIX_USE_GPU_MARKERS_V2 + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + destination = buffer; + + UINT64* eventDestination = destination++; + + const UINT8 eventSize = static_cast(destination - buffer); + const UINT8 eventMetadata = PIX_EVENT_METADATA_NONE; + *eventDestination = PIXEncodeEventInfo(0, PIXEvent_EndEvent, eventSize, eventMetadata); + PIXInsertGPUMarkerOnContextForEndEvent(context, PIXEvent_EndEvent, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#else + PIXEndGPUEventOnContext(context); +#endif + } + } +} + +#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 PIXBeginEvent(UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(color, formatString, args...); +} + +template +void PIXBeginEvent(UINT8 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 PIXSetMarker(UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(color, formatString, args...); +} + +template +void PIXSetMarker(UINT8 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 PIXBeginEvent(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT8 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT8 color, PCWSTR 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...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT8 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 PIXBeginRetailEvent(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT8 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 PIXSetRetailMarker(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT8 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...); + } + + template + PIXScopedEventObject(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, UINT8 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...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, UINT8 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...); + } + + template + PIXScopedEventObject(UINT32 color, PCWSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(UINT32 color, PCSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(INT32 color, PCWSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(INT32 color, PCSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(DWORD color, PCWSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(DWORD color, PCSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(UINT8 color, PCWSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(UINT8 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/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEventsCommon.h b/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEventsCommon.h new file mode 100644 index 000000000..69a9bb941 --- /dev/null +++ b/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEventsCommon.h @@ -0,0 +1,610 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// Don't include this file directly - use pix3.h + +#pragma once + +#ifndef _PIXEventsCommon_H_ +#define _PIXEventsCommon_H_ + +// +// 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; +}; + +extern "C" UINT64 WINAPI PIXEventsReplaceBlock(PIXEventsThreadInfo * threadInfo, bool getEarliestTime) noexcept; + +#define PIX_EVENT_METADATA_NONE 0x0 +#define PIX_EVENT_METADATA_ON_CONTEXT 0x1 +#define PIX_EVENT_METADATA_STRING_IS_ANSI 0x2 +#define PIX_EVENT_METADATA_HAS_COLOR 0xF0 + +#ifndef PIX_GAMING_XBOX +#include "PIXEventsLegacy.h" +#endif + +enum PIXEventType : UINT8 +{ + PIXEvent_EndEvent = 0x00, + PIXEvent_BeginEvent = 0x01, + PIXEvent_SetMarker = 0x02, +}; + +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-15 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; + + +// V2 events + +// Bits 00..06 (7 bits) - Size in QWORDS +static const UINT64 PIXEventsSizeWriteMask = 0x000000000000007F; +static const UINT64 PIXEventsSizeBitShift = 0; +static const UINT64 PIXEventsSizeReadMask = PIXEventsSizeWriteMask << PIXEventsSizeBitShift; +static const UINT64 PIXEventsSizeMax = (1ull << 7) - 1ull; + +// Bits 07..11 (5 bits) - Event Type +static const UINT64 PIXEventsTypeWriteMask = 0x000000000000001F; +static const UINT64 PIXEventsTypeBitShift = 7; +static const UINT64 PIXEventsTypeReadMask = PIXEventsTypeWriteMask << PIXEventsTypeBitShift; + +// Bits 12..19 (8 bits) - Event Specific Metadata +static const UINT64 PIXEventsMetadataWriteMask = 0x00000000000000FF; +static const UINT64 PIXEventsMetadataBitShift = 12; +static const UINT64 PIXEventsMetadataReadMask = PIXEventsMetadataWriteMask << PIXEventsMetadataBitShift; + +// Buts 20..63 (44 bits) - Timestamp +static const UINT64 PIXEventsTimestampWriteMask = 0x00000FFFFFFFFFFF; +static const UINT64 PIXEventsTimestampBitShift = 20; +static const UINT64 PIXEventsTimestampReadMask = PIXEventsTimestampWriteMask << PIXEventsTimestampBitShift; + +inline UINT64 PIXEncodeEventInfo(UINT64 timestamp, PIXEventType eventType, UINT8 eventSize, UINT8 eventMetadata) +{ + return + ((timestamp & PIXEventsTimestampWriteMask) << PIXEventsTimestampBitShift) | + (((UINT64)eventType & PIXEventsTypeWriteMask) << PIXEventsTypeBitShift) | + (((UINT64)eventMetadata & PIXEventsMetadataWriteMask) << PIXEventsMetadataBitShift) | + (((UINT64)eventSize & PIXEventsSizeWriteMask) << PIXEventsSizeBitShift); +} + +inline UINT8 PIXEncodeIndexColor(UINT8 color) +{ + // There are 8 index colors, indexed 0 (default) to 7 + return (color & 0x7) << 4; +} + +//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 void PIXEncodeStringInfo(UINT64*& destination, BOOL isANSI) +{ + const UINT64 encodedStringInfo = + ((sizeof(UINT64) & PIXEventsStringCopyChunkSizeWriteMask) << PIXEventsStringCopyChunkSizeBitShift) | + (((UINT64)isANSI & PIXEventsStringIsANSIWriteMask) << PIXEventsStringIsANSIBitShift); + + *destination++ = encodedStringInfo; +} + +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; + } +} + +//UINT8 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, UINT8 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 PIXCopyEventStringArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + 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; + } +} + +template +inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + PIXEncodeStringInfo(destination, TRUE); + PIXCopyEventStringArgumentSlow(destination, limit, argument); +} + +template<> +inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + PIXCopyEventStringArgumentSlow(destination, limit, argument); +} + +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + +inline void PIXCopyEventStringArgumentFast(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + constexpr UINT64 mask1 = 0x0101010101010101ULL; + constexpr UINT64 mask2 = 0x8080808080808080ULL; + UINT64* source = (UINT64*)argument; + + while (destination < limit) + { + UINT64 qword = *source++; + *destination++ = qword; + + //check if any of the characters is a terminating zero + UINT64 isTerminated = (qword - mask1) & (~qword & mask2); + + if (isTerminated) + { + break; + } + } +} +#endif + +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<8>(argument)) + { + PIXEncodeStringInfo(destination, TRUE); + PIXCopyEventStringArgumentFast(destination, limit, argument); + } + else +#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlow(destination, limit, argument); + } + } + else + { + *destination++ = 0ull; + } + } +} + +inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + if (argument != nullptr) + { +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<8>(argument)) + { + PIXCopyEventStringArgumentFast(destination, limit, argument); + } + 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 PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PSTR argument) +{ + PIXCopyStringArgument(destination, limit, (PCSTR)argument); +} + +inline void PIXCopyEventStringArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + 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; + } +} + +template +inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + PIXEncodeStringInfo(destination, FALSE); + PIXCopyEventStringArgumentSlow(destination, limit, argument); +} + +template<> +inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + PIXCopyEventStringArgumentSlow(destination, limit, argument); +} + +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY +inline void PIXCopyEventStringArgumentFast(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + 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; + } + } +} +#endif + +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<8>(argument)) + { + PIXEncodeStringInfo(destination, FALSE); + PIXCopyEventStringArgumentFast(destination, limit, argument); + } + else +#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlow(destination, limit, argument); + } + } + else + { + *destination++ = 0ull; + } + } +} + +inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + if (argument != nullptr) + { +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<8>(argument)) + { + PIXCopyEventStringArgumentFast(destination, limit, argument); + } + 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); +}; + +inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PWSTR argument) +{ + PIXCopyStringArgument(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; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; + +#endif //_PIXEventsCommon_H_ diff --git a/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEventsLegacy.h b/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEventsLegacy.h new file mode 100644 index 000000000..53230138b --- /dev/null +++ b/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/PIXEventsLegacy.h @@ -0,0 +1,565 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Don't include this file directly - use pix3.h +// This file encodes PIX events in the legacy PIX event format. + +#ifndef _PIXEventsLegacy_H_ +#define _PIXEventsLegacy_H_ + +#include + +#if defined(_M_X64) || defined(_M_IX86) +#include +#endif + +namespace PixEventsLegacy +{ + 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; + 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; + } + } + } + + 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 + 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; } + static constexpr PIXEventType End() { return PIXEvent_EndEvent; } + + // 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; } + static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent_OnContext; } +#else + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_VarArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_VarArgs; } + static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent; } +#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; } + static constexpr PIXEventType End() { return PIXEvent_EndEvent; } + +#ifdef PIX_XBOX + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_OnContext_NoArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_NoArgs; } + static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent_OnContext; } +#else + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_NoArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_NoArgs; } + static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent; } +#endif + }; + + + template + UINT64* EncodeBeginEventForContext(UINT64 (&buffer)[size], UINT64 color, STR formatString, ARGS... args) + { + UINT64* destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + *destination++ = PIXEncodeEventInfo(0, PIXEventTypeInferer::GpuBeginOnContext()); + *destination++ = color; + + PIXCopyEventArguments(destination, limit, formatString, args...); + *destination = 0ull; + + return destination; + } + + template + UINT64* EncodeSetMarkerForContext(UINT64 (&buffer)[size], UINT64 color, STR formatString, ARGS... args) + { + UINT64* destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + *destination++ = PIXEncodeEventInfo(0, PIXEventTypeInferer::GpuSetMarkerOnContext()); + *destination++ = color; + + PIXCopyEventArguments(destination, limit, formatString, args...); + *destination = 0ull; + + return destination; + } +} + +#endif //_PIXEventsLegacy_H_ diff --git a/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/pix3.h b/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/pix3.h new file mode 100644 index 000000000..13126c400 --- /dev/null +++ b/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/pix3.h @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#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_GPU_TRACE (1 << 9) +#define PIX_CAPTURE_RESERVED (1 << 15) + +union PIXCaptureParameters +{ + enum PIXCaptureStorage + { + Memory = 0, + MemoryCircular = 1, // Xbox only + FileCircular = 2, // PC only + }; + + 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; + BOOL CapturePageFaultEvents; + BOOL CaptureVideoFrames; // Xbox only + } TimingCaptureParameters; + + struct GpuTraceParameters // Xbox Series and newer only + { + PWSTR FileName; + UINT32 MaximumToolingMemorySizeMb; + + BOOL CaptureGpuOccupancy; + + } GpuTraceParameters; +}; + +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(XBOX) || defined(_XBOX_ONE) || defined(_DURANGO) || defined(_GAMING_XBOX) || defined(_GAMING_XBOX_SCARLETT) +#define PIX_XBOX +#if defined(_GAMING_XBOX) || defined(_GAMING_XBOX_SCARLETT) +#define PIX_GAMING_XBOX +#endif +#endif + +#if !defined(PIX_USE_GPU_MARKERS_V2) +#ifdef PIX_GAMING_XBOX +#define PIX_USE_GPU_MARKERS_V2 +#endif +#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 UINT32 PIX_COLOR(UINT8 r, UINT8 g, UINT8 b) { return 0xff000000u | ((UINT32)r << 16) | ((UINT32)g << 8) | (UINT32)b; } +inline UINT8 PIX_COLOR_INDEX(UINT8 i) { return i; } +const UINT8 PIX_COLOR_DEFAULT = PIX_COLOR_INDEX(0); + +#endif // _PIX3_H_ diff --git a/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/pix3_win.h b/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/pix3_win.h new file mode 100644 index 000000000..121c40cb1 --- /dev/null +++ b/Backends/Graphics5/Direct3D12/pix/Include/WinPixEventRuntime/pix3_win.h @@ -0,0 +1,509 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// 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 WINPIX_EVENT_* 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 used by pix.h in the Windows SDK. +#define WINPIX_EVENT_UNICODE_VERSION 0 +#define WINPIX_EVENT_ANSI_VERSION 1 + +// These values denote PIX marker event data that was created by the WinPixEventRuntime. +// In early 2023 we revised the PIX marker format and defined a new version number. +#define WINPIX_EVENT_PIX3BLOB_VERSION 2 +#define WINPIX_EVENT_PIX3BLOB_V2 6345127 // A number that other applications are unlikely to have used before + +// For backcompat reasons, the WinPixEventRuntime uses the older PIX3BLOB format when it passes data +// into the D3D12 runtime. It will be updated to use the V2 format in the future. +#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) +{ + // 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 + +#if defined(__d3d12_h__) + +inline void PIXInsertTimingMarkerOnContextForBeginEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandList->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertTimingMarkerOnContextForBeginEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandQueue->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertTimingMarkerOnContextForSetMarker(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandList->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertTimingMarkerOnContextForSetMarker(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandQueue->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertTimingMarkerOnContextForEndEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType) +{ + UNREFERENCED_PARAMETER(eventType); + commandList->EndEvent(); +} + +inline void PIXInsertTimingMarkerOnContextForEndEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType) +{ + UNREFERENCED_PARAMETER(eventType); + commandQueue->EndEvent(); +} + +inline void PIXInsertGPUMarkerOnContextForBeginEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandList->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertGPUMarkerOnContextForBeginEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandQueue->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertGPUMarkerOnContextForSetMarker(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandList->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertGPUMarkerOnContextForSetMarker(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandQueue->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertGPUMarkerOnContextForEndEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8, void*, UINT) +{ + commandList->EndEvent(); +} + +inline void PIXInsertGPUMarkerOnContextForEndEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8, void*, UINT) +{ + commandQueue->EndEvent(); +} + +#endif + +#endif //_PIX3_WIN_H_ diff --git a/Backends/Graphics5/Direct3D12/pix/ThirdPartyNotices.txt b/Backends/Graphics5/Direct3D12/pix/ThirdPartyNotices.txt new file mode 100644 index 000000000..90ad07dc9 --- /dev/null +++ b/Backends/Graphics5/Direct3D12/pix/ThirdPartyNotices.txt @@ -0,0 +1,579 @@ +THIRD-PARTY SOFTWARE NOTICES AND INFORMATION + +Note: While Microsoft is not the author of the files below, Microsoft is +offering you a license subject to the terms of the Microsoft Software License +Terms for Microsoft PIX Developer Tool (the "Microsoft Program"). Microsoft +reserves all other rights. The notices below are provided for informational +purposes only and are not the license terms under which Microsoft distributes +these files. + +The Microsoft Program includes the following third-party software: + +1. Boost v. 1.66.0 (https://sourceforge.net/projects/boost/files/boost/1.66.0) +2. fmt v4.1.0 (https://github.com/fmtlib/fmt/releases/tag/4.1.0) +3. SQLite 3 (http://www.sqlite.org/) +4. AMD PIX Plugin +5. nlohmann JSON (https://github.com/nlohmann/json) +6. PresentMon (https://github.com/GameTechDev/PresentMon) +7. DirectXTex (https://github.com/microsoft/directxtex) +8. DirectXTK12 (https://github.com/microsoft/DirectXTK12) +9. Guidelines Support Library (GSL) (https://github.com/microsoft/GSL) +10. Windows Implementation Library (WIL) (https://github.com/microsoft/wil) +11. GoogleTest (https://github.com/google/googletest/) +12. Newtonsoft.Json (https://www.newtonsoft.com/json) +13. WIX (https://wixtoolset.org/) +14. Moq (https://github.com/moq/moq) +15. FluentAssertions (https://github.com/fluentassertions/fluentassertions) +16. .NET Community Toolkit (https://github.com/CommunityToolkit/dotnet) +17. LiveCharts (https://lvcharts.com) +18. NVIDIA PIX Plugin + +As the recipient of the above third-party software, Microsoft sets forth a copy +of the notices and other information below. + + +BOOST NOTICES AND INFORMATION BEGIN HERE +======================================== + +Boost v. 1.66.0 +Copyright Beman Dawes, David Abrahams, 1998-2005 +Copyright Rene Rivera 2006-2007 +Provided for Informational Purposes Only +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by this +license (the "Software") to use, reproduce, display, distribute, execute, and +transmit the Software, and to prepare derivative works of the Software, and to +permit third-parties to whom the Software is furnished to do so, all subject to +the following: + +The copyright notices in the Software and this entire statement, including the +above license grant, this restriction and the following disclaimer, must be +included in all copies of the Software, in whole or in part, and all derivative +works of the Software, unless such copies or derivative works are solely in the +form of machine-executable object code generated by a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL +THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY +DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE + +END OF BOOST NOTICES AND INFORMATION +==================================== + +FMT NOTICES AND INFORMATION BEGIN HERE +====================================== + +fmt v4.1.0 +Copyright (c) 2012 - 2016, Victor Zverovich +Provided for Informational Purposes Only +BSD 2-clause + + +Copyright (c) 2012 - 2016, Victor Zverovich + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +END OF FMT NOTICES AND INFORMATION +================================== + +SQLITE3 NOTICES AND INFORMATION BEGIN HERE +========================================== + +https://www.sqlite.org/copyright.html +SQLite Is Public Domain + +All of the code and documentation in SQLite has been dedicated to the public +domain by the authors. All code authors, and representatives of the companies +they work for, have signed affidavits dedicating their contributions to the +public domain and originals of those signed affidavits are stored in a firesafe +at the main offices of Hwaci. Anyone is free to copy, modify, publish, use, +compile, sell, or distribute the original SQLite code, either in source code +form or as a compiled binary, for any purpose, commercial or non-commercial, and +by any means. + +The previous paragraph applies to the deliverable code and documentation in SQLite - +those parts of the SQLite library that you actually bundle and ship with a larger +application. Some scripts used as part of the build process (for example the "configure" +scripts generated by autoconf) might fall under other open-source licenses. Nothing +from these build scripts ever reaches the final deliverable SQLite library, however, +and so the licenses associated with those scripts should not be a factor in assessing +your rights to copy and use the SQLite library. + +All of the deliverable code in SQLite has been written from scratch. No code has been +taken from other projects or from the open internet. Every line of code can be traced +back to its original author, and all of those authors have public domain dedications +on file. So the SQLite code base is clean and is uncontaminated with licensed code +from other projects. + +END OF SQLITE3 NOTICES AND INFORMATION +====================================== + +AMD NOTICES AND INFORMATION BEGIN HERE +====================================== + +AMD copyrighted code (MIT) +Copyright (c) 2017-2023 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +Microsoft copyrighted code (MIT) +Copyright (c) Microsoft. All rights reserved. + +This code is licensed under the MIT License (MIT). +THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. + +END OF AMD NOTICES AND INFORMATION +================================== + +NLOHMANN JSON NOTICES AND INFORMATION BEGIN HERE +====================================== + +MIT License + +Copyright (c) 2013-2021 Niels Lohmann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +END OF NLOHMANN JSON NOTICES AND INFORMATION +================================== + +PRESENTMON NOTICES AND INFORMATION BEGIN HERE +====================================== + +Copyright (C) 2017-2021 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES +OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + +END OF PRESENTMON NOTICES AND INFORMATION +================================== + +DIRECTXTEX NOTICES AND INFORMATION BEGIN HERE +====================================== + +Copyright (c) 2011-2021 Microsoft Corp + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +END OF DIRECTXTEX NOTICES AND INFORMATION +================================== + +DIRECTXTK12 NOTICES AND INFORMATION BEGIN HERE +====================================== + +Copyright (c) 2016-2021 Microsoft Corp + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +END OF DIRECTXTK12 NOTICES AND INFORMATION +================================== + +GSL NOTICES AND INFORMATION BEGIN HERE +====================================== + +Copyright (c) 2015 Microsoft Corporation. All rights reserved. + +This code is licensed under the MIT License (MIT). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +END OF GSL NOTICES AND INFORMATION +================================== + +WIL NOTICES AND INFORMATION BEGIN HERE +====================================== +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE + +END OF WIL NOTICES AND INFORMATION +================================== + +GOOGLETEST NOTICES AND INFORMATION BEGIN HERE +====================================== +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +END OF GOOGLETEST NOTICES AND INFORMATION +================================== + +NEWTONSOFT.JSON NOTICES AND INFORMATION BEGIN HERE +====================================== +The MIT License (MIT) + +Copyright (c) 2007 James Newton-King + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +END OF NEWTONSOFT.JSON NOTICES AND INFORMATION +================================= + +WIX NOTICES AND INFORMATION BEGIN HERE +====================================== +Copyright (c) .NET Foundation and contributors. This software is released under +the Microsoft Reciprocal License (MS-RL) (the "License"); you may not use the +software except in compliance with the License. + +The text of the Microsoft Reciprocal License (MS-RL) can be found online at: +http://opensource.org/licenses/ms-rl + + +Microsoft Reciprocal License (MS-RL) + +This license governs use of the accompanying software. If you use the software, +you accept this license. If you do not accept the license, do not use the +software. + +1. Definitions The terms "reproduce," "reproduction," "derivative works," and +"distribution" have the same meaning here as under U.S. copyright law. A +"contribution" is the original software, or any additions or changes to the +software. A "contributor" is any person that distributes its contribution under +this license. "Licensed patents" are a contributor's patent claims that read +directly on its contribution. + +2. Grant of Rights (A) Copyright Grant- Subject to the terms of this license, +including the license conditions and limitations in section 3, each contributor +grants you a non-exclusive, worldwide, royalty-free copyright license to +reproduce its contribution, prepare derivative works of its contribution, and +distribute its contribution or any derivative works that you create. (B) Patent +Grant- Subject to the terms of this license, including the license conditions and +limitations in section 3, each contributor grants you a non-exclusive, worldwide, +royalty-free license under its licensed patents to make, have made, use, sell, +offer for sale, import, and/or otherwise dispose of its contribution in the +software or derivative works of the contribution in the software. + +3. Conditions and Limitations (A) Reciprocal Grants- For any file you distribute +that contains code from the software (in source code or binary format), you must +provide recipients the source code to that file along with a copy of this +license, which license will govern that file. You may license other files that +are entirely your own work and do not contain code from the software under any +terms you choose. (B) No Trademark License- This license does not grant you +rights to use any contributors' name, logo, or trademarks. (C) If you bring a +patent claim against any contributor over patents that you claim are infringed by +the software, your patent license from such contributor to the software ends +automatically. (D) If you distribute any portion of the software, you must retain +all copyright, patent, trademark, and attribution notices that are present in the +software. (E) If you distribute any portion of the software in source code form, +you may do so only under this license by including a complete copy of this +license with your distribution. If you distribute any portion of the software in +compiled or object code form, you may only do so under a license that complies +with this license. (F) The software is licensed "as-is." You bear the risk of +using it. The contributors give no express warranties, guarantees or conditions. +You may have additional consumer rights under your local laws which this license +cannot change. To the extent permitted under your local laws, the contributors +exclude the implied warranties of merchantability, fitness for a particular +purpose and non-infringement. + +END OF WIX NOTICES AND INFORMATION +================================= + + +MOQ NOTICES AND INFORMATION BEGIN HERE +====================================== +MIT License + +Copyright (c) Daniel Cazzulino and Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +END OF MOQ NOTICES AND INFORMATION +================================== + + +FLUENTASSERTIONS NOTICES AND INFORMATION BEGIN HERE +=================================================== +Copyright [2010-2021] [Dennis Doomen] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +END OF FLUENTASSERTIONS NOTICES AND INFORMATION +=============================================== + +.NET COMMUNITY TOOLKIT NOTICES AND INFORMATION BEGIN HERE +====================================== +MIT License + +Copyright © .NET Foundation and Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +END OF .NET COMMUNITY TOOLKIT NOTICES AND INFORMATION +================================== + +LIVE CHARTS NOTICES AND INFORMATION BEGIN HERE +====================================== +MIT License + +Copyright (c) 2021 Alberto Rodriguez Orozco + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +END OF LIVE CHARTS NOTICES AND INFORMATION +================================== + +NVIDIA PIX PLUGIN NOTICES AND INFORMATION BEGIN HERE +====================================== +Copyright (c) Microsoft Corporation. +Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +END OF NVIDIA PIX PLUGIN NOTICES AND INFORMATION +================================== \ No newline at end of file diff --git a/Backends/Graphics5/Direct3D12/pix/bin/x64/WinPixEventRuntime.dll b/Backends/Graphics5/Direct3D12/pix/bin/x64/WinPixEventRuntime.dll new file mode 100644 index 0000000000000000000000000000000000000000..5d86359dbe5894f2a66f1ff44c43746f5c1fc922 GIT binary patch literal 58368 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

*+qM47|#j$M1U=W*o~@&-D0$1 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 AJ^%m! literal 0 HcmV?d00001 diff --git a/Backends/Graphics5/Direct3D12/pix/bin/x64/WinPixEventRuntime.lib b/Backends/Graphics5/Direct3D12/pix/bin/x64/WinPixEventRuntime.lib new file mode 100644 index 0000000000000000000000000000000000000000..7a909a87225a81eea4beb4ebe8f7903e2bcca06a GIT binary patch literal 6230 zcmcIo%}*Og6n~fyf}ue8>?IOKsG%PLY(7FH)Ecm%76u$+1Zk_7#U5aVy^EHmO*pjT zl1r+btK6y{+e$t351>^~=_PHXDu*;_BMt@8_EPoIL;7ZSXFt5VwzpnZ8qe38_kQ!{ zy?Jl^$^<86x84d4_E^6wA#0!YhO|a#B&0Rhf&g#{pz%3C^Eg1uK0xQXS~`vZXz6^S zmhPtjv~;Dl@)&C@-8a?J76qWC^+YZ0_W)>VJ5|fY`vA0bOwf|a#OITXsdOe9TbfSA zlj+4&W`!4${H@prM37T^g3K2PWHJlOiG-aNKDHC9r0I8-7v?h2$@C;7JcT;31&t=I}Ud(PA zw1}G`l0j!3M!E%2<~MGyaNA@?5(_g#$dV;~Q{eK(8g~*!PF9q1^Q0h3wdcaIYQU6x;VN0!$z+UjNVpEzk(f@Dj8_9h`&n zZ~+=12=!0{ffBQ|;Buao`o4auE_^&32jyV1$x3mcWjn4fFJD{flT+H+lt-ZJkSc%% zPiqXr(c&nm4q0Q={|+q3%p6jTprA}x17CG9-*7lT?&Xr)JZRnEQ;qeN;8GroZPVa7~I*HjFD@ub5n>Fz;TW%%U=3vo9 zUM>p{53{^{Eoe_>2Xgs51P58lu924GIXXP9QLY7ZcWU9I?}ESe)&Sn->Nk)h>wBAh zOIjBa*!YBXv^oNzY!QZ)ab^vVR#uEL6pbn=y(Kr z4g*+U!iYk@F6Yf&hW6HaoPMYf;d2CD1>vA=p3h3+uDBuh^rv3yNyHcCw0TR_gguIh z7QpyLTQoM-DJ^G#h%74>c5n;AK~2qz7v|Nt3@GLRFik`NlwEAG5oOP+OpRuQ(%>S{ zX-16^I{pUz(LTx@W3twxRRGrkX2R9okri30N2>~tu?Ho!ssJQsKYQ@Kf|%k4aI&hL zI;H=btZJAIQmgu!b+npV)md9hCFf4FBG<>KXTKaCvijxe$=z>%M+vGGIBT$kUyd@R zQNN~sY5pP*VSYKn#wp#etfSSG?kqK3iI)2j%UM`#C^V|yg8)ddb*C%FLz99^a*fja+&wbDE?=*aesb_9azx*;$ubD;2bb~Q{ ze%bWlU#p0=*%fVhh3d(oi(0+n9Al2(L;u@UJ-<2d?1w9e^E_Ipb2jQC+_N8#g|#C! zN&g~t{OEO*Uav|oev7$?_PlRBrW^b2?fv|a-mn*R$)<$bC%IQ0cD&xu{|^m44XRxC zjNLB`%#lo5|Knlk5lzv8Duz-|0-sQfu@G-Uah%xycL-55+EEy94!`6(Sit3jH-DlQ N(8T1MA2lv={{wvrjjaFx literal 0 HcmV?d00001 diff --git a/Backends/Graphics5/Direct3D12/pix/license.txt b/Backends/Graphics5/Direct3D12/pix/license.txt new file mode 100644 index 000000000..44378268b --- /dev/null +++ b/Backends/Graphics5/Direct3D12/pix/license.txt @@ -0,0 +1,21 @@ +Copyright (c) Microsoft Corporation. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/kfile.js b/kfile.js index f65199d99..bf9f0d698 100644 --- a/kfile.js +++ b/kfile.js @@ -184,6 +184,12 @@ if (platform === Platform.Windows) { else { throw new Error('VR API ' + vr + ' is not available for Windows.'); } + + if (Options.pix) { + project.addDefine('KOPE_PIX'); + project.addIncludeDir('Backends/Graphics5/Direct3D12/pix/Include'); + project.addLib('Backends/Graphics5/Direct3D12/pix/bin/x64/WinPixEventRuntime'); + } } else if (platform === Platform.WindowsApp) { g4 = true;