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