PIXEventsLegacy.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. // Copyright (c) Microsoft Corporation.
  2. // Licensed under the MIT License.
  3. // Don't include this file directly - use pix3.h
  4. // This file encodes PIX events in the legacy PIX event format.
  5. #ifndef _PIXEventsLegacy_H_
  6. #define _PIXEventsLegacy_H_
  7. #include <cstdint>
  8. #if defined(_M_X64) || defined(_M_IX86)
  9. #include <emmintrin.h>
  10. #endif
  11. namespace PixEventsLegacy
  12. {
  13. enum PIXEventType
  14. {
  15. PIXEvent_EndEvent = 0x000,
  16. PIXEvent_BeginEvent_VarArgs = 0x001,
  17. PIXEvent_BeginEvent_NoArgs = 0x002,
  18. PIXEvent_SetMarker_VarArgs = 0x007,
  19. PIXEvent_SetMarker_NoArgs = 0x008,
  20. PIXEvent_EndEvent_OnContext = 0x010,
  21. PIXEvent_BeginEvent_OnContext_VarArgs = 0x011,
  22. PIXEvent_BeginEvent_OnContext_NoArgs = 0x012,
  23. PIXEvent_SetMarker_OnContext_VarArgs = 0x017,
  24. PIXEvent_SetMarker_OnContext_NoArgs = 0x018,
  25. };
  26. static const UINT64 PIXEventsReservedRecordSpaceQwords = 64;
  27. static const UINT64 PIXEventsReservedTailSpaceQwords = 2;
  28. static const UINT64 PIXEventsSafeFastCopySpaceQwords = PIXEventsReservedRecordSpaceQwords - PIXEventsReservedTailSpaceQwords;
  29. static const UINT64 PIXEventsGraphicsRecordSpaceQwords = 64;
  30. //Bits 7-19 (13 bits)
  31. static const UINT64 PIXEventsBlockEndMarker = 0x00000000000FFF80;
  32. //Bits 10-19 (10 bits)
  33. static const UINT64 PIXEventsTypeReadMask = 0x00000000000FFC00;
  34. static const UINT64 PIXEventsTypeWriteMask = 0x00000000000003FF;
  35. static const UINT64 PIXEventsTypeBitShift = 10;
  36. //Bits 20-63 (44 bits)
  37. static const UINT64 PIXEventsTimestampReadMask = 0xFFFFFFFFFFF00000;
  38. static const UINT64 PIXEventsTimestampWriteMask = 0x00000FFFFFFFFFFF;
  39. static const UINT64 PIXEventsTimestampBitShift = 20;
  40. inline UINT64 PIXEncodeEventInfo(UINT64 timestamp, PIXEventType eventType)
  41. {
  42. return ((timestamp & PIXEventsTimestampWriteMask) << PIXEventsTimestampBitShift) |
  43. (((UINT64)eventType & PIXEventsTypeWriteMask) << PIXEventsTypeBitShift);
  44. }
  45. //Bits 60-63 (4)
  46. static const UINT64 PIXEventsStringAlignmentWriteMask = 0x000000000000000F;
  47. static const UINT64 PIXEventsStringAlignmentReadMask = 0xF000000000000000;
  48. static const UINT64 PIXEventsStringAlignmentBitShift = 60;
  49. //Bits 55-59 (5)
  50. static const UINT64 PIXEventsStringCopyChunkSizeWriteMask = 0x000000000000001F;
  51. static const UINT64 PIXEventsStringCopyChunkSizeReadMask = 0x0F80000000000000;
  52. static const UINT64 PIXEventsStringCopyChunkSizeBitShift = 55;
  53. //Bit 54
  54. static const UINT64 PIXEventsStringIsANSIWriteMask = 0x0000000000000001;
  55. static const UINT64 PIXEventsStringIsANSIReadMask = 0x0040000000000000;
  56. static const UINT64 PIXEventsStringIsANSIBitShift = 54;
  57. //Bit 53
  58. static const UINT64 PIXEventsStringIsShortcutWriteMask = 0x0000000000000001;
  59. static const UINT64 PIXEventsStringIsShortcutReadMask = 0x0020000000000000;
  60. static const UINT64 PIXEventsStringIsShortcutBitShift = 53;
  61. inline UINT64 PIXEncodeStringInfo(UINT64 alignment, UINT64 copyChunkSize, BOOL isANSI, BOOL isShortcut)
  62. {
  63. return ((alignment & PIXEventsStringAlignmentWriteMask) << PIXEventsStringAlignmentBitShift) |
  64. ((copyChunkSize & PIXEventsStringCopyChunkSizeWriteMask) << PIXEventsStringCopyChunkSizeBitShift) |
  65. (((UINT64)isANSI & PIXEventsStringIsANSIWriteMask) << PIXEventsStringIsANSIBitShift) |
  66. (((UINT64)isShortcut & PIXEventsStringIsShortcutWriteMask) << PIXEventsStringIsShortcutBitShift);
  67. }
  68. template<UINT alignment, class T>
  69. inline bool PIXIsPointerAligned(T* pointer)
  70. {
  71. return !(((UINT64)pointer) & (alignment - 1));
  72. }
  73. // Generic template version slower because of the additional clear write
  74. template<class T>
  75. inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, T argument)
  76. {
  77. if (destination < limit)
  78. {
  79. *destination = 0ull;
  80. *((T*)destination) = argument;
  81. ++destination;
  82. }
  83. }
  84. // int32 specialization to avoid slower double memory writes
  85. template<>
  86. inline void PIXCopyEventArgument<INT32>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT32 argument)
  87. {
  88. if (destination < limit)
  89. {
  90. *reinterpret_cast<INT64*>(destination) = static_cast<INT64>(argument);
  91. ++destination;
  92. }
  93. }
  94. // unsigned int32 specialization to avoid slower double memory writes
  95. template<>
  96. inline void PIXCopyEventArgument<UINT32>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT32 argument)
  97. {
  98. if (destination < limit)
  99. {
  100. *destination = static_cast<UINT64>(argument);
  101. ++destination;
  102. }
  103. }
  104. // int64 specialization to avoid slower double memory writes
  105. template<>
  106. inline void PIXCopyEventArgument<INT64>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT64 argument)
  107. {
  108. if (destination < limit)
  109. {
  110. *reinterpret_cast<INT64*>(destination) = argument;
  111. ++destination;
  112. }
  113. }
  114. // unsigned int64 specialization to avoid slower double memory writes
  115. template<>
  116. inline void PIXCopyEventArgument<UINT64>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT64 argument)
  117. {
  118. if (destination < limit)
  119. {
  120. *destination = argument;
  121. ++destination;
  122. }
  123. }
  124. //floats must be cast to double during writing the data to be properly printed later when reading the data
  125. //this is needed because when float is passed to varargs function it's cast to double
  126. template<>
  127. inline void PIXCopyEventArgument<float>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, float argument)
  128. {
  129. if (destination < limit)
  130. {
  131. *reinterpret_cast<double*>(destination) = static_cast<double>(argument);
  132. ++destination;
  133. }
  134. }
  135. //char has to be cast to a longer signed integer type
  136. //this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier
  137. template<>
  138. inline void PIXCopyEventArgument<char>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, char argument)
  139. {
  140. if (destination < limit)
  141. {
  142. *reinterpret_cast<INT64*>(destination) = static_cast<INT64>(argument);
  143. ++destination;
  144. }
  145. }
  146. //unsigned char has to be cast to a longer unsigned integer type
  147. //this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier
  148. template<>
  149. inline void PIXCopyEventArgument<unsigned char>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, unsigned char argument)
  150. {
  151. if (destination < limit)
  152. {
  153. *destination = static_cast<UINT64>(argument);
  154. ++destination;
  155. }
  156. }
  157. //bool has to be cast to an integer since it's not explicitly supported by string format routines
  158. //there's no format specifier for bool type, but it should work with integer format specifiers
  159. template<>
  160. inline void PIXCopyEventArgument<bool>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, bool argument)
  161. {
  162. if (destination < limit)
  163. {
  164. *destination = static_cast<UINT64>(argument);
  165. ++destination;
  166. }
  167. }
  168. inline void PIXCopyEventArgumentSlowest(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
  169. {
  170. *destination++ = PIXEncodeStringInfo(0, 8, TRUE, FALSE);
  171. while (destination < limit)
  172. {
  173. UINT64 c = static_cast<uint8_t>(argument[0]);
  174. if (!c)
  175. {
  176. *destination++ = 0;
  177. return;
  178. }
  179. UINT64 x = c;
  180. c = static_cast<uint8_t>(argument[1]);
  181. if (!c)
  182. {
  183. *destination++ = x;
  184. return;
  185. }
  186. x |= c << 8;
  187. c = static_cast<uint8_t>(argument[2]);
  188. if (!c)
  189. {
  190. *destination++ = x;
  191. return;
  192. }
  193. x |= c << 16;
  194. c = static_cast<uint8_t>(argument[3]);
  195. if (!c)
  196. {
  197. *destination++ = x;
  198. return;
  199. }
  200. x |= c << 24;
  201. c = static_cast<uint8_t>(argument[4]);
  202. if (!c)
  203. {
  204. *destination++ = x;
  205. return;
  206. }
  207. x |= c << 32;
  208. c = static_cast<uint8_t>(argument[5]);
  209. if (!c)
  210. {
  211. *destination++ = x;
  212. return;
  213. }
  214. x |= c << 40;
  215. c = static_cast<uint8_t>(argument[6]);
  216. if (!c)
  217. {
  218. *destination++ = x;
  219. return;
  220. }
  221. x |= c << 48;
  222. c = static_cast<uint8_t>(argument[7]);
  223. if (!c)
  224. {
  225. *destination++ = x;
  226. return;
  227. }
  228. x |= c << 56;
  229. *destination++ = x;
  230. argument += 8;
  231. }
  232. }
  233. inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
  234. {
  235. #if PIX_ENABLE_BLOCK_ARGUMENT_COPY
  236. if (PIXIsPointerAligned<8>(argument))
  237. {
  238. *destination++ = PIXEncodeStringInfo(0, 8, TRUE, FALSE);
  239. UINT64* source = (UINT64*)argument;
  240. while (destination < limit)
  241. {
  242. UINT64 qword = *source++;
  243. *destination++ = qword;
  244. //check if any of the characters is a terminating zero
  245. if (!((qword & 0xFF00000000000000) &&
  246. (qword & 0xFF000000000000) &&
  247. (qword & 0xFF0000000000) &&
  248. (qword & 0xFF00000000) &&
  249. (qword & 0xFF000000) &&
  250. (qword & 0xFF0000) &&
  251. (qword & 0xFF00) &&
  252. (qword & 0xFF)))
  253. {
  254. break;
  255. }
  256. }
  257. }
  258. else
  259. #endif // PIX_ENABLE_BLOCK_ARGUMENT_COPY
  260. {
  261. PIXCopyEventArgumentSlowest(destination, limit, argument);
  262. }
  263. }
  264. template<>
  265. inline void PIXCopyEventArgument<PCSTR>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
  266. {
  267. if (destination < limit)
  268. {
  269. if (argument != nullptr)
  270. {
  271. #if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
  272. if (PIXIsPointerAligned<16>(argument))
  273. {
  274. *destination++ = PIXEncodeStringInfo(0, 16, TRUE, FALSE);
  275. __m128i zero = _mm_setzero_si128();
  276. if (PIXIsPointerAligned<16>(destination))
  277. {
  278. while (destination < limit)
  279. {
  280. __m128i mem = _mm_load_si128((__m128i*)argument);
  281. _mm_store_si128((__m128i*)destination, mem);
  282. //check if any of the characters is a terminating zero
  283. __m128i res = _mm_cmpeq_epi8(mem, zero);
  284. destination += 2;
  285. if (_mm_movemask_epi8(res))
  286. break;
  287. argument += 16;
  288. }
  289. }
  290. else
  291. {
  292. while (destination < limit)
  293. {
  294. __m128i mem = _mm_load_si128((__m128i*)argument);
  295. _mm_storeu_si128((__m128i*)destination, mem);
  296. //check if any of the characters is a terminating zero
  297. __m128i res = _mm_cmpeq_epi8(mem, zero);
  298. destination += 2;
  299. if (_mm_movemask_epi8(res))
  300. break;
  301. argument += 16;
  302. }
  303. }
  304. }
  305. else
  306. #endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
  307. {
  308. PIXCopyEventArgumentSlow(destination, limit, argument);
  309. }
  310. }
  311. else
  312. {
  313. *destination++ = 0ull;
  314. }
  315. }
  316. }
  317. template<>
  318. inline void PIXCopyEventArgument<PSTR>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PSTR argument)
  319. {
  320. PIXCopyEventArgument(destination, limit, (PCSTR)argument);
  321. }
  322. inline void PIXCopyEventArgumentSlowest(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
  323. {
  324. *destination++ = PIXEncodeStringInfo(0, 8, FALSE, FALSE);
  325. while (destination < limit)
  326. {
  327. UINT64 c = static_cast<uint16_t>(argument[0]);
  328. if (!c)
  329. {
  330. *destination++ = 0;
  331. return;
  332. }
  333. UINT64 x = c;
  334. c = static_cast<uint16_t>(argument[1]);
  335. if (!c)
  336. {
  337. *destination++ = x;
  338. return;
  339. }
  340. x |= c << 16;
  341. c = static_cast<uint16_t>(argument[2]);
  342. if (!c)
  343. {
  344. *destination++ = x;
  345. return;
  346. }
  347. x |= c << 32;
  348. c = static_cast<uint16_t>(argument[3]);
  349. if (!c)
  350. {
  351. *destination++ = x;
  352. return;
  353. }
  354. x |= c << 48;
  355. *destination++ = x;
  356. argument += 4;
  357. }
  358. }
  359. inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
  360. {
  361. #if PIX_ENABLE_BLOCK_ARGUMENT_COPY
  362. if (PIXIsPointerAligned<8>(argument))
  363. {
  364. *destination++ = PIXEncodeStringInfo(0, 8, FALSE, FALSE);
  365. UINT64* source = (UINT64*)argument;
  366. while (destination < limit)
  367. {
  368. UINT64 qword = *source++;
  369. *destination++ = qword;
  370. //check if any of the characters is a terminating zero
  371. //TODO: check if reversed condition is faster
  372. if (!((qword & 0xFFFF000000000000) &&
  373. (qword & 0xFFFF00000000) &&
  374. (qword & 0xFFFF0000) &&
  375. (qword & 0xFFFF)))
  376. {
  377. break;
  378. }
  379. }
  380. }
  381. else
  382. #endif // PIX_ENABLE_BLOCK_ARGUMENT_COPY
  383. {
  384. PIXCopyEventArgumentSlowest(destination, limit, argument);
  385. }
  386. }
  387. template<>
  388. inline void PIXCopyEventArgument<PCWSTR>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
  389. {
  390. if (destination < limit)
  391. {
  392. if (argument != nullptr)
  393. {
  394. #if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
  395. if (PIXIsPointerAligned<16>(argument))
  396. {
  397. *destination++ = PIXEncodeStringInfo(0, 16, FALSE, FALSE);
  398. __m128i zero = _mm_setzero_si128();
  399. if (PIXIsPointerAligned<16>(destination))
  400. {
  401. while (destination < limit)
  402. {
  403. __m128i mem = _mm_load_si128((__m128i*)argument);
  404. _mm_store_si128((__m128i*)destination, mem);
  405. //check if any of the characters is a terminating zero
  406. __m128i res = _mm_cmpeq_epi16(mem, zero);
  407. destination += 2;
  408. if (_mm_movemask_epi8(res))
  409. break;
  410. argument += 8;
  411. }
  412. }
  413. else
  414. {
  415. while (destination < limit)
  416. {
  417. __m128i mem = _mm_load_si128((__m128i*)argument);
  418. _mm_storeu_si128((__m128i*)destination, mem);
  419. //check if any of the characters is a terminating zero
  420. __m128i res = _mm_cmpeq_epi16(mem, zero);
  421. destination += 2;
  422. if (_mm_movemask_epi8(res))
  423. break;
  424. argument += 8;
  425. }
  426. }
  427. }
  428. else
  429. #endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
  430. {
  431. PIXCopyEventArgumentSlow(destination, limit, argument);
  432. }
  433. }
  434. else
  435. {
  436. *destination++ = 0ull;
  437. }
  438. }
  439. }
  440. inline void PIXCopyEventArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit)
  441. {
  442. // nothing
  443. UNREFERENCED_PARAMETER(destination);
  444. UNREFERENCED_PARAMETER(limit);
  445. }
  446. template<typename ARG, typename... ARGS>
  447. void PIXCopyEventArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, ARG const& arg, ARGS const&... args)
  448. {
  449. PIXCopyEventArgument(destination, limit, arg);
  450. PIXCopyEventArguments(destination, limit, args...);
  451. }
  452. template<typename... ARGS>
  453. struct PIXEventTypeInferer
  454. {
  455. static constexpr PIXEventType Begin() { return PIXEvent_BeginEvent_VarArgs; }
  456. static constexpr PIXEventType SetMarker() { return PIXEvent_SetMarker_VarArgs; }
  457. static constexpr PIXEventType BeginOnContext() { return PIXEvent_BeginEvent_OnContext_VarArgs; }
  458. static constexpr PIXEventType SetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_VarArgs; }
  459. static constexpr PIXEventType End() { return PIXEvent_EndEvent; }
  460. // Xbox and Windows store different types of events for context events.
  461. // On Xbox these include a context argument, while on Windows they do
  462. // not. It is important not to change the event types used on the
  463. // Windows version as there are OS components (eg debug layer & DRED)
  464. // that decode event structs.
  465. #ifdef PIX_XBOX
  466. static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_OnContext_VarArgs; }
  467. static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_VarArgs; }
  468. static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent_OnContext; }
  469. #else
  470. static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_VarArgs; }
  471. static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_VarArgs; }
  472. static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent; }
  473. #endif
  474. };
  475. template<>
  476. struct PIXEventTypeInferer<>
  477. {
  478. static constexpr PIXEventType Begin() { return PIXEvent_BeginEvent_NoArgs; }
  479. static constexpr PIXEventType SetMarker() { return PIXEvent_SetMarker_NoArgs; }
  480. static constexpr PIXEventType BeginOnContext() { return PIXEvent_BeginEvent_OnContext_NoArgs; }
  481. static constexpr PIXEventType SetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_NoArgs; }
  482. static constexpr PIXEventType End() { return PIXEvent_EndEvent; }
  483. #ifdef PIX_XBOX
  484. static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_OnContext_NoArgs; }
  485. static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_NoArgs; }
  486. static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent_OnContext; }
  487. #else
  488. static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_NoArgs; }
  489. static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_NoArgs; }
  490. static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent; }
  491. #endif
  492. };
  493. template<size_t size, typename STR, typename... ARGS>
  494. UINT64* EncodeBeginEventForContext(UINT64 (&buffer)[size], UINT64 color, STR formatString, ARGS... args)
  495. {
  496. UINT64* destination = buffer;
  497. UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords;
  498. *destination++ = PIXEncodeEventInfo(0, PIXEventTypeInferer<ARGS...>::GpuBeginOnContext());
  499. *destination++ = color;
  500. PIXCopyEventArguments(destination, limit, formatString, args...);
  501. *destination = 0ull;
  502. return destination;
  503. }
  504. template<size_t size, typename STR, typename... ARGS>
  505. UINT64* EncodeSetMarkerForContext(UINT64 (&buffer)[size], UINT64 color, STR formatString, ARGS... args)
  506. {
  507. UINT64* destination = buffer;
  508. UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords;
  509. *destination++ = PIXEncodeEventInfo(0, PIXEventTypeInferer<ARGS...>::GpuSetMarkerOnContext());
  510. *destination++ = color;
  511. PIXCopyEventArguments(destination, limit, formatString, args...);
  512. *destination = 0ull;
  513. return destination;
  514. }
  515. }
  516. #endif //_PIXEventsLegacy_H_