1 #pragma once
2 // This is free and unencumbered software released into the public domain.
3 // Anyone is free to copy, modify, publish, use, compile, sell, or
4 // distribute this software, either in source code form or as a compiled
5 // binary, for any purpose, commercial or non-commercial, and by any
6 // means.
7 // In jurisdictions that recognize copyright laws, the author or authors
8 // of this software dedicate any and all copyright interest in the
9 // software to the public domain. We make this dedication for the benefit
10 // of the public at large and to the detriment of our heirs and
11 // successors. We intend this dedication to be an overt act of
12 // relinquishment in perpetuity of all present and future rights to this
13 // software under copyright law.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 // For more information, please refer to <http://unlicense.org/>
22 //
23 // ***********************************************************************
24 //
25 //
26 //
27 
28 
29 #ifndef MICROPROFILE_ENABLED
30 #error "microprofile.h must be included before including microprofileui.h"
31 #endif
32 
33 #ifndef MICROPROFILEUI_ENABLED
34 #define MICROPROFILEUI_ENABLED MICROPROFILE_ENABLED
35 #endif
36 
37 #ifndef MICROPROFILEUI_API
38 #define MICROPROFILEUI_API
39 #endif
40 
41 
42 #if 0 == MICROPROFILEUI_ENABLED
43 #define MicroProfileMouseButton(foo, bar) do{}while(0)
44 #define MicroProfileMousePosition(foo, bar, z) do{}while(0)
45 #define MicroProfileModKey(key) do{}while(0)
46 #define MicroProfileDraw(foo, bar) do{}while(0)
47 #define MicroProfileIsDrawing() 0
48 #define MicroProfileToggleDisplayMode() do{}while(0)
49 #define MicroProfileSetDisplayMode(f) do{}while(0)
50 #else
51 
52 #ifndef MICROPROFILE_DRAWCURSOR
53 #define MICROPROFILE_DRAWCURSOR 0
54 #endif
55 
56 #ifndef MICROPROFILE_DETAILED_BAR_NAMES
57 #define MICROPROFILE_DETAILED_BAR_NAMES 1
58 #endif
59 
60 #ifndef MICROPROFILE_TEXT_WIDTH
61 #define MICROPROFILE_TEXT_WIDTH 5
62 #endif
63 
64 #ifndef MICROPROFILE_TEXT_HEIGHT
65 #define MICROPROFILE_TEXT_HEIGHT 8
66 #endif
67 
68 #ifndef MICROPROFILE_DETAILED_BAR_HEIGHT
69 #define MICROPROFILE_DETAILED_BAR_HEIGHT 12
70 #endif
71 
72 #ifndef MICROPROFILE_DETAILED_CONTEXT_SWITCH_HEIGHT
73 #define MICROPROFILE_DETAILED_CONTEXT_SWITCH_HEIGHT 7
74 #endif
75 
76 #ifndef MICROPROFILE_GRAPH_WIDTH
77 #define MICROPROFILE_GRAPH_WIDTH 256
78 #endif
79 
80 #ifndef MICROPROFILE_GRAPH_HEIGHT
81 #define MICROPROFILE_GRAPH_HEIGHT 256
82 #endif
83 
84 #ifndef MICROPROFILE_BORDER_SIZE
85 #define MICROPROFILE_BORDER_SIZE 1
86 #endif
87 
88 #ifndef MICROPROFILE_HELP_LEFT
89 #define MICROPROFILE_HELP_LEFT "Left-Click"
90 #endif
91 
92 #ifndef MICROPROFILE_HELP_ALT
93 #define MICROPROFILE_HELP_ALT "Alt-Click"
94 #endif
95 
96 #ifndef MICROPROFILE_HELP_MOD
97 #define MICROPROFILE_HELP_MOD "Mod"
98 #endif
99 
100 #ifndef MICROPROFILE_BAR_WIDTH
101 #define MICROPROFILE_BAR_WIDTH 100
102 #endif
103 
104 #ifndef MICROPROFILE_CUSTOM_MAX
105 #define MICROPROFILE_CUSTOM_MAX 8
106 #endif
107 
108 #ifndef MICROPROFILE_CUSTOM_MAX_TIMERS
109 #define MICROPROFILE_CUSTOM_MAX_TIMERS 64
110 #endif
111 
112 #ifndef MICROPROFILE_CUSTOM_PADDING
113 #define MICROPROFILE_CUSTOM_PADDING 12
114 #endif
115 
116 
117 #define MICROPROFILE_FRAME_HISTORY_HEIGHT 50
118 #define MICROPROFILE_FRAME_HISTORY_WIDTH 7
119 #define MICROPROFILE_FRAME_HISTORY_COLOR_CPU 0xffff7f27 //255 127 39
120 #define MICROPROFILE_FRAME_HISTORY_COLOR_GPU 0xff37a0ee //55 160 238
121 #define MICROPROFILE_FRAME_HISTORY_COLOR_HIGHTLIGHT 0x7733bb44
122 #define MICROPROFILE_FRAME_COLOR_HIGHTLIGHT 0x20009900
123 #define MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU 0x20996600
124 #define MICROPROFILE_NUM_FRAMES (MICROPROFILE_MAX_FRAME_HISTORY - (MICROPROFILE_GPU_FRAME_DELAY+1))
125 
126 #define MICROPROFILE_TOOLTIP_MAX_STRINGS (32 + MICROPROFILE_MAX_GROUPS*2)
127 #define MICROPROFILE_TOOLTIP_STRING_BUFFER_SIZE (4*1024)
128 #define MICROPROFILE_TOOLTIP_MAX_LOCKED 3
129 
130 
131 enum
132 {
133     MICROPROFILE_CUSTOM_BARS = 0x1,
134     MICROPROFILE_CUSTOM_BAR_SOURCE_MAX = 0x2,
135     MICROPROFILE_CUSTOM_BAR_SOURCE_AVG = 0,
136     MICROPROFILE_CUSTOM_STACK = 0x4,
137     MICROPROFILE_CUSTOM_STACK_SOURCE_MAX = 0x8,
138     MICROPROFILE_CUSTOM_STACK_SOURCE_AVG = 0,
139 };
140 
141 
142 MICROPROFILEUI_API void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight); //! call if drawing microprofilers
143 MICROPROFILEUI_API bool MicroProfileIsDrawing();
144 MICROPROFILEUI_API void MicroProfileToggleGraph(MicroProfileToken nToken);
145 MICROPROFILEUI_API bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight);
146 MICROPROFILEUI_API void MicroProfileToggleDisplayMode(); //switch between off, bars, detailed
147 MICROPROFILEUI_API void MicroProfileSetDisplayMode(int); //switch between off, bars, detailed
148 MICROPROFILEUI_API void MicroProfileClearGraph();
149 MICROPROFILEUI_API void MicroProfileMousePosition(uint32_t nX, uint32_t nY, int nWheelDelta);
150 MICROPROFILEUI_API void MicroProfileModKey(uint32_t nKeyState);
151 MICROPROFILEUI_API void MicroProfileMouseButton(uint32_t nLeft, uint32_t nRight);
152 MICROPROFILEUI_API void MicroProfileDrawLineVertical(int nX, int nTop, int nBottom, uint32_t nColor);
153 MICROPROFILEUI_API void MicroProfileDrawLineHorizontal(int nLeft, int nRight, int nY, uint32_t nColor);
154 MICROPROFILEUI_API void MicroProfileLoadPreset(const char* pSuffix);
155 MICROPROFILEUI_API void MicroProfileSavePreset(const char* pSuffix);
156 
157 MICROPROFILEUI_API void MicroProfileDrawText(int nX, int nY, uint32_t nColor, const char* pText, uint32_t nNumCharacters);
158 MICROPROFILEUI_API void MicroProfileDrawBox(int nX, int nY, int nX1, int nY1, uint32_t nColor, MicroProfileBoxType = MicroProfileBoxTypeFlat);
159 MICROPROFILEUI_API void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices, uint32_t nColor);
160 MICROPROFILEUI_API void MicroProfileDumpTimers();
161 
162 MICROPROFILEUI_API void MicroProfileInitUI();
163 
164 MICROPROFILEUI_API void MicroProfileCustomGroupToggle(const char* pCustomName);
165 MICROPROFILEUI_API void MicroProfileCustomGroupEnable(const char* pCustomName);
166 MICROPROFILEUI_API void MicroProfileCustomGroupEnable(uint32_t nIndex);
167 MICROPROFILEUI_API void MicroProfileCustomGroupDisable();
168 MICROPROFILEUI_API void MicroProfileCustomGroup(const char* pCustomName, uint32_t nMaxTimers, uint32_t nAggregateFlip, float fReferenceTime, uint32_t nFlags);
169 MICROPROFILEUI_API void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup, const char* pTimer);
170 
171 #ifdef MICROPROFILEUI_IMPL
172 #include <inttypes.h>
173 #include <stdio.h>
174 #include <stdlib.h>
175 #include <stdarg.h>
176 #include <math.h>
177 #include <algorithm>
178 #include <array>
179 
180 MICROPROFILE_DEFINE(g_MicroProfileDetailed, "MicroProfile", "Detailed View", 0x8888000);
181 MICROPROFILE_DEFINE(g_MicroProfileDrawGraph, "MicroProfile", "Draw Graph", 0xff44ee00);
182 MICROPROFILE_DEFINE(g_MicroProfileDrawBarView, "MicroProfile", "DrawBarView", 0x00dd77);
183 MICROPROFILE_DEFINE(g_MicroProfileDraw,"MicroProfile", "Draw", 0x737373);
184 
185 
186 struct MicroProfileStringArray
187 {
188     const char* ppStrings[MICROPROFILE_TOOLTIP_MAX_STRINGS];
189     char Buffer[MICROPROFILE_TOOLTIP_STRING_BUFFER_SIZE];
190     char* pBufferPos;
191     uint32_t nNumStrings;
192 };
193 
194 struct MicroProfileGroupMenuItem
195 {
196     uint32_t nIsCategory;
197     uint32_t nCategoryIndex;
198     uint32_t nIndex;
199     const char* pName;
200 };
201 
202 struct MicroProfileCustom
203 {
204     char pName[MICROPROFILE_NAME_MAX_LEN];
205     uint32_t nFlags;
206     uint32_t nAggregateFlip;
207     uint32_t nNumTimers;
208     uint32_t nMaxTimers;
209     uint64_t nGroupMask;
210     float fReference;
211     uint64_t* pTimers;
212 };
213 
214 struct SOptionDesc
215 {
SOptionDescSOptionDesc216     SOptionDesc(){}
SOptionDescSOptionDesc217     SOptionDesc(uint8_t nSubType, uint8_t nIndex, const char* fmt, ...):nSubType(nSubType), nIndex(nIndex)
218     {
219         va_list args;
220         va_start (args, fmt);
221         vsprintf(Text, fmt, args);
222         va_end(args);
223     }
224     char Text[32];
225     uint8_t nSubType;
226     uint8_t nIndex;
227     bool bSelected;
228 };
229 static const std::array<uint32_t, 6> g_MicroProfileAggregatePresets{0, 10, 20, 30, 60, 120};
230 static const std::array<float, 10> g_MicroProfileReferenceTimePresets{5.f, 10.f, 15.f,20.f, 33.33f, 66.66f, 100.f, 250.f, 500.f, 1000.f};
231 static const std::array<uint32_t, 4> g_MicroProfileOpacityPresets{0x40, 0x80, 0xc0, 0xff};
232 static const std::array<const char*, 7> g_MicroProfilePresetNames
233 {
234     MICROPROFILE_DEFAULT_PRESET,
235     "Render",
236     "GPU",
237     "Lighting",
238     "AI",
239     "Visibility",
240     "Sound",
241 };
242 
243 enum
244 {
245     MICROPROFILE_NUM_REFERENCE_PRESETS = g_MicroProfileReferenceTimePresets.size(),
246     MICROPROFILE_NUM_OPACITY_PRESETS = g_MicroProfileOpacityPresets.size(),
247 #if MICROPROFILE_CONTEXT_SWITCH_TRACE
248     MICROPROFILE_OPTION_SIZE = MICROPROFILE_NUM_REFERENCE_PRESETS + MICROPROFILE_NUM_OPACITY_PRESETS * 2 + 2 + 7,
249 #else
250     MICROPROFILE_OPTION_SIZE = MICROPROFILE_NUM_REFERENCE_PRESETS + MICROPROFILE_NUM_OPACITY_PRESETS * 2 + 2 + 3,
251 #endif
252 };
253 
254 struct MicroProfileUI
255 {
256     //menu/mouse over stuff
257     uint64_t nHoverToken;
258     int64_t  nHoverTime;
259     int      nHoverFrame;
260 #if MICROPROFILE_DEBUG
261     uint64_t nHoverAddressEnter;
262     uint64_t nHoverAddressLeave;
263 #endif
264 
265     uint32_t nWidth;
266     uint32_t nHeight;
267 
268 
269     int nOffsetX;
270     int nOffsetY;
271     float fDetailedOffset; //display offset relative to start of latest displayable frame.
272     float fDetailedRange; //no. of ms to display
273     float fDetailedOffsetTarget;
274     float fDetailedRangeTarget;
275     uint32_t nOpacityBackground;
276     uint32_t nOpacityForeground;
277     bool bShowSpikes;
278 
279 
280 
281     uint32_t                nMouseX;
282     uint32_t                nMouseY;
283     uint32_t                nMouseDownX;
284     uint32_t                nMouseDownY;
285     int                     nMouseWheelDelta;
286     uint32_t                nMouseDownLeft;
287     uint32_t                nMouseDownRight;
288     uint32_t                nMouseLeft;
289     uint32_t                nMouseRight;
290     uint32_t                nMouseLeftMod;
291     uint32_t                nMouseRightMod;
292     uint32_t                nModDown;
293     uint32_t                nActiveMenu;
294 
295     MicroProfileLogEntry* pDisplayMouseOver;
296 
297     int64_t                 nRangeBegin;
298     int64_t                 nRangeEnd;
299     int64_t                 nRangeBeginGpu;
300     int64_t                 nRangeEndGpu;
301     uint32_t                nRangeBeginIndex;
302     uint32_t                nRangeEndIndex;
303     MicroProfileThreadLog*  pRangeLog;
304     uint32_t                nHoverColor;
305     uint32_t                nHoverColorShared;
306 
307     MicroProfileStringArray LockedToolTips[MICROPROFILE_TOOLTIP_MAX_LOCKED];
308     uint32_t                nLockedToolTipColor[MICROPROFILE_TOOLTIP_MAX_LOCKED];
309     int                     LockedToolTipFront;
310 
311     MicroProfileGroupMenuItem   GroupMenu[MICROPROFILE_MAX_GROUPS + MICROPROFILE_MAX_CATEGORIES];
312     uint32_t                    GroupMenuCount;
313 
314 
315     uint32_t                    nCustomActive;
316     uint32_t                    nCustomTimerCount;
317     uint32_t                    nCustomCount;
318     MicroProfileCustom          Custom[MICROPROFILE_CUSTOM_MAX];
319     uint64_t                    CustomTimer[MICROPROFILE_CUSTOM_MAX_TIMERS];
320 
321     SOptionDesc Options[MICROPROFILE_OPTION_SIZE];
322 
323 
324 };
325 
326 MicroProfileUI g_MicroProfileUI;
327 #define UI g_MicroProfileUI
328 static const std::array<uint32_t, 2> g_nMicroProfileBackColors{  0x474747, 0x313131 };
329 #define MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS 16
330 static const std::array<uint32_t, MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS> g_nMicroProfileContextSwitchThreadColors //palette generated by http://tools.medialab.sciences-po.fr/iwanthue/index.php
331 {
332     0x63607B,
333     0x755E2B,
334     0x326A55,
335     0x523135,
336     0x904F42,
337     0x87536B,
338     0x346875,
339     0x5E6046,
340     0x35404C,
341     0x224038,
342     0x413D1E,
343     0x5E3A26,
344     0x5D6161,
345     0x4C6234,
346     0x7D564F,
347     0x5C4352,
348 };
349 
350 
MicroProfileInitUI()351 void MicroProfileInitUI()
352 {
353     static bool bInitialized = false;
354     if(!bInitialized)
355     {
356         bInitialized = true;
357         memset(&g_MicroProfileUI, 0, sizeof(g_MicroProfileUI));
358         UI.nActiveMenu = UINT32_MAX;
359         UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f;
360         UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f;
361 
362         UI.nOpacityBackground = 0xff<<24;
363         UI.nOpacityForeground = 0xff<<24;
364 
365         UI.bShowSpikes = false;
366 
367         UI.nWidth = 100;
368         UI.nHeight = 100;
369 
370         UI.nCustomActive = UINT32_MAX;
371         UI.nCustomTimerCount = 0;
372         UI.nCustomCount = 0;
373 
374         int nIndex = 0;
375         UI.Options[nIndex++] = SOptionDesc(0xff, 0, "%s", "Reference");
376         for(int i = 0; i < MICROPROFILE_NUM_REFERENCE_PRESETS; ++i)
377         {
378             UI.Options[nIndex++] = SOptionDesc(0, i, "  %6.2fms", g_MicroProfileReferenceTimePresets[i]);
379         }
380         UI.Options[nIndex++] = SOptionDesc(0xff, 0, "%s", "BG Opacity");
381         for(int i = 0; i < MICROPROFILE_NUM_OPACITY_PRESETS; ++i)
382         {
383             UI.Options[nIndex++] = SOptionDesc(1, i, "  %7d%%", (i+1)*25);
384         }
385         UI.Options[nIndex++] = SOptionDesc(0xff, 0, "%s", "FG Opacity");
386         for(int i = 0; i < MICROPROFILE_NUM_OPACITY_PRESETS; ++i)
387         {
388             UI.Options[nIndex++] = SOptionDesc(2, i, "  %7d%%", (i+1)*25);
389         }
390         UI.Options[nIndex++] = SOptionDesc(0xff, 0, "%s", "Spike Display");
391         UI.Options[nIndex++] = SOptionDesc(3, 0, "%s", "  Enable");
392 
393 #if MICROPROFILE_CONTEXT_SWITCH_TRACE
394         UI.Options[nIndex++] = SOptionDesc(0xff, 0, "%s", "CSwitch Trace");
395         UI.Options[nIndex++] = SOptionDesc(4, 0, "%s", "  Enable");
396         UI.Options[nIndex++] = SOptionDesc(4, 1, "%s", "  All Threads");
397         UI.Options[nIndex++] = SOptionDesc(4, 2, "%s", "  No Bars");
398 #endif
399         MP_ASSERT(nIndex == MICROPROFILE_OPTION_SIZE);
400     }
401 }
402 
MicroProfileSetDisplayMode(int nValue)403 void MicroProfileSetDisplayMode(int nValue)
404 {
405     MicroProfile& S = *MicroProfileGet();
406     nValue = nValue >= 0 && nValue < 4 ? nValue : S.nDisplay;
407     S.nDisplay = nValue;
408     UI.nOffsetY = 0;
409 }
410 
MicroProfileToggleDisplayMode()411 void MicroProfileToggleDisplayMode()
412 {
413     MicroProfile& S = *MicroProfileGet();
414     S.nDisplay = (S.nDisplay + 1) % 4;
415     UI.nOffsetY = 0;
416 }
417 
418 
MicroProfileStringArrayClear(MicroProfileStringArray * pArray)419 void MicroProfileStringArrayClear(MicroProfileStringArray* pArray)
420 {
421     pArray->nNumStrings = 0;
422     pArray->pBufferPos = &pArray->Buffer[0];
423 }
424 
MicroProfileStringArrayAddLiteral(MicroProfileStringArray * pArray,const char * pLiteral)425 void MicroProfileStringArrayAddLiteral(MicroProfileStringArray* pArray, const char* pLiteral)
426 {
427     MP_ASSERT(pArray->nNumStrings < MICROPROFILE_TOOLTIP_MAX_STRINGS);
428     pArray->ppStrings[pArray->nNumStrings++] = pLiteral;
429 }
430 
MicroProfileStringArrayFormat(MicroProfileStringArray * pArray,const char * fmt,...)431 void MicroProfileStringArrayFormat(MicroProfileStringArray* pArray, const char* fmt, ...)
432 {
433     MP_ASSERT(pArray->nNumStrings < MICROPROFILE_TOOLTIP_MAX_STRINGS);
434     pArray->ppStrings[pArray->nNumStrings++] = pArray->pBufferPos;
435     va_list args;
436     va_start (args, fmt);
437     pArray->pBufferPos += 1 + vsprintf(pArray->pBufferPos, fmt, args);
438     va_end(args);
439     MP_ASSERT(pArray->pBufferPos < pArray->Buffer + MICROPROFILE_TOOLTIP_STRING_BUFFER_SIZE);
440 }
MicroProfileStringArrayCopy(MicroProfileStringArray * pDest,MicroProfileStringArray * pSrc)441 void MicroProfileStringArrayCopy(MicroProfileStringArray* pDest, MicroProfileStringArray* pSrc)
442 {
443     memcpy(&pDest->ppStrings[0], &pSrc->ppStrings[0], sizeof(pDest->ppStrings));
444     memcpy(&pDest->Buffer[0], &pSrc->Buffer[0], sizeof(pDest->Buffer));
445     for(uint32_t i = 0; i < MICROPROFILE_TOOLTIP_MAX_STRINGS; ++i)
446     {
447         if(i < pSrc->nNumStrings)
448         {
449             if(pSrc->ppStrings[i] >= &pSrc->Buffer[0] && pSrc->ppStrings[i] < &pSrc->Buffer[0] + MICROPROFILE_TOOLTIP_STRING_BUFFER_SIZE)
450             {
451                 pDest->ppStrings[i] += &pDest->Buffer[0] - &pSrc->Buffer[0];
452             }
453         }
454     }
455     pDest->nNumStrings = pSrc->nNumStrings;
456 }
457 
458 void MicroProfileFloatWindowSize(const char** ppStrings, uint32_t nNumStrings, uint32_t* pColors, uint32_t& nWidth, uint32_t& nHeight, uint32_t* pStringLengths = 0)
459 {
460     uint32_t* nStringLengths = pStringLengths ? pStringLengths : (uint32_t*)alloca(nNumStrings * sizeof(uint32_t));
461     uint32_t nTextCount = nNumStrings/2;
462     for(uint32_t i = 0; i < nTextCount; ++i)
463     {
464         uint32_t i0 = i * 2;
465         uint32_t s0, s1;
466         nStringLengths[i0] = s0 = (uint32_t)strlen(ppStrings[i0]);
467         nStringLengths[i0+1] = s1 = (uint32_t)strlen(ppStrings[i0+1]);
468         nWidth = MicroProfileMax(s0+s1, nWidth);
469     }
470     nWidth = (MICROPROFILE_TEXT_WIDTH+1) * (2+nWidth) + 2 * MICROPROFILE_BORDER_SIZE;
471     if(pColors)
472         nWidth += MICROPROFILE_TEXT_WIDTH + 1;
473     nHeight = (MICROPROFILE_TEXT_HEIGHT+1) * nTextCount + 2 * MICROPROFILE_BORDER_SIZE;
474 }
475 
476 void MicroProfileDrawFloatWindow(uint32_t nX, uint32_t nY, const char** ppStrings, uint32_t nNumStrings, uint32_t nColor, uint32_t* pColors = 0)
477 {
478     uint32_t nWidth = 0, nHeight = 0;
479     uint32_t* nStringLengths = (uint32_t*)alloca(nNumStrings * sizeof(uint32_t));
480     MicroProfileFloatWindowSize(ppStrings, nNumStrings, pColors, nWidth, nHeight, nStringLengths);
481     uint32_t nTextCount = nNumStrings/2;
482     if(nX + nWidth > UI.nWidth)
483         nX = UI.nWidth - nWidth;
484     if(nY + nHeight > UI.nHeight)
485         nY = UI.nHeight - nHeight;
486     MicroProfileDrawBox(nX-1, nY-1, nX + nWidth+1, nY + nHeight+1, 0xff000000|nColor);
487     MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000);
488     if(pColors)
489     {
490         nX += MICROPROFILE_TEXT_WIDTH+1;
491         nWidth -= MICROPROFILE_TEXT_WIDTH+1;
492     }
493     for(uint32_t i = 0; i < nTextCount; ++i)
494     {
495         int i0 = i * 2;
496         if(pColors)
497         {
498             MicroProfileDrawBox(nX-MICROPROFILE_TEXT_WIDTH, nY, nX, nY + MICROPROFILE_TEXT_WIDTH, pColors[i]|0xff000000);
499         }
500         MicroProfileDrawText(nX + 1, nY + 1, UINT32_MAX, ppStrings[i0], (uint32_t)strlen(ppStrings[i0]));
501         MicroProfileDrawText(nX + nWidth - nStringLengths[i0+1] * (MICROPROFILE_TEXT_WIDTH+1), nY + 1, UINT32_MAX, ppStrings[i0+1], (uint32_t)strlen(ppStrings[i0+1]));
502         nY += (MICROPROFILE_TEXT_HEIGHT+1);
503     }
504 }
505 void MicroProfileDrawTextBox(uint32_t nX, uint32_t nY, const char** ppStrings, uint32_t nNumStrings, uint32_t nColor, uint32_t* pColors = 0)
506 {
507     uint32_t nWidth = 0, nHeight = 0;
508     uint32_t* nStringLengths = (uint32_t*)alloca(nNumStrings * sizeof(uint32_t));
509     for(uint32_t i = 0; i < nNumStrings; ++i)
510     {
511         nStringLengths[i] = (uint32_t)strlen(ppStrings[i]);
512         nWidth = MicroProfileMax(nWidth, nStringLengths[i]);
513         nHeight++;
514     }
515     nWidth = (MICROPROFILE_TEXT_WIDTH+1) * (2+nWidth) + 2 * MICROPROFILE_BORDER_SIZE;
516     nHeight = (MICROPROFILE_TEXT_HEIGHT+1) * nHeight + 2 * MICROPROFILE_BORDER_SIZE;
517     if(nX + nWidth > UI.nWidth)
518         nX = UI.nWidth - nWidth;
519     if(nY + nHeight > UI.nHeight)
520         nY = UI.nHeight - nHeight;
521     MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000);
522     for(uint32_t i = 0; i < nNumStrings; ++i)
523     {
524         MicroProfileDrawText(nX + 1, nY + 1, UINT32_MAX, ppStrings[i], (uint32_t)strlen(ppStrings[i]));
525         nY += (MICROPROFILE_TEXT_HEIGHT+1);
526     }
527 }
528 
529 
530 
MicroProfileToolTipMeta(MicroProfileStringArray * pToolTip)531 void MicroProfileToolTipMeta(MicroProfileStringArray* pToolTip)
532 {
533     MicroProfile& S = *MicroProfileGet();
534     if(UI.nRangeBeginIndex != UI.nRangeEndIndex && UI.pRangeLog)
535     {
536         uint64_t nMetaSum[MICROPROFILE_META_MAX] = {0};
537         uint64_t nMetaSumInclusive[MICROPROFILE_META_MAX] = {0};
538         int nStackDepth = 0;
539         uint32_t nRange[2][2];
540         MicroProfileThreadLog* pLog = UI.pRangeLog;
541 
542 
543         MicroProfileGetRange(UI.nRangeEndIndex, UI.nRangeBeginIndex, nRange);
544         for(uint32_t i = 0; i < 2; ++i)
545         {
546             uint32_t nStart = nRange[i][0];
547             uint32_t nEnd = nRange[i][1];
548             for(uint32_t j = nStart; j < nEnd; ++j)
549             {
550                 MicroProfileLogEntry LE = pLog->Log[j];
551                 int nType = MicroProfileLogType(LE);
552                 switch(nType)
553                 {
554                 case MP_LOG_META:
555                     {
556                         int64_t nMetaIndex = MicroProfileLogTimerIndex(LE);
557                         int64_t nMetaCount = MicroProfileLogGetTick(LE);
558                         MP_ASSERT(nMetaIndex < MICROPROFILE_META_MAX);
559                         if(nStackDepth>1)
560                         {
561                             nMetaSumInclusive[nMetaIndex] += nMetaCount;
562                         }
563                         else
564                         {
565                             nMetaSum[nMetaIndex] += nMetaCount;
566                         }
567                     }
568                     break;
569                 case MP_LOG_LEAVE:
570                     if(nStackDepth)
571                     {
572                         nStackDepth--;
573                     }
574                     else
575                     {
576                         for(int i = 0; i < MICROPROFILE_META_MAX; ++i)
577                         {
578                             nMetaSumInclusive[i] += nMetaSum[i];
579                             nMetaSum[i] = 0;
580                         }
581                     }
582                     break;
583                 case MP_LOG_ENTER:
584                     nStackDepth++;
585                     break;
586                 }
587 
588             }
589         }
590         bool bSpaced = false;
591         for(int i = 0; i < MICROPROFILE_META_MAX; ++i)
592         {
593             if(S.MetaCounters[i].pName && (nMetaSum[i]||nMetaSumInclusive[i]))
594             {
595                 if(!bSpaced)
596                 {
597                     bSpaced = true;
598                     MicroProfileStringArrayAddLiteral(pToolTip, "");
599                     MicroProfileStringArrayAddLiteral(pToolTip, "");
600                 }
601                 MicroProfileStringArrayFormat(pToolTip, "%s excl", S.MetaCounters[i].pName);
602                 MicroProfileStringArrayFormat(pToolTip, "%5d", nMetaSum[i]);
603                 MicroProfileStringArrayFormat(pToolTip, "%s incl", S.MetaCounters[i].pName);
604                 MicroProfileStringArrayFormat(pToolTip, "%5d", nMetaSum[i] + nMetaSumInclusive[i]);
605             }
606         }
607     }
608 }
609 
MicroProfileDrawFloatTooltip(uint32_t nX,uint32_t nY,uint32_t nToken,uint64_t nTime)610 void MicroProfileDrawFloatTooltip(uint32_t nX, uint32_t nY, uint32_t nToken, uint64_t nTime)
611 {
612     MicroProfile& S = *MicroProfileGet();
613 
614     uint32_t nIndex = MicroProfileGetTimerIndex(nToken);
615     uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
616     uint32_t nAggregateCount = S.Aggregate[nIndex].nCount ? S.Aggregate[nIndex].nCount : 1;
617 
618     uint32_t nGroupId = MicroProfileGetGroupIndex(nToken);
619     uint32_t nTimerId = MicroProfileGetTimerIndex(nToken);
620     bool bGpu = S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu;
621 
622     float fToMs = MicroProfileTickToMsMultiplier(bGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
623 
624     float fMs = fToMs * (nTime);
625     float fFrameMs = fToMs * (S.Frame[nIndex].nTicks);
626     float fAverage = fToMs * (S.Aggregate[nIndex].nTicks/nAggregateFrames);
627     float fCallAverage = fToMs * (S.Aggregate[nIndex].nTicks / nAggregateCount);
628     float fMax = fToMs * (S.AggregateMax[nIndex]);
629 
630     float fFrameMsExclusive = fToMs * (S.FrameExclusive[nIndex]);
631     float fAverageExclusive = fToMs * (S.AggregateExclusive[nIndex]/nAggregateFrames);
632     float fMaxExclusive = fToMs * (S.AggregateMaxExclusive[nIndex]);
633 
634     float fGroupAverage = fToMs * (S.AggregateGroup[nGroupId] / nAggregateFrames);
635     float fGroupMax = fToMs * (S.AggregateGroupMax[nGroupId]);
636     float fGroup = fToMs * (S.FrameGroup[nGroupId]);
637 
638 
639     MicroProfileStringArray ToolTip;
640     MicroProfileStringArrayClear(&ToolTip);
641     const char* pGroupName = S.GroupInfo[nGroupId].pName;
642     const char* pTimerName = S.TimerInfo[nTimerId].pName;
643     MicroProfileStringArrayAddLiteral(&ToolTip, "Timer:");
644     MicroProfileStringArrayFormat(&ToolTip, "%s", pTimerName);
645 
646 #if MICROPROFILE_DEBUG
647     MicroProfileStringArrayFormat(&ToolTip,"0x%p", UI.nHoverAddressEnter);
648     MicroProfileStringArrayFormat(&ToolTip,"0x%p", UI.nHoverAddressLeave);
649 #endif
650 
651     if(nTime != (uint64_t)0)
652     {
653         MicroProfileStringArrayAddLiteral(&ToolTip, "Time:");
654         MicroProfileStringArrayFormat(&ToolTip,"%6.3fms",  fMs);
655         MicroProfileStringArrayAddLiteral(&ToolTip, "");
656         MicroProfileStringArrayAddLiteral(&ToolTip, "");
657     }
658 
659     MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Time:");
660     MicroProfileStringArrayFormat(&ToolTip,"%6.3fms",  fFrameMs);
661 
662     MicroProfileStringArrayAddLiteral(&ToolTip, "Average:");
663     MicroProfileStringArrayFormat(&ToolTip,"%6.3fms",  fAverage);
664 
665     MicroProfileStringArrayAddLiteral(&ToolTip, "Max:");
666     MicroProfileStringArrayFormat(&ToolTip,"%6.3fms",  fMax);
667 
668     MicroProfileStringArrayAddLiteral(&ToolTip, "");
669     MicroProfileStringArrayAddLiteral(&ToolTip, "");
670 
671     MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Call Average:");
672     MicroProfileStringArrayFormat(&ToolTip,"%6.3fms",  fCallAverage);
673 
674     MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Call Count:");
675     MicroProfileStringArrayFormat(&ToolTip, "%6d",  nAggregateCount / nAggregateFrames);
676 
677     MicroProfileStringArrayAddLiteral(&ToolTip, "");
678     MicroProfileStringArrayAddLiteral(&ToolTip, "");
679 
680     MicroProfileStringArrayAddLiteral(&ToolTip, "Exclusive Frame Time:");
681     MicroProfileStringArrayFormat(&ToolTip, "%6.3fms",  fFrameMsExclusive);
682 
683     MicroProfileStringArrayAddLiteral(&ToolTip, "Exclusive Average:");
684     MicroProfileStringArrayFormat(&ToolTip, "%6.3fms",  fAverageExclusive);
685 
686     MicroProfileStringArrayAddLiteral(&ToolTip, "Exclusive Max:");
687     MicroProfileStringArrayFormat(&ToolTip, "%6.3fms",  fMaxExclusive);
688 
689     MicroProfileStringArrayAddLiteral(&ToolTip, "");
690     MicroProfileStringArrayAddLiteral(&ToolTip, "");
691 
692     MicroProfileStringArrayAddLiteral(&ToolTip, "Group:");
693     MicroProfileStringArrayFormat(&ToolTip, "%s", pGroupName);
694     MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Time:");
695     MicroProfileStringArrayFormat(&ToolTip, "%6.3f", fGroup);
696     MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Average:");
697     MicroProfileStringArrayFormat(&ToolTip, "%6.3f", fGroupAverage);
698     MicroProfileStringArrayAddLiteral(&ToolTip, "Frame Max:");
699     MicroProfileStringArrayFormat(&ToolTip, "%6.3f", fGroupMax);
700 
701 
702 
703 
704     MicroProfileToolTipMeta(&ToolTip);
705 
706 
707     MicroProfileDrawFloatWindow(nX, nY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, S.TimerInfo[nTimerId].nColor);
708 
709     if(UI.nMouseLeftMod)
710     {
711         int nIndex = (g_MicroProfileUI.LockedToolTipFront + MICROPROFILE_TOOLTIP_MAX_LOCKED - 1) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
712         g_MicroProfileUI.nLockedToolTipColor[nIndex] = S.TimerInfo[nTimerId].nColor;
713         MicroProfileStringArrayCopy(&g_MicroProfileUI.LockedToolTips[nIndex], &ToolTip);
714         g_MicroProfileUI.LockedToolTipFront = nIndex;
715 
716     }
717 }
718 
719 
MicroProfileZoomTo(int64_t nTickStart,int64_t nTickEnd)720 void MicroProfileZoomTo(int64_t nTickStart, int64_t nTickEnd)
721 {
722     MicroProfile& S = *MicroProfileGet();
723 
724     int64_t nStart = S.Frames[S.nFrameCurrent].nFrameStartCpu;
725     float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
726     UI.fDetailedOffsetTarget = MicroProfileLogTickDifference(nStart, nTickStart) * fToMs;
727     UI.fDetailedRangeTarget = MicroProfileLogTickDifference(nTickStart, nTickEnd) * fToMs;
728 }
729 
MicroProfileCenter(int64_t nTickCenter)730 void MicroProfileCenter(int64_t nTickCenter)
731 {
732     MicroProfile& S = *MicroProfileGet();
733     int64_t nStart = S.Frames[S.nFrameCurrent].nFrameStartCpu;
734     float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
735     float fCenter = MicroProfileLogTickDifference(nStart, nTickCenter) * fToMs;
736     UI.fDetailedOffsetTarget = UI.fDetailedOffset = fCenter - 0.5f * UI.fDetailedRange;
737 }
738 #ifdef MICROPROFILE_DEBUG
739 uint64_t* g_pMicroProfileDumpStart = 0;
740 uint64_t* g_pMicroProfileDumpEnd = 0;
MicroProfileDebugDumpRange()741 void MicroProfileDebugDumpRange()
742 {
743     MicroProfile& S = *MicroProfileGet();
744     if(g_pMicroProfileDumpStart != g_pMicroProfileDumpEnd)
745     {
746         uint64_t* pStart = g_pMicroProfileDumpStart;
747         uint64_t* pEnd = g_pMicroProfileDumpEnd;
748         while(pStart != pEnd)
749         {
750             uint64_t nTick = MicroProfileLogGetTick(*pStart);
751             uint64_t nToken = MicroProfileLogTimerIndex(*pStart);
752             uint32_t nTimerId = MicroProfileGetTimerIndex(nToken);
753 
754             const char* pTimerName = S.TimerInfo[nTimerId].pName;
755             char buffer[256];
756             int type = MicroProfileLogType(*pStart);
757 
758             const char* pBegin = type == MP_LOG_LEAVE ? "END" :
759                 (type == MP_LOG_ENTER ? "BEGIN" : "META");
760             snprintf(buffer, 255, "DUMP 0x%p: %s :: %llx: %s\n", pStart, pBegin,  nTick, pTimerName);
761 #ifdef _WIN32
762             OutputDebugString(buffer);
763 #else
764             printf("%s", buffer);
765 #endif
766             pStart++;
767         }
768 
769         g_pMicroProfileDumpStart = g_pMicroProfileDumpEnd;
770     }
771 }
772 #define MP_DEBUG_DUMP_RANGE() MicroProfileDebugDumpRange();
773 #else
774 #define MP_DEBUG_DUMP_RANGE() do{} while(0)
775 #endif
776 
777 #define MICROPROFILE_HOVER_DIST 0.5f
778 
MicroProfileDrawDetailedContextSwitchBars(uint32_t nY,uint32_t nThreadId,uint32_t nContextSwitchStart,uint32_t nContextSwitchEnd,int64_t nBaseTicks,uint32_t nBaseY)779 void MicroProfileDrawDetailedContextSwitchBars(uint32_t nY, uint32_t nThreadId, uint32_t nContextSwitchStart, uint32_t nContextSwitchEnd, int64_t nBaseTicks, uint32_t nBaseY)
780 {
781     MicroProfile& S = *MicroProfileGet();
782     int64_t nTickIn = -1;
783     uint32_t nThreadBefore = UINT32_MAX;
784     float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
785     float fMsToScreen = UI.nWidth / UI.fDetailedRange;
786     float fMouseX = (float)UI.nMouseX;
787     float fMouseY = (float)UI.nMouseY;
788 
789 
790     for(uint32_t j = nContextSwitchStart; j != nContextSwitchEnd; j = (j+1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE)
791     {
792         MP_ASSERT(j < MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE);
793         MicroProfileContextSwitch CS = S.ContextSwitch[j];
794 
795         if(nTickIn == -1)
796         {
797             if(CS.nThreadIn == nThreadId)
798             {
799                 nTickIn = CS.nTicks;
800                 nThreadBefore = CS.nThreadOut;
801             }
802         }
803         else
804         {
805             if(CS.nThreadOut == nThreadId)
806             {
807                 int64_t nTickOut = CS.nTicks;
808                 float fMsStart = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickIn);
809                 float fMsEnd = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickOut);
810                 if(fMsStart <= fMsEnd)
811                 {
812                     float fXStart = fMsStart * fMsToScreen;
813                     float fXEnd = fMsEnd * fMsToScreen;
814                     float fYStart = (float)nY;
815                     float fYEnd = fYStart + (MICROPROFILE_DETAILED_CONTEXT_SWITCH_HEIGHT);
816                     uint32_t nColor = g_nMicroProfileContextSwitchThreadColors[CS.nCpu%MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS];
817                     float fXDist = MicroProfileMax(fXStart - fMouseX, fMouseX - fXEnd);
818                     bool bHover = fXDist < MICROPROFILE_HOVER_DIST && fYStart <= fMouseY && fMouseY <= fYEnd && nBaseY < fMouseY;
819                     if(bHover)
820                     {
821                         UI.nRangeBegin = nTickIn;
822                         UI.nRangeEnd = nTickOut;
823                         S.nContextSwitchHoverTickIn = nTickIn;
824                         S.nContextSwitchHoverTickOut = nTickOut;
825                         S.nContextSwitchHoverThread = CS.nThreadOut;
826                         S.nContextSwitchHoverThreadBefore = nThreadBefore;
827                         S.nContextSwitchHoverThreadAfter = CS.nThreadIn;
828                         S.nContextSwitchHoverCpuNext = CS.nCpu;
829                         nColor = UI.nHoverColor;
830                     }
831                     if(CS.nCpu == S.nContextSwitchHoverCpu)
832                     {
833                         nColor = UI.nHoverColorShared;
834                     }
835                     MicroProfileDrawBox(fXStart, fYStart, fXEnd, fYEnd, nColor|UI.nOpacityForeground, MicroProfileBoxTypeFlat);
836                 }
837                 nTickIn = -1;
838             }
839         }
840     }
841 }
842 
MicroProfileDrawDetailedBars(uint32_t nWidth,uint32_t nHeight,int nBaseY,int nSelectedFrame)843 void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int nBaseY, int nSelectedFrame)
844 {
845     MicroProfile& S = *MicroProfileGet();
846     MP_DEBUG_DUMP_RANGE();
847     int nY = nBaseY - UI.nOffsetY;
848     int64_t nNumBoxes = 0;
849     int64_t nNumLines = 0;
850 
851     uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
852     MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
853     MicroProfileFrameState* pFrameNext = &S.Frames[nFrameNext];
854 
855     UI.nRangeBegin = 0;
856     UI.nRangeEnd = 0;
857     UI.nRangeBeginGpu = 0;
858     UI.nRangeEndGpu = 0;
859     UI.nRangeBeginIndex = UI.nRangeEndIndex = 0;
860     UI.pRangeLog = 0;
861     int64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu;
862     int64_t nFrameStartGpu = pFrameCurrent->nFrameStartGpu;
863     int64_t nTicksPerSecondCpu = MicroProfileTicksPerSecondCpu();
864     int64_t nTicksPerSecondGpu = MicroProfileTicksPerSecondGpu();
865     float fToMsCpu = MicroProfileTickToMsMultiplier(nTicksPerSecondCpu);
866     float fToMsGpu = MicroProfileTickToMsMultiplier(nTicksPerSecondGpu);
867 
868     float fDetailedOffset = UI.fDetailedOffset;
869     float fDetailedRange = UI.fDetailedRange;
870 
871 
872     int64_t nDetailedOffsetTicksCpu = MicroProfileMsToTick(fDetailedOffset, MicroProfileTicksPerSecondCpu());
873     int64_t nDetailedOffsetTicksGpu = MicroProfileMsToTick(fDetailedOffset, MicroProfileTicksPerSecondGpu());
874     int64_t nBaseTicksCpu = nDetailedOffsetTicksCpu + nFrameStartCpu;
875     int64_t nBaseTicksGpu = nDetailedOffsetTicksGpu + nFrameStartGpu;
876     int64_t nBaseTicksEndCpu = nBaseTicksCpu + MicroProfileMsToTick(fDetailedRange, MicroProfileTicksPerSecondCpu());
877 
878     int64_t nTickReferenceCpu = 0, nTickReferenceGpu = 0;
879     static int64_t nRefCpu = 0, nRefGpu = 0;
880     if(MicroProfileGetGpuTickReference(&nTickReferenceCpu, &nTickReferenceGpu))
881     {
882         if(0 == nRefCpu || std::abs(nRefCpu-nBaseTicksCpu) > std::abs(nTickReferenceCpu-nBaseTicksCpu))
883         {
884             nRefCpu = nTickReferenceCpu;
885             nRefGpu = nTickReferenceGpu;
886         }
887         else
888         {
889             nTickReferenceCpu = nRefCpu;
890             nTickReferenceGpu = nRefGpu;
891         }
892         nBaseTicksGpu = (nBaseTicksCpu - nTickReferenceCpu) * nTicksPerSecondGpu / nTicksPerSecondCpu + nTickReferenceGpu;
893     }
894     int64_t nBaseTicksEndGpu = nBaseTicksCpu + MicroProfileMsToTick(fDetailedRange, MicroProfileTicksPerSecondCpu());
895 
896     MicroProfileFrameState* pFrameFirst = pFrameCurrent;
897     int64_t nGapTime = MicroProfileTicksPerSecondCpu() * MICROPROFILE_GAP_TIME / 1000;
898     for(uint32_t i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY; ++i)
899     {
900         uint32_t nNextIndex = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY;
901         pFrameFirst = &S.Frames[nNextIndex];
902         if(pFrameFirst->nFrameStartCpu <= nBaseTicksCpu-nGapTime)
903             break;
904     }
905 
906     float fMsBase = fToMsCpu * nDetailedOffsetTicksCpu;
907     float fMs = fDetailedRange;
908     float fMsEnd = fMs + fMsBase;
909     float fWidth = (float)nWidth;
910     float fMsToScreen = fWidth / fMs;
911 
912     {
913         float fRate = floor(2*(log10(fMs)-1))/2;
914         float fStep = powf(10.f, fRate);
915         float fRcpStep = 1.f / fStep;
916         int nColorIndex = (int)(floor(fMsBase*fRcpStep));
917         float fStart = floor(fMsBase*fRcpStep) * fStep;
918         for(float f = fStart; f < fMsEnd; )
919         {
920             float fStart = f;
921             float fNext = f + fStep;
922             MicroProfileDrawBox(((fStart-fMsBase) * fMsToScreen), nBaseY, (fNext-fMsBase) * fMsToScreen+1, nBaseY + nHeight, UI.nOpacityBackground | g_nMicroProfileBackColors[nColorIndex++ & 1]);
923             f = fNext;
924         }
925     }
926 
927     nY += MICROPROFILE_TEXT_HEIGHT+1;
928     MicroProfileLogEntry* pMouseOver = UI.pDisplayMouseOver;
929     MicroProfileLogEntry* pMouseOverNext = 0;
930     uint64_t nMouseOverToken = pMouseOver ? MicroProfileLogTimerIndex(*pMouseOver) : MICROPROFILE_INVALID_TOKEN;
931     float fMouseX = (float)UI.nMouseX;
932     float fMouseY = (float)UI.nMouseY;
933     uint64_t nHoverToken = MICROPROFILE_INVALID_TOKEN;
934     int64_t nHoverTime = 0;
935 
936     static int nHoverCounter = 155;
937     static int nHoverCounterDelta = 10;
938     nHoverCounter += nHoverCounterDelta;
939     if(nHoverCounter >= 245)
940         nHoverCounterDelta = -10;
941     else if(nHoverCounter < 100)
942         nHoverCounterDelta = 10;
943     UI.nHoverColor = (nHoverCounter<<24)|(nHoverCounter<<16)|(nHoverCounter<<8)|nHoverCounter;
944     uint32_t nHoverCounterShared = nHoverCounter>>2;
945     UI.nHoverColorShared = (nHoverCounterShared<<24)|(nHoverCounterShared<<16)|(nHoverCounterShared<<8)|nHoverCounterShared;
946 
947     uint32_t nLinesDrawn[MICROPROFILE_STACK_MAX]={0};
948 
949     uint32_t nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadAfter;
950     uint32_t nContextSwitchHoverThreadBefore = S.nContextSwitchHoverThreadBefore;
951     S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = UINT32_MAX;
952 
953     uint32_t nContextSwitchStart = UINT32_MAX;
954     uint32_t nContextSwitchEnd = UINT32_MAX;
955     S.nContextSwitchHoverCpuNext = 0xff;
956     S.nContextSwitchHoverTickIn = -1;
957     S.nContextSwitchHoverTickOut = -1;
958     if(S.bContextSwitchRunning)
959     {
960         MicroProfileContextSwitchSearch(&nContextSwitchStart, &nContextSwitchEnd, nBaseTicksCpu, nBaseTicksEndCpu);
961     }
962 
963     bool bSkipBarView = S.bContextSwitchRunning && S.bContextSwitchNoBars;
964 
965     if(!bSkipBarView)
966     {
967         for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
968         {
969             MicroProfileThreadLog* pLog = S.Pool[i];
970             if(!pLog)
971                 continue;
972 
973             uint32_t nPut = pFrameNext->nLogStart[i];
974             ///note: this may display new samples as old data, but this will only happen when
975             //       unpaused, where the detailed view is hardly perceptible
976             uint32_t nFront = S.Pool[i]->nPut.load(std::memory_order_relaxed);
977             MicroProfileFrameState* pFrameLogFirst = pFrameCurrent;
978             MicroProfileFrameState* pFrameLogLast = pFrameNext;
979             uint32_t nGet = pFrameLogFirst->nLogStart[i];
980             do
981             {
982                 MP_ASSERT(pFrameLogFirst >= &S.Frames[0] && pFrameLogFirst < &S.Frames[MICROPROFILE_MAX_FRAME_HISTORY]);
983                 uint32_t nNewGet = pFrameLogFirst->nLogStart[i];
984                 bool bIsValid = false;
985                 if(nPut < nFront)
986                 {
987                     bIsValid = nNewGet <= nPut || nNewGet >= nFront;
988                 }
989                 else
990                 {
991                     bIsValid = nNewGet <= nPut && nNewGet >= nFront;
992                 }
993                 if(bIsValid)
994                 {
995                     nGet = nNewGet;
996                     pFrameLogFirst--;
997                     if(pFrameLogFirst < &S.Frames[0])
998                         pFrameLogFirst = &S.Frames[MICROPROFILE_MAX_FRAME_HISTORY-1];
999                 }
1000                 else
1001                 {
1002                     break;
1003                 }
1004             }while(pFrameLogFirst != pFrameFirst);
1005 
1006 
1007             if (nGet == UINT32_MAX) {
1008                 continue;
1009             }
1010             MP_ASSERT(nGet != UINT32_MAX);
1011 
1012             nPut = pFrameLogLast->nLogStart[i];
1013 
1014             uint32_t nRange[2][2] = { {0, 0}, {0, 0}, };
1015 
1016             MicroProfileGetRange(nPut, nGet, nRange);
1017             if(nPut == nGet)
1018                 continue;
1019             uint32_t nMaxStackDepth = 0;
1020 
1021             bool bGpu = pLog->nGpu != 0;
1022             float fToMs = bGpu ? fToMsGpu : fToMsCpu;
1023             int64_t nBaseTicks = bGpu ? nBaseTicksGpu : nBaseTicksCpu;
1024             char ThreadName[MicroProfileThreadLog::THREAD_MAX_LEN + 16];
1025             uint64_t nThreadId = pLog->nThreadId;
1026             snprintf(ThreadName, sizeof(ThreadName)-1, "%04" PRIx64 ": %s", nThreadId, &pLog->ThreadName[0] );
1027             nY += 3;
1028             uint32_t nThreadColor = UINT32_MAX;
1029             if(pLog->nThreadId == nContextSwitchHoverThreadAfter || pLog->nThreadId == nContextSwitchHoverThreadBefore)
1030                 nThreadColor = UI.nHoverColorShared|0x906060;
1031             MicroProfileDrawText(0, nY, nThreadColor, &ThreadName[0], (uint32_t)strlen(&ThreadName[0]));
1032             nY += 3;
1033             nY += MICROPROFILE_TEXT_HEIGHT + 1;
1034 
1035             if(S.bContextSwitchRunning)
1036             {
1037                 MicroProfileDrawDetailedContextSwitchBars(nY, pLog->nThreadId, nContextSwitchStart, nContextSwitchEnd, nBaseTicks, nBaseY);
1038                 nY -= MICROPROFILE_DETAILED_BAR_HEIGHT;
1039                 nY += MICROPROFILE_DETAILED_CONTEXT_SWITCH_HEIGHT+1;
1040             }
1041 
1042             uint32_t nYDelta = MICROPROFILE_DETAILED_BAR_HEIGHT;
1043             uint32_t nStack[MICROPROFILE_STACK_MAX];
1044             uint32_t nStackPos = 0;
1045             for(uint32_t j = 0; j < 2; ++j)
1046             {
1047                 uint32_t nStart = nRange[j][0];
1048                 uint32_t nEnd = nRange[j][1];
1049                 for(uint32_t k = nStart; k < nEnd; ++k)
1050                 {
1051                     MicroProfileLogEntry* pEntry = &pLog->Log[k];
1052                     int nType = MicroProfileLogType(*pEntry);
1053                     if(MP_LOG_ENTER == nType)
1054                     {
1055                         MP_ASSERT(nStackPos < MICROPROFILE_STACK_MAX);
1056                         nStack[nStackPos++] = k;
1057                     }
1058                     else if(MP_LOG_META == nType)
1059                     {
1060 
1061                     }
1062                     else if(MP_LOG_LEAVE == nType)
1063                     {
1064                         if(0 == nStackPos)
1065                         {
1066                             continue;
1067                         }
1068 
1069                         MicroProfileLogEntry* pEntryEnter = &pLog->Log[nStack[nStackPos-1]];
1070                         if(MicroProfileLogTimerIndex(*pEntryEnter) != MicroProfileLogTimerIndex(*pEntry))
1071                         {
1072                             //uprintf("mismatch %llx %llx\n", pEntryEnter->nToken, pEntry->nToken);
1073                             continue;
1074                         }
1075                         int64_t nTickStart = MicroProfileLogGetTick(*pEntryEnter);
1076                         int64_t nTickEnd = MicroProfileLogGetTick(*pEntry);
1077                         uint64_t nTimerIndex = MicroProfileLogTimerIndex(*pEntry);
1078                         uint32_t nColor = S.TimerInfo[nTimerIndex].nColor;
1079                         if(nMouseOverToken == nTimerIndex)
1080                         {
1081                             if(pEntry == pMouseOver)
1082                             {
1083                                 nColor = UI.nHoverColor;
1084                                 if(bGpu)
1085                                 {
1086                                     UI.nRangeBeginGpu = *pEntryEnter;
1087                                     UI.nRangeEndGpu = *pEntry;
1088                                     uint32_t nCpuBegin = (nStack[nStackPos-1] + 1) % MICROPROFILE_BUFFER_SIZE;
1089                                     uint32_t nCpuEnd = (k + 1) % MICROPROFILE_BUFFER_SIZE;
1090                                     MicroProfileLogEntry LogCpuBegin = pLog->Log[nCpuBegin];
1091                                     MicroProfileLogEntry LogCpuEnd = pLog->Log[nCpuEnd];
1092                                     if(MicroProfileLogType(LogCpuBegin)==3 && MicroProfileLogType(LogCpuEnd) == 3)
1093                                     {
1094                                         UI.nRangeBegin = LogCpuBegin;
1095                                         UI.nRangeEnd = LogCpuEnd;
1096                                     }
1097                                     UI.nRangeBeginIndex = nStack[nStackPos-1];
1098                                     UI.nRangeEndIndex = k;
1099                                     UI.pRangeLog = pLog;
1100                                 }
1101                                 else
1102                                 {
1103                                     UI.nRangeBegin = *pEntryEnter;
1104                                     UI.nRangeEnd = *pEntry;
1105                                     UI.nRangeBeginIndex = nStack[nStackPos-1];
1106                                     UI.nRangeEndIndex = k;
1107                                     UI.pRangeLog = pLog;
1108 
1109                                 }
1110                             }
1111                             else
1112                             {
1113                                 nColor = UI.nHoverColorShared;
1114                             }
1115                         }
1116 
1117                         nMaxStackDepth = MicroProfileMax(nMaxStackDepth, nStackPos);
1118                         float fMsStart = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickStart);
1119                         float fMsEnd = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickEnd);
1120                         float fXStart = fMsStart * fMsToScreen;
1121                         float fXEnd = fMsEnd * fMsToScreen;
1122                         float fYStart = (float)(nY + nStackPos * nYDelta);
1123                         float fYEnd = fYStart + (MICROPROFILE_DETAILED_BAR_HEIGHT);
1124                         float fXDist = MicroProfileMax(fXStart - fMouseX, fMouseX - fXEnd);
1125                         bool bHover = fXDist < MICROPROFILE_HOVER_DIST && fYStart <= fMouseY && fMouseY <= fYEnd && nBaseY < fMouseY;
1126                         uint32_t nIntegerWidth = (uint32_t)(fXEnd - fXStart);
1127                         if(nIntegerWidth)
1128                         {
1129                             if(bHover && UI.nActiveMenu == UINT32_MAX)
1130                             {
1131                                 nHoverToken = MicroProfileLogTimerIndex(*pEntry);
1132     #if MICROPROFILE_DEBUG
1133                                 UI.nHoverAddressEnter = (uint64_t)pEntryEnter;
1134                                 UI.nHoverAddressLeave = (uint64_t)pEntry;
1135     #endif
1136                                 nHoverTime = MicroProfileLogTickDifference(nTickStart, nTickEnd);
1137                                 pMouseOverNext = pEntry;
1138                             }
1139 
1140                             MicroProfileDrawBox(fXStart, fYStart, fXEnd, fYEnd, nColor|UI.nOpacityForeground, MicroProfileBoxTypeBar);
1141 #if MICROPROFILE_DETAILED_BAR_NAMES
1142                             if(nIntegerWidth>3*MICROPROFILE_TEXT_WIDTH)
1143                             {
1144                                 float fXStartText = MicroProfileMax(fXStart, 0.f);
1145                                 int nTextWidth = (int)(fXEnd - fXStartText);
1146                                 int nCharacters = (nTextWidth - 2*MICROPROFILE_TEXT_WIDTH) / MICROPROFILE_TEXT_WIDTH;
1147                                 if(nCharacters>0)
1148                                 {
1149                                     MicroProfileDrawText(fXStartText + 1, fYStart + 1, UINT32_MAX, S.TimerInfo[nTimerIndex].pName, MicroProfileMin<uint32_t>(S.TimerInfo[nTimerIndex].nNameLen, nCharacters));
1150                                 }
1151                             }
1152 #endif
1153                             ++nNumBoxes;
1154                         }
1155                         else
1156                         {
1157                             float fXAvg = 0.5f * (fXStart + fXEnd);
1158                             int nLineX = (int)floor(fXAvg+0.5f);
1159                             if(nLineX != (int)nLinesDrawn[nStackPos])
1160                             {
1161                                 if(bHover && UI.nActiveMenu == UINT32_MAX)
1162                                 {
1163                                     nHoverToken = (uint32_t)MicroProfileLogTimerIndex(*pEntry);
1164                                     nHoverTime = MicroProfileLogTickDifference(nTickStart, nTickEnd);
1165                                     pMouseOverNext = pEntry;
1166                                 }
1167                                 nLinesDrawn[nStackPos] = nLineX;
1168                                 MicroProfileDrawLineVertical(nLineX, fYStart + 0.5f, fYEnd + 0.5f, nColor|UI.nOpacityForeground);
1169                                 ++nNumLines;
1170                             }
1171                         }
1172                         nStackPos--;
1173                         if(0 == nStackPos)
1174                         {
1175                             if(bGpu ? (nTickStart > nBaseTicksEndGpu) : (nTickStart > nBaseTicksEndCpu))
1176                             {
1177                                 break;
1178                             }
1179                         }
1180                     }
1181                 }
1182             }
1183             nY += nMaxStackDepth * nYDelta + MICROPROFILE_DETAILED_BAR_HEIGHT+1;
1184         }
1185     }
1186     if(S.bContextSwitchRunning && (S.bContextSwitchAllThreads||S.bContextSwitchNoBars))
1187     {
1188         uint32_t nNumThreads = 0;
1189         uint32_t nThreads[MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS];
1190         for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS && S.Pool[i]; ++i)
1191             nThreads[nNumThreads++] = S.Pool[i]->nThreadId;
1192         uint32_t nNumThreadsBase = nNumThreads;
1193         if(S.bContextSwitchAllThreads)
1194         {
1195             for(uint32_t i = nContextSwitchStart; i != nContextSwitchEnd; i = (i+1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE)
1196             {
1197                 MicroProfileContextSwitch CS = S.ContextSwitch[i];
1198                 ThreadIdType nThreadId = CS.nThreadIn;
1199                 if(nThreadId)
1200                 {
1201                     bool bSeen = false;
1202                     for(uint32_t j = 0; j < nNumThreads; ++j)
1203                     {
1204                         if(nThreads[j] == nThreadId)
1205                         {
1206                             bSeen = true;
1207                             break;
1208                         }
1209                     }
1210                     if(!bSeen)
1211                     {
1212                         nThreads[nNumThreads++] = nThreadId;
1213                     }
1214                 }
1215                 if(nNumThreads == MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS)
1216                 {
1217                     S.nOverflow = 10;
1218                     break;
1219                 }
1220             }
1221             std::sort(&nThreads[nNumThreadsBase], &nThreads[nNumThreads]);
1222         }
1223         uint32_t nStart = nNumThreadsBase;
1224         if(S.bContextSwitchNoBars)
1225             nStart = 0;
1226         for(uint32_t i = nStart; i < nNumThreads; ++i)
1227         {
1228             ThreadIdType nThreadId = nThreads[i];
1229             if(nThreadId)
1230             {
1231                 char ThreadName[MicroProfileThreadLog::THREAD_MAX_LEN + 16];
1232                 const char* cLocal = MicroProfileIsLocalThread(nThreadId) ? "*": " ";
1233 
1234 #if defined(_WIN32)
1235                 // nThreadId is 32-bit on Windows
1236                 int nStrLen = snprintf(ThreadName, sizeof(ThreadName)-1, "%04x: %s%s", nThreadId, cLocal, i < nNumThreadsBase ? &S.Pool[i]->ThreadName[0] : MICROPROFILE_THREAD_NAME_FROM_ID(nThreadId) );
1237 #else
1238                 int nStrLen = snprintf(ThreadName, sizeof(ThreadName)-1, "%04" PRIx64 ": %s%s", nThreadId, cLocal, i < nNumThreadsBase ? &S.Pool[i]->ThreadName[0] : MICROPROFILE_THREAD_NAME_FROM_ID(nThreadId) );
1239 #endif
1240                 uint32_t nThreadColor = UINT32_MAX;
1241                 if(nThreadId == nContextSwitchHoverThreadAfter || nThreadId == nContextSwitchHoverThreadBefore)
1242                     nThreadColor = UI.nHoverColorShared|0x906060;
1243                 MicroProfileDrawDetailedContextSwitchBars(nY+2, nThreadId, nContextSwitchStart, nContextSwitchEnd, nBaseTicksCpu, nBaseY);
1244                 MicroProfileDrawText(0, nY, nThreadColor, &ThreadName[0], nStrLen);
1245                 nY += MICROPROFILE_TEXT_HEIGHT+1;
1246             }
1247         }
1248     }
1249 
1250     S.nContextSwitchHoverCpu = S.nContextSwitchHoverCpuNext;
1251 
1252     UI.pDisplayMouseOver = pMouseOverNext;
1253 
1254     if(!S.nRunning)
1255     {
1256         if(nHoverToken != MICROPROFILE_INVALID_TOKEN && nHoverTime)
1257         {
1258             UI.nHoverToken = nHoverToken;
1259             UI.nHoverTime = nHoverTime;
1260         }
1261 
1262         if(nSelectedFrame != -1)
1263         {
1264             UI.nRangeBegin = S.Frames[nSelectedFrame].nFrameStartCpu;
1265             UI.nRangeEnd = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu;
1266             UI.nRangeBeginGpu = S.Frames[nSelectedFrame].nFrameStartGpu;
1267             UI.nRangeEndGpu = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartGpu;
1268         }
1269         if(UI.nRangeBegin != UI.nRangeEnd)
1270         {
1271             float fMsStart = fToMsCpu * MicroProfileLogTickDifference(nBaseTicksCpu, UI.nRangeBegin);
1272             float fMsEnd = fToMsCpu * MicroProfileLogTickDifference(nBaseTicksCpu, UI.nRangeEnd);
1273             float fXStart = fMsStart * fMsToScreen;
1274             float fXEnd = fMsEnd * fMsToScreen;
1275             MicroProfileDrawBox(fXStart, nBaseY, fXEnd, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT, MicroProfileBoxTypeFlat);
1276             MicroProfileDrawLineVertical(fXStart, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT | 0x44000000);
1277             MicroProfileDrawLineVertical(fXEnd, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT | 0x44000000);
1278 
1279             fMsStart += fDetailedOffset;
1280             fMsEnd += fDetailedOffset;
1281             char sBuffer[32];
1282             uint32_t nLenStart = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsStart);
1283             float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
1284             float fStartTextX = fXStart - fStartTextWidth - 2;
1285             MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1286             MicroProfileDrawText(fStartTextX+1, nBaseY, UINT32_MAX, sBuffer, nLenStart);
1287             uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
1288             MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1289             MicroProfileDrawText(fXEnd+2, nBaseY+1, UINT32_MAX, sBuffer, nLenEnd);
1290 
1291             if(UI.nMouseRight)
1292             {
1293                 MicroProfileZoomTo(UI.nRangeBegin, UI.nRangeEnd);
1294             }
1295         }
1296 
1297         if(UI.nRangeBeginGpu != UI.nRangeEndGpu)
1298         {
1299             float fMsStart = fToMsGpu * MicroProfileLogTickDifference(nBaseTicksGpu, UI.nRangeBeginGpu);
1300             float fMsEnd = fToMsGpu * MicroProfileLogTickDifference(nBaseTicksGpu, UI.nRangeEndGpu);
1301             float fXStart = fMsStart * fMsToScreen;
1302             float fXEnd = fMsEnd * fMsToScreen;
1303             MicroProfileDrawBox(fXStart, nBaseY, fXEnd, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU, MicroProfileBoxTypeFlat);
1304             MicroProfileDrawLineVertical(fXStart, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU | 0x44000000);
1305             MicroProfileDrawLineVertical(fXEnd, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU | 0x44000000);
1306 
1307             nBaseY += MICROPROFILE_TEXT_HEIGHT+1;
1308 
1309             fMsStart += fDetailedOffset;
1310             fMsEnd += fDetailedOffset;
1311             char sBuffer[32];
1312             uint32_t nLenStart = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsStart);
1313             float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
1314             float fStartTextX = fXStart - fStartTextWidth - 2;
1315             MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1316             MicroProfileDrawText(fStartTextX+1, nBaseY, UINT32_MAX, sBuffer, nLenStart);
1317             uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
1318             MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1319             MicroProfileDrawText(fXEnd+2, nBaseY+1, UINT32_MAX, sBuffer, nLenEnd);
1320         }
1321     }
1322 }
1323 
1324 
MicroProfileDrawDetailedFrameHistory(uint32_t nWidth,uint32_t nHeight,uint32_t nBaseY,uint32_t nSelectedFrame)1325 void MicroProfileDrawDetailedFrameHistory(uint32_t nWidth, uint32_t nHeight, uint32_t nBaseY, uint32_t nSelectedFrame)
1326 {
1327     MicroProfile& S = *MicroProfileGet();
1328 
1329     const uint32_t nBarHeight = MICROPROFILE_FRAME_HISTORY_HEIGHT;
1330     float fBaseX = (float)nWidth;
1331     float fDx = fBaseX / MICROPROFILE_NUM_FRAMES;
1332 
1333     uint32_t nLastIndex =  (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
1334     MicroProfileDrawBox(0, nBaseY, nWidth, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, 0xff000000 | g_nMicroProfileBackColors[0], MicroProfileBoxTypeFlat);
1335     float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * S.fRcpReferenceTime;
1336     float fToMsGpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu()) * S.fRcpReferenceTime;
1337 
1338 
1339     MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
1340     uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu;
1341     int64_t nDetailedOffsetTicksCpu = MicroProfileMsToTick(UI.fDetailedOffset, MicroProfileTicksPerSecondCpu());
1342     int64_t nCpuStart = nDetailedOffsetTicksCpu + nFrameStartCpu;
1343     int64_t nCpuEnd = nCpuStart + MicroProfileMsToTick(UI.fDetailedRange, MicroProfileTicksPerSecondCpu());;
1344 
1345 
1346     float fSelectionStart = (float)nWidth;
1347     float fSelectionEnd = 0.f;
1348     for(uint32_t i = 0; i < MICROPROFILE_NUM_FRAMES; ++i)
1349     {
1350         uint32_t nIndex = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY;
1351         MicroProfileFrameState* pCurrent = &S.Frames[nIndex];
1352         MicroProfileFrameState* pNext = &S.Frames[nLastIndex];
1353 
1354         int64_t nTicks = pNext->nFrameStartCpu - pCurrent->nFrameStartCpu;
1355         int64_t nTicksGpu = pNext->nFrameStartGpu - pCurrent->nFrameStartGpu;
1356         float fScale = fToMs * nTicks;
1357         float fScaleGpu = fToMsGpu * nTicksGpu;
1358         fScale = fScale > 1.f ? 0.f : 1.f - fScale;
1359         fScaleGpu = fScaleGpu > 1.f ? 0.f : 1.f - fScaleGpu;
1360         float fXEnd = fBaseX;
1361         float fXStart = fBaseX - fDx;
1362         fBaseX = fXStart;
1363         uint32_t nColor = MICROPROFILE_FRAME_HISTORY_COLOR_CPU;
1364         if(nIndex == nSelectedFrame)
1365             nColor = UINT32_MAX;
1366         MicroProfileDrawBox(fXStart, nBaseY + fScale * nBarHeight, fXEnd, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, nColor, MicroProfileBoxTypeBar);
1367         if(pNext->nFrameStartCpu > nCpuStart)
1368         {
1369             fSelectionStart = fXStart;
1370         }
1371         if(pCurrent->nFrameStartCpu < nCpuEnd && fSelectionEnd == 0.f)
1372         {
1373             fSelectionEnd = fXEnd;
1374         }
1375         nLastIndex = nIndex;
1376     }
1377     MicroProfileDrawBox(fSelectionStart, nBaseY, fSelectionEnd, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, MICROPROFILE_FRAME_HISTORY_COLOR_HIGHTLIGHT, MicroProfileBoxTypeFlat);
1378 }
MicroProfileDrawDetailedView(uint32_t nWidth,uint32_t nHeight)1379 void MicroProfileDrawDetailedView(uint32_t nWidth, uint32_t nHeight)
1380 {
1381     MicroProfile& S = *MicroProfileGet();
1382 
1383     MICROPROFILE_SCOPE(g_MicroProfileDetailed);
1384     uint32_t nBaseY = MICROPROFILE_TEXT_HEIGHT + 1;
1385 
1386     int nSelectedFrame = -1;
1387     if(UI.nMouseY > nBaseY && UI.nMouseY <= nBaseY + MICROPROFILE_FRAME_HISTORY_HEIGHT && UI.nActiveMenu == UINT32_MAX)
1388     {
1389 
1390         nSelectedFrame = ((MICROPROFILE_NUM_FRAMES) * (UI.nWidth-UI.nMouseX) / UI.nWidth);
1391         nSelectedFrame = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - nSelectedFrame) % MICROPROFILE_MAX_FRAME_HISTORY;
1392         UI.nHoverFrame = nSelectedFrame;
1393         if(UI.nMouseRight)
1394         {
1395             int64_t nRangeBegin = S.Frames[nSelectedFrame].nFrameStartCpu;
1396             int64_t nRangeEnd = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu;
1397             MicroProfileZoomTo(nRangeBegin, nRangeEnd);
1398         }
1399         if(UI.nMouseDownLeft)
1400         {
1401             uint64_t nFrac = (1024 * (MICROPROFILE_NUM_FRAMES) * (UI.nMouseX) / UI.nWidth) % 1024;
1402             int64_t nRangeBegin = S.Frames[nSelectedFrame].nFrameStartCpu;
1403             int64_t nRangeEnd = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu;
1404             MicroProfileCenter(nRangeBegin + (nRangeEnd-nRangeBegin) * nFrac / 1024);
1405         }
1406     }
1407     else
1408     {
1409         UI.nHoverFrame = -1;
1410     }
1411 
1412     MicroProfileDrawDetailedBars(nWidth, nHeight, nBaseY + MICROPROFILE_FRAME_HISTORY_HEIGHT, nSelectedFrame);
1413     MicroProfileDrawDetailedFrameHistory(nWidth, nHeight, nBaseY, nSelectedFrame);
1414 }
1415 
MicroProfileDrawTextRight(uint32_t nX,uint32_t nY,uint32_t nColor,const char * pStr,uint32_t nStrLen)1416 void MicroProfileDrawTextRight(uint32_t nX, uint32_t nY, uint32_t nColor, const char* pStr, uint32_t nStrLen)
1417 {
1418     MicroProfileDrawText(nX - nStrLen * (MICROPROFILE_TEXT_WIDTH+1), nY, nColor, pStr, nStrLen);
1419 }
MicroProfileDrawHeader(int32_t nX,uint32_t nWidth,const char * pName)1420 void MicroProfileDrawHeader(int32_t nX, uint32_t nWidth, const char* pName)
1421 {
1422     if(pName)
1423     {
1424         MicroProfileDrawBox(nX-8, MICROPROFILE_TEXT_HEIGHT + 2, nX + nWidth+5, MICROPROFILE_TEXT_HEIGHT + 2 + (MICROPROFILE_TEXT_HEIGHT+1), 0xff000000|g_nMicroProfileBackColors[1]);
1425         MicroProfileDrawText(nX, MICROPROFILE_TEXT_HEIGHT + 2, UINT32_MAX, pName, (uint32_t)strlen(pName));
1426     }
1427 }
1428 
1429 
1430 typedef void (*MicroProfileLoopGroupCallback)(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pData);
1431 
MicroProfileLoopActiveGroupsDraw(int32_t nX,int32_t nY,const char * pName,MicroProfileLoopGroupCallback CB,void * pData)1432 void MicroProfileLoopActiveGroupsDraw(int32_t nX, int32_t nY, const char* pName, MicroProfileLoopGroupCallback CB, void* pData)
1433 {
1434     MicroProfile& S = *MicroProfileGet();
1435     nY += MICROPROFILE_TEXT_HEIGHT + 2;
1436     uint64_t nGroup = S.nAllGroupsWanted ? S.nGroupMask : S.nActiveGroupWanted;
1437     uint32_t nCount = 0;
1438     for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1439     {
1440         uint64_t nMask = 1ULL << j;
1441         if(nMask & nGroup)
1442         {
1443             nY += MICROPROFILE_TEXT_HEIGHT + 1;
1444             for(uint32_t i = 0; i < S.nTotalTimers;++i)
1445             {
1446                 uint64_t nTokenMask = MicroProfileGetGroupMask(S.TimerInfo[i].nToken);
1447                 if(nTokenMask & nMask)
1448                 {
1449                     if(nY >= 0)
1450                         CB(i, nCount, nMask, nX, nY, pData);
1451 
1452                     nCount += 2;
1453                     nY += MICROPROFILE_TEXT_HEIGHT + 1;
1454 
1455                     if(nY > (int)UI.nHeight)
1456                         return;
1457                 }
1458             }
1459 
1460         }
1461     }
1462 }
1463 
1464 
MicroProfileCalcTimers(float * pTimers,float * pAverage,float * pMax,float * pCallAverage,float * pExclusive,float * pAverageExclusive,float * pMaxExclusive,uint64_t nGroup,uint32_t nSize)1465 void MicroProfileCalcTimers(float* pTimers, float* pAverage, float* pMax, float* pCallAverage, float* pExclusive, float* pAverageExclusive, float* pMaxExclusive, uint64_t nGroup, uint32_t nSize)
1466 {
1467     MicroProfile& S = *MicroProfileGet();
1468 
1469     uint32_t nCount = 0;
1470     uint64_t nMask = 1;
1471 
1472     for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1473     {
1474         if(nMask & nGroup)
1475         {
1476             const float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[j].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
1477             for(uint32_t i = 0; i < S.nTotalTimers;++i)
1478             {
1479                 uint64_t nTokenMask = MicroProfileGetGroupMask(S.TimerInfo[i].nToken);
1480                 if(nTokenMask & nMask)
1481                 {
1482                     {
1483                         uint32_t nTimer = i;
1484                         uint32_t nIdx = nCount;
1485                         uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
1486                         uint32_t nAggregateCount = S.Aggregate[nTimer].nCount ? S.Aggregate[nTimer].nCount : 1;
1487                         float fToPrc = S.fRcpReferenceTime;
1488                         float fMs = fToMs * (S.Frame[nTimer].nTicks);
1489                         float fPrc = MicroProfileMin(fMs * fToPrc, 1.f);
1490                         float fAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateFrames);
1491                         float fAveragePrc = MicroProfileMin(fAverageMs * fToPrc, 1.f);
1492                         float fMaxMs = fToMs * (S.AggregateMax[nTimer]);
1493                         float fMaxPrc = MicroProfileMin(fMaxMs * fToPrc, 1.f);
1494                         float fCallAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateCount);
1495                         float fCallAveragePrc = MicroProfileMin(fCallAverageMs * fToPrc, 1.f);
1496                         float fMsExclusive = fToMs * (S.FrameExclusive[nTimer]);
1497                         float fPrcExclusive = MicroProfileMin(fMsExclusive * fToPrc, 1.f);
1498                         float fAverageMsExclusive = fToMs * (S.AggregateExclusive[nTimer] / nAggregateFrames);
1499                         float fAveragePrcExclusive = MicroProfileMin(fAverageMsExclusive * fToPrc, 1.f);
1500                         float fMaxMsExclusive = fToMs * (S.AggregateMaxExclusive[nTimer]);
1501                         float fMaxPrcExclusive = MicroProfileMin(fMaxMsExclusive * fToPrc, 1.f);
1502                         pTimers[nIdx] = fMs;
1503                         pTimers[nIdx+1] = fPrc;
1504                         pAverage[nIdx] = fAverageMs;
1505                         pAverage[nIdx+1] = fAveragePrc;
1506                         pMax[nIdx] = fMaxMs;
1507                         pMax[nIdx+1] = fMaxPrc;
1508                         pCallAverage[nIdx] = fCallAverageMs;
1509                         pCallAverage[nIdx+1] = fCallAveragePrc;
1510                         pExclusive[nIdx] = fMsExclusive;
1511                         pExclusive[nIdx+1] = fPrcExclusive;
1512                         pAverageExclusive[nIdx] = fAverageMsExclusive;
1513                         pAverageExclusive[nIdx+1] = fAveragePrcExclusive;
1514                         pMaxExclusive[nIdx] = fMaxMsExclusive;
1515                         pMaxExclusive[nIdx+1] = fMaxPrcExclusive;
1516                     }
1517                     nCount += 2;
1518                 }
1519             }
1520         }
1521         nMask <<= 1;
1522     }
1523 }
1524 
1525 #define SBUF_MAX 32
1526 
MicroProfileDrawBarArrayCallback(uint32_t nTimer,uint32_t nIdx,uint64_t nGroupMask,uint32_t nX,uint32_t nY,void * pExtra)1527 void MicroProfileDrawBarArrayCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1528 {
1529     const uint32_t nHeight = MICROPROFILE_TEXT_HEIGHT;
1530     const uint32_t nTextWidth = 6 * (1+MICROPROFILE_TEXT_WIDTH);
1531     const float fWidth = (float)MICROPROFILE_BAR_WIDTH;
1532 
1533     float* pTimers = ((float**)pExtra)[0];
1534     float* pTimers2 = ((float**)pExtra)[1];
1535     MicroProfile& S = *MicroProfileGet();
1536     char sBuffer[SBUF_MAX];
1537     if (pTimers2 && pTimers2[nIdx] > 0.1f)
1538         snprintf(sBuffer, SBUF_MAX-1, "%5.2f %3.1fx", pTimers[nIdx], pTimers[nIdx] / pTimers2[nIdx]);
1539     else
1540         snprintf(sBuffer, SBUF_MAX-1, "%5.2f", pTimers[nIdx]);
1541     if (!pTimers2)
1542         MicroProfileDrawBox(nX + nTextWidth, nY, nX + nTextWidth + fWidth * pTimers[nIdx+1], nY + nHeight, UI.nOpacityForeground|S.TimerInfo[nTimer].nColor, MicroProfileBoxTypeBar);
1543     MicroProfileDrawText(nX, nY, UINT32_MAX, sBuffer, (uint32_t)strlen(sBuffer));
1544 }
1545 
1546 
1547 uint32_t MicroProfileDrawBarArray(int32_t nX, int32_t nY, float* pTimers, const char* pName, uint32_t nTotalHeight, float* pTimers2 = NULL)
1548 {
1549     const uint32_t nTextWidth = 6 * (1+MICROPROFILE_TEXT_WIDTH);
1550     const uint32_t nWidth = MICROPROFILE_BAR_WIDTH;
1551 
1552     MicroProfileDrawLineVertical(nX-5, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1553     float* pTimersArray[2] = {pTimers, pTimers2};
1554     MicroProfileLoopActiveGroupsDraw(nX, nY, pName, MicroProfileDrawBarArrayCallback, pTimersArray);
1555     MicroProfileDrawHeader(nX, nTextWidth + nWidth, pName);
1556     return nWidth + 5 + nTextWidth;
1557 
1558 }
MicroProfileDrawBarCallCountCallback(uint32_t nTimer,uint32_t nIdx,uint64_t nGroupMask,uint32_t nX,uint32_t nY,void * pExtra)1559 void MicroProfileDrawBarCallCountCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1560 {
1561     MicroProfile& S = *MicroProfileGet();
1562     char sBuffer[SBUF_MAX];
1563     int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5d", S.Frame[nTimer].nCount);//fix
1564     MicroProfileDrawText(nX, nY, UINT32_MAX, sBuffer, nLen);
1565 }
1566 
MicroProfileDrawBarCallCount(int32_t nX,int32_t nY,const char * pName)1567 uint32_t MicroProfileDrawBarCallCount(int32_t nX, int32_t nY, const char* pName)
1568 {
1569     MicroProfileLoopActiveGroupsDraw(nX, nY, pName, MicroProfileDrawBarCallCountCallback, 0);
1570     const uint32_t nTextWidth = 6 * MICROPROFILE_TEXT_WIDTH;
1571     MicroProfileDrawHeader(nX, 5 + nTextWidth, pName);
1572     return 5 + nTextWidth;
1573 }
1574 
1575 struct MicroProfileMetaAverageArgs
1576 {
1577     uint64_t* pCounters;
1578     float fRcpFrames;
1579 };
1580 
MicroProfileDrawBarMetaAverageCallback(uint32_t nTimer,uint32_t nIdx,uint64_t nGroupMask,uint32_t nX,uint32_t nY,void * pExtra)1581 void MicroProfileDrawBarMetaAverageCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1582 {
1583     MicroProfileMetaAverageArgs* pArgs = (MicroProfileMetaAverageArgs*)pExtra;
1584     uint64_t* pCounters = pArgs->pCounters;
1585     float fRcpFrames = pArgs->fRcpFrames;
1586     char sBuffer[SBUF_MAX];
1587     int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5.2f", pCounters[nTimer] * fRcpFrames);
1588     MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, UINT32_MAX, sBuffer, nLen);
1589 }
1590 
MicroProfileDrawBarMetaAverage(int32_t nX,int32_t nY,uint64_t * pCounters,const char * pName,uint32_t nTotalHeight)1591 uint32_t MicroProfileDrawBarMetaAverage(int32_t nX, int32_t nY, uint64_t* pCounters, const char* pName, uint32_t nTotalHeight)
1592 {
1593     if(!pName)
1594         return 0;
1595     MicroProfileDrawLineVertical(nX-5, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1596     uint32_t nTextWidth = (1+MICROPROFILE_TEXT_WIDTH) * MicroProfileMax<uint32_t>(6, (uint32_t)strlen(pName));
1597     float fRcpFrames = 1.f / (MicroProfileGet()->nAggregateFrames ? MicroProfileGet()->nAggregateFrames : 1);
1598     MicroProfileMetaAverageArgs Args = {pCounters, fRcpFrames};
1599     MicroProfileLoopActiveGroupsDraw(nX + nTextWidth, nY, pName, MicroProfileDrawBarMetaAverageCallback, &Args);
1600     MicroProfileDrawHeader(nX, 5 + nTextWidth, pName);
1601     return 5 + nTextWidth;
1602 }
1603 
1604 
MicroProfileDrawBarMetaCountCallback(uint32_t nTimer,uint32_t nIdx,uint64_t nGroupMask,uint32_t nX,uint32_t nY,void * pExtra)1605 void MicroProfileDrawBarMetaCountCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1606 {
1607     uint64_t* pCounters = (uint64_t*)pExtra;
1608     char sBuffer[SBUF_MAX];
1609     int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5" PRIu64, pCounters[nTimer]);
1610     MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, UINT32_MAX, sBuffer, nLen);
1611 }
1612 
MicroProfileDrawBarMetaCount(int32_t nX,int32_t nY,uint64_t * pCounters,const char * pName,uint32_t nTotalHeight)1613 uint32_t MicroProfileDrawBarMetaCount(int32_t nX, int32_t nY, uint64_t* pCounters, const char* pName, uint32_t nTotalHeight)
1614 {
1615     if(!pName)
1616         return 0;
1617 
1618     MicroProfileDrawLineVertical(nX-5, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1619     uint32_t nTextWidth = (1+MICROPROFILE_TEXT_WIDTH) * MicroProfileMax<uint32_t>(6, (uint32_t)strlen(pName));
1620     MicroProfileLoopActiveGroupsDraw(nX + nTextWidth, nY, pName, MicroProfileDrawBarMetaCountCallback, pCounters);
1621     MicroProfileDrawHeader(nX, 5 + nTextWidth, pName);
1622     return 5 + nTextWidth;
1623 }
1624 
MicroProfileDrawBarLegendCallback(uint32_t nTimer,uint32_t nIdx,uint64_t nGroupMask,uint32_t nX,uint32_t nY,void * pExtra)1625 void MicroProfileDrawBarLegendCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1626 {
1627     MicroProfile& S = *MicroProfileGet();
1628     if (S.TimerInfo[nTimer].bGraph)
1629     {
1630         MicroProfileDrawText(nX, nY, S.TimerInfo[nTimer].nColor, ">", 1);
1631     }
1632     MicroProfileDrawTextRight(nX, nY, S.TimerInfo[nTimer].nColor, S.TimerInfo[nTimer].pName, (uint32_t)strlen(S.TimerInfo[nTimer].pName));
1633     if(UI.nMouseY >= nY && UI.nMouseY < nY + MICROPROFILE_TEXT_HEIGHT+1)
1634     {
1635         UI.nHoverToken = nTimer;
1636         UI.nHoverTime = 0;
1637     }
1638 }
1639 
MicroProfileDrawBarLegend(int32_t nX,int32_t nY,uint32_t nTotalHeight,uint32_t nMaxWidth)1640 uint32_t MicroProfileDrawBarLegend(int32_t nX, int32_t nY, uint32_t nTotalHeight, uint32_t nMaxWidth)
1641 {
1642     MicroProfileDrawLineVertical(nX-5, nY, nTotalHeight, UI.nOpacityBackground | g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1643     MicroProfileLoopActiveGroupsDraw(nMaxWidth, nY, 0, MicroProfileDrawBarLegendCallback, 0);
1644     return nX;
1645 }
1646 
MicroProfileDrawGraph(uint32_t nScreenWidth,uint32_t nScreenHeight)1647 bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight)
1648 {
1649     MicroProfile& S = *MicroProfileGet();
1650 
1651     MICROPROFILE_SCOPE(g_MicroProfileDrawGraph);
1652     bool bEnabled = false;
1653     for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1654         if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
1655             bEnabled = true;
1656     if(!bEnabled)
1657         return false;
1658 
1659     uint32_t nX = nScreenWidth - MICROPROFILE_GRAPH_WIDTH;
1660     uint32_t nY = nScreenHeight - MICROPROFILE_GRAPH_HEIGHT;
1661     MicroProfileDrawBox(nX, nY, nX + MICROPROFILE_GRAPH_WIDTH, nY + MICROPROFILE_GRAPH_HEIGHT, 0x88000000 | g_nMicroProfileBackColors[0]);
1662     bool bMouseOver = UI.nMouseX >= nX && UI.nMouseY >= nY;
1663     float fMouseXPrc =(float(UI.nMouseX - nX)) / MICROPROFILE_GRAPH_WIDTH;
1664     if(bMouseOver)
1665     {
1666         float fXAvg = fMouseXPrc * MICROPROFILE_GRAPH_WIDTH + nX;
1667         MicroProfileDrawLineVertical(fXAvg, nY, nY + MICROPROFILE_GRAPH_HEIGHT, UINT32_MAX);
1668     }
1669 
1670 
1671     float fY = (float)nScreenHeight;
1672     float fDX = MICROPROFILE_GRAPH_WIDTH * 1.f / MICROPROFILE_GRAPH_HISTORY;
1673     float fDY = MICROPROFILE_GRAPH_HEIGHT;
1674     uint32_t nPut = S.nGraphPut;
1675     float* pGraphData = (float*)alloca(sizeof(float)* MICROPROFILE_GRAPH_HISTORY*2);
1676     for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1677     {
1678         if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
1679         {
1680             uint32_t nGroupId = MicroProfileGetGroupIndex(S.Graph[i].nToken);
1681             bool bGpu = S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu;
1682             float fToMs = MicroProfileTickToMsMultiplier(bGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
1683             float fToPrc = fToMs * S.fRcpReferenceTime * 3 / 4;
1684 
1685             float fX = (float)nX;
1686             for(uint32_t j = 0; j < MICROPROFILE_GRAPH_HISTORY; ++j)
1687             {
1688                 float fWeigth = MicroProfileMin(fToPrc * (S.Graph[i].nHistory[(j+nPut)%MICROPROFILE_GRAPH_HISTORY]), 1.f);
1689                 pGraphData[(j*2)] = fX;
1690                 pGraphData[(j*2)+1] = fY - fDY * fWeigth;
1691                 fX += fDX;
1692             }
1693             MicroProfileDrawLine2D(MICROPROFILE_GRAPH_HISTORY, pGraphData, S.TimerInfo[MicroProfileGetTimerIndex(S.Graph[i].nToken)].nColor);
1694         }
1695     }
1696     {
1697         float fY1 = 0.25f * MICROPROFILE_GRAPH_HEIGHT + nY;
1698         float fY2 = 0.50f * MICROPROFILE_GRAPH_HEIGHT + nY;
1699         float fY3 = 0.75f * MICROPROFILE_GRAPH_HEIGHT + nY;
1700         MicroProfileDrawLineHorizontal(nX, nX + MICROPROFILE_GRAPH_WIDTH, fY1, 0xffdd4444);
1701         MicroProfileDrawLineHorizontal(nX, nX + MICROPROFILE_GRAPH_WIDTH, fY2, 0xff000000| g_nMicroProfileBackColors[0]);
1702         MicroProfileDrawLineHorizontal(nX, nX + MICROPROFILE_GRAPH_WIDTH, fY3, 0xff000000|g_nMicroProfileBackColors[0]);
1703 
1704         char buf[32];
1705         int nLen = snprintf(buf, sizeof(buf)-1, "%5.2fms", S.fReferenceTime);
1706         MicroProfileDrawText(nX+1, fY1 - (2+MICROPROFILE_TEXT_HEIGHT), UINT32_MAX, buf, nLen);
1707     }
1708 
1709 
1710 
1711     if(bMouseOver)
1712     {
1713         uint32_t pColors[MICROPROFILE_MAX_GRAPHS];
1714         MicroProfileStringArray Strings;
1715         MicroProfileStringArrayClear(&Strings);
1716         uint32_t nTextCount = 0;
1717         uint32_t nGraphIndex = (S.nGraphPut + MICROPROFILE_GRAPH_HISTORY - int(MICROPROFILE_GRAPH_HISTORY*(1.f - fMouseXPrc))) % MICROPROFILE_GRAPH_HISTORY;
1718 
1719         uint32_t nX = UI.nMouseX;
1720         uint32_t nY = UI.nMouseY + 20;
1721 
1722         for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1723         {
1724             if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
1725             {
1726                 uint32_t nGroupId = MicroProfileGetGroupIndex(S.Graph[i].nToken);
1727                 bool bGpu = S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu;
1728                 float fToMs = MicroProfileTickToMsMultiplier(bGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
1729                 uint32_t nIndex = MicroProfileGetTimerIndex(S.Graph[i].nToken);
1730                 uint32_t nColor = S.TimerInfo[nIndex].nColor;
1731                 const char* pName = S.TimerInfo[nIndex].pName;
1732                 pColors[nTextCount++] = nColor;
1733                 MicroProfileStringArrayAddLiteral(&Strings, pName);
1734                 MicroProfileStringArrayFormat(&Strings, "%5.2fms", fToMs * (S.Graph[i].nHistory[nGraphIndex]));
1735             }
1736         }
1737         if(nTextCount)
1738         {
1739             MicroProfileDrawFloatWindow(nX, nY, Strings.ppStrings, Strings.nNumStrings, 0, pColors);
1740         }
1741 
1742         if(UI.nMouseRight)
1743         {
1744             for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1745             {
1746                 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
1747             }
1748         }
1749     }
1750 
1751     return bMouseOver;
1752 }
1753 
MicroProfileDumpTimers()1754 void MicroProfileDumpTimers()
1755 {
1756     MicroProfile& S = *MicroProfileGet();
1757 
1758     uint64_t nActiveGroup = S.nGroupMask;
1759 
1760     uint32_t nNumTimers = S.nTotalTimers;
1761     uint32_t nBlockSize = 2 * nNumTimers;
1762     float* pTimers = (float*)alloca(nBlockSize * 7 * sizeof(float));
1763     float* pAverage = pTimers + nBlockSize;
1764     float* pMax = pTimers + 2 * nBlockSize;
1765     float* pCallAverage = pTimers + 3 * nBlockSize;
1766     float* pTimersExclusive = pTimers + 4 * nBlockSize;
1767     float* pAverageExclusive = pTimers + 5 * nBlockSize;
1768     float* pMaxExclusive = pTimers + 6 * nBlockSize;
1769     MicroProfileCalcTimers(pTimers, pAverage, pMax, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, nActiveGroup, nNumTimers);
1770 
1771     MICROPROFILE_PRINTF("%11s, ", "Time");
1772     MICROPROFILE_PRINTF("%11s, ", "Average");
1773     MICROPROFILE_PRINTF("%11s, ", "Max");
1774     MICROPROFILE_PRINTF("%11s, ", "Call Avg");
1775     MICROPROFILE_PRINTF("%9s, ", "Count");
1776     MICROPROFILE_PRINTF("%11s, ", "Excl");
1777     MICROPROFILE_PRINTF("%11s, ", "Avg Excl");
1778     MICROPROFILE_PRINTF("%11s, \n", "Max Excl");
1779 
1780     for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1781     {
1782         uint64_t nMask = 1ULL << j;
1783         if(nMask & nActiveGroup)
1784         {
1785             MICROPROFILE_PRINTF("%s\n", S.GroupInfo[j].pName);
1786             for(uint32_t i = 0; i < S.nTotalTimers;++i)
1787             {
1788                 uint64_t nTokenMask = MicroProfileGetGroupMask(S.TimerInfo[i].nToken);
1789                 if(nTokenMask & nMask)
1790                 {
1791                     uint32_t nIdx = i * 2;
1792                     MICROPROFILE_PRINTF("%9.2fms, ", pTimers[nIdx]);
1793                     MICROPROFILE_PRINTF("%9.2fms, ", pAverage[nIdx]);
1794                     MICROPROFILE_PRINTF("%9.2fms, ", pMax[nIdx]);
1795                     MICROPROFILE_PRINTF("%9.2fms, ", pCallAverage[nIdx]);
1796                     MICROPROFILE_PRINTF("%9d, ", S.Frame[i].nCount);
1797                     MICROPROFILE_PRINTF("%9.2fms, ", pTimersExclusive[nIdx]);
1798                     MICROPROFILE_PRINTF("%9.2fms, ", pAverageExclusive[nIdx]);
1799                     MICROPROFILE_PRINTF("%9.2fms, ", pMaxExclusive[nIdx]);
1800                     MICROPROFILE_PRINTF("%s\n", S.TimerInfo[i].pName);
1801                 }
1802             }
1803         }
1804     }
1805 }
1806 
MicroProfileDrawBarView(uint32_t nScreenWidth,uint32_t nScreenHeight)1807 void MicroProfileDrawBarView(uint32_t nScreenWidth, uint32_t nScreenHeight)
1808 {
1809     MicroProfile& S = *MicroProfileGet();
1810 
1811     uint64_t nActiveGroup = S.nAllGroupsWanted ? S.nGroupMask : S.nActiveGroupWanted;
1812     if(!nActiveGroup)
1813         return;
1814     MICROPROFILE_SCOPE(g_MicroProfileDrawBarView);
1815 
1816     const uint32_t nHeight = MICROPROFILE_TEXT_HEIGHT;
1817     int nColorIndex = 0;
1818     uint32_t nMaxTimerNameLen = 1;
1819     uint32_t nNumTimers = 0;
1820     uint32_t nNumGroups = 0;
1821     for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1822     {
1823         if(nActiveGroup & (1ULL << j))
1824         {
1825             nNumTimers += S.GroupInfo[j].nNumTimers;
1826             nNumGroups += 1;
1827             nMaxTimerNameLen = MicroProfileMax(nMaxTimerNameLen, S.GroupInfo[j].nMaxTimerNameLen);
1828         }
1829     }
1830     uint32_t nTimerWidth = 2+(4+nMaxTimerNameLen) * (MICROPROFILE_TEXT_WIDTH+1);
1831     uint32_t nX = nTimerWidth + UI.nOffsetX;
1832     uint32_t nY = nHeight + 3 - UI.nOffsetY;
1833     uint32_t nBlockSize = 2 * nNumTimers;
1834     float* pTimers = (float*)alloca(nBlockSize * 7 * sizeof(float));
1835     float* pAverage = pTimers + nBlockSize;
1836     float* pMax = pTimers + 2 * nBlockSize;
1837     float* pCallAverage = pTimers + 3 * nBlockSize;
1838     float* pTimersExclusive = pTimers + 4 * nBlockSize;
1839     float* pAverageExclusive = pTimers + 5 * nBlockSize;
1840     float* pMaxExclusive = pTimers + 6 * nBlockSize;
1841     MicroProfileCalcTimers(pTimers, pAverage, pMax, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, nActiveGroup, nNumTimers);
1842     uint32_t nWidth = 0;
1843     {
1844         uint32_t nMetaIndex = 0;
1845         for(uint32_t i = 1; i ; i <<= 1)
1846         {
1847             if(S.nBars & i)
1848             {
1849                 if(i >= MP_DRAW_META_FIRST)
1850                 {
1851                     if(nMetaIndex < MICROPROFILE_META_MAX && S.MetaCounters[nMetaIndex].pName)
1852                     {
1853                         uint32_t nStrWidth = strlen(S.MetaCounters[nMetaIndex].pName);
1854                         if(S.nBars & MP_DRAW_TIMERS)
1855                             nWidth += 6 + (1+MICROPROFILE_TEXT_WIDTH) * (nStrWidth);
1856                         if(S.nBars & MP_DRAW_AVERAGE)
1857                             nWidth += 6 + (1+MICROPROFILE_TEXT_WIDTH) * (nStrWidth + 4);
1858                         if(S.nBars & MP_DRAW_MAX)
1859                             nWidth += 6 + (1+MICROPROFILE_TEXT_WIDTH) * (nStrWidth + 4);
1860                     }
1861                 }
1862                 else
1863                 {
1864                     nWidth += MICROPROFILE_BAR_WIDTH + 6 + 6 * (1+MICROPROFILE_TEXT_WIDTH);
1865                     if(i & MP_DRAW_CALL_COUNT)
1866                         nWidth += 6 + 6 * MICROPROFILE_TEXT_WIDTH;
1867                 }
1868             }
1869             if(i >= MP_DRAW_META_FIRST)
1870             {
1871                 ++nMetaIndex;
1872             }
1873         }
1874         nWidth += (1+nMaxTimerNameLen) * (MICROPROFILE_TEXT_WIDTH+1);
1875         for(uint32_t i = 0; i < nNumTimers+nNumGroups+1; ++i)
1876         {
1877             uint32_t nY0 = nY + i * (nHeight + 1);
1878             bool bInside = (UI.nActiveMenu == UINT32_MAX) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
1879             MicroProfileDrawBox(nX, nY0, nWidth+nX, nY0 + (nHeight+1)+1, UI.nOpacityBackground | (g_nMicroProfileBackColors[nColorIndex++ & 1] + ((bInside) ? 0x002c2c2c : 0)));
1880         }
1881         nX += 10;
1882     }
1883     int nTotalHeight = (nNumTimers+nNumGroups+1) * (nHeight+1);
1884     uint32_t nLegendOffset = 1;
1885     if(S.nBars & MP_DRAW_TIMERS)
1886         nX += MicroProfileDrawBarArray(nX, nY, pTimers, "Time", nTotalHeight) + 1;
1887     if(S.nBars & MP_DRAW_AVERAGE)
1888         nX += MicroProfileDrawBarArray(nX, nY, pAverage, "Average", nTotalHeight) + 1;
1889     if(S.nBars & MP_DRAW_MAX)
1890         nX += MicroProfileDrawBarArray(nX, nY, pMax, (!UI.bShowSpikes) ? "Max Time" : "Max Time, Spike", nTotalHeight, UI.bShowSpikes ? pAverage : NULL) + 1;
1891     if(S.nBars & MP_DRAW_CALL_COUNT)
1892     {
1893         nX += MicroProfileDrawBarArray(nX, nY, pCallAverage, "Call Average", nTotalHeight) + 1;
1894         nX += MicroProfileDrawBarCallCount(nX, nY, "Count") + 1;
1895     }
1896     if(S.nBars & MP_DRAW_TIMERS_EXCLUSIVE)
1897         nX += MicroProfileDrawBarArray(nX, nY, pTimersExclusive, "Exclusive Time", nTotalHeight) + 1;
1898     if(S.nBars & MP_DRAW_AVERAGE_EXCLUSIVE)
1899         nX += MicroProfileDrawBarArray(nX, nY, pAverageExclusive, "Exclusive Average", nTotalHeight) + 1;
1900     if(S.nBars & MP_DRAW_MAX_EXCLUSIVE)
1901         nX += MicroProfileDrawBarArray(nX, nY, pMaxExclusive, (!UI.bShowSpikes) ? "Exclusive Max Time" :"Excl Max Time, Spike", nTotalHeight, UI.bShowSpikes ? pAverageExclusive : NULL) + 1;
1902 
1903     for(int i = 0; i < MICROPROFILE_META_MAX; ++i)
1904     {
1905         if(0 != (S.nBars & (MP_DRAW_META_FIRST<<i)) && S.MetaCounters[i].pName)
1906         {
1907             uint32_t nBufferSize = strlen(S.MetaCounters[i].pName) + 32;
1908             char* buffer = (char*)alloca(nBufferSize);
1909             if(S.nBars & MP_DRAW_TIMERS)
1910                 nX += MicroProfileDrawBarMetaCount(nX, nY, &S.MetaCounters[i].nCounters[0], S.MetaCounters[i].pName, nTotalHeight) + 1;
1911             if(S.nBars & MP_DRAW_AVERAGE)
1912             {
1913                 snprintf(buffer, nBufferSize-1, "%s Avg", S.MetaCounters[i].pName);
1914                 nX += MicroProfileDrawBarMetaAverage(nX, nY, &S.MetaCounters[i].nAggregate[0], buffer, nTotalHeight) + 1;
1915             }
1916             if(S.nBars & MP_DRAW_MAX)
1917             {
1918                 snprintf(buffer, nBufferSize-1, "%s Max", S.MetaCounters[i].pName);
1919                 nX += MicroProfileDrawBarMetaCount(nX, nY, &S.MetaCounters[i].nAggregateMax[0], buffer, nTotalHeight) + 1;
1920             }
1921         }
1922     }
1923     nX = 0;
1924     nY = nHeight + 3 - UI.nOffsetY;
1925     for(uint32_t i = 0; i < nNumTimers+nNumGroups+1; ++i)
1926     {
1927         const uint32_t nY0 = nY + i * (nHeight + 1);
1928         const bool bInside = (UI.nActiveMenu == UINT32_MAX) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
1929         MicroProfileDrawBox(nX, nY0, nTimerWidth, nY0 + (nHeight+1)+1, 0xff0000000 | (g_nMicroProfileBackColors[nColorIndex++ & 1] + ((bInside) ? 0x002c2c2c : 0)));
1930     }
1931     nX += MicroProfileDrawBarLegend(nX, nY, nTotalHeight, nTimerWidth-5) + 1;
1932 
1933     for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1934     {
1935         if(nActiveGroup & (1ULL << j))
1936         {
1937             MicroProfileDrawText(nX, nY + (1+nHeight) * nLegendOffset, UINT32_MAX, S.GroupInfo[j].pName, S.GroupInfo[j].nNameLen);
1938             nLegendOffset += S.GroupInfo[j].nNumTimers+1;
1939         }
1940     }
1941     MicroProfileDrawHeader(nX, nTimerWidth-5, "Group");
1942     MicroProfileDrawTextRight(nTimerWidth-3, MICROPROFILE_TEXT_HEIGHT + 2, UINT32_MAX, "Timer", 5);
1943     MicroProfileDrawLineVertical(nTimerWidth, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1944     MicroProfileDrawLineHorizontal(0, nWidth, 2*MICROPROFILE_TEXT_HEIGHT + 3, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1945 }
1946 
1947 typedef const char* (*MicroProfileSubmenuCallback)(int, bool* bSelected);
1948 typedef void (*MicroProfileClickCallback)(int);
1949 
1950 
MicroProfileUIMenuMode(int nIndex,bool * bSelected)1951 const char* MicroProfileUIMenuMode(int nIndex, bool* bSelected)
1952 {
1953     MicroProfile& S = *MicroProfileGet();
1954     switch(nIndex)
1955     {
1956         case 0:
1957             *bSelected = S.nDisplay == MP_DRAW_DETAILED;
1958             return "Detailed";
1959         case 1:
1960             *bSelected = S.nDisplay == MP_DRAW_BARS;
1961             return "Timers";
1962         case 2:
1963             *bSelected = S.nDisplay == MP_DRAW_HIDDEN;
1964             return "Hidden";
1965         case 3:
1966             *bSelected = true;
1967             return "Off";
1968         case 4:
1969             *bSelected = true;
1970             return "------";
1971         case 5:
1972             *bSelected = S.nForceEnable != 0;
1973             return "Force Enable";
1974 
1975         default: return 0;
1976     }
1977 }
1978 
MicroProfileUIMenuGroups(int nIndex,bool * bSelected)1979 const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
1980 {
1981     MicroProfile& S = *MicroProfileGet();
1982     *bSelected = false;
1983     if(nIndex == 0)
1984     {
1985         *bSelected = S.nAllGroupsWanted != 0;
1986         return "[ALL]";
1987     }
1988     else
1989     {
1990         nIndex = nIndex-1;
1991         if(nIndex < UI.GroupMenuCount)
1992         {
1993             MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
1994             static char buffer[MICROPROFILE_NAME_MAX_LEN+32];
1995             if(Item.nIsCategory)
1996             {
1997                 uint64_t nGroupMask = S.CategoryInfo[Item.nIndex].nGroupMask;
1998                 *bSelected = nGroupMask == (nGroupMask & S.nActiveGroupWanted);
1999                 snprintf(buffer, sizeof(buffer)-1, "[%s]", Item.pName);
2000             }
2001             else
2002             {
2003                 *bSelected = 0 != (S.nActiveGroupWanted & (1ULL << Item.nIndex));
2004                 snprintf(buffer, sizeof(buffer)-1, "   %s", Item.pName);
2005             }
2006             return buffer;
2007         }
2008         return 0;
2009     }
2010 }
2011 
MicroProfileUIMenuAggregate(int nIndex,bool * bSelected)2012 const char* MicroProfileUIMenuAggregate(int nIndex, bool* bSelected)
2013 {
2014     MicroProfile& S = *MicroProfileGet();
2015     if(static_cast<uint32_t>(nIndex) < g_MicroProfileAggregatePresets.size())
2016     {
2017         uint32_t val = g_MicroProfileAggregatePresets[nIndex];
2018         *bSelected = S.nAggregateFlip == val;
2019         if (0 == val)
2020         {
2021             return "Infinite";
2022         }
2023         else
2024         {
2025             static char buf[128];
2026             snprintf(buf, sizeof(buf)-1, "%7u", val);
2027             return buf;
2028         }
2029     }
2030     return 0;
2031 
2032 }
2033 
MicroProfileUIMenuTimers(int nIndex,bool * bSelected)2034 const char* MicroProfileUIMenuTimers(int nIndex, bool* bSelected)
2035 {
2036     MicroProfile& S = *MicroProfileGet();
2037     *bSelected = 0 != (S.nBars & (1 << nIndex));
2038     switch(nIndex)
2039     {
2040         case 0: return "Time";
2041         case 1: return "Average";
2042         case 2: return "Max";
2043         case 3: return "Call Count";
2044         case 4: return "Exclusive Timers";
2045         case 5: return "Exclusive Average";
2046         case 6: return "Exclusive Max";
2047     }
2048     int nMetaIndex = nIndex - 7;
2049     if(nMetaIndex < MICROPROFILE_META_MAX)
2050     {
2051         return S.MetaCounters[nMetaIndex].pName;
2052     }
2053     return 0;
2054 }
2055 
MicroProfileUIMenuOptions(int nIndex,bool * bSelected)2056 const char* MicroProfileUIMenuOptions(int nIndex, bool* bSelected)
2057 {
2058     MicroProfile& S = *MicroProfileGet();
2059     if(nIndex >= MICROPROFILE_OPTION_SIZE) return 0;
2060     switch(UI.Options[nIndex].nSubType)
2061     {
2062     case 0:
2063         *bSelected = S.fReferenceTime == g_MicroProfileReferenceTimePresets[UI.Options[nIndex].nIndex];
2064         break;
2065     case 1:
2066         *bSelected = UI.nOpacityBackground>>24 == g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex];
2067         break;
2068     case 2:
2069         *bSelected = UI.nOpacityForeground>>24 == g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex];
2070         break;
2071     case 3:
2072         *bSelected = UI.bShowSpikes;
2073         break;
2074 #if MICROPROFILE_CONTEXT_SWITCH_TRACE
2075     case 4:
2076         {
2077             switch(UI.Options[nIndex].nIndex)
2078             {
2079             case 0:
2080                 *bSelected = S.bContextSwitchRunning;
2081                 break;
2082             case 1:
2083                 *bSelected = S.bContextSwitchAllThreads;
2084                 break;
2085             case 2:
2086                 *bSelected = S.bContextSwitchNoBars;
2087                 break;
2088             }
2089         }
2090         break;
2091 #endif
2092     }
2093     return UI.Options[nIndex].Text;
2094 }
2095 
MicroProfileUIMenuPreset(int nIndex,bool * bSelected)2096 const char* MicroProfileUIMenuPreset(int nIndex, bool* bSelected)
2097 {
2098     static char buf[128];
2099     *bSelected = false;
2100     int nNumPresets = static_cast<int>(g_MicroProfilePresetNames.size());
2101     int nIndexSave = nIndex - nNumPresets - 1;
2102     if (nIndex == nNumPresets)
2103     {
2104         return "--";
2105     }
2106     else if(nIndexSave >=0 && nIndexSave < nNumPresets)
2107     {
2108         snprintf(buf, sizeof(buf)-1, "Save '%s'", g_MicroProfilePresetNames[nIndexSave]);
2109         return buf;
2110     }
2111     else if(nIndex < nNumPresets)
2112     {
2113         snprintf(buf, sizeof(buf)-1, "Load '%s'", g_MicroProfilePresetNames[nIndex]);
2114         return buf;
2115     }
2116     else
2117     {
2118         return 0;
2119     }
2120 }
2121 
MicroProfileUIMenuCustom(int nIndex,bool * bSelected)2122 const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected)
2123 {
2124     if(UINT32_MAX == UI.nCustomActive)
2125     {
2126         *bSelected = nIndex == 0;
2127     }
2128     else
2129     {
2130         *bSelected = nIndex-2 == static_cast<int>(UI.nCustomActive);
2131     }
2132     switch(nIndex)
2133     {
2134     case 0: return "Disable";
2135     case 1: return "--";
2136     default:
2137         nIndex -= 2;
2138         if(nIndex < UI.nCustomCount)
2139         {
2140             return UI.Custom[nIndex].pName;
2141         }
2142         else
2143         {
2144             return 0;
2145         }
2146     }
2147 }
2148 
MicroProfileUIMenuEmpty(int nIndex,bool * bSelected)2149 const char* MicroProfileUIMenuEmpty(int nIndex, bool* bSelected)
2150 {
2151     return 0;
2152 }
2153 
2154 
MicroProfileUIClickMode(int nIndex)2155 void MicroProfileUIClickMode(int nIndex)
2156 {
2157     MicroProfile& S = *MicroProfileGet();
2158     switch(nIndex)
2159     {
2160         case 0:
2161             S.nDisplay = MP_DRAW_DETAILED;
2162             break;
2163         case 1:
2164             S.nDisplay = MP_DRAW_BARS;
2165             break;
2166         case 2:
2167             S.nDisplay = MP_DRAW_HIDDEN;
2168             break;
2169         case 3:
2170             S.nDisplay = 0;
2171             break;
2172         case 4:
2173             break;
2174         case 5:
2175             S.nForceEnable = !S.nForceEnable;
2176             break;
2177     }
2178 }
2179 
MicroProfileUIClickGroups(int nIndex)2180 void MicroProfileUIClickGroups(int nIndex)
2181 {
2182     MicroProfile& S = *MicroProfileGet();
2183     if(nIndex == 0)
2184         S.nAllGroupsWanted = 1-S.nAllGroupsWanted;
2185     else
2186     {
2187         nIndex -= 1;
2188         if(nIndex < UI.GroupMenuCount)
2189         {
2190             MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
2191             if(Item.nIsCategory)
2192             {
2193                 uint64_t nGroupMask = S.CategoryInfo[Item.nIndex].nGroupMask;
2194                 if(nGroupMask != (nGroupMask & S.nActiveGroupWanted))
2195                 {
2196                     S.nActiveGroupWanted |= nGroupMask;
2197                 }
2198                 else
2199                 {
2200                     S.nActiveGroupWanted &= ~nGroupMask;
2201                 }
2202             }
2203             else
2204             {
2205                 MP_ASSERT(Item.nIndex < S.nGroupCount);
2206                 S.nActiveGroupWanted ^= (1ULL << Item.nIndex);
2207             }
2208         }
2209     }
2210 }
2211 
MicroProfileUIClickAggregate(int nIndex)2212 void MicroProfileUIClickAggregate(int nIndex)
2213 {
2214     MicroProfile& S = *MicroProfileGet();
2215     S.nAggregateFlip = g_MicroProfileAggregatePresets[nIndex];
2216     if(0 == S.nAggregateFlip)
2217     {
2218         S.nAggregateClear = 1;
2219     }
2220 }
2221 
MicroProfileUIClickTimers(int nIndex)2222 void MicroProfileUIClickTimers(int nIndex)
2223 {
2224     MicroProfile& S = *MicroProfileGet();
2225     S.nBars ^= (1 << nIndex);
2226 }
2227 
MicroProfileUIClickOptions(int nIndex)2228 void MicroProfileUIClickOptions(int nIndex)
2229 {
2230     MicroProfile& S = *MicroProfileGet();
2231     switch(UI.Options[nIndex].nSubType)
2232     {
2233     case 0:
2234         S.fReferenceTime = g_MicroProfileReferenceTimePresets[UI.Options[nIndex].nIndex];
2235         S.fRcpReferenceTime = 1.f / S.fReferenceTime;
2236         break;
2237     case 1:
2238         UI.nOpacityBackground = g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex]<<24;
2239         break;
2240     case 2:
2241         UI.nOpacityForeground = g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex]<<24;
2242         break;
2243     case 3:
2244         UI.bShowSpikes = !UI.bShowSpikes;
2245         break;
2246 #if MICROPROFILE_CONTEXT_SWITCH_TRACE
2247     case 4:
2248         {
2249             switch(UI.Options[nIndex].nIndex)
2250             {
2251             case 0:
2252                 if(S.bContextSwitchRunning)
2253                 {
2254                     MicroProfileStopContextSwitchTrace();
2255                 }
2256                 else
2257                 {
2258                     MicroProfileStartContextSwitchTrace();
2259                 }
2260                 break;
2261             case 1:
2262                 S.bContextSwitchAllThreads = !S.bContextSwitchAllThreads;
2263                 break;
2264             case 2:
2265                 S.bContextSwitchNoBars= !S.bContextSwitchNoBars;
2266                 break;
2267 
2268             }
2269         }
2270         break;
2271 #endif
2272     }
2273 }
2274 
MicroProfileUIClickPreset(int nIndex)2275 void MicroProfileUIClickPreset(int nIndex)
2276 {
2277     int nNumPresets = static_cast<int>(g_MicroProfilePresetNames.size());
2278     int nIndexSave = nIndex - nNumPresets - 1;
2279     if(nIndexSave >= 0 && nIndexSave < nNumPresets)
2280     {
2281         MicroProfileSavePreset(g_MicroProfilePresetNames[nIndexSave]);
2282     }
2283     else if(nIndex >= 0 && nIndex < nNumPresets)
2284     {
2285         MicroProfileLoadPreset(g_MicroProfilePresetNames[nIndex]);
2286     }
2287 }
2288 
MicroProfileUIClickCustom(int nIndex)2289 void MicroProfileUIClickCustom(int nIndex)
2290 {
2291     if(nIndex == 0)
2292     {
2293         MicroProfileCustomGroupDisable();
2294     }
2295     else
2296     {
2297         MicroProfileCustomGroupEnable(nIndex-2);
2298     }
2299 
2300 }
2301 
MicroProfileUIClickEmpty(int nIndex)2302 void MicroProfileUIClickEmpty(int nIndex)
2303 {
2304 
2305 }
2306 
2307 
MicroProfileDrawMenu(uint32_t nWidth,uint32_t nHeight)2308 void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
2309 {
2310     MicroProfile& S = *MicroProfileGet();
2311 
2312     uint32_t nX = 0;
2313     uint32_t nY = 0;
2314 
2315 #define SBUF_SIZE 256
2316     char buffer[256];
2317     MicroProfileDrawBox(nX, nY, nX + nWidth, nY + (MICROPROFILE_TEXT_HEIGHT+1)+1, 0xff000000|g_nMicroProfileBackColors[1]);
2318 
2319 #define MICROPROFILE_MENU_MAX 16
2320     const char* pMenuText[MICROPROFILE_MENU_MAX] = {0};
2321     uint32_t    nMenuX[MICROPROFILE_MENU_MAX] = {0};
2322     uint32_t nNumMenuItems = 0;
2323 
2324     int nLen = snprintf(buffer, 127, "MicroProfile");
2325     MicroProfileDrawText(nX, nY, UINT32_MAX, buffer, nLen);
2326     nX += (sizeof("MicroProfile")+2) * (MICROPROFILE_TEXT_WIDTH+1);
2327     pMenuText[nNumMenuItems++] = "Mode";
2328     pMenuText[nNumMenuItems++] = "Groups";
2329     char AggregateText[64];
2330     snprintf(AggregateText, sizeof(AggregateText)-1, "Aggregate[%d]", S.nAggregateFlip ? S.nAggregateFlip : S.nAggregateFlipCount);
2331     pMenuText[nNumMenuItems++] = &AggregateText[0];
2332     pMenuText[nNumMenuItems++] = "Timers";
2333     pMenuText[nNumMenuItems++] = "Options";
2334     pMenuText[nNumMenuItems++] = "Preset";
2335     pMenuText[nNumMenuItems++] = "Custom";
2336     const int nPauseIndex = nNumMenuItems;
2337     pMenuText[nNumMenuItems++] = S.nRunning ? "Pause" : "Unpause";
2338     pMenuText[nNumMenuItems++] = "Help";
2339 
2340     if(S.nOverflow)
2341     {
2342         pMenuText[nNumMenuItems++] = "!BUFFERSFULL!";
2343     }
2344 
2345 
2346     if(UI.GroupMenuCount != S.nGroupCount + S.nCategoryCount)
2347     {
2348         UI.GroupMenuCount = S.nGroupCount + S.nCategoryCount;
2349         for(uint32_t i = 0; i < S.nCategoryCount; ++i)
2350         {
2351             UI.GroupMenu[i].nIsCategory = 1;
2352             UI.GroupMenu[i].nCategoryIndex = i;
2353             UI.GroupMenu[i].nIndex = i;
2354             UI.GroupMenu[i].pName = S.CategoryInfo[i].pName;
2355         }
2356         for(uint32_t i = 0; i < S.nGroupCount; ++i)
2357         {
2358             uint32_t idx = i + S.nCategoryCount;
2359             UI.GroupMenu[idx].nIsCategory = 0;
2360             UI.GroupMenu[idx].nCategoryIndex = S.GroupInfo[i].nCategory;
2361             UI.GroupMenu[idx].nIndex = i;
2362             UI.GroupMenu[idx].pName = S.GroupInfo[i].pName;
2363         }
2364         std::sort(&UI.GroupMenu[0], &UI.GroupMenu[UI.GroupMenuCount],
2365             [] (const MicroProfileGroupMenuItem& l, const MicroProfileGroupMenuItem& r) -> bool
2366             {
2367                 if(l.nCategoryIndex < r.nCategoryIndex)
2368                 {
2369                     return true;
2370                 }
2371                 else if(r.nCategoryIndex < l.nCategoryIndex)
2372                 {
2373                     return false;
2374                 }
2375                 if(r.nIsCategory || l.nIsCategory)
2376                 {
2377                     return l.nIsCategory > r.nIsCategory;
2378                 }
2379                 return MP_STRCASECMP(l.pName, r.pName)<0;
2380             }
2381         );
2382     }
2383 
2384     MicroProfileSubmenuCallback GroupCallback[MICROPROFILE_MENU_MAX] =
2385     {
2386         MicroProfileUIMenuMode,
2387         MicroProfileUIMenuGroups,
2388         MicroProfileUIMenuAggregate,
2389         MicroProfileUIMenuTimers,
2390         MicroProfileUIMenuOptions,
2391         MicroProfileUIMenuPreset,
2392         MicroProfileUIMenuCustom,
2393         MicroProfileUIMenuEmpty,
2394         MicroProfileUIMenuEmpty,
2395         MicroProfileUIMenuEmpty,
2396     };
2397 
2398     MicroProfileClickCallback CBClick[MICROPROFILE_MENU_MAX] =
2399     {
2400         MicroProfileUIClickMode,
2401         MicroProfileUIClickGroups,
2402         MicroProfileUIClickAggregate,
2403         MicroProfileUIClickTimers,
2404         MicroProfileUIClickOptions,
2405         MicroProfileUIClickPreset,
2406         MicroProfileUIClickCustom,
2407         MicroProfileUIClickEmpty,
2408         MicroProfileUIClickEmpty,
2409         MicroProfileUIClickEmpty,
2410     };
2411 
2412 
2413     uint32_t nSelectMenu = UINT32_MAX;
2414     for(uint32_t i = 0; i < nNumMenuItems; ++i)
2415     {
2416         nMenuX[i] = nX;
2417         uint32_t nLen = (uint32_t)strlen(pMenuText[i]);
2418         uint32_t nEnd = nX + nLen * (MICROPROFILE_TEXT_WIDTH+1);
2419         if(UI.nMouseY <= MICROPROFILE_TEXT_HEIGHT && UI.nMouseX <= nEnd && UI.nMouseX >= nX)
2420         {
2421             MicroProfileDrawBox(nX-1, nY, nX + nLen * (MICROPROFILE_TEXT_WIDTH+1), nY +(MICROPROFILE_TEXT_HEIGHT+1)+1, 0xff888888);
2422             nSelectMenu = i;
2423             if((UI.nMouseLeft || UI.nMouseRight) && i == (uint32_t)nPauseIndex)
2424             {
2425                 S.nToggleRunning = 1;
2426             }
2427         }
2428         MicroProfileDrawText(nX, nY, UINT32_MAX, pMenuText[i], (uint32_t)strlen(pMenuText[i]));
2429         nX += (nLen+1) * (MICROPROFILE_TEXT_WIDTH+1);
2430     }
2431     uint32_t nMenu = nSelectMenu != UINT32_MAX ? nSelectMenu : UI.nActiveMenu;
2432     UI.nActiveMenu = nMenu;
2433     if(UINT32_MAX != nMenu)
2434     {
2435         nX = nMenuX[nMenu];
2436         nY += MICROPROFILE_TEXT_HEIGHT+1;
2437         MicroProfileSubmenuCallback CB = GroupCallback[nMenu];
2438         int nNumLines = 0;
2439         bool bSelected = false;
2440         const char* pString = CB(nNumLines, &bSelected);
2441         uint32_t nWidth = 0, nHeight = 0;
2442         while(pString)
2443         {
2444             nWidth = MicroProfileMax<int>(nWidth, (int)strlen(pString));
2445             nNumLines++;
2446             pString = CB(nNumLines, &bSelected);
2447         }
2448         nWidth = (2+nWidth) * (MICROPROFILE_TEXT_WIDTH+1);
2449         nHeight = nNumLines * (MICROPROFILE_TEXT_HEIGHT+1);
2450         if(UI.nMouseY <= nY + nHeight+0 && UI.nMouseY >= nY-0 && UI.nMouseX <= nX + nWidth + 0 && UI.nMouseX >= nX - 0)
2451         {
2452             UI.nActiveMenu = nMenu;
2453         }
2454         else if(nSelectMenu == UINT32_MAX)
2455         {
2456             UI.nActiveMenu = UINT32_MAX;
2457         }
2458         MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000|g_nMicroProfileBackColors[1]);
2459         for(int i = 0; i < nNumLines; ++i)
2460         {
2461             bool bSelected = false;
2462             const char* pString = CB(i, &bSelected);
2463             if(UI.nMouseY >= nY && UI.nMouseY < nY + MICROPROFILE_TEXT_HEIGHT + 1)
2464             {
2465                 if(UI.nMouseLeft || UI.nMouseRight)
2466                 {
2467                     CBClick[nMenu](i);
2468                 }
2469                 MicroProfileDrawBox(nX, nY, nX + nWidth, nY + MICROPROFILE_TEXT_HEIGHT + 1, 0xff888888);
2470             }
2471             int nLen = snprintf(buffer, SBUF_SIZE-1, "%c %s", bSelected ? '*' : ' ' ,pString);
2472             MicroProfileDrawText(nX, nY, UINT32_MAX, buffer, nLen);
2473             nY += MICROPROFILE_TEXT_HEIGHT+1;
2474         }
2475     }
2476 
2477 
2478     {
2479         static char FrameTimeMessage[64];
2480         float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2481         uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
2482         float fMs = fToMs * (S.nFlipTicks);
2483         float fAverageMs = fToMs * (S.nFlipAggregateDisplay / nAggregateFrames);
2484         float fMaxMs = fToMs * S.nFlipMaxDisplay;
2485         int nLen = snprintf(FrameTimeMessage, sizeof(FrameTimeMessage)-1, "Time[%6.2f] Avg[%6.2f] Max[%6.2f]", fMs, fAverageMs, fMaxMs);
2486         pMenuText[nNumMenuItems++] = &FrameTimeMessage[0];
2487         MicroProfileDrawText(nWidth - nLen * (MICROPROFILE_TEXT_WIDTH+1), 0, UINT32_MAX, FrameTimeMessage, nLen);
2488     }
2489 }
2490 
2491 
MicroProfileMoveGraph()2492 void MicroProfileMoveGraph()
2493 {
2494 
2495     int nZoom = UI.nMouseWheelDelta;
2496     int nPanX = 0;
2497     int nPanY = 0;
2498     static int X = 0, Y = 0;
2499     if(UI.nMouseDownLeft && !UI.nModDown)
2500     {
2501         nPanX = UI.nMouseX - X;
2502         nPanY = UI.nMouseY - Y;
2503     }
2504     X = UI.nMouseX;
2505     Y = UI.nMouseY;
2506 
2507     if(nZoom)
2508     {
2509         float fOldRange = UI.fDetailedRange;
2510         if(nZoom>0)
2511         {
2512             UI.fDetailedRangeTarget = UI.fDetailedRange *= UI.nModDown ? 1.40f : 1.05f;
2513         }
2514         else
2515         {
2516             float fNewDetailedRange = UI.fDetailedRange / (UI.nModDown ? 1.40f : 1.05f);
2517             if(fNewDetailedRange < 1e-4f) //100ns
2518                 fNewDetailedRange = 1e-4f;
2519             UI.fDetailedRangeTarget = UI.fDetailedRange = fNewDetailedRange;
2520         }
2521 
2522         float fDiff = fOldRange - UI.fDetailedRange;
2523         float fMousePrc = MicroProfileMax((float)UI.nMouseX / UI.nWidth ,0.f);
2524         UI.fDetailedOffsetTarget = UI.fDetailedOffset += fDiff * fMousePrc;
2525 
2526     }
2527     if(nPanX)
2528     {
2529         UI.fDetailedOffsetTarget = UI.fDetailedOffset += -nPanX * UI.fDetailedRange / UI.nWidth;
2530     }
2531     UI.nOffsetY -= nPanY;
2532     UI.nOffsetX += nPanX;
2533     if(UI.nOffsetX > 0)
2534         UI.nOffsetX = 0;
2535     if(UI.nOffsetY<0)
2536         UI.nOffsetY = 0;
2537 }
2538 
MicroProfileDrawCustom(uint32_t nWidth,uint32_t nHeight)2539 void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
2540 {
2541     if(UINT32_MAX != UI.nCustomActive)
2542     {
2543         MicroProfile& S = *MicroProfileGet();
2544         MP_ASSERT(UI.nCustomActive < MICROPROFILE_CUSTOM_MAX);
2545         MicroProfileCustom* pCustom = &UI.Custom[UI.nCustomActive];
2546         uint32_t nCount = pCustom->nNumTimers;
2547         uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
2548         uint32_t nExtraOffset = 1 + ((pCustom->nFlags & MICROPROFILE_CUSTOM_STACK) != 0 ? 3 : 0);
2549         uint32_t nOffsetYBase = nHeight - (nExtraOffset+nCount)* (1+MICROPROFILE_TEXT_HEIGHT) - MICROPROFILE_CUSTOM_PADDING;
2550         uint32_t nOffsetY = nOffsetYBase;
2551         float fReference = pCustom->fReference;
2552         float fRcpReference = 1.f / fReference;
2553         uint32_t nReducedWidth = UI.nWidth - 2*MICROPROFILE_CUSTOM_PADDING - MICROPROFILE_GRAPH_WIDTH;
2554 
2555         char Buffer[MICROPROFILE_NAME_MAX_LEN*2+1];
2556         float* pTime = (float*)alloca(sizeof(float)*nCount);
2557         float* pTimeAvg = (float*)alloca(sizeof(float)*nCount);
2558         float* pTimeMax = (float*)alloca(sizeof(float)*nCount);
2559         uint32_t* pColors = (uint32_t*)alloca(sizeof(uint32_t)*nCount);
2560         uint32_t nMaxOffsetX = 0;
2561         MicroProfileDrawBox(MICROPROFILE_CUSTOM_PADDING-1, nOffsetY-1, MICROPROFILE_CUSTOM_PADDING+nReducedWidth+1, UI.nHeight - MICROPROFILE_CUSTOM_PADDING+1, 0x88000000|g_nMicroProfileBackColors[0]);
2562 
2563         for(uint32_t i = 0; i < nCount; ++i)
2564         {
2565             uint16_t nTimerIndex = MicroProfileGetTimerIndex(pCustom->pTimers[i]);
2566             uint16_t nGroupIndex = MicroProfileGetGroupIndex(pCustom->pTimers[i]);
2567             float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupIndex].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
2568             pTime[i] = S.Frame[nTimerIndex].nTicks * fToMs;
2569             pTimeAvg[i] = fToMs * (S.Aggregate[nTimerIndex].nTicks / nAggregateFrames);
2570             pTimeMax[i] = fToMs * (S.AggregateMax[nTimerIndex]);
2571             pColors[i] = S.TimerInfo[nTimerIndex].nColor;
2572         }
2573 
2574         MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 3*MICROPROFILE_TEXT_WIDTH, nOffsetY, UINT32_MAX, "Avg", sizeof("Avg")-1);
2575         MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 13*MICROPROFILE_TEXT_WIDTH, nOffsetY, UINT32_MAX, "Max", sizeof("Max")-1);
2576         for(uint32_t i = 0; i < nCount; ++i)
2577         {
2578             nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
2579             uint16_t nTimerIndex = MicroProfileGetTimerIndex(pCustom->pTimers[i]);
2580             uint16_t nGroupIndex = MicroProfileGetGroupIndex(pCustom->pTimers[i]);
2581             MicroProfileTimerInfo* pTimerInfo = &S.TimerInfo[nTimerIndex];
2582             int nSize;
2583             uint32_t nOffsetX = MICROPROFILE_CUSTOM_PADDING;
2584             nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2f", pTimeAvg[i]);
2585             MicroProfileDrawText(nOffsetX, nOffsetY, UINT32_MAX, Buffer, nSize);
2586             nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
2587             nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2f", pTimeMax[i]);
2588             MicroProfileDrawText(nOffsetX, nOffsetY, UINT32_MAX, Buffer, nSize);
2589             nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
2590             nSize = snprintf(Buffer, sizeof(Buffer)-1, "%s:%s", S.GroupInfo[nGroupIndex].pName, pTimerInfo->pName);
2591             MicroProfileDrawText(nOffsetX, nOffsetY, pTimerInfo->nColor, Buffer, nSize);
2592             nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
2593             nMaxOffsetX = MicroProfileMax(nMaxOffsetX, nOffsetX);
2594         }
2595         uint32_t nMaxWidth = nReducedWidth- nMaxOffsetX;
2596 
2597         if(pCustom->nFlags & MICROPROFILE_CUSTOM_BARS)
2598         {
2599             nOffsetY = nOffsetYBase;
2600             float* pMs = pCustom->nFlags & MICROPROFILE_CUSTOM_BAR_SOURCE_MAX ? pTimeMax : pTimeAvg;
2601             const char* pString = pCustom->nFlags & MICROPROFILE_CUSTOM_BAR_SOURCE_MAX ? "Max" : "Avg";
2602             MicroProfileDrawText(nMaxOffsetX, nOffsetY, UINT32_MAX, pString, static_cast<uint32_t>(strlen(pString)));
2603             int nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2fms", fReference);
2604             MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, UINT32_MAX, Buffer, nSize);
2605             for(uint32_t i = 0; i < nCount; ++i)
2606             {
2607                 nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
2608                 uint32_t nWidth = MicroProfileMin(nMaxWidth, (uint32_t)(nMaxWidth * pMs[i] * fRcpReference));
2609                 MicroProfileDrawBox(nMaxOffsetX, nOffsetY, nMaxOffsetX+nWidth, nOffsetY+MICROPROFILE_TEXT_HEIGHT, pColors[i]|0xff000000);
2610             }
2611         }
2612         if(pCustom->nFlags & MICROPROFILE_CUSTOM_STACK)
2613         {
2614             nOffsetY += 2*(1+MICROPROFILE_TEXT_HEIGHT);
2615             const char* pString = pCustom->nFlags & MICROPROFILE_CUSTOM_STACK_SOURCE_MAX ? "Max" : "Avg";
2616             MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING, nOffsetY, UINT32_MAX, pString, static_cast<uint32_t>(strlen(pString)));
2617             int nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2fms", fReference);
2618             MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, UINT32_MAX, Buffer, nSize);
2619             nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
2620             float fPosX = MICROPROFILE_CUSTOM_PADDING;
2621             float* pMs = pCustom->nFlags & MICROPROFILE_CUSTOM_STACK_SOURCE_MAX ? pTimeMax : pTimeAvg;
2622             for(uint32_t i = 0; i < nCount; ++i)
2623             {
2624                 float fWidth = pMs[i] * fRcpReference * nReducedWidth;
2625                 uint32_t nX = fPosX;
2626                 fPosX += fWidth;
2627                 uint32_t nXEnd = fPosX;
2628                 if(nX < nXEnd)
2629                 {
2630                     MicroProfileDrawBox(nX, nOffsetY, nXEnd, nOffsetY+MICROPROFILE_TEXT_HEIGHT, pColors[i]|0xff000000);
2631                 }
2632             }
2633         }
2634     }
2635 }
MicroProfileDraw(uint32_t nWidth,uint32_t nHeight)2636 void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
2637 {
2638     MICROPROFILE_SCOPE(g_MicroProfileDraw);
2639     MicroProfile& S = *MicroProfileGet();
2640 
2641     {
2642         static int once = 0;
2643         if(0 == once)
2644         {
2645             std::recursive_mutex& m = MicroProfileGetMutex();
2646             m.lock();
2647             MicroProfileInitUI();
2648 
2649 
2650 
2651             uint32_t nDisplay = S.nDisplay;
2652             MicroProfileLoadPreset(MICROPROFILE_DEFAULT_PRESET);
2653             once++;
2654             S.nDisplay = nDisplay;// dont load display, just state
2655             m.unlock();
2656 
2657         }
2658     }
2659 
2660 
2661     if(S.nDisplay)
2662     {
2663         std::recursive_mutex& m = MicroProfileGetMutex();
2664         m.lock();
2665         UI.nWidth = nWidth;
2666         UI.nHeight = nHeight;
2667         UI.nHoverToken = MICROPROFILE_INVALID_TOKEN;
2668         UI.nHoverTime = 0;
2669         UI.nHoverFrame = -1;
2670         if(S.nDisplay != MP_DRAW_DETAILED)
2671             S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = UINT32_MAX;
2672         MicroProfileMoveGraph();
2673 
2674 
2675         if(S.nDisplay == MP_DRAW_DETAILED)
2676         {
2677             MicroProfileDrawDetailedView(nWidth, nHeight);
2678         }
2679         else if(S.nDisplay == MP_DRAW_BARS && S.nBars)
2680         {
2681             MicroProfileDrawBarView(nWidth, nHeight);
2682         }
2683 
2684         MicroProfileDrawMenu(nWidth, nHeight);
2685         bool bMouseOverGraph = MicroProfileDrawGraph(nWidth, nHeight);
2686         MicroProfileDrawCustom(nWidth, nHeight);
2687         bool bHidden = S.nDisplay == MP_DRAW_HIDDEN;
2688         if(!bHidden)
2689         {
2690             uint32_t nLockedToolTipX = 3;
2691             bool bDeleted = false;
2692             for(int i = 0; i < MICROPROFILE_TOOLTIP_MAX_LOCKED; ++i)
2693             {
2694                 int nIndex = (g_MicroProfileUI.LockedToolTipFront + i) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
2695                 if(g_MicroProfileUI.LockedToolTips[nIndex].ppStrings[0])
2696                 {
2697                     uint32_t nToolTipWidth = 0, nToolTipHeight = 0;
2698                     MicroProfileFloatWindowSize(g_MicroProfileUI.LockedToolTips[nIndex].ppStrings, g_MicroProfileUI.LockedToolTips[nIndex].nNumStrings, 0, nToolTipWidth, nToolTipHeight, 0);
2699                     uint32_t nStartY = nHeight - nToolTipHeight - 2;
2700                     if(!bDeleted && UI.nMouseY > nStartY && UI.nMouseX > nLockedToolTipX && UI.nMouseX <= nLockedToolTipX + nToolTipWidth && (UI.nMouseLeft || UI.nMouseRight) )
2701                     {
2702                         bDeleted = true;
2703                         int j = i;
2704                         for(; j < MICROPROFILE_TOOLTIP_MAX_LOCKED-1; ++j)
2705                         {
2706                             int nIndex0 = (g_MicroProfileUI.LockedToolTipFront + j) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
2707                             int nIndex1 = (g_MicroProfileUI.LockedToolTipFront + j+1) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
2708                             MicroProfileStringArrayCopy(&g_MicroProfileUI.LockedToolTips[nIndex0], &g_MicroProfileUI.LockedToolTips[nIndex1]);
2709                         }
2710                         MicroProfileStringArrayClear(&g_MicroProfileUI.LockedToolTips[(g_MicroProfileUI.LockedToolTipFront + j) % MICROPROFILE_TOOLTIP_MAX_LOCKED]);
2711                     }
2712                     else
2713                     {
2714                         MicroProfileDrawFloatWindow(nLockedToolTipX, nHeight-nToolTipHeight-2, &g_MicroProfileUI.LockedToolTips[nIndex].ppStrings[0], g_MicroProfileUI.LockedToolTips[nIndex].nNumStrings, g_MicroProfileUI.nLockedToolTipColor[nIndex]);
2715                         nLockedToolTipX += nToolTipWidth + 4;
2716                     }
2717                 }
2718             }
2719 
2720             if(UI.nActiveMenu == 8)
2721             {
2722                 if(S.nDisplay & MP_DRAW_DETAILED)
2723                 {
2724                     MicroProfileStringArray DetailedHelp;
2725                     MicroProfileStringArrayClear(&DetailedHelp);
2726                     MicroProfileStringArrayFormat(&DetailedHelp, "%s", MICROPROFILE_HELP_LEFT);
2727                     MicroProfileStringArrayAddLiteral(&DetailedHelp, "Toggle Graph");
2728                     MicroProfileStringArrayFormat(&DetailedHelp, "%s", MICROPROFILE_HELP_ALT);
2729                     MicroProfileStringArrayAddLiteral(&DetailedHelp, "Zoom");
2730                     MicroProfileStringArrayFormat(&DetailedHelp, "%s + %s", MICROPROFILE_HELP_MOD, MICROPROFILE_HELP_LEFT);
2731                     MicroProfileStringArrayAddLiteral(&DetailedHelp, "Lock Tooltip");
2732                     MicroProfileStringArrayAddLiteral(&DetailedHelp, "Drag");
2733                     MicroProfileStringArrayAddLiteral(&DetailedHelp, "Pan View");
2734                     MicroProfileStringArrayAddLiteral(&DetailedHelp, "Mouse Wheel");
2735                     MicroProfileStringArrayAddLiteral(&DetailedHelp, "Zoom");
2736                     MicroProfileDrawFloatWindow(nWidth, MICROPROFILE_FRAME_HISTORY_HEIGHT+20, DetailedHelp.ppStrings, DetailedHelp.nNumStrings, 0xff777777);
2737 
2738                     MicroProfileStringArray DetailedHistoryHelp;
2739                     MicroProfileStringArrayClear(&DetailedHistoryHelp);
2740                     MicroProfileStringArrayFormat(&DetailedHistoryHelp, "%s", MICROPROFILE_HELP_LEFT);
2741                     MicroProfileStringArrayAddLiteral(&DetailedHistoryHelp, "Center View");
2742                     MicroProfileStringArrayFormat(&DetailedHistoryHelp, "%s", MICROPROFILE_HELP_ALT);
2743                     MicroProfileStringArrayAddLiteral(&DetailedHistoryHelp, "Zoom to frame");
2744                     MicroProfileDrawFloatWindow(nWidth, 20, DetailedHistoryHelp.ppStrings, DetailedHistoryHelp.nNumStrings, 0xff777777);
2745 
2746 
2747 
2748                 }
2749                 else if(0 != (S.nDisplay & MP_DRAW_BARS) && S.nBars)
2750                 {
2751                     MicroProfileStringArray BarHelp;
2752                     MicroProfileStringArrayClear(&BarHelp);
2753                     MicroProfileStringArrayFormat(&BarHelp, "%s", MICROPROFILE_HELP_LEFT);
2754                     MicroProfileStringArrayAddLiteral(&BarHelp, "Toggle Graph");
2755                     MicroProfileStringArrayFormat(&BarHelp, "%s + %s", MICROPROFILE_HELP_MOD, MICROPROFILE_HELP_LEFT);
2756                     MicroProfileStringArrayAddLiteral(&BarHelp, "Lock Tooltip");
2757                     MicroProfileStringArrayAddLiteral(&BarHelp, "Drag");
2758                     MicroProfileStringArrayAddLiteral(&BarHelp, "Pan View");
2759                     MicroProfileDrawFloatWindow(nWidth, MICROPROFILE_FRAME_HISTORY_HEIGHT+20, BarHelp.ppStrings, BarHelp.nNumStrings, 0xff777777);
2760 
2761                 }
2762                 MicroProfileStringArray Debug;
2763                 MicroProfileStringArrayClear(&Debug);
2764                 MicroProfileStringArrayAddLiteral(&Debug, "Memory Usage");
2765                 MicroProfileStringArrayFormat(&Debug, "%4.2fmb", S.nMemUsage / (1024.f * 1024.f));
2766                 MicroProfileStringArrayAddLiteral(&Debug, "Web Server Port");
2767                 MicroProfileStringArrayFormat(&Debug, "%d", MicroProfileWebServerPort());
2768                 uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
2769                 MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
2770                 MicroProfileFrameState* pFrameNext = &S.Frames[nFrameNext];
2771 
2772 
2773                 MicroProfileStringArrayAddLiteral(&Debug, "");
2774                 MicroProfileStringArrayAddLiteral(&Debug, "");
2775                 MicroProfileStringArrayAddLiteral(&Debug, "Usage");
2776                 MicroProfileStringArrayAddLiteral(&Debug, "markers [frames] ");
2777 
2778 #if MICROPROFILE_CONTEXT_SWITCH_TRACE
2779                 MicroProfileStringArrayAddLiteral(&Debug, "Context Switch");
2780                 MicroProfileStringArrayFormat(&Debug, "%9d [%7d]", S.nContextSwitchUsage, MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE / S.nContextSwitchUsage );
2781 #endif
2782 
2783                 for(int i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
2784                 {
2785                     if(pFrameCurrent->nLogStart[i] && S.Pool[i])
2786                     {
2787                         uint32_t nEnd = pFrameNext->nLogStart[i];
2788                         uint32_t nStart = pFrameCurrent->nLogStart[i];
2789                         uint32_t nUsage = nStart < nEnd ? (nEnd - nStart) : (nEnd + MICROPROFILE_BUFFER_SIZE - nStart);
2790                         uint32_t nFrameSupport = MICROPROFILE_BUFFER_SIZE / nUsage;
2791                         MicroProfileStringArrayFormat(&Debug, "%s", &S.Pool[i]->ThreadName[0]);
2792                         MicroProfileStringArrayFormat(&Debug, "%9d [%7d]", nUsage, nFrameSupport);
2793                     }
2794                 }
2795 
2796                 MicroProfileDrawFloatWindow(0, nHeight-10, Debug.ppStrings, Debug.nNumStrings, 0xff777777);
2797             }
2798 
2799 
2800 
2801             if(UI.nActiveMenu == UINT32_MAX && !bMouseOverGraph)
2802             {
2803                 if(UI.nHoverToken != MICROPROFILE_INVALID_TOKEN)
2804                 {
2805                     MicroProfileDrawFloatTooltip(UI.nMouseX, UI.nMouseY, UI.nHoverToken, UI.nHoverTime);
2806                 }
2807                 else if(S.nContextSwitchHoverThreadAfter != UINT32_MAX && S.nContextSwitchHoverThreadBefore != UINT32_MAX)
2808                 {
2809                     float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2810                     MicroProfileStringArray ToolTip;
2811                     MicroProfileStringArrayClear(&ToolTip);
2812                     MicroProfileStringArrayAddLiteral(&ToolTip, "Context Switch");
2813                     MicroProfileStringArrayFormat(&ToolTip, "%04x", S.nContextSwitchHoverThread);
2814                     MicroProfileStringArrayAddLiteral(&ToolTip, "Before");
2815                     MicroProfileStringArrayFormat(&ToolTip, "%04x", S.nContextSwitchHoverThreadBefore);
2816                     MicroProfileStringArrayAddLiteral(&ToolTip, "After");
2817                     MicroProfileStringArrayFormat(&ToolTip, "%04x", S.nContextSwitchHoverThreadAfter);
2818                     MicroProfileStringArrayAddLiteral(&ToolTip, "Duration");
2819                     int64_t nDifference = MicroProfileLogTickDifference(S.nContextSwitchHoverTickIn, S.nContextSwitchHoverTickOut);
2820                     MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fToMs * nDifference );
2821                     MicroProfileStringArrayAddLiteral(&ToolTip, "CPU");
2822                     MicroProfileStringArrayFormat(&ToolTip, "%d", S.nContextSwitchHoverCpu);
2823                     MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, UINT32_MAX);
2824 
2825 
2826                 }
2827                 else if(UI.nHoverFrame != -1)
2828                 {
2829                     uint32_t nNextFrame = (UI.nHoverFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY;
2830                     int64_t nTick = S.Frames[UI.nHoverFrame].nFrameStartCpu;
2831                     int64_t nTickNext = S.Frames[nNextFrame].nFrameStartCpu;
2832                     int64_t nTickGpu = S.Frames[UI.nHoverFrame].nFrameStartGpu;
2833                     int64_t nTickNextGpu = S.Frames[nNextFrame].nFrameStartGpu;
2834 
2835                     float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2836                     float fToMsGpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());
2837                     float fMs = fToMs * (nTickNext - nTick);
2838                     float fMsGpu = fToMsGpu * (nTickNextGpu - nTickGpu);
2839                     MicroProfileStringArray ToolTip;
2840                     MicroProfileStringArrayClear(&ToolTip);
2841                     MicroProfileStringArrayFormat(&ToolTip, "Frame %d", UI.nHoverFrame);
2842     #if MICROPROFILE_DEBUG
2843                     MicroProfileStringArrayFormat(&ToolTip, "%p", &S.Frames[UI.nHoverFrame]);
2844     #else
2845                     MicroProfileStringArrayAddLiteral(&ToolTip, "");
2846     #endif
2847                     MicroProfileStringArrayAddLiteral(&ToolTip, "CPU Time");
2848                     MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fMs);
2849                     MicroProfileStringArrayAddLiteral(&ToolTip, "GPU Time");
2850                     MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fMsGpu);
2851                     #if MICROPROFILE_DEBUG
2852                     for(int i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
2853                     {
2854                         if(S.Frames[UI.nHoverFrame].nLogStart[i])
2855                         {
2856                             MicroProfileStringArrayFormat(&ToolTip, "%d", i);
2857                             MicroProfileStringArrayFormat(&ToolTip, "%d", S.Frames[UI.nHoverFrame].nLogStart[i]);
2858                         }
2859                     }
2860                     #endif
2861                     MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, UINT32_MAX);
2862                 }
2863                 if(UI.nMouseLeft)
2864                 {
2865                     if(UI.nHoverToken != MICROPROFILE_INVALID_TOKEN)
2866                         MicroProfileToggleGraph(UI.nHoverToken);
2867                 }
2868             }
2869         }
2870 
2871 #if MICROPROFILE_DRAWCURSOR
2872         {
2873             float fCursor[8] =
2874             {
2875                 MicroProfileMax(0, (int)UI.nMouseX-3), UI.nMouseY,
2876                 MicroProfileMin(nWidth, UI.nMouseX+3), UI.nMouseY,
2877                 UI.nMouseX, MicroProfileMax((int)UI.nMouseY-3, 0),
2878                 UI.nMouseX, MicroProfileMin(nHeight, UI.nMouseY+3),
2879             };
2880             MicroProfileDrawLine2D(2, &fCursor[0], 0xff00ff00);
2881             MicroProfileDrawLine2D(2, &fCursor[4], 0xff00ff00);
2882         }
2883 #endif
2884         m.unlock();
2885     }
2886     else if(UI.nCustomActive != UINT32_MAX)
2887     {
2888         std::recursive_mutex& m = MicroProfileGetMutex();
2889         m.lock();
2890         MicroProfileDrawGraph(nWidth, nHeight);
2891         MicroProfileDrawCustom(nWidth, nHeight);
2892         m.unlock();
2893 
2894     }
2895     UI.nMouseLeft = UI.nMouseRight = 0;
2896     UI.nMouseLeftMod = UI.nMouseRightMod = 0;
2897     UI.nMouseWheelDelta = 0;
2898     if(S.nOverflow)
2899         S.nOverflow--;
2900 
2901     UI.fDetailedOffset = UI.fDetailedOffset + (UI.fDetailedOffsetTarget - UI.fDetailedOffset) * MICROPROFILE_ANIM_DELAY_PRC;
2902     UI.fDetailedRange = UI.fDetailedRange + (UI.fDetailedRangeTarget - UI.fDetailedRange) * MICROPROFILE_ANIM_DELAY_PRC;
2903 
2904 
2905 }
2906 
MicroProfileIsDrawing()2907 bool MicroProfileIsDrawing()
2908 {
2909     MicroProfile& S = *MicroProfileGet();
2910     return S.nDisplay != 0;
2911 }
2912 
MicroProfileToggleGraph(MicroProfileToken nToken)2913 void MicroProfileToggleGraph(MicroProfileToken nToken)
2914 {
2915     MicroProfile& S = *MicroProfileGet();
2916     uint32_t nTimerId = MicroProfileGetTimerIndex(nToken);
2917     nToken &= 0xffff;
2918     int32_t nMinSort = 0x7fffffff;
2919     int32_t nFreeIndex = -1;
2920     int32_t nMinIndex = 0;
2921     int32_t nMaxSort = 0x80000000;
2922     for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
2923     {
2924         if(S.Graph[i].nToken == MICROPROFILE_INVALID_TOKEN)
2925             nFreeIndex = i;
2926         if(S.Graph[i].nToken == nToken)
2927         {
2928             S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
2929             S.TimerInfo[nTimerId].bGraph = false;
2930             return;
2931         }
2932         if(S.Graph[i].nKey < nMinSort)
2933         {
2934             nMinSort = S.Graph[i].nKey;
2935             nMinIndex = i;
2936         }
2937         if(S.Graph[i].nKey > nMaxSort)
2938         {
2939             nMaxSort = S.Graph[i].nKey;
2940         }
2941     }
2942     int nIndex = nFreeIndex > -1 ? nFreeIndex : nMinIndex;
2943     if (nFreeIndex == -1)
2944     {
2945         uint32_t idx = MicroProfileGetTimerIndex(S.Graph[nIndex].nToken);
2946         S.TimerInfo[idx].bGraph = false;
2947     }
2948     S.Graph[nIndex].nToken = nToken;
2949     S.Graph[nIndex].nKey = nMaxSort+1;
2950     memset(&S.Graph[nIndex].nHistory[0], 0, sizeof(S.Graph[nIndex].nHistory));
2951     S.TimerInfo[nTimerId].bGraph = true;
2952 }
2953 
2954 
MicroProfileMousePosition(uint32_t nX,uint32_t nY,int nWheelDelta)2955 void MicroProfileMousePosition(uint32_t nX, uint32_t nY, int nWheelDelta)
2956 {
2957     UI.nMouseX = nX;
2958     UI.nMouseY = nY;
2959     UI.nMouseWheelDelta = nWheelDelta;
2960 }
2961 
MicroProfileModKey(uint32_t nKeyState)2962 void MicroProfileModKey(uint32_t nKeyState)
2963 {
2964     UI.nModDown = nKeyState ? 1 : 0;
2965 }
2966 
MicroProfileClearGraph()2967 void MicroProfileClearGraph()
2968 {
2969     MicroProfile& S = *MicroProfileGet();
2970     for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
2971     {
2972         if(S.Graph[i].nToken != 0)
2973         {
2974             S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
2975         }
2976     }
2977 }
2978 
MicroProfileMouseButton(uint32_t nLeft,uint32_t nRight)2979 void MicroProfileMouseButton(uint32_t nLeft, uint32_t nRight)
2980 {
2981     bool bCanRelease = abs((int)(UI.nMouseDownX - UI.nMouseX)) + abs((int)(UI.nMouseDownY - UI.nMouseY)) < 3;
2982 
2983     if(0 == nLeft && UI.nMouseDownLeft && bCanRelease)
2984     {
2985         if(UI.nModDown)
2986             UI.nMouseLeftMod = 1;
2987         else
2988             UI.nMouseLeft = 1;
2989     }
2990 
2991     if(0 == nRight && UI.nMouseDownRight && bCanRelease)
2992     {
2993         if(UI.nModDown)
2994             UI.nMouseRightMod = 1;
2995         else
2996             UI.nMouseRight = 1;
2997     }
2998     if((nLeft || nRight) && !(UI.nMouseDownLeft || UI.nMouseDownRight))
2999     {
3000         UI.nMouseDownX = UI.nMouseX;
3001         UI.nMouseDownY = UI.nMouseY;
3002     }
3003 
3004     UI.nMouseDownLeft = nLeft;
3005     UI.nMouseDownRight = nRight;
3006 
3007 }
3008 
MicroProfileDrawLineVertical(int nX,int nTop,int nBottom,uint32_t nColor)3009 void MicroProfileDrawLineVertical(int nX, int nTop, int nBottom, uint32_t nColor)
3010 {
3011     MicroProfileDrawBox(nX, nTop, nX + 1, nBottom, nColor);
3012 }
3013 
MicroProfileDrawLineHorizontal(int nLeft,int nRight,int nY,uint32_t nColor)3014 void MicroProfileDrawLineHorizontal(int nLeft, int nRight, int nY, uint32_t nColor)
3015 {
3016     MicroProfileDrawBox(nLeft, nY, nRight, nY + 1, nColor);
3017 }
3018 
3019 
3020 
3021 #include <stdio.h>
3022 
3023 #define MICROPROFILE_PRESET_HEADER_MAGIC 0x28586813
3024 #define MICROPROFILE_PRESET_HEADER_VERSION 0x00000102
3025 struct MicroProfilePresetHeader
3026 {
3027     uint32_t nMagic;
3028     uint32_t nVersion;
3029     //groups, threads, aggregate, reference frame, graphs timers
3030     uint32_t nGroups[MICROPROFILE_MAX_GROUPS];
3031     uint32_t nThreads[MICROPROFILE_MAX_THREADS];
3032     uint32_t nGraphName[MICROPROFILE_MAX_GRAPHS];
3033     uint32_t nGraphGroupName[MICROPROFILE_MAX_GRAPHS];
3034     uint32_t nAllGroupsWanted;
3035     uint32_t nAllThreadsWanted;
3036     uint32_t nAggregateFlip;
3037     float fReferenceTime;
3038     uint32_t nBars;
3039     uint32_t nDisplay;
3040     uint32_t nOpacityBackground;
3041     uint32_t nOpacityForeground;
3042     uint32_t nShowSpikes;
3043 };
3044 
3045 #ifndef MICROPROFILE_PRESET_FILENAME_FUNC
3046 #define MICROPROFILE_PRESET_FILENAME_FUNC MicroProfilePresetFilename
MicroProfilePresetFilename(const char * pSuffix)3047 static const char* MicroProfilePresetFilename(const char* pSuffix)
3048 {
3049     static char filename[512];
3050     snprintf(filename, sizeof(filename)-1, ".microprofilepreset.%s", pSuffix);
3051     return filename;
3052 }
3053 #endif
3054 
MicroProfileSavePreset(const char * pPresetName)3055 void MicroProfileSavePreset(const char* pPresetName)
3056 {
3057     std::lock_guard<std::recursive_mutex> Lock(MicroProfileGetMutex());
3058     FILE* F = fopen(MICROPROFILE_PRESET_FILENAME_FUNC(pPresetName), "wb");
3059     if(!F) return;
3060 
3061     MicroProfile& S = *MicroProfileGet();
3062 
3063     MicroProfilePresetHeader Header;
3064     memset(&Header, 0, sizeof(Header));
3065     Header.nAggregateFlip = S.nAggregateFlip;
3066     Header.nBars = S.nBars;
3067     Header.fReferenceTime = S.fReferenceTime;
3068     Header.nAllGroupsWanted = S.nAllGroupsWanted;
3069     Header.nAllThreadsWanted = S.nAllThreadsWanted;
3070     Header.nMagic = MICROPROFILE_PRESET_HEADER_MAGIC;
3071     Header.nVersion = MICROPROFILE_PRESET_HEADER_VERSION;
3072     Header.nDisplay = S.nDisplay;
3073     Header.nOpacityBackground = UI.nOpacityBackground;
3074     Header.nOpacityForeground = UI.nOpacityForeground;
3075     Header.nShowSpikes = UI.bShowSpikes ? 1 : 0;
3076     fwrite(&Header, sizeof(Header), 1, F);
3077     uint64_t nMask = 1;
3078     for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
3079     {
3080         if(S.nActiveGroupWanted & nMask)
3081         {
3082             uint32_t offset = ftell(F);
3083             const char* pName = S.GroupInfo[i].pName;
3084             int nLen = (int)strlen(pName)+1;
3085             fwrite(pName, nLen, 1, F);
3086             Header.nGroups[i] = offset;
3087         }
3088         nMask <<= 1;
3089     }
3090     for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
3091     {
3092         MicroProfileThreadLog* pLog = S.Pool[i];
3093         if(pLog && S.nThreadActive[i])
3094         {
3095             uint32_t nOffset = ftell(F);
3096             const char* pName = &pLog->ThreadName[0];
3097             int nLen = (int)strlen(pName)+1;
3098             fwrite(pName, nLen, 1, F);
3099             Header.nThreads[i] = nOffset;
3100         }
3101     }
3102     for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
3103     {
3104         MicroProfileToken nToken = S.Graph[i].nToken;
3105         if(nToken != MICROPROFILE_INVALID_TOKEN)
3106         {
3107             uint32_t nGroupIndex = MicroProfileGetGroupIndex(nToken);
3108             uint32_t nTimerIndex = MicroProfileGetTimerIndex(nToken);
3109             const char* pGroupName = S.GroupInfo[nGroupIndex].pName;
3110             const char* pTimerName = S.TimerInfo[nTimerIndex].pName;
3111             MP_ASSERT(pGroupName);
3112             MP_ASSERT(pTimerName);
3113             int nGroupLen = (int)strlen(pGroupName)+1;
3114             int nTimerLen = (int)strlen(pTimerName)+1;
3115 
3116             uint32_t nOffsetGroup = ftell(F);
3117             fwrite(pGroupName, nGroupLen, 1, F);
3118             uint32_t nOffsetTimer = ftell(F);
3119             fwrite(pTimerName, nTimerLen, 1, F);
3120             Header.nGraphName[i] = nOffsetTimer;
3121             Header.nGraphGroupName[i] = nOffsetGroup;
3122         }
3123     }
3124     fseek(F, 0, SEEK_SET);
3125     fwrite(&Header, sizeof(Header), 1, F);
3126 
3127     fclose(F);
3128 
3129 }
3130 
3131 
3132 
MicroProfileLoadPreset(const char * pSuffix)3133 void MicroProfileLoadPreset(const char* pSuffix)
3134 {
3135     std::lock_guard<std::recursive_mutex> Lock(MicroProfileGetMutex());
3136     FILE* F = fopen(MICROPROFILE_PRESET_FILENAME_FUNC(pSuffix), "rb");
3137     if(!F)
3138     {
3139         return;
3140     }
3141     fseek(F, 0, SEEK_END);
3142     int nSize = ftell(F);
3143     char* const pBuffer = (char*)alloca(nSize);
3144     fseek(F, 0, SEEK_SET);
3145     int nRead = (int)fread(pBuffer, nSize, 1, F);
3146     fclose(F);
3147     if(1 != nRead)
3148         return;
3149 
3150     MicroProfile& S = *MicroProfileGet();
3151 
3152     MicroProfilePresetHeader& Header = *(MicroProfilePresetHeader*)pBuffer;
3153 
3154     if(Header.nMagic != MICROPROFILE_PRESET_HEADER_MAGIC || Header.nVersion != MICROPROFILE_PRESET_HEADER_VERSION)
3155     {
3156         return;
3157     }
3158 
3159     S.nAggregateFlip = Header.nAggregateFlip;
3160     S.nBars = Header.nBars;
3161     S.fReferenceTime = Header.fReferenceTime;
3162     S.fRcpReferenceTime = 1.f / Header.fReferenceTime;
3163     S.nAllGroupsWanted = Header.nAllGroupsWanted;
3164     S.nAllThreadsWanted = Header.nAllThreadsWanted;
3165     S.nDisplay = Header.nDisplay;
3166     S.nActiveGroupWanted = 0;
3167     UI.nOpacityBackground = Header.nOpacityBackground;
3168     UI.nOpacityForeground = Header.nOpacityForeground;
3169     UI.bShowSpikes = Header.nShowSpikes == 1;
3170 
3171     memset(&S.nThreadActive[0], 0, sizeof(S.nThreadActive));
3172 
3173     for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
3174     {
3175         if(Header.nGroups[i])
3176         {
3177             const char* pGroupName = pBuffer + Header.nGroups[i];
3178             for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
3179             {
3180                 if(0 == MP_STRCASECMP(pGroupName, S.GroupInfo[j].pName))
3181                 {
3182                     S.nActiveGroupWanted |= (1ULL << j);
3183                 }
3184             }
3185         }
3186     }
3187     for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
3188     {
3189         if(Header.nThreads[i])
3190         {
3191             const char* pThreadName = pBuffer + Header.nThreads[i];
3192             for(uint32_t j = 0; j < MICROPROFILE_MAX_THREADS; ++j)
3193             {
3194                 MicroProfileThreadLog* pLog = S.Pool[j];
3195                 if(pLog && 0 == MP_STRCASECMP(pThreadName, &pLog->ThreadName[0]))
3196                 {
3197                     S.nThreadActive[j] = 1;
3198                 }
3199             }
3200         }
3201     }
3202     for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
3203     {
3204         MicroProfileToken nPrevToken = S.Graph[i].nToken;
3205         S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
3206         if(Header.nGraphName[i] && Header.nGraphGroupName[i])
3207         {
3208             const char* pGraphName = pBuffer + Header.nGraphName[i];
3209             const char* pGraphGroupName = pBuffer + Header.nGraphGroupName[i];
3210             for(uint32_t j = 0; j < S.nTotalTimers; ++j)
3211             {
3212                 uint64_t nGroupIndex = S.TimerInfo[j].nGroupIndex;
3213                 if(0 == MP_STRCASECMP(pGraphName, S.TimerInfo[j].pName) && 0 == MP_STRCASECMP(pGraphGroupName, S.GroupInfo[nGroupIndex].pName))
3214                 {
3215                     MicroProfileToken nToken = MicroProfileMakeToken(1ULL << nGroupIndex, (uint16_t)j);
3216                     S.Graph[i].nToken = nToken;         // note: group index is stored here but is checked without in MicroProfileToggleGraph()!
3217                     S.TimerInfo[j].bGraph = true;
3218                     if(nToken != nPrevToken)
3219                     {
3220                         memset(&S.Graph[i].nHistory, 0, sizeof(S.Graph[i].nHistory));
3221                     }
3222                     break;
3223                 }
3224             }
3225         }
3226     }
3227 }
3228 
MicroProfileCustomGroupFind(const char * pCustomName)3229 uint32_t MicroProfileCustomGroupFind(const char* pCustomName)
3230 {
3231     for(uint32_t i = 0; i < UI.nCustomCount; ++i)
3232     {
3233         if(!MP_STRCASECMP(pCustomName, UI.Custom[i].pName))
3234         {
3235             return i;
3236         }
3237     }
3238     return UINT32_MAX;
3239 }
3240 
MicroProfileCustomGroup(const char * pCustomName)3241 uint32_t MicroProfileCustomGroup(const char* pCustomName)
3242 {
3243     for(uint32_t i = 0; i < UI.nCustomCount; ++i)
3244     {
3245         if(!MP_STRCASECMP(pCustomName, UI.Custom[i].pName))
3246         {
3247             return i;
3248         }
3249     }
3250     MP_ASSERT(UI.nCustomCount < MICROPROFILE_CUSTOM_MAX);
3251     uint32_t nIndex = UI.nCustomCount;
3252     UI.nCustomCount++;
3253     memset(&UI.Custom[nIndex], 0, sizeof(UI.Custom[nIndex]));
3254     size_t nLen = strlen(pCustomName);
3255     if(nLen > MICROPROFILE_NAME_MAX_LEN-1)
3256         nLen = MICROPROFILE_NAME_MAX_LEN-1;
3257     memcpy(&UI.Custom[nIndex].pName[0], pCustomName, nLen);
3258     UI.Custom[nIndex].pName[nLen] = '\0';
3259     return nIndex;
3260 }
MicroProfileCustomGroup(const char * pCustomName,uint32_t nMaxTimers,uint32_t nAggregateFlip,float fReferenceTime,uint32_t nFlags)3261 void MicroProfileCustomGroup(const char* pCustomName, uint32_t nMaxTimers, uint32_t nAggregateFlip, float fReferenceTime, uint32_t nFlags)
3262 {
3263     uint32_t nIndex = MicroProfileCustomGroup(pCustomName);
3264     MP_ASSERT(UI.Custom[nIndex].pTimers == 0);//only call once!
3265     UI.Custom[nIndex].pTimers = &UI.CustomTimer[UI.nCustomTimerCount];
3266     UI.Custom[nIndex].nMaxTimers = nMaxTimers;
3267     UI.Custom[nIndex].fReference = fReferenceTime;
3268     UI.nCustomTimerCount += nMaxTimers;
3269     MP_ASSERT(UI.nCustomTimerCount <= MICROPROFILE_CUSTOM_MAX_TIMERS); //bump MICROPROFILE_CUSTOM_MAX_TIMERS
3270     UI.Custom[nIndex].nFlags = nFlags;
3271     UI.Custom[nIndex].nAggregateFlip = nAggregateFlip;
3272 }
3273 
MicroProfileCustomGroupEnable(uint32_t nIndex)3274 void MicroProfileCustomGroupEnable(uint32_t nIndex)
3275 {
3276     if(nIndex < UI.nCustomCount)
3277     {
3278         MicroProfile& S = *MicroProfileGet();
3279         S.nForceGroupUI = UI.Custom[nIndex].nGroupMask;
3280         MicroProfileSetAggregateFrames(UI.Custom[nIndex].nAggregateFlip);
3281         S.fReferenceTime = UI.Custom[nIndex].fReference;
3282         S.fRcpReferenceTime = 1.f / UI.Custom[nIndex].fReference;
3283         UI.nCustomActive = nIndex;
3284 
3285         for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
3286         {
3287             if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
3288             {
3289                 uint32_t nTimerId = MicroProfileGetTimerIndex(S.Graph[i].nToken);
3290                 S.TimerInfo[nTimerId].bGraph = false;
3291                 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
3292             }
3293         }
3294 
3295         for(uint32_t i = 0; i < UI.Custom[nIndex].nNumTimers; ++i)
3296         {
3297             if(i == MICROPROFILE_MAX_GRAPHS)
3298             {
3299                 break;
3300             }
3301             S.Graph[i].nToken = UI.Custom[nIndex].pTimers[i];
3302             S.Graph[i].nKey = i;
3303             uint32_t nTimerId = MicroProfileGetTimerIndex(S.Graph[i].nToken);
3304             S.TimerInfo[nTimerId].bGraph = true;
3305         }
3306     }
3307 }
3308 
MicroProfileCustomGroupToggle(const char * pCustomName)3309 void MicroProfileCustomGroupToggle(const char* pCustomName)
3310 {
3311     uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
3312     if(nIndex == UINT32_MAX || nIndex == UI.nCustomActive)
3313     {
3314         MicroProfileCustomGroupDisable();
3315     }
3316     else
3317     {
3318         MicroProfileCustomGroupEnable(nIndex);
3319     }
3320 }
3321 
MicroProfileCustomGroupEnable(const char * pCustomName)3322 void MicroProfileCustomGroupEnable(const char* pCustomName)
3323 {
3324     uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
3325     MicroProfileCustomGroupEnable(nIndex);
3326 }
MicroProfileCustomGroupDisable()3327 void MicroProfileCustomGroupDisable()
3328 {
3329     MicroProfile& S = *MicroProfileGet();
3330     S.nForceGroupUI = 0;
3331     UI.nCustomActive = UINT32_MAX;
3332 }
3333 
MicroProfileCustomGroupAddTimer(const char * pCustomName,const char * pGroup,const char * pTimer)3334 void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup, const char* pTimer)
3335 {
3336     uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
3337     if(UINT32_MAX == nIndex)
3338     {
3339         return;
3340     }
3341     uint32_t nTimerIndex = UI.Custom[nIndex].nNumTimers;
3342     MP_ASSERT(nTimerIndex < UI.Custom[nIndex].nMaxTimers);
3343     uint64_t nToken = MicroProfileFindToken(pGroup, pTimer);
3344     MP_ASSERT(nToken != MICROPROFILE_INVALID_TOKEN); //Timer must be registered first.
3345     UI.Custom[nIndex].pTimers[nTimerIndex] = nToken;
3346     uint16_t nGroup = MicroProfileGetGroupIndex(nToken);
3347     UI.Custom[nIndex].nGroupMask |= (1ULL << nGroup);
3348     UI.Custom[nIndex].nNumTimers++;
3349 }
3350 
3351 #undef UI
3352 
3353 #endif
3354 #endif
3355