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