summaryrefslogtreecommitdiff
path: root/externals/microprofile/microprofileui.h
diff options
context:
space:
mode:
Diffstat (limited to 'externals/microprofile/microprofileui.h')
-rw-r--r--externals/microprofile/microprofileui.h3348
1 files changed, 3348 insertions, 0 deletions
diff --git a/externals/microprofile/microprofileui.h b/externals/microprofile/microprofileui.h
new file mode 100644
index 000000000..eac1119a4
--- /dev/null
+++ b/externals/microprofile/microprofileui.h
@@ -0,0 +1,3348 @@
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
131enum
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
142MICROPROFILEUI_API void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight); //! call if drawing microprofilers
143MICROPROFILEUI_API bool MicroProfileIsDrawing();
144MICROPROFILEUI_API void MicroProfileToggleGraph(MicroProfileToken nToken);
145MICROPROFILEUI_API bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight);
146MICROPROFILEUI_API void MicroProfileToggleDisplayMode(); //switch between off, bars, detailed
147MICROPROFILEUI_API void MicroProfileSetDisplayMode(int); //switch between off, bars, detailed
148MICROPROFILEUI_API void MicroProfileClearGraph();
149MICROPROFILEUI_API void MicroProfileMousePosition(uint32_t nX, uint32_t nY, int nWheelDelta);
150MICROPROFILEUI_API void MicroProfileModKey(uint32_t nKeyState);
151MICROPROFILEUI_API void MicroProfileMouseButton(uint32_t nLeft, uint32_t nRight);
152MICROPROFILEUI_API void MicroProfileDrawLineVertical(int nX, int nTop, int nBottom, uint32_t nColor);
153MICROPROFILEUI_API void MicroProfileDrawLineHorizontal(int nLeft, int nRight, int nY, uint32_t nColor);
154MICROPROFILEUI_API void MicroProfileLoadPreset(const char* pSuffix);
155MICROPROFILEUI_API void MicroProfileSavePreset(const char* pSuffix);
156
157MICROPROFILEUI_API void MicroProfileDrawText(int nX, int nY, uint32_t nColor, const char* pText, uint32_t nNumCharacters);
158MICROPROFILEUI_API void MicroProfileDrawBox(int nX, int nY, int nX1, int nY1, uint32_t nColor, MicroProfileBoxType = MicroProfileBoxTypeFlat);
159MICROPROFILEUI_API void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices, uint32_t nColor);
160MICROPROFILEUI_API void MicroProfileDumpTimers();
161
162MICROPROFILEUI_API void MicroProfileInitUI();
163
164MICROPROFILEUI_API void MicroProfileCustomGroupToggle(const char* pCustomName);
165MICROPROFILEUI_API void MicroProfileCustomGroupEnable(const char* pCustomName);
166MICROPROFILEUI_API void MicroProfileCustomGroupEnable(uint32_t nIndex);
167MICROPROFILEUI_API void MicroProfileCustomGroupDisable();
168MICROPROFILEUI_API void MicroProfileCustomGroup(const char* pCustomName, uint32_t nMaxTimers, uint32_t nAggregateFlip, float fReferenceTime, uint32_t nFlags);
169MICROPROFILEUI_API void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup, const char* pTimer);
170
171#ifdef MICROPROFILEUI_IMPL
172#ifdef _WIN32
173#define snprintf _snprintf
174#endif
175#include <stdlib.h>
176#include <stdarg.h>
177#include <math.h>
178#include <algorithm>
179
180MICROPROFILE_DEFINE(g_MicroProfileDetailed, "MicroProfile", "Detailed View", 0x8888000);
181MICROPROFILE_DEFINE(g_MicroProfileDrawGraph, "MicroProfile", "Draw Graph", 0xff44ee00);
182MICROPROFILE_DEFINE(g_MicroProfileDrawBarView, "MicroProfile", "DrawBarView", 0x00dd77);
183MICROPROFILE_DEFINE(g_MicroProfileDraw,"MicroProfile", "Draw", 0x737373);
184
185
186struct 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
194struct MicroProfileGroupMenuItem
195{
196 uint32_t nIsCategory;
197 uint32_t nCategoryIndex;
198 uint32_t nIndex;
199 const char* pName;
200};
201
202struct 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
214struct SOptionDesc
215{
216 SOptionDesc(){}
217 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};
229static uint32_t g_MicroProfileAggregatePresets[] = {0, 10, 20, 30, 60, 120};
230static float g_MicroProfileReferenceTimePresets[] = {5.f, 10.f, 15.f,20.f, 33.33f, 66.66f, 100.f, 250.f, 500.f, 1000.f};
231static uint32_t g_MicroProfileOpacityPresets[] = {0x40, 0x80, 0xc0, 0xff};
232static const char* g_MicroProfilePresetNames[] =
233{
234 MICROPROFILE_DEFAULT_PRESET,
235 "Render",
236 "GPU",
237 "Lighting",
238 "AI",
239 "Visibility",
240 "Sound",
241};
242
243enum
244{
245 MICROPROFILE_NUM_REFERENCE_PRESETS = sizeof(g_MicroProfileReferenceTimePresets)/sizeof(g_MicroProfileReferenceTimePresets[0]),
246 MICROPROFILE_NUM_OPACITY_PRESETS = sizeof(g_MicroProfileOpacityPresets)/sizeof(g_MicroProfileOpacityPresets[0]),
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
254struct 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
326MicroProfileUI g_MicroProfileUI;
327#define UI g_MicroProfileUI
328static uint32_t g_nMicroProfileBackColors[2] = { 0x474747, 0x313131 };
329#define MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS 16
330static uint32_t g_nMicroProfileContextSwitchThreadColors[MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS] = //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
351void 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_t)-1;
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_t)-1;
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
403void 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
411void MicroProfileToggleDisplayMode()
412{
413 MicroProfile& S = *MicroProfileGet();
414 S.nDisplay = (S.nDisplay + 1) % 4;
415 UI.nOffsetY = 0;
416}
417
418
419void MicroProfileStringArrayClear(MicroProfileStringArray* pArray)
420{
421 pArray->nNumStrings = 0;
422 pArray->pBufferPos = &pArray->Buffer[0];
423}
424
425void MicroProfileStringArrayAddLiteral(MicroProfileStringArray* pArray, const char* pLiteral)
426{
427 MP_ASSERT(pArray->nNumStrings < MICROPROFILE_TOOLTIP_MAX_STRINGS);
428 pArray->ppStrings[pArray->nNumStrings++] = pLiteral;
429}
430
431void 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}
441void 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
458void 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
476void 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_t)-1, ppStrings[i0], (uint32_t)strlen(ppStrings[i0]));
501 MicroProfileDrawText(nX + nWidth - nStringLengths[i0+1] * (MICROPROFILE_TEXT_WIDTH+1), nY + 1, (uint32_t)-1, ppStrings[i0+1], (uint32_t)strlen(ppStrings[i0+1]));
502 nY += (MICROPROFILE_TEXT_HEIGHT+1);
503 }
504}
505void 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_t)-1, ppStrings[i], (uint32_t)strlen(ppStrings[i]));
525 nY += (MICROPROFILE_TEXT_HEIGHT+1);
526 }
527}
528
529
530
531void 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
610void 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
720void 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
730void 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
739uint64_t* g_pMicroProfileDumpStart = 0;
740uint64_t* g_pMicroProfileDumpEnd = 0;
741void 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
779void 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 = -1;
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
843void 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 || abs(nRefCpu-nBaseTicksCpu) > 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 = -1;
952
953 uint32_t nContextSwitchStart = -1;
954 uint32_t nContextSwitchEnd = -1;
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_t)-1)
1008 continue;
1009 MP_ASSERT(nGet != (uint32_t)-1);
1010
1011 nPut = pFrameLogLast->nLogStart[i];
1012
1013 uint32_t nRange[2][2] = { {0, 0}, {0, 0}, };
1014
1015 MicroProfileGetRange(nPut, nGet, nRange);
1016 if(nPut == nGet)
1017 continue;
1018 uint32_t nMaxStackDepth = 0;
1019
1020 bool bGpu = pLog->nGpu != 0;
1021 float fToMs = bGpu ? fToMsGpu : fToMsCpu;
1022 int64_t nBaseTicks = bGpu ? nBaseTicksGpu : nBaseTicksCpu;
1023 char ThreadName[MicroProfileThreadLog::THREAD_MAX_LEN + 16];
1024 uint64_t nThreadId = pLog->nThreadId;
1025 snprintf(ThreadName, sizeof(ThreadName)-1, "%04llx: %s", nThreadId, &pLog->ThreadName[0] );
1026 nY += 3;
1027 uint32_t nThreadColor = -1;
1028 if(pLog->nThreadId == nContextSwitchHoverThreadAfter || pLog->nThreadId == nContextSwitchHoverThreadBefore)
1029 nThreadColor = UI.nHoverColorShared|0x906060;
1030 MicroProfileDrawText(0, nY, nThreadColor, &ThreadName[0], (uint32_t)strlen(&ThreadName[0]));
1031 nY += 3;
1032 nY += MICROPROFILE_TEXT_HEIGHT + 1;
1033
1034 if(S.bContextSwitchRunning)
1035 {
1036 MicroProfileDrawDetailedContextSwitchBars(nY, pLog->nThreadId, nContextSwitchStart, nContextSwitchEnd, nBaseTicks, nBaseY);
1037 nY -= MICROPROFILE_DETAILED_BAR_HEIGHT;
1038 nY += MICROPROFILE_DETAILED_CONTEXT_SWITCH_HEIGHT+1;
1039 }
1040
1041 uint32_t nYDelta = MICROPROFILE_DETAILED_BAR_HEIGHT;
1042 uint32_t nStack[MICROPROFILE_STACK_MAX];
1043 uint32_t nStackPos = 0;
1044 for(uint32_t j = 0; j < 2; ++j)
1045 {
1046 uint32_t nStart = nRange[j][0];
1047 uint32_t nEnd = nRange[j][1];
1048 for(uint32_t k = nStart; k < nEnd; ++k)
1049 {
1050 MicroProfileLogEntry* pEntry = pLog->Log + k;
1051 int nType = MicroProfileLogType(*pEntry);
1052 if(MP_LOG_ENTER == nType)
1053 {
1054 MP_ASSERT(nStackPos < MICROPROFILE_STACK_MAX);
1055 nStack[nStackPos++] = k;
1056 }
1057 else if(MP_LOG_META == nType)
1058 {
1059
1060 }
1061 else if(MP_LOG_LEAVE == nType)
1062 {
1063 if(0 == nStackPos)
1064 {
1065 continue;
1066 }
1067
1068 MicroProfileLogEntry* pEntryEnter = pLog->Log + nStack[nStackPos-1];
1069 if(MicroProfileLogTimerIndex(*pEntryEnter) != MicroProfileLogTimerIndex(*pEntry))
1070 {
1071 //uprintf("mismatch %llx %llx\n", pEntryEnter->nToken, pEntry->nToken);
1072 continue;
1073 }
1074 int64_t nTickStart = MicroProfileLogGetTick(*pEntryEnter);
1075 int64_t nTickEnd = MicroProfileLogGetTick(*pEntry);
1076 uint64_t nTimerIndex = MicroProfileLogTimerIndex(*pEntry);
1077 uint32_t nColor = S.TimerInfo[nTimerIndex].nColor;
1078 if(nMouseOverToken == nTimerIndex)
1079 {
1080 if(pEntry == pMouseOver)
1081 {
1082 nColor = UI.nHoverColor;
1083 if(bGpu)
1084 {
1085 UI.nRangeBeginGpu = *pEntryEnter;
1086 UI.nRangeEndGpu = *pEntry;
1087 uint32_t nCpuBegin = (nStack[nStackPos-1] + 1) % MICROPROFILE_BUFFER_SIZE;
1088 uint32_t nCpuEnd = (k + 1) % MICROPROFILE_BUFFER_SIZE;
1089 MicroProfileLogEntry LogCpuBegin = pLog->Log[nCpuBegin];
1090 MicroProfileLogEntry LogCpuEnd = pLog->Log[nCpuEnd];
1091 if(MicroProfileLogType(LogCpuBegin)==3 && MicroProfileLogType(LogCpuEnd) == 3)
1092 {
1093 UI.nRangeBegin = LogCpuBegin;
1094 UI.nRangeEnd = LogCpuEnd;
1095 }
1096 UI.nRangeBeginIndex = nStack[nStackPos-1];
1097 UI.nRangeEndIndex = k;
1098 UI.pRangeLog = pLog;
1099 }
1100 else
1101 {
1102 UI.nRangeBegin = *pEntryEnter;
1103 UI.nRangeEnd = *pEntry;
1104 UI.nRangeBeginIndex = nStack[nStackPos-1];
1105 UI.nRangeEndIndex = k;
1106 UI.pRangeLog = pLog;
1107
1108 }
1109 }
1110 else
1111 {
1112 nColor = UI.nHoverColorShared;
1113 }
1114 }
1115
1116 nMaxStackDepth = MicroProfileMax(nMaxStackDepth, nStackPos);
1117 float fMsStart = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickStart);
1118 float fMsEnd = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickEnd);
1119 float fXStart = fMsStart * fMsToScreen;
1120 float fXEnd = fMsEnd * fMsToScreen;
1121 float fYStart = (float)(nY + nStackPos * nYDelta);
1122 float fYEnd = fYStart + (MICROPROFILE_DETAILED_BAR_HEIGHT);
1123 float fXDist = MicroProfileMax(fXStart - fMouseX, fMouseX - fXEnd);
1124 bool bHover = fXDist < MICROPROFILE_HOVER_DIST && fYStart <= fMouseY && fMouseY <= fYEnd && nBaseY < fMouseY;
1125 uint32_t nIntegerWidth = (uint32_t)(fXEnd - fXStart);
1126 if(nIntegerWidth)
1127 {
1128 if(bHover && UI.nActiveMenu == -1)
1129 {
1130 nHoverToken = MicroProfileLogTimerIndex(*pEntry);
1131 #if MICROPROFILE_DEBUG
1132 UI.nHoverAddressEnter = (uint64_t)pEntryEnter;
1133 UI.nHoverAddressLeave = (uint64_t)pEntry;
1134 #endif
1135 nHoverTime = MicroProfileLogTickDifference(nTickStart, nTickEnd);
1136 pMouseOverNext = pEntry;
1137 }
1138
1139 MicroProfileDrawBox(fXStart, fYStart, fXEnd, fYEnd, nColor|UI.nOpacityForeground, MicroProfileBoxTypeBar);
1140#if MICROPROFILE_DETAILED_BAR_NAMES
1141 if(nIntegerWidth>3*MICROPROFILE_TEXT_WIDTH)
1142 {
1143 float fXStartText = MicroProfileMax(fXStart, 0.f);
1144 int nTextWidth = (int)(fXEnd - fXStartText);
1145 int nCharacters = (nTextWidth - 2*MICROPROFILE_TEXT_WIDTH) / MICROPROFILE_TEXT_WIDTH;
1146 if(nCharacters>0)
1147 {
1148 MicroProfileDrawText(fXStartText+1, fYStart+1, -1, S.TimerInfo[nTimerIndex].pName, MicroProfileMin<uint32_t>(S.TimerInfo[nTimerIndex].nNameLen, nCharacters));
1149 }
1150 }
1151#endif
1152 ++nNumBoxes;
1153 }
1154 else
1155 {
1156 float fXAvg = 0.5f * (fXStart + fXEnd);
1157 int nLineX = (int)floor(fXAvg+0.5f);
1158 if(nLineX != (int)nLinesDrawn[nStackPos])
1159 {
1160 if(bHover && UI.nActiveMenu == -1)
1161 {
1162 nHoverToken = (uint32_t)MicroProfileLogTimerIndex(*pEntry);
1163 nHoverTime = MicroProfileLogTickDifference(nTickStart, nTickEnd);
1164 pMouseOverNext = pEntry;
1165 }
1166 nLinesDrawn[nStackPos] = nLineX;
1167 MicroProfileDrawLineVertical(nLineX, fYStart + 0.5f, fYEnd + 0.5f, nColor|UI.nOpacityForeground);
1168 ++nNumLines;
1169 }
1170 }
1171 nStackPos--;
1172 if(0 == nStackPos)
1173 {
1174 if(bGpu ? (nTickStart > nBaseTicksEndGpu) : (nTickStart > nBaseTicksEndCpu))
1175 {
1176 break;
1177 }
1178 }
1179 }
1180 }
1181 }
1182 nY += nMaxStackDepth * nYDelta + MICROPROFILE_DETAILED_BAR_HEIGHT+1;
1183 }
1184 }
1185 if(S.bContextSwitchRunning && (S.bContextSwitchAllThreads||S.bContextSwitchNoBars))
1186 {
1187 uint32_t nNumThreads = 0;
1188 uint32_t nThreads[MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS];
1189 for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS && S.Pool[i]; ++i)
1190 nThreads[nNumThreads++] = S.Pool[i]->nThreadId;
1191 uint32_t nNumThreadsBase = nNumThreads;
1192 if(S.bContextSwitchAllThreads)
1193 {
1194 for(uint32_t i = nContextSwitchStart; i != nContextSwitchEnd; i = (i+1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE)
1195 {
1196 MicroProfileContextSwitch CS = S.ContextSwitch[i];
1197 ThreadIdType nThreadId = CS.nThreadIn;
1198 if(nThreadId)
1199 {
1200 bool bSeen = false;
1201 for(uint32_t j = 0; j < nNumThreads; ++j)
1202 {
1203 if(nThreads[j] == nThreadId)
1204 {
1205 bSeen = true;
1206 break;
1207 }
1208 }
1209 if(!bSeen)
1210 {
1211 nThreads[nNumThreads++] = nThreadId;
1212 }
1213 }
1214 if(nNumThreads == MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS)
1215 {
1216 S.nOverflow = 10;
1217 break;
1218 }
1219 }
1220 std::sort(&nThreads[nNumThreadsBase], &nThreads[nNumThreads]);
1221 }
1222 uint32_t nStart = nNumThreadsBase;
1223 if(S.bContextSwitchNoBars)
1224 nStart = 0;
1225 for(uint32_t i = nStart; i < nNumThreads; ++i)
1226 {
1227 ThreadIdType nThreadId = nThreads[i];
1228 if(nThreadId)
1229 {
1230 char ThreadName[MicroProfileThreadLog::THREAD_MAX_LEN + 16];
1231 const char* cLocal = MicroProfileIsLocalThread(nThreadId) ? "*": " ";
1232
1233 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) );
1234 uint32_t nThreadColor = -1;
1235 if(nThreadId == nContextSwitchHoverThreadAfter || nThreadId == nContextSwitchHoverThreadBefore)
1236 nThreadColor = UI.nHoverColorShared|0x906060;
1237 MicroProfileDrawDetailedContextSwitchBars(nY+2, nThreadId, nContextSwitchStart, nContextSwitchEnd, nBaseTicksCpu, nBaseY);
1238 MicroProfileDrawText(0, nY, nThreadColor, &ThreadName[0], nStrLen);
1239 nY += MICROPROFILE_TEXT_HEIGHT+1;
1240 }
1241 }
1242 }
1243
1244 S.nContextSwitchHoverCpu = S.nContextSwitchHoverCpuNext;
1245
1246
1247
1248
1249 UI.pDisplayMouseOver = pMouseOverNext;
1250
1251 if(!S.nRunning)
1252 {
1253 if(nHoverToken != MICROPROFILE_INVALID_TOKEN && nHoverTime)
1254 {
1255 UI.nHoverToken = nHoverToken;
1256 UI.nHoverTime = nHoverTime;
1257 }
1258
1259 if(nSelectedFrame != -1)
1260 {
1261 UI.nRangeBegin = S.Frames[nSelectedFrame].nFrameStartCpu;
1262 UI.nRangeEnd = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu;
1263 UI.nRangeBeginGpu = S.Frames[nSelectedFrame].nFrameStartGpu;
1264 UI.nRangeEndGpu = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartGpu;
1265 }
1266 if(UI.nRangeBegin != UI.nRangeEnd)
1267 {
1268 float fMsStart = fToMsCpu * MicroProfileLogTickDifference(nBaseTicksCpu, UI.nRangeBegin);
1269 float fMsEnd = fToMsCpu * MicroProfileLogTickDifference(nBaseTicksCpu, UI.nRangeEnd);
1270 float fXStart = fMsStart * fMsToScreen;
1271 float fXEnd = fMsEnd * fMsToScreen;
1272 MicroProfileDrawBox(fXStart, nBaseY, fXEnd, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT, MicroProfileBoxTypeFlat);
1273 MicroProfileDrawLineVertical(fXStart, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT | 0x44000000);
1274 MicroProfileDrawLineVertical(fXEnd, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT | 0x44000000);
1275
1276 fMsStart += fDetailedOffset;
1277 fMsEnd += fDetailedOffset;
1278 char sBuffer[32];
1279 uint32_t nLenStart = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsStart);
1280 float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
1281 float fStartTextX = fXStart - fStartTextWidth - 2;
1282 MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1283 MicroProfileDrawText(fStartTextX+1, nBaseY, (uint32_t)-1, sBuffer, nLenStart);
1284 uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
1285 MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1286 MicroProfileDrawText(fXEnd+2, nBaseY+1, (uint32_t)-1, sBuffer, nLenEnd);
1287
1288 if(UI.nMouseRight)
1289 {
1290 MicroProfileZoomTo(UI.nRangeBegin, UI.nRangeEnd);
1291 }
1292 }
1293
1294 if(UI.nRangeBeginGpu != UI.nRangeEndGpu)
1295 {
1296 float fMsStart = fToMsGpu * MicroProfileLogTickDifference(nBaseTicksGpu, UI.nRangeBeginGpu);
1297 float fMsEnd = fToMsGpu * MicroProfileLogTickDifference(nBaseTicksGpu, UI.nRangeEndGpu);
1298 float fXStart = fMsStart * fMsToScreen;
1299 float fXEnd = fMsEnd * fMsToScreen;
1300 MicroProfileDrawBox(fXStart, nBaseY, fXEnd, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU, MicroProfileBoxTypeFlat);
1301 MicroProfileDrawLineVertical(fXStart, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU | 0x44000000);
1302 MicroProfileDrawLineVertical(fXEnd, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU | 0x44000000);
1303
1304 nBaseY += MICROPROFILE_TEXT_HEIGHT+1;
1305
1306 fMsStart += fDetailedOffset;
1307 fMsEnd += fDetailedOffset;
1308 char sBuffer[32];
1309 uint32_t nLenStart = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsStart);
1310 float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
1311 float fStartTextX = fXStart - fStartTextWidth - 2;
1312 MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1313 MicroProfileDrawText(fStartTextX+1, nBaseY, (uint32_t)-1, sBuffer, nLenStart);
1314 uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
1315 MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
1316 MicroProfileDrawText(fXEnd+2, nBaseY+1, (uint32_t)-1, sBuffer, nLenEnd);
1317 }
1318 }
1319}
1320
1321
1322void MicroProfileDrawDetailedFrameHistory(uint32_t nWidth, uint32_t nHeight, uint32_t nBaseY, uint32_t nSelectedFrame)
1323{
1324 MicroProfile& S = *MicroProfileGet();
1325
1326 const uint32_t nBarHeight = MICROPROFILE_FRAME_HISTORY_HEIGHT;
1327 float fBaseX = (float)nWidth;
1328 float fDx = fBaseX / MICROPROFILE_NUM_FRAMES;
1329
1330 uint32_t nLastIndex = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
1331 MicroProfileDrawBox(0, nBaseY, nWidth, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, 0xff000000 | g_nMicroProfileBackColors[0], MicroProfileBoxTypeFlat);
1332 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * S.fRcpReferenceTime;
1333 float fToMsGpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu()) * S.fRcpReferenceTime;
1334
1335
1336 MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
1337 uint64_t nFrameStartCpu = pFrameCurrent->nFrameStartCpu;
1338 int64_t nDetailedOffsetTicksCpu = MicroProfileMsToTick(UI.fDetailedOffset, MicroProfileTicksPerSecondCpu());
1339 int64_t nCpuStart = nDetailedOffsetTicksCpu + nFrameStartCpu;
1340 int64_t nCpuEnd = nCpuStart + MicroProfileMsToTick(UI.fDetailedRange, MicroProfileTicksPerSecondCpu());;
1341
1342
1343 float fSelectionStart = (float)nWidth;
1344 float fSelectionEnd = 0.f;
1345 for(uint32_t i = 0; i < MICROPROFILE_NUM_FRAMES; ++i)
1346 {
1347 uint32_t nIndex = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY;
1348 MicroProfileFrameState* pCurrent = &S.Frames[nIndex];
1349 MicroProfileFrameState* pNext = &S.Frames[nLastIndex];
1350
1351 int64_t nTicks = pNext->nFrameStartCpu - pCurrent->nFrameStartCpu;
1352 int64_t nTicksGpu = pNext->nFrameStartGpu - pCurrent->nFrameStartGpu;
1353 float fScale = fToMs * nTicks;
1354 float fScaleGpu = fToMsGpu * nTicksGpu;
1355 fScale = fScale > 1.f ? 0.f : 1.f - fScale;
1356 fScaleGpu = fScaleGpu > 1.f ? 0.f : 1.f - fScaleGpu;
1357 float fXEnd = fBaseX;
1358 float fXStart = fBaseX - fDx;
1359 fBaseX = fXStart;
1360 uint32_t nColor = MICROPROFILE_FRAME_HISTORY_COLOR_CPU;
1361 if(nIndex == nSelectedFrame)
1362 nColor = (uint32_t)-1;
1363 MicroProfileDrawBox(fXStart, nBaseY + fScale * nBarHeight, fXEnd, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, nColor, MicroProfileBoxTypeBar);
1364 if(pNext->nFrameStartCpu > nCpuStart)
1365 {
1366 fSelectionStart = fXStart;
1367 }
1368 if(pCurrent->nFrameStartCpu < nCpuEnd && fSelectionEnd == 0.f)
1369 {
1370 fSelectionEnd = fXEnd;
1371 }
1372 nLastIndex = nIndex;
1373 }
1374 MicroProfileDrawBox(fSelectionStart, nBaseY, fSelectionEnd, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, MICROPROFILE_FRAME_HISTORY_COLOR_HIGHTLIGHT, MicroProfileBoxTypeFlat);
1375}
1376void MicroProfileDrawDetailedView(uint32_t nWidth, uint32_t nHeight)
1377{
1378 MicroProfile& S = *MicroProfileGet();
1379
1380 MICROPROFILE_SCOPE(g_MicroProfileDetailed);
1381 uint32_t nBaseY = MICROPROFILE_TEXT_HEIGHT + 1;
1382
1383 int nSelectedFrame = -1;
1384 if(UI.nMouseY > nBaseY && UI.nMouseY <= nBaseY + MICROPROFILE_FRAME_HISTORY_HEIGHT && UI.nActiveMenu == -1)
1385 {
1386
1387 nSelectedFrame = ((MICROPROFILE_NUM_FRAMES) * (UI.nWidth-UI.nMouseX) / UI.nWidth);
1388 nSelectedFrame = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - nSelectedFrame) % MICROPROFILE_MAX_FRAME_HISTORY;
1389 UI.nHoverFrame = nSelectedFrame;
1390 if(UI.nMouseRight)
1391 {
1392 int64_t nRangeBegin = S.Frames[nSelectedFrame].nFrameStartCpu;
1393 int64_t nRangeEnd = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu;
1394 MicroProfileZoomTo(nRangeBegin, nRangeEnd);
1395 }
1396 if(UI.nMouseDownLeft)
1397 {
1398 uint64_t nFrac = (1024 * (MICROPROFILE_NUM_FRAMES) * (UI.nMouseX) / UI.nWidth) % 1024;
1399 int64_t nRangeBegin = S.Frames[nSelectedFrame].nFrameStartCpu;
1400 int64_t nRangeEnd = S.Frames[(nSelectedFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu;
1401 MicroProfileCenter(nRangeBegin + (nRangeEnd-nRangeBegin) * nFrac / 1024);
1402 }
1403 }
1404 else
1405 {
1406 UI.nHoverFrame = -1;
1407 }
1408
1409 MicroProfileDrawDetailedBars(nWidth, nHeight, nBaseY + MICROPROFILE_FRAME_HISTORY_HEIGHT, nSelectedFrame);
1410 MicroProfileDrawDetailedFrameHistory(nWidth, nHeight, nBaseY, nSelectedFrame);
1411}
1412
1413void MicroProfileDrawTextRight(uint32_t nX, uint32_t nY, uint32_t nColor, const char* pStr, uint32_t nStrLen)
1414{
1415 MicroProfileDrawText(nX - nStrLen * (MICROPROFILE_TEXT_WIDTH+1), nY, nColor, pStr, nStrLen);
1416}
1417void MicroProfileDrawHeader(int32_t nX, uint32_t nWidth, const char* pName)
1418{
1419 if(pName)
1420 {
1421 MicroProfileDrawBox(nX-8, MICROPROFILE_TEXT_HEIGHT + 2, nX + nWidth+5, MICROPROFILE_TEXT_HEIGHT + 2 + (MICROPROFILE_TEXT_HEIGHT+1), 0xff000000|g_nMicroProfileBackColors[1]);
1422 MicroProfileDrawText(nX, MICROPROFILE_TEXT_HEIGHT + 2, (uint32_t)-1, pName, (uint32_t)strlen(pName));
1423 }
1424}
1425
1426
1427typedef void (*MicroProfileLoopGroupCallback)(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pData);
1428
1429void MicroProfileLoopActiveGroupsDraw(int32_t nX, int32_t nY, const char* pName, MicroProfileLoopGroupCallback CB, void* pData)
1430{
1431 MicroProfile& S = *MicroProfileGet();
1432 nY += MICROPROFILE_TEXT_HEIGHT + 2;
1433 uint64_t nGroup = S.nAllGroupsWanted ? S.nGroupMask : S.nActiveGroupWanted;
1434 uint32_t nCount = 0;
1435 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1436 {
1437 uint64_t nMask = 1ll << j;
1438 if(nMask & nGroup)
1439 {
1440 nY += MICROPROFILE_TEXT_HEIGHT + 1;
1441 for(uint32_t i = 0; i < S.nTotalTimers;++i)
1442 {
1443 uint64_t nTokenMask = MicroProfileGetGroupMask(S.TimerInfo[i].nToken);
1444 if(nTokenMask & nMask)
1445 {
1446 if(nY >= 0)
1447 CB(i, nCount, nMask, nX, nY, pData);
1448
1449 nCount += 2;
1450 nY += MICROPROFILE_TEXT_HEIGHT + 1;
1451
1452 if(nY > (int)UI.nHeight)
1453 return;
1454 }
1455 }
1456
1457 }
1458 }
1459}
1460
1461
1462void MicroProfileCalcTimers(float* pTimers, float* pAverage, float* pMax, float* pCallAverage, float* pExclusive, float* pAverageExclusive, float* pMaxExclusive, uint64_t nGroup, uint32_t nSize)
1463{
1464 MicroProfile& S = *MicroProfileGet();
1465
1466 uint32_t nCount = 0;
1467 uint64_t nMask = 1;
1468
1469 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1470 {
1471 if(nMask & nGroup)
1472 {
1473 const float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[j].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
1474 for(uint32_t i = 0; i < S.nTotalTimers;++i)
1475 {
1476 uint64_t nTokenMask = MicroProfileGetGroupMask(S.TimerInfo[i].nToken);
1477 if(nTokenMask & nMask)
1478 {
1479 {
1480 uint32_t nTimer = i;
1481 uint32_t nIdx = nCount;
1482 uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
1483 uint32_t nAggregateCount = S.Aggregate[nTimer].nCount ? S.Aggregate[nTimer].nCount : 1;
1484 float fToPrc = S.fRcpReferenceTime;
1485 float fMs = fToMs * (S.Frame[nTimer].nTicks);
1486 float fPrc = MicroProfileMin(fMs * fToPrc, 1.f);
1487 float fAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateFrames);
1488 float fAveragePrc = MicroProfileMin(fAverageMs * fToPrc, 1.f);
1489 float fMaxMs = fToMs * (S.AggregateMax[nTimer]);
1490 float fMaxPrc = MicroProfileMin(fMaxMs * fToPrc, 1.f);
1491 float fCallAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateCount);
1492 float fCallAveragePrc = MicroProfileMin(fCallAverageMs * fToPrc, 1.f);
1493 float fMsExclusive = fToMs * (S.FrameExclusive[nTimer]);
1494 float fPrcExclusive = MicroProfileMin(fMsExclusive * fToPrc, 1.f);
1495 float fAverageMsExclusive = fToMs * (S.AggregateExclusive[nTimer] / nAggregateFrames);
1496 float fAveragePrcExclusive = MicroProfileMin(fAverageMsExclusive * fToPrc, 1.f);
1497 float fMaxMsExclusive = fToMs * (S.AggregateMaxExclusive[nTimer]);
1498 float fMaxPrcExclusive = MicroProfileMin(fMaxMsExclusive * fToPrc, 1.f);
1499 pTimers[nIdx] = fMs;
1500 pTimers[nIdx+1] = fPrc;
1501 pAverage[nIdx] = fAverageMs;
1502 pAverage[nIdx+1] = fAveragePrc;
1503 pMax[nIdx] = fMaxMs;
1504 pMax[nIdx+1] = fMaxPrc;
1505 pCallAverage[nIdx] = fCallAverageMs;
1506 pCallAverage[nIdx+1] = fCallAveragePrc;
1507 pExclusive[nIdx] = fMsExclusive;
1508 pExclusive[nIdx+1] = fPrcExclusive;
1509 pAverageExclusive[nIdx] = fAverageMsExclusive;
1510 pAverageExclusive[nIdx+1] = fAveragePrcExclusive;
1511 pMaxExclusive[nIdx] = fMaxMsExclusive;
1512 pMaxExclusive[nIdx+1] = fMaxPrcExclusive;
1513 }
1514 nCount += 2;
1515 }
1516 }
1517 }
1518 nMask <<= 1ll;
1519 }
1520}
1521
1522#define SBUF_MAX 32
1523
1524void MicroProfileDrawBarArrayCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1525{
1526 const uint32_t nHeight = MICROPROFILE_TEXT_HEIGHT;
1527 const uint32_t nTextWidth = 6 * (1+MICROPROFILE_TEXT_WIDTH);
1528 const float fWidth = (float)MICROPROFILE_BAR_WIDTH;
1529
1530 float* pTimers = ((float**)pExtra)[0];
1531 float* pTimers2 = ((float**)pExtra)[1];
1532 MicroProfile& S = *MicroProfileGet();
1533 char sBuffer[SBUF_MAX];
1534 if (pTimers2 && pTimers2[nIdx] > 0.1f)
1535 snprintf(sBuffer, SBUF_MAX-1, "%5.2f %3.1fx", pTimers[nIdx], pTimers[nIdx] / pTimers2[nIdx]);
1536 else
1537 snprintf(sBuffer, SBUF_MAX-1, "%5.2f", pTimers[nIdx]);
1538 if (!pTimers2)
1539 MicroProfileDrawBox(nX + nTextWidth, nY, nX + nTextWidth + fWidth * pTimers[nIdx+1], nY + nHeight, UI.nOpacityForeground|S.TimerInfo[nTimer].nColor, MicroProfileBoxTypeBar);
1540 MicroProfileDrawText(nX, nY, (uint32_t)-1, sBuffer, (uint32_t)strlen(sBuffer));
1541}
1542
1543
1544uint32_t MicroProfileDrawBarArray(int32_t nX, int32_t nY, float* pTimers, const char* pName, uint32_t nTotalHeight, float* pTimers2 = NULL)
1545{
1546 const uint32_t nTextWidth = 6 * (1+MICROPROFILE_TEXT_WIDTH);
1547 const uint32_t nWidth = MICROPROFILE_BAR_WIDTH;
1548
1549 MicroProfileDrawLineVertical(nX-5, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1550 float* pTimersArray[2] = {pTimers, pTimers2};
1551 MicroProfileLoopActiveGroupsDraw(nX, nY, pName, MicroProfileDrawBarArrayCallback, pTimersArray);
1552 MicroProfileDrawHeader(nX, nTextWidth + nWidth, pName);
1553 return nWidth + 5 + nTextWidth;
1554
1555}
1556void MicroProfileDrawBarCallCountCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1557{
1558 MicroProfile& S = *MicroProfileGet();
1559 char sBuffer[SBUF_MAX];
1560 int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5d", S.Frame[nTimer].nCount);//fix
1561 MicroProfileDrawText(nX, nY, (uint32_t)-1, sBuffer, nLen);
1562}
1563
1564uint32_t MicroProfileDrawBarCallCount(int32_t nX, int32_t nY, const char* pName)
1565{
1566 MicroProfileLoopActiveGroupsDraw(nX, nY, pName, MicroProfileDrawBarCallCountCallback, 0);
1567 const uint32_t nTextWidth = 6 * MICROPROFILE_TEXT_WIDTH;
1568 MicroProfileDrawHeader(nX, 5 + nTextWidth, pName);
1569 return 5 + nTextWidth;
1570}
1571
1572struct MicroProfileMetaAverageArgs
1573{
1574 uint64_t* pCounters;
1575 float fRcpFrames;
1576};
1577
1578void MicroProfileDrawBarMetaAverageCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1579{
1580 MicroProfileMetaAverageArgs* pArgs = (MicroProfileMetaAverageArgs*)pExtra;
1581 uint64_t* pCounters = pArgs->pCounters;
1582 float fRcpFrames = pArgs->fRcpFrames;
1583 char sBuffer[SBUF_MAX];
1584 int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5.2f", pCounters[nTimer] * fRcpFrames);
1585 MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, (uint32_t)-1, sBuffer, nLen);
1586}
1587
1588uint32_t MicroProfileDrawBarMetaAverage(int32_t nX, int32_t nY, uint64_t* pCounters, const char* pName, uint32_t nTotalHeight)
1589{
1590 if(!pName)
1591 return 0;
1592 MicroProfileDrawLineVertical(nX-5, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1593 uint32_t nTextWidth = (1+MICROPROFILE_TEXT_WIDTH) * MicroProfileMax<uint32_t>(6, (uint32_t)strlen(pName));
1594 float fRcpFrames = 1.f / (MicroProfileGet()->nAggregateFrames ? MicroProfileGet()->nAggregateFrames : 1);
1595 MicroProfileMetaAverageArgs Args = {pCounters, fRcpFrames};
1596 MicroProfileLoopActiveGroupsDraw(nX + nTextWidth, nY, pName, MicroProfileDrawBarMetaAverageCallback, &Args);
1597 MicroProfileDrawHeader(nX, 5 + nTextWidth, pName);
1598 return 5 + nTextWidth;
1599}
1600
1601
1602void MicroProfileDrawBarMetaCountCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1603{
1604 uint64_t* pCounters = (uint64_t*)pExtra;
1605 char sBuffer[SBUF_MAX];
1606 int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5llu", pCounters[nTimer]);
1607 MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, (uint32_t)-1, sBuffer, nLen);
1608}
1609
1610uint32_t MicroProfileDrawBarMetaCount(int32_t nX, int32_t nY, uint64_t* pCounters, const char* pName, uint32_t nTotalHeight)
1611{
1612 if(!pName)
1613 return 0;
1614
1615 MicroProfileDrawLineVertical(nX-5, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1616 uint32_t nTextWidth = (1+MICROPROFILE_TEXT_WIDTH) * MicroProfileMax<uint32_t>(6, (uint32_t)strlen(pName));
1617 MicroProfileLoopActiveGroupsDraw(nX + nTextWidth, nY, pName, MicroProfileDrawBarMetaCountCallback, pCounters);
1618 MicroProfileDrawHeader(nX, 5 + nTextWidth, pName);
1619 return 5 + nTextWidth;
1620}
1621
1622void MicroProfileDrawBarLegendCallback(uint32_t nTimer, uint32_t nIdx, uint64_t nGroupMask, uint32_t nX, uint32_t nY, void* pExtra)
1623{
1624 MicroProfile& S = *MicroProfileGet();
1625 if (S.TimerInfo[nTimer].bGraph)
1626 {
1627 MicroProfileDrawText(nX, nY, S.TimerInfo[nTimer].nColor, ">", 1);
1628 }
1629 MicroProfileDrawTextRight(nX, nY, S.TimerInfo[nTimer].nColor, S.TimerInfo[nTimer].pName, (uint32_t)strlen(S.TimerInfo[nTimer].pName));
1630 if(UI.nMouseY >= nY && UI.nMouseY < nY + MICROPROFILE_TEXT_HEIGHT+1)
1631 {
1632 UI.nHoverToken = nTimer;
1633 UI.nHoverTime = 0;
1634 }
1635}
1636
1637uint32_t MicroProfileDrawBarLegend(int32_t nX, int32_t nY, uint32_t nTotalHeight, uint32_t nMaxWidth)
1638{
1639 MicroProfileDrawLineVertical(nX-5, nY, nTotalHeight, UI.nOpacityBackground | g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1640 MicroProfileLoopActiveGroupsDraw(nMaxWidth, nY, 0, MicroProfileDrawBarLegendCallback, 0);
1641 return nX;
1642}
1643
1644bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight)
1645{
1646 MicroProfile& S = *MicroProfileGet();
1647
1648 MICROPROFILE_SCOPE(g_MicroProfileDrawGraph);
1649 bool bEnabled = false;
1650 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1651 if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
1652 bEnabled = true;
1653 if(!bEnabled)
1654 return false;
1655
1656 uint32_t nX = nScreenWidth - MICROPROFILE_GRAPH_WIDTH;
1657 uint32_t nY = nScreenHeight - MICROPROFILE_GRAPH_HEIGHT;
1658 MicroProfileDrawBox(nX, nY, nX + MICROPROFILE_GRAPH_WIDTH, nY + MICROPROFILE_GRAPH_HEIGHT, 0x88000000 | g_nMicroProfileBackColors[0]);
1659 bool bMouseOver = UI.nMouseX >= nX && UI.nMouseY >= nY;
1660 float fMouseXPrc =(float(UI.nMouseX - nX)) / MICROPROFILE_GRAPH_WIDTH;
1661 if(bMouseOver)
1662 {
1663 float fXAvg = fMouseXPrc * MICROPROFILE_GRAPH_WIDTH + nX;
1664 MicroProfileDrawLineVertical(fXAvg, nY, nY + MICROPROFILE_GRAPH_HEIGHT, (uint32_t)-1);
1665 }
1666
1667
1668 float fY = (float)nScreenHeight;
1669 float fDX = MICROPROFILE_GRAPH_WIDTH * 1.f / MICROPROFILE_GRAPH_HISTORY;
1670 float fDY = MICROPROFILE_GRAPH_HEIGHT;
1671 uint32_t nPut = S.nGraphPut;
1672 float* pGraphData = (float*)alloca(sizeof(float)* MICROPROFILE_GRAPH_HISTORY*2);
1673 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1674 {
1675 if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
1676 {
1677 uint32_t nGroupId = MicroProfileGetGroupIndex(S.Graph[i].nToken);
1678 bool bGpu = S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu;
1679 float fToMs = MicroProfileTickToMsMultiplier(bGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
1680 float fToPrc = fToMs * S.fRcpReferenceTime * 3 / 4;
1681
1682 float fX = (float)nX;
1683 for(uint32_t j = 0; j < MICROPROFILE_GRAPH_HISTORY; ++j)
1684 {
1685 float fWeigth = MicroProfileMin(fToPrc * (S.Graph[i].nHistory[(j+nPut)%MICROPROFILE_GRAPH_HISTORY]), 1.f);
1686 pGraphData[(j*2)] = fX;
1687 pGraphData[(j*2)+1] = fY - fDY * fWeigth;
1688 fX += fDX;
1689 }
1690 MicroProfileDrawLine2D(MICROPROFILE_GRAPH_HISTORY, pGraphData, S.TimerInfo[MicroProfileGetTimerIndex(S.Graph[i].nToken)].nColor);
1691 }
1692 }
1693 {
1694 float fY1 = 0.25f * MICROPROFILE_GRAPH_HEIGHT + nY;
1695 float fY2 = 0.50f * MICROPROFILE_GRAPH_HEIGHT + nY;
1696 float fY3 = 0.75f * MICROPROFILE_GRAPH_HEIGHT + nY;
1697 MicroProfileDrawLineHorizontal(nX, nX + MICROPROFILE_GRAPH_WIDTH, fY1, 0xffdd4444);
1698 MicroProfileDrawLineHorizontal(nX, nX + MICROPROFILE_GRAPH_WIDTH, fY2, 0xff000000| g_nMicroProfileBackColors[0]);
1699 MicroProfileDrawLineHorizontal(nX, nX + MICROPROFILE_GRAPH_WIDTH, fY3, 0xff000000|g_nMicroProfileBackColors[0]);
1700
1701 char buf[32];
1702 int nLen = snprintf(buf, sizeof(buf)-1, "%5.2fms", S.fReferenceTime);
1703 MicroProfileDrawText(nX+1, fY1 - (2+MICROPROFILE_TEXT_HEIGHT), (uint32_t)-1, buf, nLen);
1704 }
1705
1706
1707
1708 if(bMouseOver)
1709 {
1710 uint32_t pColors[MICROPROFILE_MAX_GRAPHS];
1711 MicroProfileStringArray Strings;
1712 MicroProfileStringArrayClear(&Strings);
1713 uint32_t nTextCount = 0;
1714 uint32_t nGraphIndex = (S.nGraphPut + MICROPROFILE_GRAPH_HISTORY - int(MICROPROFILE_GRAPH_HISTORY*(1.f - fMouseXPrc))) % MICROPROFILE_GRAPH_HISTORY;
1715
1716 uint32_t nX = UI.nMouseX;
1717 uint32_t nY = UI.nMouseY + 20;
1718
1719 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1720 {
1721 if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
1722 {
1723 uint32_t nGroupId = MicroProfileGetGroupIndex(S.Graph[i].nToken);
1724 bool bGpu = S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu;
1725 float fToMs = MicroProfileTickToMsMultiplier(bGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
1726 uint32_t nIndex = MicroProfileGetTimerIndex(S.Graph[i].nToken);
1727 uint32_t nColor = S.TimerInfo[nIndex].nColor;
1728 const char* pName = S.TimerInfo[nIndex].pName;
1729 pColors[nTextCount++] = nColor;
1730 MicroProfileStringArrayAddLiteral(&Strings, pName);
1731 MicroProfileStringArrayFormat(&Strings, "%5.2fms", fToMs * (S.Graph[i].nHistory[nGraphIndex]));
1732 }
1733 }
1734 if(nTextCount)
1735 {
1736 MicroProfileDrawFloatWindow(nX, nY, Strings.ppStrings, Strings.nNumStrings, 0, pColors);
1737 }
1738
1739 if(UI.nMouseRight)
1740 {
1741 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
1742 {
1743 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
1744 }
1745 }
1746 }
1747
1748 return bMouseOver;
1749}
1750
1751void MicroProfileDumpTimers()
1752{
1753 MicroProfile& S = *MicroProfileGet();
1754
1755 uint64_t nActiveGroup = S.nGroupMask;
1756
1757 uint32_t nNumTimers = S.nTotalTimers;
1758 uint32_t nBlockSize = 2 * nNumTimers;
1759 float* pTimers = (float*)alloca(nBlockSize * 7 * sizeof(float));
1760 float* pAverage = pTimers + nBlockSize;
1761 float* pMax = pTimers + 2 * nBlockSize;
1762 float* pCallAverage = pTimers + 3 * nBlockSize;
1763 float* pTimersExclusive = pTimers + 4 * nBlockSize;
1764 float* pAverageExclusive = pTimers + 5 * nBlockSize;
1765 float* pMaxExclusive = pTimers + 6 * nBlockSize;
1766 MicroProfileCalcTimers(pTimers, pAverage, pMax, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, nActiveGroup, nNumTimers);
1767
1768 MICROPROFILE_PRINTF("%11s, ", "Time");
1769 MICROPROFILE_PRINTF("%11s, ", "Average");
1770 MICROPROFILE_PRINTF("%11s, ", "Max");
1771 MICROPROFILE_PRINTF("%11s, ", "Call Avg");
1772 MICROPROFILE_PRINTF("%9s, ", "Count");
1773 MICROPROFILE_PRINTF("%11s, ", "Excl");
1774 MICROPROFILE_PRINTF("%11s, ", "Avg Excl");
1775 MICROPROFILE_PRINTF("%11s, \n", "Max Excl");
1776
1777 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1778 {
1779 uint64_t nMask = 1ll << j;
1780 if(nMask & nActiveGroup)
1781 {
1782 MICROPROFILE_PRINTF("%s\n", S.GroupInfo[j].pName);
1783 for(uint32_t i = 0; i < S.nTotalTimers;++i)
1784 {
1785 uint64_t nTokenMask = MicroProfileGetGroupMask(S.TimerInfo[i].nToken);
1786 if(nTokenMask & nMask)
1787 {
1788 uint32_t nIdx = i * 2;
1789 MICROPROFILE_PRINTF("%9.2fms, ", pTimers[nIdx]);
1790 MICROPROFILE_PRINTF("%9.2fms, ", pAverage[nIdx]);
1791 MICROPROFILE_PRINTF("%9.2fms, ", pMax[nIdx]);
1792 MICROPROFILE_PRINTF("%9.2fms, ", pCallAverage[nIdx]);
1793 MICROPROFILE_PRINTF("%9d, ", S.Frame[i].nCount);
1794 MICROPROFILE_PRINTF("%9.2fms, ", pTimersExclusive[nIdx]);
1795 MICROPROFILE_PRINTF("%9.2fms, ", pAverageExclusive[nIdx]);
1796 MICROPROFILE_PRINTF("%9.2fms, ", pMaxExclusive[nIdx]);
1797 MICROPROFILE_PRINTF("%s\n", S.TimerInfo[i].pName);
1798 }
1799 }
1800 }
1801 }
1802}
1803
1804void MicroProfileDrawBarView(uint32_t nScreenWidth, uint32_t nScreenHeight)
1805{
1806 MicroProfile& S = *MicroProfileGet();
1807
1808 uint64_t nActiveGroup = S.nAllGroupsWanted ? S.nGroupMask : S.nActiveGroupWanted;
1809 if(!nActiveGroup)
1810 return;
1811 MICROPROFILE_SCOPE(g_MicroProfileDrawBarView);
1812
1813 const uint32_t nHeight = MICROPROFILE_TEXT_HEIGHT;
1814 int nColorIndex = 0;
1815 uint32_t nMaxTimerNameLen = 1;
1816 uint32_t nNumTimers = 0;
1817 uint32_t nNumGroups = 0;
1818 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1819 {
1820 if(nActiveGroup & (1ll << j))
1821 {
1822 nNumTimers += S.GroupInfo[j].nNumTimers;
1823 nNumGroups += 1;
1824 nMaxTimerNameLen = MicroProfileMax(nMaxTimerNameLen, S.GroupInfo[j].nMaxTimerNameLen);
1825 }
1826 }
1827 uint32_t nTimerWidth = 2+(4+nMaxTimerNameLen) * (MICROPROFILE_TEXT_WIDTH+1);
1828 uint32_t nX = nTimerWidth + UI.nOffsetX;
1829 uint32_t nY = nHeight + 3 - UI.nOffsetY;
1830 uint32_t nBlockSize = 2 * nNumTimers;
1831 float* pTimers = (float*)alloca(nBlockSize * 7 * sizeof(float));
1832 float* pAverage = pTimers + nBlockSize;
1833 float* pMax = pTimers + 2 * nBlockSize;
1834 float* pCallAverage = pTimers + 3 * nBlockSize;
1835 float* pTimersExclusive = pTimers + 4 * nBlockSize;
1836 float* pAverageExclusive = pTimers + 5 * nBlockSize;
1837 float* pMaxExclusive = pTimers + 6 * nBlockSize;
1838 MicroProfileCalcTimers(pTimers, pAverage, pMax, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, nActiveGroup, nNumTimers);
1839 uint32_t nWidth = 0;
1840 {
1841 uint32_t nMetaIndex = 0;
1842 for(uint32_t i = 1; i ; i <<= 1)
1843 {
1844 if(S.nBars & i)
1845 {
1846 if(i >= MP_DRAW_META_FIRST)
1847 {
1848 if(nMetaIndex < MICROPROFILE_META_MAX && S.MetaCounters[nMetaIndex].pName)
1849 {
1850 uint32_t nStrWidth = strlen(S.MetaCounters[nMetaIndex].pName);
1851 if(S.nBars & MP_DRAW_TIMERS)
1852 nWidth += 6 + (1+MICROPROFILE_TEXT_WIDTH) * (nStrWidth);
1853 if(S.nBars & MP_DRAW_AVERAGE)
1854 nWidth += 6 + (1+MICROPROFILE_TEXT_WIDTH) * (nStrWidth + 4);
1855 if(S.nBars & MP_DRAW_MAX)
1856 nWidth += 6 + (1+MICROPROFILE_TEXT_WIDTH) * (nStrWidth + 4);
1857 }
1858 }
1859 else
1860 {
1861 nWidth += MICROPROFILE_BAR_WIDTH + 6 + 6 * (1+MICROPROFILE_TEXT_WIDTH);
1862 if(i & MP_DRAW_CALL_COUNT)
1863 nWidth += 6 + 6 * MICROPROFILE_TEXT_WIDTH;
1864 }
1865 }
1866 if(i >= MP_DRAW_META_FIRST)
1867 {
1868 ++nMetaIndex;
1869 }
1870 }
1871 nWidth += (1+nMaxTimerNameLen) * (MICROPROFILE_TEXT_WIDTH+1);
1872 for(uint32_t i = 0; i < nNumTimers+nNumGroups+1; ++i)
1873 {
1874 uint32_t nY0 = nY + i * (nHeight + 1);
1875 bool bInside = (UI.nActiveMenu == -1) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
1876 MicroProfileDrawBox(nX, nY0, nWidth+nX, nY0 + (nHeight+1)+1, UI.nOpacityBackground | (g_nMicroProfileBackColors[nColorIndex++ & 1] + ((bInside) ? 0x002c2c2c : 0)));
1877 }
1878 nX += 10;
1879 }
1880 int nTotalHeight = (nNumTimers+nNumGroups+1) * (nHeight+1);
1881 uint32_t nLegendOffset = 1;
1882 if(S.nBars & MP_DRAW_TIMERS)
1883 nX += MicroProfileDrawBarArray(nX, nY, pTimers, "Time", nTotalHeight) + 1;
1884 if(S.nBars & MP_DRAW_AVERAGE)
1885 nX += MicroProfileDrawBarArray(nX, nY, pAverage, "Average", nTotalHeight) + 1;
1886 if(S.nBars & MP_DRAW_MAX)
1887 nX += MicroProfileDrawBarArray(nX, nY, pMax, (!UI.bShowSpikes) ? "Max Time" : "Max Time, Spike", nTotalHeight, UI.bShowSpikes ? pAverage : NULL) + 1;
1888 if(S.nBars & MP_DRAW_CALL_COUNT)
1889 {
1890 nX += MicroProfileDrawBarArray(nX, nY, pCallAverage, "Call Average", nTotalHeight) + 1;
1891 nX += MicroProfileDrawBarCallCount(nX, nY, "Count") + 1;
1892 }
1893 if(S.nBars & MP_DRAW_TIMERS_EXCLUSIVE)
1894 nX += MicroProfileDrawBarArray(nX, nY, pTimersExclusive, "Exclusive Time", nTotalHeight) + 1;
1895 if(S.nBars & MP_DRAW_AVERAGE_EXCLUSIVE)
1896 nX += MicroProfileDrawBarArray(nX, nY, pAverageExclusive, "Exclusive Average", nTotalHeight) + 1;
1897 if(S.nBars & MP_DRAW_MAX_EXCLUSIVE)
1898 nX += MicroProfileDrawBarArray(nX, nY, pMaxExclusive, (!UI.bShowSpikes) ? "Exclusive Max Time" :"Excl Max Time, Spike", nTotalHeight, UI.bShowSpikes ? pAverageExclusive : NULL) + 1;
1899
1900 for(int i = 0; i < MICROPROFILE_META_MAX; ++i)
1901 {
1902 if(0 != (S.nBars & (MP_DRAW_META_FIRST<<i)) && S.MetaCounters[i].pName)
1903 {
1904 uint32_t nBufferSize = strlen(S.MetaCounters[i].pName) + 32;
1905 char* buffer = (char*)alloca(nBufferSize);
1906 if(S.nBars & MP_DRAW_TIMERS)
1907 nX += MicroProfileDrawBarMetaCount(nX, nY, &S.MetaCounters[i].nCounters[0], S.MetaCounters[i].pName, nTotalHeight) + 1;
1908 if(S.nBars & MP_DRAW_AVERAGE)
1909 {
1910 snprintf(buffer, nBufferSize-1, "%s Avg", S.MetaCounters[i].pName);
1911 nX += MicroProfileDrawBarMetaAverage(nX, nY, &S.MetaCounters[i].nAggregate[0], buffer, nTotalHeight) + 1;
1912 }
1913 if(S.nBars & MP_DRAW_MAX)
1914 {
1915 snprintf(buffer, nBufferSize-1, "%s Max", S.MetaCounters[i].pName);
1916 nX += MicroProfileDrawBarMetaCount(nX, nY, &S.MetaCounters[i].nAggregateMax[0], buffer, nTotalHeight) + 1;
1917 }
1918 }
1919 }
1920 nX = 0;
1921 nY = nHeight + 3 - UI.nOffsetY;
1922 for(uint32_t i = 0; i < nNumTimers+nNumGroups+1; ++i)
1923 {
1924 uint32_t nY0 = nY + i * (nHeight + 1);
1925 bool bInside = (UI.nActiveMenu == -1) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
1926 MicroProfileDrawBox(nX, nY0, nTimerWidth, nY0 + (nHeight+1)+1, 0xff0000000 | (g_nMicroProfileBackColors[nColorIndex++ & 1] + ((bInside) ? 0x002c2c2c : 0)));
1927 }
1928 nX += MicroProfileDrawBarLegend(nX, nY, nTotalHeight, nTimerWidth-5) + 1;
1929
1930 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
1931 {
1932 if(nActiveGroup & (1ll << j))
1933 {
1934 MicroProfileDrawText(nX, nY + (1+nHeight) * nLegendOffset, (uint32_t)-1, S.GroupInfo[j].pName, S.GroupInfo[j].nNameLen);
1935 nLegendOffset += S.GroupInfo[j].nNumTimers+1;
1936 }
1937 }
1938 MicroProfileDrawHeader(nX, nTimerWidth-5, "Group");
1939 MicroProfileDrawTextRight(nTimerWidth-3, MICROPROFILE_TEXT_HEIGHT + 2, (uint32_t)-1, "Timer", 5);
1940 MicroProfileDrawLineVertical(nTimerWidth, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1941 MicroProfileDrawLineHorizontal(0, nWidth, 2*MICROPROFILE_TEXT_HEIGHT + 3, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
1942}
1943
1944typedef const char* (*MicroProfileSubmenuCallback)(int, bool* bSelected);
1945typedef void (*MicroProfileClickCallback)(int);
1946
1947
1948const char* MicroProfileUIMenuMode(int nIndex, bool* bSelected)
1949{
1950 MicroProfile& S = *MicroProfileGet();
1951 switch(nIndex)
1952 {
1953 case 0:
1954 *bSelected = S.nDisplay == MP_DRAW_DETAILED;
1955 return "Detailed";
1956 case 1:
1957 *bSelected = S.nDisplay == MP_DRAW_BARS;
1958 return "Timers";
1959 case 2:
1960 *bSelected = S.nDisplay == MP_DRAW_HIDDEN;
1961 return "Hidden";
1962 case 3:
1963 *bSelected = true;
1964 return "Off";
1965 case 4:
1966 *bSelected = true;
1967 return "------";
1968 case 5:
1969 *bSelected = S.nForceEnable != 0;
1970 return "Force Enable";
1971
1972 default: return 0;
1973 }
1974}
1975
1976const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
1977{
1978 MicroProfile& S = *MicroProfileGet();
1979 *bSelected = false;
1980 if(nIndex == 0)
1981 {
1982 *bSelected = S.nAllGroupsWanted != 0;
1983 return "[ALL]";
1984 }
1985 else
1986 {
1987 nIndex = nIndex-1;
1988 if(nIndex < UI.GroupMenuCount)
1989 {
1990 MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
1991 static char buffer[MICROPROFILE_NAME_MAX_LEN+32];
1992 if(Item.nIsCategory)
1993 {
1994 uint64_t nGroupMask = S.CategoryInfo[Item.nIndex].nGroupMask;
1995 *bSelected = nGroupMask == (nGroupMask & S.nActiveGroupWanted);
1996 snprintf(buffer, sizeof(buffer)-1, "[%s]", Item.pName);
1997 }
1998 else
1999 {
2000 *bSelected = 0 != (S.nActiveGroupWanted & (1ll << Item.nIndex));
2001 snprintf(buffer, sizeof(buffer)-1, " %s", Item.pName);
2002 }
2003 return buffer;
2004 }
2005 return 0;
2006 }
2007}
2008
2009const char* MicroProfileUIMenuAggregate(int nIndex, bool* bSelected)
2010{
2011 MicroProfile& S = *MicroProfileGet();
2012 if(nIndex < sizeof(g_MicroProfileAggregatePresets)/sizeof(g_MicroProfileAggregatePresets[0]))
2013 {
2014 int val = g_MicroProfileAggregatePresets[nIndex];
2015 *bSelected = (int)S.nAggregateFlip == val;
2016 if(0 == val)
2017 return "Infinite";
2018 else
2019 {
2020 static char buf[128];
2021 snprintf(buf, sizeof(buf)-1, "%7d", val);
2022 return buf;
2023 }
2024 }
2025 return 0;
2026
2027}
2028
2029const char* MicroProfileUIMenuTimers(int nIndex, bool* bSelected)
2030{
2031 MicroProfile& S = *MicroProfileGet();
2032 *bSelected = 0 != (S.nBars & (1 << nIndex));
2033 switch(nIndex)
2034 {
2035 case 0: return "Time";
2036 case 1: return "Average";
2037 case 2: return "Max";
2038 case 3: return "Call Count";
2039 case 4: return "Exclusive Timers";
2040 case 5: return "Exclusive Average";
2041 case 6: return "Exclusive Max";
2042 }
2043 int nMetaIndex = nIndex - 7;
2044 if(nMetaIndex < MICROPROFILE_META_MAX)
2045 {
2046 return S.MetaCounters[nMetaIndex].pName;
2047 }
2048 return 0;
2049}
2050
2051const char* MicroProfileUIMenuOptions(int nIndex, bool* bSelected)
2052{
2053 MicroProfile& S = *MicroProfileGet();
2054 if(nIndex >= MICROPROFILE_OPTION_SIZE) return 0;
2055 switch(UI.Options[nIndex].nSubType)
2056 {
2057 case 0:
2058 *bSelected = S.fReferenceTime == g_MicroProfileReferenceTimePresets[UI.Options[nIndex].nIndex];
2059 break;
2060 case 1:
2061 *bSelected = UI.nOpacityBackground>>24 == g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex];
2062 break;
2063 case 2:
2064 *bSelected = UI.nOpacityForeground>>24 == g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex];
2065 break;
2066 case 3:
2067 *bSelected = UI.bShowSpikes;
2068 break;
2069#if MICROPROFILE_CONTEXT_SWITCH_TRACE
2070 case 4:
2071 {
2072 switch(UI.Options[nIndex].nIndex)
2073 {
2074 case 0:
2075 *bSelected = S.bContextSwitchRunning;
2076 break;
2077 case 1:
2078 *bSelected = S.bContextSwitchAllThreads;
2079 break;
2080 case 2:
2081 *bSelected = S.bContextSwitchNoBars;
2082 break;
2083 }
2084 }
2085 break;
2086#endif
2087 }
2088 return UI.Options[nIndex].Text;
2089}
2090
2091const char* MicroProfileUIMenuPreset(int nIndex, bool* bSelected)
2092{
2093 static char buf[128];
2094 *bSelected = false;
2095 int nNumPresets = sizeof(g_MicroProfilePresetNames) / sizeof(g_MicroProfilePresetNames[0]);
2096 int nIndexSave = nIndex - nNumPresets - 1;
2097 if(nIndex == nNumPresets)
2098 return "--";
2099 else if(nIndexSave >=0 && nIndexSave <nNumPresets)
2100 {
2101 snprintf(buf, sizeof(buf)-1, "Save '%s'", g_MicroProfilePresetNames[nIndexSave]);
2102 return buf;
2103 }
2104 else if(nIndex < nNumPresets)
2105 {
2106 snprintf(buf, sizeof(buf)-1, "Load '%s'", g_MicroProfilePresetNames[nIndex]);
2107 return buf;
2108 }
2109 else
2110 {
2111 return 0;
2112 }
2113}
2114
2115const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected)
2116{
2117 if((uint32_t)-1 == UI.nCustomActive)
2118 {
2119 *bSelected = nIndex == 0;
2120 }
2121 else
2122 {
2123 *bSelected = nIndex-2 == UI.nCustomActive;
2124 }
2125 switch(nIndex)
2126 {
2127 case 0: return "Disable";
2128 case 1: return "--";
2129 default:
2130 nIndex -= 2;
2131 if(nIndex < UI.nCustomCount)
2132 {
2133 return UI.Custom[nIndex].pName;
2134 }
2135 else
2136 {
2137 return 0;
2138 }
2139 }
2140}
2141
2142const char* MicroProfileUIMenuEmpty(int nIndex, bool* bSelected)
2143{
2144 return 0;
2145}
2146
2147
2148void MicroProfileUIClickMode(int nIndex)
2149{
2150 MicroProfile& S = *MicroProfileGet();
2151 switch(nIndex)
2152 {
2153 case 0:
2154 S.nDisplay = MP_DRAW_DETAILED;
2155 break;
2156 case 1:
2157 S.nDisplay = MP_DRAW_BARS;
2158 break;
2159 case 2:
2160 S.nDisplay = MP_DRAW_HIDDEN;
2161 break;
2162 case 3:
2163 S.nDisplay = 0;
2164 break;
2165 case 4:
2166 break;
2167 case 5:
2168 S.nForceEnable = !S.nForceEnable;
2169 break;
2170 }
2171}
2172
2173void MicroProfileUIClickGroups(int nIndex)
2174{
2175 MicroProfile& S = *MicroProfileGet();
2176 if(nIndex == 0)
2177 S.nAllGroupsWanted = 1-S.nAllGroupsWanted;
2178 else
2179 {
2180 nIndex -= 1;
2181 if(nIndex < UI.GroupMenuCount)
2182 {
2183 MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
2184 if(Item.nIsCategory)
2185 {
2186 uint64_t nGroupMask = S.CategoryInfo[Item.nIndex].nGroupMask;
2187 if(nGroupMask != (nGroupMask & S.nActiveGroupWanted))
2188 {
2189 S.nActiveGroupWanted |= nGroupMask;
2190 }
2191 else
2192 {
2193 S.nActiveGroupWanted &= ~nGroupMask;
2194 }
2195 }
2196 else
2197 {
2198 MP_ASSERT(Item.nIndex < S.nGroupCount);
2199 S.nActiveGroupWanted ^= (1ll << Item.nIndex);
2200 }
2201 }
2202 }
2203}
2204
2205void MicroProfileUIClickAggregate(int nIndex)
2206{
2207 MicroProfile& S = *MicroProfileGet();
2208 S.nAggregateFlip = g_MicroProfileAggregatePresets[nIndex];
2209 if(0 == S.nAggregateFlip)
2210 {
2211 S.nAggregateClear = 1;
2212 }
2213}
2214
2215void MicroProfileUIClickTimers(int nIndex)
2216{
2217 MicroProfile& S = *MicroProfileGet();
2218 S.nBars ^= (1 << nIndex);
2219}
2220
2221void MicroProfileUIClickOptions(int nIndex)
2222{
2223 MicroProfile& S = *MicroProfileGet();
2224 switch(UI.Options[nIndex].nSubType)
2225 {
2226 case 0:
2227 S.fReferenceTime = g_MicroProfileReferenceTimePresets[UI.Options[nIndex].nIndex];
2228 S.fRcpReferenceTime = 1.f / S.fReferenceTime;
2229 break;
2230 case 1:
2231 UI.nOpacityBackground = g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex]<<24;
2232 break;
2233 case 2:
2234 UI.nOpacityForeground = g_MicroProfileOpacityPresets[UI.Options[nIndex].nIndex]<<24;
2235 break;
2236 case 3:
2237 UI.bShowSpikes = !UI.bShowSpikes;
2238 break;
2239#if MICROPROFILE_CONTEXT_SWITCH_TRACE
2240 case 4:
2241 {
2242 switch(UI.Options[nIndex].nIndex)
2243 {
2244 case 0:
2245 if(S.bContextSwitchRunning)
2246 {
2247 MicroProfileStopContextSwitchTrace();
2248 }
2249 else
2250 {
2251 MicroProfileStartContextSwitchTrace();
2252 }
2253 break;
2254 case 1:
2255 S.bContextSwitchAllThreads = !S.bContextSwitchAllThreads;
2256 break;
2257 case 2:
2258 S.bContextSwitchNoBars= !S.bContextSwitchNoBars;
2259 break;
2260
2261 }
2262 }
2263 break;
2264#endif
2265 }
2266}
2267
2268void MicroProfileUIClickPreset(int nIndex)
2269{
2270 int nNumPresets = sizeof(g_MicroProfilePresetNames) / sizeof(g_MicroProfilePresetNames[0]);
2271 int nIndexSave = nIndex - nNumPresets - 1;
2272 if(nIndexSave >= 0 && nIndexSave < nNumPresets)
2273 {
2274 MicroProfileSavePreset(g_MicroProfilePresetNames[nIndexSave]);
2275 }
2276 else if(nIndex >= 0 && nIndex < nNumPresets)
2277 {
2278 MicroProfileLoadPreset(g_MicroProfilePresetNames[nIndex]);
2279 }
2280}
2281
2282void MicroProfileUIClickCustom(int nIndex)
2283{
2284 if(nIndex == 0)
2285 {
2286 MicroProfileCustomGroupDisable();
2287 }
2288 else
2289 {
2290 MicroProfileCustomGroupEnable(nIndex-2);
2291 }
2292
2293}
2294
2295void MicroProfileUIClickEmpty(int nIndex)
2296{
2297
2298}
2299
2300
2301void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
2302{
2303 MicroProfile& S = *MicroProfileGet();
2304
2305 uint32_t nX = 0;
2306 uint32_t nY = 0;
2307 bool bMouseOver = UI.nMouseY < MICROPROFILE_TEXT_HEIGHT + 1;
2308#define SBUF_SIZE 256
2309 char buffer[256];
2310 MicroProfileDrawBox(nX, nY, nX + nWidth, nY + (MICROPROFILE_TEXT_HEIGHT+1)+1, 0xff000000|g_nMicroProfileBackColors[1]);
2311
2312#define MICROPROFILE_MENU_MAX 16
2313 const char* pMenuText[MICROPROFILE_MENU_MAX] = {0};
2314 uint32_t nMenuX[MICROPROFILE_MENU_MAX] = {0};
2315 uint32_t nNumMenuItems = 0;
2316
2317 int nLen = snprintf(buffer, 127, "MicroProfile");
2318 MicroProfileDrawText(nX, nY, (uint32_t)-1, buffer, nLen);
2319 nX += (sizeof("MicroProfile")+2) * (MICROPROFILE_TEXT_WIDTH+1);
2320 pMenuText[nNumMenuItems++] = "Mode";
2321 pMenuText[nNumMenuItems++] = "Groups";
2322 char AggregateText[64];
2323 snprintf(AggregateText, sizeof(AggregateText)-1, "Aggregate[%d]", S.nAggregateFlip ? S.nAggregateFlip : S.nAggregateFlipCount);
2324 pMenuText[nNumMenuItems++] = &AggregateText[0];
2325 pMenuText[nNumMenuItems++] = "Timers";
2326 pMenuText[nNumMenuItems++] = "Options";
2327 pMenuText[nNumMenuItems++] = "Preset";
2328 pMenuText[nNumMenuItems++] = "Custom";
2329 const int nPauseIndex = nNumMenuItems;
2330 pMenuText[nNumMenuItems++] = S.nRunning ? "Pause" : "Unpause";
2331 pMenuText[nNumMenuItems++] = "Help";
2332
2333 if(S.nOverflow)
2334 {
2335 pMenuText[nNumMenuItems++] = "!BUFFERSFULL!";
2336 }
2337
2338
2339 if(UI.GroupMenuCount != S.nGroupCount + S.nCategoryCount)
2340 {
2341 UI.GroupMenuCount = S.nGroupCount + S.nCategoryCount;
2342 for(uint32_t i = 0; i < S.nCategoryCount; ++i)
2343 {
2344 UI.GroupMenu[i].nIsCategory = 1;
2345 UI.GroupMenu[i].nCategoryIndex = i;
2346 UI.GroupMenu[i].nIndex = i;
2347 UI.GroupMenu[i].pName = S.CategoryInfo[i].pName;
2348 }
2349 for(uint32_t i = 0; i < S.nGroupCount; ++i)
2350 {
2351 uint32_t idx = i + S.nCategoryCount;
2352 UI.GroupMenu[idx].nIsCategory = 0;
2353 UI.GroupMenu[idx].nCategoryIndex = S.GroupInfo[i].nCategory;
2354 UI.GroupMenu[idx].nIndex = i;
2355 UI.GroupMenu[idx].pName = S.GroupInfo[i].pName;
2356 }
2357 std::sort(&UI.GroupMenu[0], &UI.GroupMenu[UI.GroupMenuCount],
2358 [] (const MicroProfileGroupMenuItem& l, const MicroProfileGroupMenuItem& r) -> bool
2359 {
2360 if(l.nCategoryIndex < r.nCategoryIndex)
2361 {
2362 return true;
2363 }
2364 else if(r.nCategoryIndex < l.nCategoryIndex)
2365 {
2366 return false;
2367 }
2368 if(r.nIsCategory || l.nIsCategory)
2369 {
2370 return l.nIsCategory > r.nIsCategory;
2371 }
2372 return MP_STRCASECMP(l.pName, r.pName)<0;
2373 }
2374 );
2375 }
2376
2377 MicroProfileSubmenuCallback GroupCallback[MICROPROFILE_MENU_MAX] =
2378 {
2379 MicroProfileUIMenuMode,
2380 MicroProfileUIMenuGroups,
2381 MicroProfileUIMenuAggregate,
2382 MicroProfileUIMenuTimers,
2383 MicroProfileUIMenuOptions,
2384 MicroProfileUIMenuPreset,
2385 MicroProfileUIMenuCustom,
2386 MicroProfileUIMenuEmpty,
2387 MicroProfileUIMenuEmpty,
2388 MicroProfileUIMenuEmpty,
2389 };
2390
2391 MicroProfileClickCallback CBClick[MICROPROFILE_MENU_MAX] =
2392 {
2393 MicroProfileUIClickMode,
2394 MicroProfileUIClickGroups,
2395 MicroProfileUIClickAggregate,
2396 MicroProfileUIClickTimers,
2397 MicroProfileUIClickOptions,
2398 MicroProfileUIClickPreset,
2399 MicroProfileUIClickCustom,
2400 MicroProfileUIClickEmpty,
2401 MicroProfileUIClickEmpty,
2402 MicroProfileUIClickEmpty,
2403 };
2404
2405
2406 uint32_t nSelectMenu = (uint32_t)-1;
2407 for(uint32_t i = 0; i < nNumMenuItems; ++i)
2408 {
2409 nMenuX[i] = nX;
2410 uint32_t nLen = (uint32_t)strlen(pMenuText[i]);
2411 uint32_t nEnd = nX + nLen * (MICROPROFILE_TEXT_WIDTH+1);
2412 if(UI.nMouseY <= MICROPROFILE_TEXT_HEIGHT && UI.nMouseX <= nEnd && UI.nMouseX >= nX)
2413 {
2414 MicroProfileDrawBox(nX-1, nY, nX + nLen * (MICROPROFILE_TEXT_WIDTH+1), nY +(MICROPROFILE_TEXT_HEIGHT+1)+1, 0xff888888);
2415 nSelectMenu = i;
2416 if((UI.nMouseLeft || UI.nMouseRight) && i == (int)nPauseIndex)
2417 {
2418 S.nToggleRunning = 1;
2419 }
2420 }
2421 MicroProfileDrawText(nX, nY, (uint32_t)-1, pMenuText[i], (uint32_t)strlen(pMenuText[i]));
2422 nX += (nLen+1) * (MICROPROFILE_TEXT_WIDTH+1);
2423 }
2424 uint32_t nMenu = nSelectMenu != (uint32_t)-1 ? nSelectMenu : UI.nActiveMenu;
2425 UI.nActiveMenu = nMenu;
2426 if((uint32_t)-1 != nMenu)
2427 {
2428 nX = nMenuX[nMenu];
2429 nY += MICROPROFILE_TEXT_HEIGHT+1;
2430 MicroProfileSubmenuCallback CB = GroupCallback[nMenu];
2431 int nNumLines = 0;
2432 bool bSelected = false;
2433 const char* pString = CB(nNumLines, &bSelected);
2434 uint32_t nWidth = 0, nHeight = 0;
2435 while(pString)
2436 {
2437 nWidth = MicroProfileMax<int>(nWidth, (int)strlen(pString));
2438 nNumLines++;
2439 pString = CB(nNumLines, &bSelected);
2440 }
2441 nWidth = (2+nWidth) * (MICROPROFILE_TEXT_WIDTH+1);
2442 nHeight = nNumLines * (MICROPROFILE_TEXT_HEIGHT+1);
2443 if(UI.nMouseY <= nY + nHeight+0 && UI.nMouseY >= nY-0 && UI.nMouseX <= nX + nWidth + 0 && UI.nMouseX >= nX - 0)
2444 {
2445 UI.nActiveMenu = nMenu;
2446 }
2447 else if(nSelectMenu == (uint32_t)-1)
2448 {
2449 UI.nActiveMenu = (uint32_t)-1;
2450 }
2451 MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000|g_nMicroProfileBackColors[1]);
2452 for(int i = 0; i < nNumLines; ++i)
2453 {
2454 bool bSelected = false;
2455 const char* pString = CB(i, &bSelected);
2456 if(UI.nMouseY >= nY && UI.nMouseY < nY + MICROPROFILE_TEXT_HEIGHT + 1)
2457 {
2458 bMouseOver = true;
2459 if(UI.nMouseLeft || UI.nMouseRight)
2460 {
2461 CBClick[nMenu](i);
2462 }
2463 MicroProfileDrawBox(nX, nY, nX + nWidth, nY + MICROPROFILE_TEXT_HEIGHT + 1, 0xff888888);
2464 }
2465 int nLen = snprintf(buffer, SBUF_SIZE-1, "%c %s", bSelected ? '*' : ' ' ,pString);
2466 MicroProfileDrawText(nX, nY, (uint32_t)-1, buffer, nLen);
2467 nY += MICROPROFILE_TEXT_HEIGHT+1;
2468 }
2469 }
2470
2471
2472 {
2473 static char FrameTimeMessage[64];
2474 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2475 uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
2476 float fMs = fToMs * (S.nFlipTicks);
2477 float fAverageMs = fToMs * (S.nFlipAggregateDisplay / nAggregateFrames);
2478 float fMaxMs = fToMs * S.nFlipMaxDisplay;
2479 int nLen = snprintf(FrameTimeMessage, sizeof(FrameTimeMessage)-1, "Time[%6.2f] Avg[%6.2f] Max[%6.2f]", fMs, fAverageMs, fMaxMs);
2480 pMenuText[nNumMenuItems++] = &FrameTimeMessage[0];
2481 MicroProfileDrawText(nWidth - nLen * (MICROPROFILE_TEXT_WIDTH+1), 0, -1, FrameTimeMessage, nLen);
2482 }
2483}
2484
2485
2486void MicroProfileMoveGraph()
2487{
2488
2489 int nZoom = UI.nMouseWheelDelta;
2490 int nPanX = 0;
2491 int nPanY = 0;
2492 static int X = 0, Y = 0;
2493 if(UI.nMouseDownLeft && !UI.nModDown)
2494 {
2495 nPanX = UI.nMouseX - X;
2496 nPanY = UI.nMouseY - Y;
2497 }
2498 X = UI.nMouseX;
2499 Y = UI.nMouseY;
2500
2501 if(nZoom)
2502 {
2503 float fOldRange = UI.fDetailedRange;
2504 if(nZoom>0)
2505 {
2506 UI.fDetailedRangeTarget = UI.fDetailedRange *= UI.nModDown ? 1.40f : 1.05f;
2507 }
2508 else
2509 {
2510 float fNewDetailedRange = UI.fDetailedRange / (UI.nModDown ? 1.40f : 1.05f);
2511 if(fNewDetailedRange < 1e-4f) //100ns
2512 fNewDetailedRange = 1e-4f;
2513 UI.fDetailedRangeTarget = UI.fDetailedRange = fNewDetailedRange;
2514 }
2515
2516 float fDiff = fOldRange - UI.fDetailedRange;
2517 float fMousePrc = MicroProfileMax((float)UI.nMouseX / UI.nWidth ,0.f);
2518 UI.fDetailedOffsetTarget = UI.fDetailedOffset += fDiff * fMousePrc;
2519
2520 }
2521 if(nPanX)
2522 {
2523 UI.fDetailedOffsetTarget = UI.fDetailedOffset += -nPanX * UI.fDetailedRange / UI.nWidth;
2524 }
2525 UI.nOffsetY -= nPanY;
2526 UI.nOffsetX += nPanX;
2527 if(UI.nOffsetX > 0)
2528 UI.nOffsetX = 0;
2529 if(UI.nOffsetY<0)
2530 UI.nOffsetY = 0;
2531}
2532
2533void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
2534{
2535 if((uint32_t)-1 != UI.nCustomActive)
2536 {
2537 MicroProfile& S = *MicroProfileGet();
2538 MP_ASSERT(UI.nCustomActive < MICROPROFILE_CUSTOM_MAX);
2539 MicroProfileCustom* pCustom = &UI.Custom[UI.nCustomActive];
2540 uint32_t nCount = pCustom->nNumTimers;
2541 uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1;
2542 uint32_t nExtraOffset = 1 + ((pCustom->nFlags & MICROPROFILE_CUSTOM_STACK) != 0 ? 3 : 0);
2543 uint32_t nOffsetYBase = nHeight - (nExtraOffset+nCount)* (1+MICROPROFILE_TEXT_HEIGHT) - MICROPROFILE_CUSTOM_PADDING;
2544 uint32_t nOffsetY = nOffsetYBase;
2545 float fReference = pCustom->fReference;
2546 float fRcpReference = 1.f / fReference;
2547 uint32_t nReducedWidth = UI.nWidth - 2*MICROPROFILE_CUSTOM_PADDING - MICROPROFILE_GRAPH_WIDTH;
2548
2549 char Buffer[MICROPROFILE_NAME_MAX_LEN*2+1];
2550 float* pTime = (float*)alloca(sizeof(float)*nCount);
2551 float* pTimeAvg = (float*)alloca(sizeof(float)*nCount);
2552 float* pTimeMax = (float*)alloca(sizeof(float)*nCount);
2553 uint32_t* pColors = (uint32_t*)alloca(sizeof(uint32_t)*nCount);
2554 uint32_t nMaxOffsetX = 0;
2555 MicroProfileDrawBox(MICROPROFILE_CUSTOM_PADDING-1, nOffsetY-1, MICROPROFILE_CUSTOM_PADDING+nReducedWidth+1, UI.nHeight - MICROPROFILE_CUSTOM_PADDING+1, 0x88000000|g_nMicroProfileBackColors[0]);
2556
2557 for(uint32_t i = 0; i < nCount; ++i)
2558 {
2559 uint16_t nTimerIndex = MicroProfileGetTimerIndex(pCustom->pTimers[i]);
2560 uint16_t nGroupIndex = MicroProfileGetGroupIndex(pCustom->pTimers[i]);
2561 float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupIndex].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu());
2562 pTime[i] = S.Frame[nTimerIndex].nTicks * fToMs;
2563 pTimeAvg[i] = fToMs * (S.Aggregate[nTimerIndex].nTicks / nAggregateFrames);
2564 pTimeMax[i] = fToMs * (S.AggregateMax[nTimerIndex]);
2565 pColors[i] = S.TimerInfo[nTimerIndex].nColor;
2566 }
2567
2568 MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 3*MICROPROFILE_TEXT_WIDTH, nOffsetY, (uint32_t)-1, "Avg", sizeof("Avg")-1);
2569 MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 13*MICROPROFILE_TEXT_WIDTH, nOffsetY, (uint32_t)-1, "Max", sizeof("Max")-1);
2570 for(uint32_t i = 0; i < nCount; ++i)
2571 {
2572 nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
2573 uint16_t nTimerIndex = MicroProfileGetTimerIndex(pCustom->pTimers[i]);
2574 uint16_t nGroupIndex = MicroProfileGetGroupIndex(pCustom->pTimers[i]);
2575 MicroProfileTimerInfo* pTimerInfo = &S.TimerInfo[nTimerIndex];
2576 int nSize;
2577 uint32_t nOffsetX = MICROPROFILE_CUSTOM_PADDING;
2578 nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2f", pTimeAvg[i]);
2579 MicroProfileDrawText(nOffsetX, nOffsetY, (uint32_t)-1, Buffer, nSize);
2580 nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
2581 nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2f", pTimeMax[i]);
2582 MicroProfileDrawText(nOffsetX, nOffsetY, (uint32_t)-1, Buffer, nSize);
2583 nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
2584 nSize = snprintf(Buffer, sizeof(Buffer)-1, "%s:%s", S.GroupInfo[nGroupIndex].pName, pTimerInfo->pName);
2585 MicroProfileDrawText(nOffsetX, nOffsetY, pTimerInfo->nColor, Buffer, nSize);
2586 nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
2587 nMaxOffsetX = MicroProfileMax(nMaxOffsetX, nOffsetX);
2588 }
2589 uint32_t nMaxWidth = nReducedWidth- nMaxOffsetX;
2590
2591 if(pCustom->nFlags & MICROPROFILE_CUSTOM_BARS)
2592 {
2593 nOffsetY = nOffsetYBase;
2594 float* pMs = pCustom->nFlags & MICROPROFILE_CUSTOM_BAR_SOURCE_MAX ? pTimeMax : pTimeAvg;
2595 const char* pString = pCustom->nFlags & MICROPROFILE_CUSTOM_BAR_SOURCE_MAX ? "Max" : "Avg";
2596 MicroProfileDrawText(nMaxOffsetX, nOffsetY, (uint32_t)-1, pString, strlen(pString));
2597 int nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2fms", fReference);
2598 MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, (uint32_t)-1, Buffer, nSize);
2599 for(uint32_t i = 0; i < nCount; ++i)
2600 {
2601 nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
2602 uint32_t nWidth = MicroProfileMin(nMaxWidth, (uint32_t)(nMaxWidth * pMs[i] * fRcpReference));
2603 MicroProfileDrawBox(nMaxOffsetX, nOffsetY, nMaxOffsetX+nWidth, nOffsetY+MICROPROFILE_TEXT_HEIGHT, pColors[i]|0xff000000);
2604 }
2605 }
2606 if(pCustom->nFlags & MICROPROFILE_CUSTOM_STACK)
2607 {
2608 nOffsetY += 2*(1+MICROPROFILE_TEXT_HEIGHT);
2609 const char* pString = pCustom->nFlags & MICROPROFILE_CUSTOM_STACK_SOURCE_MAX ? "Max" : "Avg";
2610 MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING, nOffsetY, (uint32_t)-1, pString, strlen(pString));
2611 int nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2fms", fReference);
2612 MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, (uint32_t)-1, Buffer, nSize);
2613 nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
2614 float fPosX = MICROPROFILE_CUSTOM_PADDING;
2615 float* pMs = pCustom->nFlags & MICROPROFILE_CUSTOM_STACK_SOURCE_MAX ? pTimeMax : pTimeAvg;
2616 for(uint32_t i = 0; i < nCount; ++i)
2617 {
2618 float fWidth = pMs[i] * fRcpReference * nReducedWidth;
2619 uint32_t nX = fPosX;
2620 fPosX += fWidth;
2621 uint32_t nXEnd = fPosX;
2622 if(nX < nXEnd)
2623 {
2624 MicroProfileDrawBox(nX, nOffsetY, nXEnd, nOffsetY+MICROPROFILE_TEXT_HEIGHT, pColors[i]|0xff000000);
2625 }
2626 }
2627 }
2628 }
2629}
2630void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
2631{
2632 MICROPROFILE_SCOPE(g_MicroProfileDraw);
2633 MicroProfile& S = *MicroProfileGet();
2634
2635 {
2636 static int once = 0;
2637 if(0 == once)
2638 {
2639 std::recursive_mutex& m = MicroProfileGetMutex();
2640 m.lock();
2641 MicroProfileInitUI();
2642
2643
2644
2645 uint32_t nDisplay = S.nDisplay;
2646 MicroProfileLoadPreset(MICROPROFILE_DEFAULT_PRESET);
2647 once++;
2648 S.nDisplay = nDisplay;// dont load display, just state
2649 m.unlock();
2650
2651 }
2652 }
2653
2654
2655 if(S.nDisplay)
2656 {
2657 std::recursive_mutex& m = MicroProfileGetMutex();
2658 m.lock();
2659 UI.nWidth = nWidth;
2660 UI.nHeight = nHeight;
2661 UI.nHoverToken = MICROPROFILE_INVALID_TOKEN;
2662 UI.nHoverTime = 0;
2663 UI.nHoverFrame = -1;
2664 if(S.nDisplay != MP_DRAW_DETAILED)
2665 S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = -1;
2666 MicroProfileMoveGraph();
2667
2668
2669 if(S.nDisplay == MP_DRAW_DETAILED)
2670 {
2671 MicroProfileDrawDetailedView(nWidth, nHeight);
2672 }
2673 else if(S.nDisplay == MP_DRAW_BARS && S.nBars)
2674 {
2675 MicroProfileDrawBarView(nWidth, nHeight);
2676 }
2677
2678 MicroProfileDrawMenu(nWidth, nHeight);
2679 bool bMouseOverGraph = MicroProfileDrawGraph(nWidth, nHeight);
2680 MicroProfileDrawCustom(nWidth, nHeight);
2681 bool bHidden = S.nDisplay == MP_DRAW_HIDDEN;
2682 if(!bHidden)
2683 {
2684 uint32_t nLockedToolTipX = 3;
2685 bool bDeleted = false;
2686 for(int i = 0; i < MICROPROFILE_TOOLTIP_MAX_LOCKED; ++i)
2687 {
2688 int nIndex = (g_MicroProfileUI.LockedToolTipFront + i) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
2689 if(g_MicroProfileUI.LockedToolTips[nIndex].ppStrings[0])
2690 {
2691 uint32_t nToolTipWidth = 0, nToolTipHeight = 0;
2692 MicroProfileFloatWindowSize(g_MicroProfileUI.LockedToolTips[nIndex].ppStrings, g_MicroProfileUI.LockedToolTips[nIndex].nNumStrings, 0, nToolTipWidth, nToolTipHeight, 0);
2693 uint32_t nStartY = nHeight - nToolTipHeight - 2;
2694 if(!bDeleted && UI.nMouseY > nStartY && UI.nMouseX > nLockedToolTipX && UI.nMouseX <= nLockedToolTipX + nToolTipWidth && (UI.nMouseLeft || UI.nMouseRight) )
2695 {
2696 bDeleted = true;
2697 int j = i;
2698 for(; j < MICROPROFILE_TOOLTIP_MAX_LOCKED-1; ++j)
2699 {
2700 int nIndex0 = (g_MicroProfileUI.LockedToolTipFront + j) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
2701 int nIndex1 = (g_MicroProfileUI.LockedToolTipFront + j+1) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
2702 MicroProfileStringArrayCopy(&g_MicroProfileUI.LockedToolTips[nIndex0], &g_MicroProfileUI.LockedToolTips[nIndex1]);
2703 }
2704 MicroProfileStringArrayClear(&g_MicroProfileUI.LockedToolTips[(g_MicroProfileUI.LockedToolTipFront + j) % MICROPROFILE_TOOLTIP_MAX_LOCKED]);
2705 }
2706 else
2707 {
2708 MicroProfileDrawFloatWindow(nLockedToolTipX, nHeight-nToolTipHeight-2, &g_MicroProfileUI.LockedToolTips[nIndex].ppStrings[0], g_MicroProfileUI.LockedToolTips[nIndex].nNumStrings, g_MicroProfileUI.nLockedToolTipColor[nIndex]);
2709 nLockedToolTipX += nToolTipWidth + 4;
2710 }
2711 }
2712 }
2713
2714 if(UI.nActiveMenu == 8)
2715 {
2716 if(S.nDisplay & MP_DRAW_DETAILED)
2717 {
2718 MicroProfileStringArray DetailedHelp;
2719 MicroProfileStringArrayClear(&DetailedHelp);
2720 MicroProfileStringArrayFormat(&DetailedHelp, "%s", MICROPROFILE_HELP_LEFT);
2721 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Toggle Graph");
2722 MicroProfileStringArrayFormat(&DetailedHelp, "%s", MICROPROFILE_HELP_ALT);
2723 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Zoom");
2724 MicroProfileStringArrayFormat(&DetailedHelp, "%s + %s", MICROPROFILE_HELP_MOD, MICROPROFILE_HELP_LEFT);
2725 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Lock Tooltip");
2726 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Drag");
2727 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Pan View");
2728 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Mouse Wheel");
2729 MicroProfileStringArrayAddLiteral(&DetailedHelp, "Zoom");
2730 MicroProfileDrawFloatWindow(nWidth, MICROPROFILE_FRAME_HISTORY_HEIGHT+20, DetailedHelp.ppStrings, DetailedHelp.nNumStrings, 0xff777777);
2731
2732 MicroProfileStringArray DetailedHistoryHelp;
2733 MicroProfileStringArrayClear(&DetailedHistoryHelp);
2734 MicroProfileStringArrayFormat(&DetailedHistoryHelp, "%s", MICROPROFILE_HELP_LEFT);
2735 MicroProfileStringArrayAddLiteral(&DetailedHistoryHelp, "Center View");
2736 MicroProfileStringArrayFormat(&DetailedHistoryHelp, "%s", MICROPROFILE_HELP_ALT);
2737 MicroProfileStringArrayAddLiteral(&DetailedHistoryHelp, "Zoom to frame");
2738 MicroProfileDrawFloatWindow(nWidth, 20, DetailedHistoryHelp.ppStrings, DetailedHistoryHelp.nNumStrings, 0xff777777);
2739
2740
2741
2742 }
2743 else if(0 != (S.nDisplay & MP_DRAW_BARS) && S.nBars)
2744 {
2745 MicroProfileStringArray BarHelp;
2746 MicroProfileStringArrayClear(&BarHelp);
2747 MicroProfileStringArrayFormat(&BarHelp, "%s", MICROPROFILE_HELP_LEFT);
2748 MicroProfileStringArrayAddLiteral(&BarHelp, "Toggle Graph");
2749 MicroProfileStringArrayFormat(&BarHelp, "%s + %s", MICROPROFILE_HELP_MOD, MICROPROFILE_HELP_LEFT);
2750 MicroProfileStringArrayAddLiteral(&BarHelp, "Lock Tooltip");
2751 MicroProfileStringArrayAddLiteral(&BarHelp, "Drag");
2752 MicroProfileStringArrayAddLiteral(&BarHelp, "Pan View");
2753 MicroProfileDrawFloatWindow(nWidth, MICROPROFILE_FRAME_HISTORY_HEIGHT+20, BarHelp.ppStrings, BarHelp.nNumStrings, 0xff777777);
2754
2755 }
2756 MicroProfileStringArray Debug;
2757 MicroProfileStringArrayClear(&Debug);
2758 MicroProfileStringArrayAddLiteral(&Debug, "Memory Usage");
2759 MicroProfileStringArrayFormat(&Debug, "%4.2fmb", S.nMemUsage / (1024.f * 1024.f));
2760 MicroProfileStringArrayAddLiteral(&Debug, "Web Server Port");
2761 MicroProfileStringArrayFormat(&Debug, "%d", MicroProfileWebServerPort());
2762 uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY;
2763 MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent];
2764 MicroProfileFrameState* pFrameNext = &S.Frames[nFrameNext];
2765
2766
2767 MicroProfileStringArrayAddLiteral(&Debug, "");
2768 MicroProfileStringArrayAddLiteral(&Debug, "");
2769 MicroProfileStringArrayAddLiteral(&Debug, "Usage");
2770 MicroProfileStringArrayAddLiteral(&Debug, "markers [frames] ");
2771
2772#if MICROPROFILE_CONTEXT_SWITCH_TRACE
2773 MicroProfileStringArrayAddLiteral(&Debug, "Context Switch");
2774 MicroProfileStringArrayFormat(&Debug, "%9d [%7d]", S.nContextSwitchUsage, MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE / S.nContextSwitchUsage );
2775#endif
2776
2777 for(int i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
2778 {
2779 if(pFrameCurrent->nLogStart[i] && S.Pool[i])
2780 {
2781 uint32_t nEnd = pFrameNext->nLogStart[i];
2782 uint32_t nStart = pFrameCurrent->nLogStart[i];
2783 uint32_t nUsage = nStart < nEnd ? (nEnd - nStart) : (nEnd + MICROPROFILE_BUFFER_SIZE - nStart);
2784 uint32_t nFrameSupport = MICROPROFILE_BUFFER_SIZE / nUsage;
2785 MicroProfileStringArrayFormat(&Debug, "%s", &S.Pool[i]->ThreadName[0]);
2786 MicroProfileStringArrayFormat(&Debug, "%9d [%7d]", nUsage, nFrameSupport);
2787 }
2788 }
2789
2790 MicroProfileDrawFloatWindow(0, nHeight-10, Debug.ppStrings, Debug.nNumStrings, 0xff777777);
2791 }
2792
2793
2794
2795 if(UI.nActiveMenu == -1 && !bMouseOverGraph)
2796 {
2797 if(UI.nHoverToken != MICROPROFILE_INVALID_TOKEN)
2798 {
2799 MicroProfileDrawFloatTooltip(UI.nMouseX, UI.nMouseY, UI.nHoverToken, UI.nHoverTime);
2800 }
2801 else if(S.nContextSwitchHoverThreadAfter != -1 && S.nContextSwitchHoverThreadBefore != -1)
2802 {
2803 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2804 MicroProfileStringArray ToolTip;
2805 MicroProfileStringArrayClear(&ToolTip);
2806 MicroProfileStringArrayAddLiteral(&ToolTip, "Context Switch");
2807 MicroProfileStringArrayFormat(&ToolTip, "%04x", S.nContextSwitchHoverThread);
2808 MicroProfileStringArrayAddLiteral(&ToolTip, "Before");
2809 MicroProfileStringArrayFormat(&ToolTip, "%04x", S.nContextSwitchHoverThreadBefore);
2810 MicroProfileStringArrayAddLiteral(&ToolTip, "After");
2811 MicroProfileStringArrayFormat(&ToolTip, "%04x", S.nContextSwitchHoverThreadAfter);
2812 MicroProfileStringArrayAddLiteral(&ToolTip, "Duration");
2813 int64_t nDifference = MicroProfileLogTickDifference(S.nContextSwitchHoverTickIn, S.nContextSwitchHoverTickOut);
2814 MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fToMs * nDifference );
2815 MicroProfileStringArrayAddLiteral(&ToolTip, "CPU");
2816 MicroProfileStringArrayFormat(&ToolTip, "%d", S.nContextSwitchHoverCpu);
2817 MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, -1);
2818
2819
2820 }
2821 else if(UI.nHoverFrame != -1)
2822 {
2823 uint32_t nNextFrame = (UI.nHoverFrame+1)%MICROPROFILE_MAX_FRAME_HISTORY;
2824 int64_t nTick = S.Frames[UI.nHoverFrame].nFrameStartCpu;
2825 int64_t nTickNext = S.Frames[nNextFrame].nFrameStartCpu;
2826 int64_t nTickGpu = S.Frames[UI.nHoverFrame].nFrameStartGpu;
2827 int64_t nTickNextGpu = S.Frames[nNextFrame].nFrameStartGpu;
2828
2829 float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
2830 float fToMsGpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu());
2831 float fMs = fToMs * (nTickNext - nTick);
2832 float fMsGpu = fToMsGpu * (nTickNextGpu - nTickGpu);
2833 MicroProfileStringArray ToolTip;
2834 MicroProfileStringArrayClear(&ToolTip);
2835 MicroProfileStringArrayFormat(&ToolTip, "Frame %d", UI.nHoverFrame);
2836 #if MICROPROFILE_DEBUG
2837 MicroProfileStringArrayFormat(&ToolTip, "%p", &S.Frames[UI.nHoverFrame]);
2838 #else
2839 MicroProfileStringArrayAddLiteral(&ToolTip, "");
2840 #endif
2841 MicroProfileStringArrayAddLiteral(&ToolTip, "CPU Time");
2842 MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fMs);
2843 MicroProfileStringArrayAddLiteral(&ToolTip, "GPU Time");
2844 MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fMsGpu);
2845 #if MICROPROFILE_DEBUG
2846 for(int i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
2847 {
2848 if(S.Frames[UI.nHoverFrame].nLogStart[i])
2849 {
2850 MicroProfileStringArrayFormat(&ToolTip, "%d", i);
2851 MicroProfileStringArrayFormat(&ToolTip, "%d", S.Frames[UI.nHoverFrame].nLogStart[i]);
2852 }
2853 }
2854 #endif
2855 MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, -1);
2856 }
2857 if(UI.nMouseLeft)
2858 {
2859 if(UI.nHoverToken != MICROPROFILE_INVALID_TOKEN)
2860 MicroProfileToggleGraph(UI.nHoverToken);
2861 }
2862 }
2863 }
2864
2865#if MICROPROFILE_DRAWCURSOR
2866 {
2867 float fCursor[8] =
2868 {
2869 MicroProfileMax(0, (int)UI.nMouseX-3), UI.nMouseY,
2870 MicroProfileMin(nWidth, UI.nMouseX+3), UI.nMouseY,
2871 UI.nMouseX, MicroProfileMax((int)UI.nMouseY-3, 0),
2872 UI.nMouseX, MicroProfileMin(nHeight, UI.nMouseY+3),
2873 };
2874 MicroProfileDrawLine2D(2, &fCursor[0], 0xff00ff00);
2875 MicroProfileDrawLine2D(2, &fCursor[4], 0xff00ff00);
2876 }
2877#endif
2878 m.unlock();
2879 }
2880 else if(UI.nCustomActive != (uint32_t)-1)
2881 {
2882 std::recursive_mutex& m = MicroProfileGetMutex();
2883 m.lock();
2884 MicroProfileDrawGraph(nWidth, nHeight);
2885 MicroProfileDrawCustom(nWidth, nHeight);
2886 m.unlock();
2887
2888 }
2889 UI.nMouseLeft = UI.nMouseRight = 0;
2890 UI.nMouseLeftMod = UI.nMouseRightMod = 0;
2891 UI.nMouseWheelDelta = 0;
2892 if(S.nOverflow)
2893 S.nOverflow--;
2894
2895 UI.fDetailedOffset = UI.fDetailedOffset + (UI.fDetailedOffsetTarget - UI.fDetailedOffset) * MICROPROFILE_ANIM_DELAY_PRC;
2896 UI.fDetailedRange = UI.fDetailedRange + (UI.fDetailedRangeTarget - UI.fDetailedRange) * MICROPROFILE_ANIM_DELAY_PRC;
2897
2898
2899}
2900
2901bool MicroProfileIsDrawing()
2902{
2903 MicroProfile& S = *MicroProfileGet();
2904 return S.nDisplay != 0;
2905}
2906
2907void MicroProfileToggleGraph(MicroProfileToken nToken)
2908{
2909 MicroProfile& S = *MicroProfileGet();
2910 uint32_t nTimerId = MicroProfileGetTimerIndex(nToken);
2911 nToken &= 0xffff;
2912 int32_t nMinSort = 0x7fffffff;
2913 int32_t nFreeIndex = -1;
2914 int32_t nMinIndex = 0;
2915 int32_t nMaxSort = 0x80000000;
2916 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
2917 {
2918 if(S.Graph[i].nToken == MICROPROFILE_INVALID_TOKEN)
2919 nFreeIndex = i;
2920 if(S.Graph[i].nToken == nToken)
2921 {
2922 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
2923 S.TimerInfo[nTimerId].bGraph = false;
2924 return;
2925 }
2926 if(S.Graph[i].nKey < nMinSort)
2927 {
2928 nMinSort = S.Graph[i].nKey;
2929 nMinIndex = i;
2930 }
2931 if(S.Graph[i].nKey > nMaxSort)
2932 {
2933 nMaxSort = S.Graph[i].nKey;
2934 }
2935 }
2936 int nIndex = nFreeIndex > -1 ? nFreeIndex : nMinIndex;
2937 if (nFreeIndex == -1)
2938 {
2939 uint32_t idx = MicroProfileGetTimerIndex(S.Graph[nIndex].nToken);
2940 S.TimerInfo[idx].bGraph = false;
2941 }
2942 S.Graph[nIndex].nToken = nToken;
2943 S.Graph[nIndex].nKey = nMaxSort+1;
2944 memset(&S.Graph[nIndex].nHistory[0], 0, sizeof(S.Graph[nIndex].nHistory));
2945 S.TimerInfo[nTimerId].bGraph = true;
2946}
2947
2948
2949void MicroProfileMousePosition(uint32_t nX, uint32_t nY, int nWheelDelta)
2950{
2951 UI.nMouseX = nX;
2952 UI.nMouseY = nY;
2953 UI.nMouseWheelDelta = nWheelDelta;
2954}
2955
2956void MicroProfileModKey(uint32_t nKeyState)
2957{
2958 UI.nModDown = nKeyState ? 1 : 0;
2959}
2960
2961void MicroProfileClearGraph()
2962{
2963 MicroProfile& S = *MicroProfileGet();
2964 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
2965 {
2966 if(S.Graph[i].nToken != 0)
2967 {
2968 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
2969 }
2970 }
2971}
2972
2973void MicroProfileMouseButton(uint32_t nLeft, uint32_t nRight)
2974{
2975 bool bCanRelease = abs((int)(UI.nMouseDownX - UI.nMouseX)) + abs((int)(UI.nMouseDownY - UI.nMouseY)) < 3;
2976
2977 if(0 == nLeft && UI.nMouseDownLeft && bCanRelease)
2978 {
2979 if(UI.nModDown)
2980 UI.nMouseLeftMod = 1;
2981 else
2982 UI.nMouseLeft = 1;
2983 }
2984
2985 if(0 == nRight && UI.nMouseDownRight && bCanRelease)
2986 {
2987 if(UI.nModDown)
2988 UI.nMouseRightMod = 1;
2989 else
2990 UI.nMouseRight = 1;
2991 }
2992 if((nLeft || nRight) && !(UI.nMouseDownLeft || UI.nMouseDownRight))
2993 {
2994 UI.nMouseDownX = UI.nMouseX;
2995 UI.nMouseDownY = UI.nMouseY;
2996 }
2997
2998 UI.nMouseDownLeft = nLeft;
2999 UI.nMouseDownRight = nRight;
3000
3001}
3002
3003void MicroProfileDrawLineVertical(int nX, int nTop, int nBottom, uint32_t nColor)
3004{
3005 MicroProfileDrawBox(nX, nTop, nX + 1, nBottom, nColor);
3006}
3007
3008void MicroProfileDrawLineHorizontal(int nLeft, int nRight, int nY, uint32_t nColor)
3009{
3010 MicroProfileDrawBox(nLeft, nY, nRight, nY + 1, nColor);
3011}
3012
3013
3014
3015#include <stdio.h>
3016
3017#define MICROPROFILE_PRESET_HEADER_MAGIC 0x28586813
3018#define MICROPROFILE_PRESET_HEADER_VERSION 0x00000102
3019struct MicroProfilePresetHeader
3020{
3021 uint32_t nMagic;
3022 uint32_t nVersion;
3023 //groups, threads, aggregate, reference frame, graphs timers
3024 uint32_t nGroups[MICROPROFILE_MAX_GROUPS];
3025 uint32_t nThreads[MICROPROFILE_MAX_THREADS];
3026 uint32_t nGraphName[MICROPROFILE_MAX_GRAPHS];
3027 uint32_t nGraphGroupName[MICROPROFILE_MAX_GRAPHS];
3028 uint32_t nAllGroupsWanted;
3029 uint32_t nAllThreadsWanted;
3030 uint32_t nAggregateFlip;
3031 float fReferenceTime;
3032 uint32_t nBars;
3033 uint32_t nDisplay;
3034 uint32_t nOpacityBackground;
3035 uint32_t nOpacityForeground;
3036 uint32_t nShowSpikes;
3037};
3038
3039#ifndef MICROPROFILE_PRESET_FILENAME_FUNC
3040#define MICROPROFILE_PRESET_FILENAME_FUNC MicroProfilePresetFilename
3041static const char* MicroProfilePresetFilename(const char* pSuffix)
3042{
3043 static char filename[512];
3044 snprintf(filename, sizeof(filename)-1, ".microprofilepreset.%s", pSuffix);
3045 return filename;
3046}
3047#endif
3048
3049void MicroProfileSavePreset(const char* pPresetName)
3050{
3051 std::lock_guard<std::recursive_mutex> Lock(MicroProfileGetMutex());
3052 FILE* F = fopen(MICROPROFILE_PRESET_FILENAME_FUNC(pPresetName), "wb");
3053 if(!F) return;
3054
3055 MicroProfile& S = *MicroProfileGet();
3056
3057 MicroProfilePresetHeader Header;
3058 memset(&Header, 0, sizeof(Header));
3059 Header.nAggregateFlip = S.nAggregateFlip;
3060 Header.nBars = S.nBars;
3061 Header.fReferenceTime = S.fReferenceTime;
3062 Header.nAllGroupsWanted = S.nAllGroupsWanted;
3063 Header.nAllThreadsWanted = S.nAllThreadsWanted;
3064 Header.nMagic = MICROPROFILE_PRESET_HEADER_MAGIC;
3065 Header.nVersion = MICROPROFILE_PRESET_HEADER_VERSION;
3066 Header.nDisplay = S.nDisplay;
3067 Header.nOpacityBackground = UI.nOpacityBackground;
3068 Header.nOpacityForeground = UI.nOpacityForeground;
3069 Header.nShowSpikes = UI.bShowSpikes ? 1 : 0;
3070 fwrite(&Header, sizeof(Header), 1, F);
3071 uint64_t nMask = 1;
3072 for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
3073 {
3074 if(S.nActiveGroupWanted & nMask)
3075 {
3076 uint32_t offset = ftell(F);
3077 const char* pName = S.GroupInfo[i].pName;
3078 int nLen = (int)strlen(pName)+1;
3079 fwrite(pName, nLen, 1, F);
3080 Header.nGroups[i] = offset;
3081 }
3082 nMask <<= 1;
3083 }
3084 for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
3085 {
3086 MicroProfileThreadLog* pLog = S.Pool[i];
3087 if(pLog && S.nThreadActive[i])
3088 {
3089 uint32_t nOffset = ftell(F);
3090 const char* pName = &pLog->ThreadName[0];
3091 int nLen = (int)strlen(pName)+1;
3092 fwrite(pName, nLen, 1, F);
3093 Header.nThreads[i] = nOffset;
3094 }
3095 }
3096 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
3097 {
3098 MicroProfileToken nToken = S.Graph[i].nToken;
3099 if(nToken != MICROPROFILE_INVALID_TOKEN)
3100 {
3101 uint32_t nGroupIndex = MicroProfileGetGroupIndex(nToken);
3102 uint32_t nTimerIndex = MicroProfileGetTimerIndex(nToken);
3103 const char* pGroupName = S.GroupInfo[nGroupIndex].pName;
3104 const char* pTimerName = S.TimerInfo[nTimerIndex].pName;
3105 MP_ASSERT(pGroupName);
3106 MP_ASSERT(pTimerName);
3107 int nGroupLen = (int)strlen(pGroupName)+1;
3108 int nTimerLen = (int)strlen(pTimerName)+1;
3109
3110 uint32_t nOffsetGroup = ftell(F);
3111 fwrite(pGroupName, nGroupLen, 1, F);
3112 uint32_t nOffsetTimer = ftell(F);
3113 fwrite(pTimerName, nTimerLen, 1, F);
3114 Header.nGraphName[i] = nOffsetTimer;
3115 Header.nGraphGroupName[i] = nOffsetGroup;
3116 }
3117 }
3118 fseek(F, 0, SEEK_SET);
3119 fwrite(&Header, sizeof(Header), 1, F);
3120
3121 fclose(F);
3122
3123}
3124
3125
3126
3127void MicroProfileLoadPreset(const char* pSuffix)
3128{
3129 std::lock_guard<std::recursive_mutex> Lock(MicroProfileGetMutex());
3130 FILE* F = fopen(MICROPROFILE_PRESET_FILENAME_FUNC(pSuffix), "rb");
3131 if(!F)
3132 {
3133 return;
3134 }
3135 fseek(F, 0, SEEK_END);
3136 int nSize = ftell(F);
3137 char* const pBuffer = (char*)alloca(nSize);
3138 fseek(F, 0, SEEK_SET);
3139 int nRead = (int)fread(pBuffer, nSize, 1, F);
3140 fclose(F);
3141 if(1 != nRead)
3142 return;
3143
3144 MicroProfile& S = *MicroProfileGet();
3145
3146 MicroProfilePresetHeader& Header = *(MicroProfilePresetHeader*)pBuffer;
3147
3148 if(Header.nMagic != MICROPROFILE_PRESET_HEADER_MAGIC || Header.nVersion != MICROPROFILE_PRESET_HEADER_VERSION)
3149 {
3150 return;
3151 }
3152
3153 S.nAggregateFlip = Header.nAggregateFlip;
3154 S.nBars = Header.nBars;
3155 S.fReferenceTime = Header.fReferenceTime;
3156 S.fRcpReferenceTime = 1.f / Header.fReferenceTime;
3157 S.nAllGroupsWanted = Header.nAllGroupsWanted;
3158 S.nAllThreadsWanted = Header.nAllThreadsWanted;
3159 S.nDisplay = Header.nDisplay;
3160 S.nActiveGroupWanted = 0;
3161 UI.nOpacityBackground = Header.nOpacityBackground;
3162 UI.nOpacityForeground = Header.nOpacityForeground;
3163 UI.bShowSpikes = Header.nShowSpikes == 1;
3164
3165 memset(&S.nThreadActive[0], 0, sizeof(S.nThreadActive));
3166
3167 for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i)
3168 {
3169 if(Header.nGroups[i])
3170 {
3171 const char* pGroupName = pBuffer + Header.nGroups[i];
3172 for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
3173 {
3174 if(0 == MP_STRCASECMP(pGroupName, S.GroupInfo[j].pName))
3175 {
3176 S.nActiveGroupWanted |= (1ll << j);
3177 }
3178 }
3179 }
3180 }
3181 for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i)
3182 {
3183 if(Header.nThreads[i])
3184 {
3185 const char* pThreadName = pBuffer + Header.nThreads[i];
3186 for(uint32_t j = 0; j < MICROPROFILE_MAX_THREADS; ++j)
3187 {
3188 MicroProfileThreadLog* pLog = S.Pool[j];
3189 if(pLog && 0 == MP_STRCASECMP(pThreadName, &pLog->ThreadName[0]))
3190 {
3191 S.nThreadActive[j] = 1;
3192 }
3193 }
3194 }
3195 }
3196 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
3197 {
3198 MicroProfileToken nPrevToken = S.Graph[i].nToken;
3199 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
3200 if(Header.nGraphName[i] && Header.nGraphGroupName[i])
3201 {
3202 const char* pGraphName = pBuffer + Header.nGraphName[i];
3203 const char* pGraphGroupName = pBuffer + Header.nGraphGroupName[i];
3204 for(uint32_t j = 0; j < S.nTotalTimers; ++j)
3205 {
3206 uint64_t nGroupIndex = S.TimerInfo[j].nGroupIndex;
3207 if(0 == MP_STRCASECMP(pGraphName, S.TimerInfo[j].pName) && 0 == MP_STRCASECMP(pGraphGroupName, S.GroupInfo[nGroupIndex].pName))
3208 {
3209 MicroProfileToken nToken = MicroProfileMakeToken(1ll << nGroupIndex, (uint16_t)j);
3210 S.Graph[i].nToken = nToken; // note: group index is stored here but is checked without in MicroProfileToggleGraph()!
3211 S.TimerInfo[j].bGraph = true;
3212 if(nToken != nPrevToken)
3213 {
3214 memset(&S.Graph[i].nHistory, 0, sizeof(S.Graph[i].nHistory));
3215 }
3216 break;
3217 }
3218 }
3219 }
3220 }
3221}
3222
3223uint32_t MicroProfileCustomGroupFind(const char* pCustomName)
3224{
3225 for(uint32_t i = 0; i < UI.nCustomCount; ++i)
3226 {
3227 if(!MP_STRCASECMP(pCustomName, UI.Custom[i].pName))
3228 {
3229 return i;
3230 }
3231 }
3232 return (uint32_t)-1;
3233}
3234
3235uint32_t MicroProfileCustomGroup(const char* pCustomName)
3236{
3237 for(uint32_t i = 0; i < UI.nCustomCount; ++i)
3238 {
3239 if(!MP_STRCASECMP(pCustomName, UI.Custom[i].pName))
3240 {
3241 return i;
3242 }
3243 }
3244 MP_ASSERT(UI.nCustomCount < MICROPROFILE_CUSTOM_MAX);
3245 uint32_t nIndex = UI.nCustomCount;
3246 UI.nCustomCount++;
3247 memset(&UI.Custom[nIndex], 0, sizeof(UI.Custom[nIndex]));
3248 uint32_t nLen = (uint32_t)strlen(pCustomName);
3249 if(nLen > MICROPROFILE_NAME_MAX_LEN-1)
3250 nLen = MICROPROFILE_NAME_MAX_LEN-1;
3251 memcpy(&UI.Custom[nIndex].pName[0], pCustomName, nLen);
3252 UI.Custom[nIndex].pName[nLen] = '\0';
3253 return nIndex;
3254}
3255void MicroProfileCustomGroup(const char* pCustomName, uint32_t nMaxTimers, uint32_t nAggregateFlip, float fReferenceTime, uint32_t nFlags)
3256{
3257 uint32_t nIndex = MicroProfileCustomGroup(pCustomName);
3258 MP_ASSERT(UI.Custom[nIndex].pTimers == 0);//only call once!
3259 UI.Custom[nIndex].pTimers = &UI.CustomTimer[UI.nCustomTimerCount];
3260 UI.Custom[nIndex].nMaxTimers = nMaxTimers;
3261 UI.Custom[nIndex].fReference = fReferenceTime;
3262 UI.nCustomTimerCount += nMaxTimers;
3263 MP_ASSERT(UI.nCustomTimerCount <= MICROPROFILE_CUSTOM_MAX_TIMERS); //bump MICROPROFILE_CUSTOM_MAX_TIMERS
3264 UI.Custom[nIndex].nFlags = nFlags;
3265 UI.Custom[nIndex].nAggregateFlip = nAggregateFlip;
3266}
3267
3268void MicroProfileCustomGroupEnable(uint32_t nIndex)
3269{
3270 if(nIndex < UI.nCustomCount)
3271 {
3272 MicroProfile& S = *MicroProfileGet();
3273 S.nForceGroupUI = UI.Custom[nIndex].nGroupMask;
3274 MicroProfileSetAggregateFrames(UI.Custom[nIndex].nAggregateFlip);
3275 S.fReferenceTime = UI.Custom[nIndex].fReference;
3276 S.fRcpReferenceTime = 1.f / UI.Custom[nIndex].fReference;
3277 UI.nCustomActive = nIndex;
3278
3279 for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
3280 {
3281 if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN)
3282 {
3283 uint32_t nTimerId = MicroProfileGetTimerIndex(S.Graph[i].nToken);
3284 S.TimerInfo[nTimerId].bGraph = false;
3285 S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN;
3286 }
3287 }
3288
3289 for(uint32_t i = 0; i < UI.Custom[nIndex].nNumTimers; ++i)
3290 {
3291 if(i == MICROPROFILE_MAX_GRAPHS)
3292 {
3293 break;
3294 }
3295 S.Graph[i].nToken = UI.Custom[nIndex].pTimers[i];
3296 S.Graph[i].nKey = i;
3297 uint32_t nTimerId = MicroProfileGetTimerIndex(S.Graph[i].nToken);
3298 S.TimerInfo[nTimerId].bGraph = true;
3299 }
3300 }
3301}
3302
3303void MicroProfileCustomGroupToggle(const char* pCustomName)
3304{
3305 uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
3306 if(nIndex == (uint32_t)-1 || nIndex == UI.nCustomActive)
3307 {
3308 MicroProfileCustomGroupDisable();
3309 }
3310 else
3311 {
3312 MicroProfileCustomGroupEnable(nIndex);
3313 }
3314}
3315
3316void MicroProfileCustomGroupEnable(const char* pCustomName)
3317{
3318 uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
3319 MicroProfileCustomGroupEnable(nIndex);
3320}
3321void MicroProfileCustomGroupDisable()
3322{
3323 MicroProfile& S = *MicroProfileGet();
3324 S.nForceGroupUI = 0;
3325 UI.nCustomActive = (uint32_t)-1;
3326}
3327
3328void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup, const char* pTimer)
3329{
3330 uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
3331 if((uint32_t)-1 == nIndex)
3332 {
3333 return;
3334 }
3335 uint32_t nTimerIndex = UI.Custom[nIndex].nNumTimers;
3336 MP_ASSERT(nTimerIndex < UI.Custom[nIndex].nMaxTimers);
3337 uint64_t nToken = MicroProfileFindToken(pGroup, pTimer);
3338 MP_ASSERT(nToken != MICROPROFILE_INVALID_TOKEN); //Timer must be registered first.
3339 UI.Custom[nIndex].pTimers[nTimerIndex] = nToken;
3340 uint16_t nGroup = MicroProfileGetGroupIndex(nToken);
3341 UI.Custom[nIndex].nGroupMask |= (1ll << nGroup);
3342 UI.Custom[nIndex].nNumTimers++;
3343}
3344
3345#undef UI
3346
3347#endif
3348#endif