diff options
Diffstat (limited to 'indra/newview/llfasttimerview.cpp')
-rw-r--r-- | indra/newview/llfasttimerview.cpp | 1084 |
1 files changed, 1084 insertions, 0 deletions
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp new file mode 100644 index 0000000000..c8c1d0d878 --- /dev/null +++ b/indra/newview/llfasttimerview.cpp @@ -0,0 +1,1084 @@ +/** + * @file llfasttimerview.cpp + * @brief LLFastTimerView class implementation + * + * Copyright (c) 2004-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "indra_constants.h" +#include "llfasttimerview.h" +#include "llviewerwindow.h" +#include "llrect.h" +#include "llerror.h" +#include "llgl.h" +#include "llmath.h" +#include "llfontgl.h" + +#include "viewer.h" +#include "llviewerimagelist.h" +#include "llui.h" +#include "llviewercontrol.h" +#include "llstat.h" + +#include "llfasttimer.h" + +////////////////////////////////////////////////////////////////////////////// + +static const S32 MAX_VISIBLE_HISTORY = 10; +static const S32 LINE_GRAPH_HEIGHT = 240; + +struct ft_display_info { + int timer; + const char *desc; + LLColor4 *color; + S32 disabled; // initialized to 0 + int level; // calculated based on desc + int parent; // calculated +}; + +static LLColor4 red0(0.5f, 0.0f, 0.0f, 1.0f); +static LLColor4 green0(0.0f, 0.5f, 0.0f, 1.0f); +static LLColor4 blue0(0.0f, 0.0f, 0.5f, 1.0f); +static LLColor4 blue7(0.0f, 0.0f, 0.5f, 1.0f); + +static LLColor4 green7(0.6f, 1.0f, 0.4f, 1.0f); +static LLColor4 green8(0.4f, 1.0f, 0.6f, 1.0f); +static LLColor4 green9(0.6f, 1.0f, 0.6f, 1.0f); + +// green(6), blue, yellow, orange, pink(2), cyan +// red (5) magenta (4) +static struct ft_display_info ft_display_table[] = +{ + { LLFastTimer::FTM_FRAME, "Frame", &LLColor4::white, 0 }, + { LLFastTimer::FTM_MESSAGES, " Messages", &LLColor4::grey1, 0 }, + { LLFastTimer::FTM_SLEEP, " Sleep", &LLColor4::grey2, 0 }, + { LLFastTimer::FTM_IDLE, " Idle", &blue0, 0 }, + { LLFastTimer::FTM_INVENTORY, " Inventory Update", &LLColor4::purple6, 1 }, + { LLFastTimer::FTM_AUTO_SELECT, " Open and Select", &LLColor4::red, 0 }, + { LLFastTimer::FTM_FILTER, " Filter", &LLColor4::red2, 0 }, + { LLFastTimer::FTM_ARRANGE, " Arrange", &LLColor4::red3, 0 }, + { LLFastTimer::FTM_REFRESH, " Refresh", &LLColor4::red4, 0 }, + { LLFastTimer::FTM_SORT, " Sort", &LLColor4::red5, 0 }, + { LLFastTimer::FTM_RESET_DRAWORDER, " ResetDrawOrder", &LLColor4::pink1, 0 }, + { LLFastTimer::FTM_WORLD_UPDATE, " World Update", &LLColor4::blue1, 1 }, + { LLFastTimer::FTM_UPDATE_MOVE, " Move Objects", &LLColor4::pink2, 0 }, + { LLFastTimer::FTM_OCTREE_BALANCE, " Octree Balance", &LLColor4::red3, 0 }, + { LLFastTimer::FTM_CULL, " Object Cull", &LLColor4::blue2, 0 }, + { LLFastTimer::FTM_CULL_REBOUND, " Rebound", &LLColor4::blue3, 0 }, + { LLFastTimer::FTM_HUD_EFFECTS, " HUD Effects", &LLColor4::orange1, 0 }, + { LLFastTimer::FTM_HUD_UPDATE, " HUD Update", &LLColor4::orange2, 0 }, + { LLFastTimer::FTM_OCCLUSION, " Object Occlude",&LLColor4::pink1, 0 }, + { LLFastTimer::FTM_OCCLUSION_READBACK, " Occlusion Read",&LLColor4::red2, 0 }, + { LLFastTimer::FTM_GEO_UPDATE, " Geo Update", &LLColor4::blue3, 0 }, + { LLFastTimer::FTM_UPDATE_PRIMITIVES, " Volumes", &LLColor4::blue4, 0 }, + { LLFastTimer::FTM_GEN_VOLUME, " Gen Volume", &LLColor4::yellow3, 0 }, + { LLFastTimer::FTM_GEN_FLEX, " Flexible", &LLColor4::yellow4, 0 }, + { LLFastTimer::FTM_GEN_TRIANGLES, " Triangles", &LLColor4::yellow5, 0 }, + { LLFastTimer::FTM_GEO_LIGHT, " Lighting", &LLColor4::yellow1, 0 }, + { LLFastTimer::FTM_GEO_SHADOW, " Shadow", &LLColor4::black, 0 }, + { LLFastTimer::FTM_UPDATE_PARTICLES, " Particles", &LLColor4::blue5, 0 }, + { LLFastTimer::FTM_GEO_RESERVE, " Reserve", &LLColor4::blue6, 0 }, + { LLFastTimer::FTM_UPDATE_LIGHTS, " Lights", &LLColor4::yellow2, 0 }, + { LLFastTimer::FTM_UPDATE_SKY, " Sky Update", &LLColor4::cyan1, 0 }, + { LLFastTimer::FTM_OBJECTLIST_UPDATE, " Object Update", &LLColor4::purple1, 1 }, + { LLFastTimer::FTM_AVATAR_UPDATE, " Avatars", &LLColor4::purple2, 0 }, + { LLFastTimer::FTM_JOINT_UPDATE, " Joints", &LLColor4::purple3, 0 }, + { LLFastTimer::FTM_ATTACHMENT_UPDATE, " Attachments", &LLColor4::purple4, 0 }, + { LLFastTimer::FTM_UPDATE_ANIMATION, " Animation", &LLColor4::purple5, 0 }, + { LLFastTimer::FTM_FLEXIBLE_UPDATE, " Flex Update", &LLColor4::pink2, 0 }, + { LLFastTimer::FTM_LOD_UPDATE, " LOD Update", &LLColor4::magenta1, 0 }, + { LLFastTimer::FTM_REGION_UPDATE, " Region Update", &LLColor4::cyan2, 0 }, + { LLFastTimer::FTM_NETWORK, " Network", &LLColor4::orange1, 1 }, + { LLFastTimer::FTM_IDLE_NETWORK, " Decode Msgs", &LLColor4::orange2, 0 }, + { LLFastTimer::FTM_PROCESS_MESSAGES, " Process Msgs", &LLColor4::orange3, 0 }, + { LLFastTimer::FTM_PROCESS_OBJECTS, " Object Updates",&LLColor4::orange4, 0 }, + { LLFastTimer::FTM_CREATE_OBJECT, " Create Obj", &LLColor4::orange5, 0 }, +// { LLFastTimer::FTM_LOAD_AVATAR, " Load Avatar", &LLColor4::pink2, 0 }, + { LLFastTimer::FTM_PROCESS_IMAGES, " Image Updates",&LLColor4::orange6, 0 }, + { LLFastTimer::FTM_PIPELINE, " Pipeline", &LLColor4::magenta4, 0 }, + { LLFastTimer::FTM_CLEANUP, " Cleanup", &LLColor4::cyan3, 0 }, + { LLFastTimer::FTM_AUDIO_UPDATE, " Audio Update", &LLColor4::yellow3, 0 }, + { LLFastTimer::FTM_IMAGE_UPDATE, " Image Update", &LLColor4::yellow4, 1 }, + { LLFastTimer::FTM_IMAGE_CREATE, " Image CreateGL",&LLColor4::yellow5, 0 }, + { LLFastTimer::FTM_IMAGE_DECODE, " Image Decode", &LLColor4::yellow6, 0 }, + { LLFastTimer::FTM_VFILE_WAIT, " VFile Wait", &LLColor4::cyan6, 0 }, +// { LLFastTimer::FTM_IDLE_CB, " Callbacks", &LLColor4::pink1, 0 }, + { LLFastTimer::FTM_RENDER, " Render", &green0, 0 }, + { LLFastTimer::FTM_REBUILD, " Rebuild", &LLColor4::green1, 1 }, + { LLFastTimer::FTM_STATESORT, " State Sort", &LLColor4::orange1, 1 }, + { LLFastTimer::FTM_RENDER_GEOMETRY, " Geometry", &LLColor4::green2, 1 }, + { LLFastTimer::FTM_POOLS, " Pools", &LLColor4::green3, 0 }, + { LLFastTimer::FTM_POOLRENDER, " RenderPool", &LLColor4::green4, 0 }, + { LLFastTimer::FTM_RENDER_TERRAIN, " Terrain", &LLColor4::green6, 0 }, + { LLFastTimer::FTM_RENDER_CHARACTERS, " Avatars", &LLColor4::yellow1, 0 }, + { LLFastTimer::FTM_RENDER_SIMPLE, " Simple", &LLColor4::yellow2, 0 }, + { LLFastTimer::FTM_RENDER_SHINY, " Shiny", &LLColor4::yellow3, 0 }, + { LLFastTimer::FTM_RENDER_BUMP, " Bump", &LLColor4::yellow4, 0 }, + { LLFastTimer::FTM_RENDER_TREES, " Trees", &LLColor4::yellow8, 0 }, + { LLFastTimer::FTM_RENDER_OCCLUSION, " Occlusion", &LLColor4::red1, 0 }, + { LLFastTimer::FTM_RENDER_CLOUDS, " Clouds", &LLColor4::yellow5, 0 }, + { LLFastTimer::FTM_RENDER_ALPHA, " Alpha", &LLColor4::yellow6, 0 }, + { LLFastTimer::FTM_RENDER_HUD, " HUD", &LLColor4::yellow7, 0 }, + { LLFastTimer::FTM_RENDER_WATER, " Water", &LLColor4::yellow9, 0 }, + { LLFastTimer::FTM_RENDER_UI, " UI", &LLColor4::cyan4, 1 }, + { LLFastTimer::FTM_RENDER_TIMER, " Timers", &LLColor4::cyan5, 1, 0 }, +// { LLFastTimer::FTM_RENDER_FONTS, " Fonts", &LLColor4::pink1, 0 }, +// { LLFastTimer::FTM_UPDATE_TEXTURES, " Textures", &LLColor4::pink2, 0 }, + { LLFastTimer::FTM_SWAP, " Swap", &LLColor4::pink1, 0 }, + +// { LLFastTimer::FTM_TEMP1, " Temp1", &LLColor4::red1, 0 }, +// { LLFastTimer::FTM_TEMP2, " Temp2", &LLColor4::magenta1, 0 }, +// { LLFastTimer::FTM_TEMP3, " Temp3", &LLColor4::red2, 0 }, +// { LLFastTimer::FTM_TEMP4, " Temp4", &LLColor4::magenta2, 0 }, +// { LLFastTimer::FTM_TEMP5, " Temp5", &LLColor4::red3, 0 }, +// { LLFastTimer::FTM_TEMP6, " Temp6", &LLColor4::magenta3, 0 }, +// { LLFastTimer::FTM_TEMP7, " Temp7", &LLColor4::red4, 0 }, +// { LLFastTimer::FTM_TEMP8, " Temp8", &LLColor4::magenta4, 0 }, + + { LLFastTimer::FTM_OTHER, " Other", &red0 } +}; +static int ft_display_didcalc = 0; +static const int FTV_DISPLAY_NUM = (sizeof(ft_display_table)/sizeof(ft_display_table[0])); + +S32 ft_display_idx[FTV_DISPLAY_NUM]; // line of table entry for display purposes (for collapse) + +LLFastTimerView::LLFastTimerView(const std::string& name, const LLRect& rect) +: LLView(name, rect, TRUE) +{ + setVisible(FALSE); + mDisplayMode = 0; + mAvgCountTotal = 0; + mMaxCountTotal = 0; + mDisplayCenter = 1; + mDisplayCalls = 0; + mScrollIndex = 0; + mHoverIndex = -1; + mHoverBarIndex = -1; + mBarStart = new S32[(MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM]; + memset(mBarStart, 0, (MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM * sizeof(S32)); + mBarEnd = new S32[(MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM]; + memset(mBarEnd, 0, (MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM * sizeof(S32)); + mSubtractHidden = 0; + mPrintStats = -1; + + // One-time setup + if (!ft_display_didcalc) + { + int pidx[FTV_DISPLAY_NUM]; + int pdisabled[FTV_DISPLAY_NUM]; + for (S32 i=0; i < FTV_DISPLAY_NUM; i++) + { + int level = 0; + const char *text = ft_display_table[i].desc; + while(text[0] == ' ') + { + text++; + level++; + } + llassert(level < FTV_DISPLAY_NUM); + ft_display_table[i].desc = text; + ft_display_table[i].level = level; + if (level > 0) + { + ft_display_table[i].parent = pidx[level-1]; + if (pdisabled[level-1]) + { + ft_display_table[i].disabled = 3; + } + } + else + { + ft_display_table[i].parent = -1; + } + ft_display_idx[i] = i; + pidx[level] = i; + pdisabled[level] = ft_display_table[i].disabled; + } + ft_display_didcalc = 1; + } +} + +LLFastTimerView::~LLFastTimerView() +{ + delete[] mBarStart; + delete[] mBarEnd; +} + +EWidgetType LLFastTimerView::getWidgetType() const +{ + return WIDGET_TYPE_FAST_TIMER_VIEW; +} + +LLString LLFastTimerView::getWidgetTag() const +{ + return LL_FAST_TIMER_VIEW_TAG; +} + +BOOL LLFastTimerView::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mBarRect.pointInRect(x, y)) + { + S32 bar_idx = MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight()); + bar_idx = llclamp(bar_idx, 0, MAX_VISIBLE_HISTORY); + mPrintStats = bar_idx; +// return TRUE; // for now, pass all mouse events through + } + return FALSE; +} + +S32 LLFastTimerView::getLegendIndex(S32 y) +{ + S32 idx = (mRect.getHeight() - y) / ((S32) LLFontGL::sMonospace->getLineHeight()+2) - 5; + if (idx >= 0 && idx < FTV_DISPLAY_NUM) + { + return ft_display_idx[idx]; + } + + return -1; +} + +BOOL LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (x < mBarRect.mLeft) + { + S32 legend_index = getLegendIndex(y); + if (legend_index >= 0 && legend_index < FTV_DISPLAY_NUM) + { + S32 disabled = ft_display_table[legend_index].disabled; + if (++disabled > 2) + disabled = 0; + ft_display_table[legend_index].disabled = disabled; + S32 level = ft_display_table[legend_index].level; + + // propagate enable/disable to all children + legend_index++; + while (legend_index < FTV_DISPLAY_NUM && ft_display_table[legend_index].level > level) + { + ft_display_table[legend_index].disabled = disabled ? 3 : 0; + legend_index++; + } + } + } + else if (mask & MASK_SHIFT) + { + if (++mDisplayMode > 3) + mDisplayMode = 0; + } + else if (mask & MASK_CONTROL) + { + if (++mDisplayCenter > 2) + mDisplayCenter = 0; + } + else + { + // pause/unpause + LLFastTimer::sPauseHistory = !LLFastTimer::sPauseHistory; + // reset scroll to bottom when unpausing + if (!LLFastTimer::sPauseHistory) + { + mScrollIndex = 0; + } + } + // RN: for now, pass all mouse events through + return FALSE; +} + +BOOL LLFastTimerView::handleMouseUp(S32 x, S32 y, MASK mask) +{ + return FALSE; +} + + +BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask) +{ + if(LLFastTimer::sPauseHistory && mBarRect.pointInRect(x, y)) + { + mHoverIndex = -1; + mHoverBarIndex = MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight()); + if (mHoverBarIndex == 0) + { + return TRUE; + } + else if (mHoverBarIndex == -1) + { + mHoverBarIndex = 0; + } + for (S32 i = 0; i < FTV_DISPLAY_NUM; i++) + { + if (x > mBarStart[mHoverBarIndex * FTV_DISPLAY_NUM + i] && + x < mBarEnd[mHoverBarIndex * FTV_DISPLAY_NUM + i] && + ft_display_table[i].disabled <= 1) + { + mHoverIndex = i; + } + } + } + else if (x < mBarRect.mLeft) + { + S32 legend_index = getLegendIndex(y); + if (legend_index >= 0 && legend_index < FTV_DISPLAY_NUM) + { + mHoverIndex = legend_index; + } + } + + return FALSE; +} + +BOOL LLFastTimerView::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + if (getVisible() && pointInView(x, y)) + { + LLFastTimer::sPauseHistory = TRUE; + mScrollIndex = llclamp(mScrollIndex - clicks, + 0, llmin(LLFastTimer::sLastFrameIndex, (S32)LLFastTimer::FTM_HISTORY_NUM-MAX_VISIBLE_HISTORY)); + return TRUE; + } + return FALSE; +} + +BOOL LLFastTimerView::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ + // Otherwise space key gets eaten from the rest of the UI. JC + if (getVisible()) + { + switch (key) + { + case '=': + mDisplayCalls = !mDisplayCalls; + return TRUE; + case '-': + mSubtractHidden = !mSubtractHidden; + return TRUE; + case ' ': + // pause/unpause + LLFastTimer::sPauseHistory = !LLFastTimer::sPauseHistory; + // reset scroll to bottom when unpausing + if (!LLFastTimer::sPauseHistory) + { + mScrollIndex = 0; + } + return TRUE; + } + } + return FALSE; +} + +void LLFastTimerView::draw() +{ + LLFastTimer t(LLFastTimer::FTM_RENDER_TIMER); + + std::string tdesc; + + F64 clock_freq = (F64)LLFastTimer::countsPerSecond(); + F64 iclock_freq = 1000.0 / clock_freq; + + S32 margin = 10; + S32 height = (S32) (gViewerWindow->getVirtualWindowRect().getHeight()*0.75f); + S32 width = (S32) (gViewerWindow->getVirtualWindowRect().getWidth() * 0.75f); + + mRect.setLeftTopAndSize(mRect.mLeft, mRect.mTop, width, height); + + S32 left, top, right, bottom; + S32 x, y, barw, barh, dx, dy; + S32 texth, textw; + LLViewerImage* box_imagep = gImageList.getImage(LLUUID(gViewerArt.getString("rounded_square.tga")), MIPMAP_FALSE, TRUE); + + // Make sure all timers are accounted for + // Set 'FTM_OTHER' to unaccounted ticks last frame + { + S32 display_timer[LLFastTimer::FTM_NUM_TYPES]; + S32 hidx = LLFastTimer::sLastFrameIndex % LLFastTimer::FTM_HISTORY_NUM; + for (S32 i=0; i < LLFastTimer::FTM_NUM_TYPES; i++) + { + display_timer[i] = 0; + } + for (S32 i=0; i < FTV_DISPLAY_NUM; i++) + { + S32 tidx = ft_display_table[i].timer; + display_timer[tidx] = 1; + } + LLFastTimer::sCountHistory[hidx][LLFastTimer::FTM_OTHER] = 0; + LLFastTimer::sCallHistory[hidx][LLFastTimer::FTM_OTHER] = 0; + for (S32 tidx = 0; tidx < LLFastTimer::FTM_NUM_TYPES; tidx++) + { + U64 counts = LLFastTimer::sCountHistory[hidx][tidx]; + if (counts > 0 && display_timer[tidx] == 0) + { + LLFastTimer::sCountHistory[hidx][LLFastTimer::FTM_OTHER] += counts; + LLFastTimer::sCallHistory[hidx][LLFastTimer::FTM_OTHER] += 1; + } + } + LLFastTimer::sCountAverage[LLFastTimer::FTM_OTHER] = 0; + LLFastTimer::sCallAverage[LLFastTimer::FTM_OTHER] = 0; + for (S32 h = 0; h < LLFastTimer::FTM_HISTORY_NUM; h++) + { + LLFastTimer::sCountAverage[LLFastTimer::FTM_OTHER] += LLFastTimer::sCountHistory[h][LLFastTimer::FTM_OTHER]; + LLFastTimer::sCallAverage[LLFastTimer::FTM_OTHER] += LLFastTimer::sCallHistory[h][LLFastTimer::FTM_OTHER]; + } + LLFastTimer::sCountAverage[LLFastTimer::FTM_OTHER] /= LLFastTimer::FTM_HISTORY_NUM; + LLFastTimer::sCallAverage[LLFastTimer::FTM_OTHER] /= LLFastTimer::FTM_HISTORY_NUM; + } + + // Draw the window background + { + LLGLSNoTexture gls_ui_no_texture; + gl_rect_2d(0, mRect.getHeight(), mRect.getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f)); + } + + S32 xleft = margin; + S32 ytop = margin; + + // Draw some help + { + + x = xleft; + y = height - ytop; + texth = (S32)LLFontGL::sMonospace->getLineHeight(); + + char modedesc[][32] = { + "2 x Average ", + "Max ", + "Recent Max ", + "100 ms " + }; + char centerdesc[][32] = { + "Left ", + "Centered ", + "Ordered " + }; + + tdesc = llformat("Full bar = %s [Click to pause/reset] [SHIFT-Click to toggle]",modedesc[mDisplayMode]); + LLFontGL::sMonospace->renderUTF8(tdesc, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP); + + textw = LLFontGL::sMonospace->getWidth(tdesc); + + x = xleft, y -= (texth + 2); + tdesc = llformat("Justification = %s [CTRL-Click to toggle]",centerdesc[mDisplayCenter]); + LLFontGL::sMonospace->renderUTF8(tdesc, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP); + y -= (texth + 2); + + LLFontGL::sMonospace->renderUTF8("[Right-click to log selected] [= to toggle counts] [- to subtract hidden]", + 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP); + y -= (texth + 2); + } + + // Calc the total ticks + S32 histmax = llmin(LLFastTimer::sLastFrameIndex+1, MAX_VISIBLE_HISTORY); + U64 ticks_sum[LLFastTimer::FTM_HISTORY_NUM+1][FTV_DISPLAY_NUM]; + for (S32 j=-1; j<LLFastTimer::FTM_HISTORY_NUM; j++) + { + S32 hidx; + if (j >= 0) + hidx = (LLFastTimer::sLastFrameIndex+j) % LLFastTimer::FTM_HISTORY_NUM; + else + hidx = -1; + + // calculate tick info by adding child ticks to parents + for (S32 i=0; i < FTV_DISPLAY_NUM; i++) + { + if (mSubtractHidden && ft_display_table[i].disabled > 1) + { + continue; + } + // Get ticks + S32 tidx = ft_display_table[i].timer; + if (hidx >= 0) + ticks_sum[j+1][i] = LLFastTimer::sCountHistory[hidx][tidx]; + else + ticks_sum[j+1][i] = LLFastTimer::sCountAverage[tidx]; + S32 pidx = ft_display_table[i].parent; + // Add ticks to parents + while (pidx >= 0) + { + ticks_sum[j+1][pidx] += ticks_sum[j+1][i]; + pidx = ft_display_table[pidx].parent; + } + } + } + + // Draw the legend + + S32 legendwidth = 0; + xleft = margin; + ytop = y; + + y -= (texth + 2); + + S32 cur_line = 0; + S32 display_line[FTV_DISPLAY_NUM]; + for (S32 i=0; i<FTV_DISPLAY_NUM; i++) + { + S32 disabled = ft_display_table[i].disabled; + if (disabled == 3) + { + continue; // skip row + } + display_line[i] = cur_line; + ft_display_idx[cur_line] = i; + cur_line++; + S32 level = ft_display_table[i].level; + S32 parent = ft_display_table[i].parent; + + x = xleft; + + left = x; right = x + texth; + top = y; bottom = y - texth; + S32 scale_offset = 0; + if (i == mHoverIndex) + { + scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 2.f); + } + gl_rect_2d(left - scale_offset, top + scale_offset, right + scale_offset, bottom - scale_offset, *ft_display_table[i].color); + + int tidx = ft_display_table[i].timer; + F32 ms = 0; + S32 calls = 0; + if (mHoverBarIndex > 0 && mHoverIndex >= 0) + { + S32 hidx = (LLFastTimer::sLastFrameIndex + (mHoverBarIndex - 1) - mScrollIndex) % LLFastTimer::FTM_HISTORY_NUM; + S32 bidx = LLFastTimer::FTM_HISTORY_NUM - mScrollIndex - mHoverBarIndex; + U64 ticks = ticks_sum[bidx+1][i]; // : LLFastTimer::sCountHistory[hidx][tidx]; + ms = (F32)((F64)ticks * iclock_freq); + calls = (S32)LLFastTimer::sCallHistory[hidx][tidx]; + } + else + { + U64 ticks = disabled >= 1 ? ticks_sum[0][i] : LLFastTimer::sCountAverage[tidx]; + ms = (F32)((F64)ticks * iclock_freq); + calls = (S32)LLFastTimer::sCallAverage[tidx]; + } + if (mDisplayCalls) + { + tdesc = llformat("%s (%d)",ft_display_table[i].desc,calls); + } + else + { + tdesc = llformat("%s [%.1f]",ft_display_table[i].desc,ms); + } + dx = (texth+4) + level*8; + + LLColor4 color = disabled > 1 ? LLColor4::grey : LLColor4::white; + if (level > 0) + { + S32 line_start_y = (top + bottom) / 2; + S32 line_end_y = line_start_y + ((texth + 2) * (display_line[i] - display_line[parent])) - (texth / 2); + gl_line_2d(x + dx - 8, line_start_y, x + dx, line_start_y, color); + S32 line_x = x + (texth + 4) + ((level - 1) * 8); + gl_line_2d(line_x, line_start_y, line_x, line_end_y, color); + if (disabled == 1) + { + gl_line_2d(line_x+4, line_start_y-3, line_x+4, line_start_y+4, color); + } + } + + x += dx; + BOOL is_child_of_hover_item = (i == mHoverIndex); + S32 next_parent = ft_display_table[i].parent; + while(!is_child_of_hover_item && next_parent >= 0) + { + is_child_of_hover_item = (mHoverIndex == next_parent); + next_parent = ft_display_table[next_parent].parent; + } + + if (is_child_of_hover_item) + { + LLFontGL::sMonospace->renderUTF8(tdesc, 0, x, y, color, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::BOLD); + } + else + { + LLFontGL::sMonospace->renderUTF8(tdesc, 0, x, y, color, LLFontGL::LEFT, LLFontGL::TOP); + } + y -= (texth + 2); + + textw = dx + LLFontGL::sMonospace->getWidth(ft_display_table[i].desc) + 40; + if (textw > legendwidth) + legendwidth = textw; + } + for (S32 i=cur_line; i<FTV_DISPLAY_NUM; i++) + { + ft_display_idx[i] = -1; + } + xleft += legendwidth + 8; + // ytop = ytop; + + // update rectangle that includes timer bars + mBarRect.mLeft = xleft; + mBarRect.mRight = mRect.mRight - xleft; + mBarRect.mTop = ytop - ((S32)LLFontGL::sMonospace->getLineHeight() + 4); + mBarRect.mBottom = margin + LINE_GRAPH_HEIGHT; + + y = ytop; + barh = (ytop - margin - LINE_GRAPH_HEIGHT) / (MAX_VISIBLE_HISTORY + 2); + dy = barh>>2; // spacing between bars + if (dy < 1) dy = 1; + barh -= dy; + barw = width - xleft - margin; + + // Draw the history bars + if (LLFastTimer::sLastFrameIndex >= 0) + { + U64 totalticks; + if (!LLFastTimer::sPauseHistory) + { + U64 ticks = 0; + int hidx = (LLFastTimer::sLastFrameIndex - mScrollIndex) % LLFastTimer::FTM_HISTORY_NUM; + for (S32 i=0; i<FTV_DISPLAY_NUM; i++) + { + if (mSubtractHidden && ft_display_table[i].disabled > 1) + { + continue; + } + int tidx = ft_display_table[i].timer; + ticks += LLFastTimer::sCountHistory[hidx][tidx]; + } + if (LLFastTimer::sCurFrameIndex >= 10) + { + U64 framec = LLFastTimer::sCurFrameIndex; + U64 avg = (U64)mAvgCountTotal; + mAvgCountTotal = (avg*framec + ticks) / (framec + 1); + if (ticks > mMaxCountTotal) + { + mMaxCountTotal = ticks; + } + } +#if 1 + if (ticks < mAvgCountTotal/100 || ticks > mAvgCountTotal*100) + LLFastTimer::sResetHistory = 1; +#endif + if (LLFastTimer::sCurFrameIndex < 10 || LLFastTimer::sResetHistory) + { + mAvgCountTotal = ticks; + mMaxCountTotal = ticks; + } + } + + if (mDisplayMode == 0) + { + totalticks = mAvgCountTotal*2; + } + else if (mDisplayMode == 1) + { + totalticks = mMaxCountTotal; + } + else if (mDisplayMode == 2) + { + // Calculate the max total ticks for the current history + totalticks = 0; + for (S32 j=0; j<histmax; j++) + { + U64 ticks = 0; + for (S32 i=0; i<FTV_DISPLAY_NUM; i++) + { + if (mSubtractHidden && ft_display_table[i].disabled > 1) + { + continue; + } + int tidx = ft_display_table[i].timer; + ticks += LLFastTimer::sCountHistory[j][tidx]; + } + if (ticks > totalticks) + totalticks = ticks; + } + } + else + { + totalticks = (U64)(clock_freq * .1); // 100 ms + } + + // Draw MS ticks + { + U32 ms = (U32)((F64)totalticks * iclock_freq) ; + + tdesc = llformat("%.1f ms |", (F32)ms*.25f); + x = xleft + barw/4 - LLFontGL::sMonospace->getWidth(tdesc); + LLFontGL::sMonospace->renderUTF8(tdesc, 0, x, y, LLColor4::white, + LLFontGL::LEFT, LLFontGL::TOP); + + tdesc = llformat("%.1f ms |", (F32)ms*.50f); + x = xleft + barw/2 - LLFontGL::sMonospace->getWidth(tdesc); + LLFontGL::sMonospace->renderUTF8(tdesc, 0, x, y, LLColor4::white, + LLFontGL::LEFT, LLFontGL::TOP); + + tdesc = llformat("%.1f ms |", (F32)ms*.75f); + x = xleft + (barw*3)/4 - LLFontGL::sMonospace->getWidth(tdesc); + LLFontGL::sMonospace->renderUTF8(tdesc, 0, x, y, LLColor4::white, + LLFontGL::LEFT, LLFontGL::TOP); + + tdesc = llformat( "%d ms |", ms); + x = xleft + barw - LLFontGL::sMonospace->getWidth(tdesc); + LLFontGL::sMonospace->renderUTF8(tdesc, 0, x, y, LLColor4::white, + LLFontGL::LEFT, LLFontGL::TOP); + } + + LLRect graph_rect; + // Draw borders + { + LLGLSNoTexture gls_ui_no_texture; + glColor4f(0.5f,0.5f,0.5f,0.5f); + + S32 by = y + 2; + + y -= ((S32)LLFontGL::sMonospace->getLineHeight() + 4); + + //heading + gl_rect_2d(xleft-5, by, mRect.getWidth()-5, y+5, FALSE); + + //tree view + gl_rect_2d(5, by, xleft-10, 5, FALSE); + + by = y + 5; + //average bar + gl_rect_2d(xleft-5, by, mRect.getWidth()-5, by-barh-dy-5, FALSE); + + by -= barh*2+dy; + + //current frame bar + gl_rect_2d(xleft-5, by, mRect.getWidth()-5, by-barh-dy-2, FALSE); + + by -= barh+dy+1; + + //history bars + gl_rect_2d(xleft-5, by, mRect.getWidth()-5, LINE_GRAPH_HEIGHT-barh-dy-2, FALSE); + + by = LINE_GRAPH_HEIGHT-barh-dy-7; + + //line graph + graph_rect = LLRect(xleft-5, by, mRect.getWidth()-5, 5); + + gl_rect_2d(graph_rect, FALSE); + } + + // Draw bars for each history entry + // Special: -1 = show running average + LLViewerImage::bindTexture(box_imagep); + for (S32 j=-1; j<histmax && y > LINE_GRAPH_HEIGHT; j++) + { + int sublevel_dx[FTV_DISPLAY_NUM+1]; + int sublevel_left[FTV_DISPLAY_NUM+1]; + int sublevel_right[FTV_DISPLAY_NUM+1]; + S32 tidx; + if (j >= 0) + { + tidx = LLFastTimer::FTM_HISTORY_NUM - j - 1 - mScrollIndex; + } + else + { + tidx = -1; + } + + x = xleft; + + // draw the bars for each stat + int xpos[FTV_DISPLAY_NUM+1]; + int deltax[FTV_DISPLAY_NUM+1]; + xpos[0] = xleft; + + for (S32 i = 0; i < FTV_DISPLAY_NUM; i++) + { + if (ft_display_table[i].disabled > 1) + { + continue; + } + + F32 frac = (F32)ticks_sum[tidx+1][i] / (F32)totalticks; + + dx = llround(frac * (F32)barw); + deltax[i] = dx; + + int level = ft_display_table[i].level; + int parent = ft_display_table[i].parent; + llassert(level < FTV_DISPLAY_NUM); + llassert(parent < FTV_DISPLAY_NUM); + + left = xpos[level]; + + S32 prev_idx = i - 1; + while (prev_idx > 0) + { + if (ft_display_table[prev_idx].disabled <= 1) + { + break; + } + prev_idx--; + } + S32 next_idx = i + 1; + while (next_idx < FTV_DISPLAY_NUM) + { + if (ft_display_table[next_idx].disabled <= 1) + { + break; + } + next_idx++; + } + + if (level == 0) + { + sublevel_left[level] = xleft; + sublevel_dx[level] = dx; + sublevel_right[level] = sublevel_left[level] + sublevel_dx[level]; + } + else if (i==0 || ft_display_table[prev_idx].level < level) + { + // If we are the first entry at a new sublevel block, calc the + // total width of this sublevel and modify left to align block. + U64 sublevelticks = ticks_sum[tidx+1][i]; + for (S32 k=i+1; k<FTV_DISPLAY_NUM; k++) + { + if (ft_display_table[k].level < level) + break; + if (ft_display_table[k].disabled <= 1 && ft_display_table[k].level == level) + sublevelticks += ticks_sum[tidx+1][k]; + } + F32 subfrac = (F32)sublevelticks / (F32)totalticks; + sublevel_dx[level] = (int)(subfrac * (F32)barw + .5f); + + if (mDisplayCenter == 1) // center aligned + { + left += (deltax[parent] - sublevel_dx[level])/2; + } + else if (mDisplayCenter == 2) // right aligned + { + left += (deltax[parent] - sublevel_dx[level]); + } + + sublevel_left[level] = left; + sublevel_right[level] = sublevel_left[level] + sublevel_dx[level]; + } + + right = left + dx; + xpos[level] = right; + xpos[level+1] = left; + + mBarStart[(j + 1) * FTV_DISPLAY_NUM + i] = left; + mBarEnd[(j + 1) * FTV_DISPLAY_NUM + i] = right; + + top = y; + bottom = y - barh; + + if (right > left) + { + //U32 rounded_edges = 0; + LLColor4 color = *ft_display_table[i].color; + S32 scale_offset = 0; + + BOOL is_child_of_hover_item = (i == mHoverIndex); + S32 next_parent = ft_display_table[i].parent; + while(!is_child_of_hover_item && next_parent >= 0) + { + is_child_of_hover_item = (mHoverIndex == next_parent); + next_parent = ft_display_table[next_parent].parent; + } + + if (i == mHoverIndex) + { + scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 3.f); + //color = lerp(color, LLColor4::black, -0.4f); + } + else if (mHoverIndex >= 0 && !is_child_of_hover_item) + { + color = lerp(color, LLColor4::grey, 0.8f); + } + + glColor4fv(color.mV); + F32 start_fragment = llclamp((F32)(left - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f); + F32 end_fragment = llclamp((F32)(right - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f); + gl_segmented_rect_2d_fragment_tex(sublevel_left[level], top - level + scale_offset, sublevel_right[level], bottom + level - scale_offset, box_imagep->getWidth(), box_imagep->getHeight(), 16, start_fragment, end_fragment); + + } + + } + y -= (barh + dy); + if (j < 0) + y -= barh; + } + + //draw line graph history + { + LLGLSNoTexture no_texture; + LLGLEnable scissor(GL_SCISSOR_TEST); + LLUI::setScissorRegionLocal(graph_rect); + + //normalize based on last frame's maximum + static U64 last_max = 0; + static F32 alpha_interp = 0.f; + U64 max_ticks = llmax(last_max, (U64) 1); + F32 ms = (F32)((F64)max_ticks * iclock_freq); + + //display y-axis range + LLString tdesc = llformat("%4.2f ms", ms); + x = graph_rect.mRight - LLFontGL::sMonospace->getWidth(tdesc)-5; + y = graph_rect.mTop - ((S32)LLFontGL::sMonospace->getLineHeight()); + + LLFontGL::sMonospace->renderUTF8(tdesc, 0, x, y, LLColor4::white, + LLFontGL::LEFT, LLFontGL::TOP); + + //highlight visible range + { + S32 first_frame = LLFastTimer::FTM_HISTORY_NUM - mScrollIndex; + S32 last_frame = first_frame - MAX_VISIBLE_HISTORY; + + F32 frame_delta = ((F32) (graph_rect.getWidth()))/(LLFastTimer::FTM_HISTORY_NUM-1); + + F32 right = (F32) graph_rect.mLeft + frame_delta*first_frame; + F32 left = (F32) graph_rect.mLeft + frame_delta*last_frame; + + glColor4f(0.5f,0.5f,0.5f,0.3f); + gl_rect_2d((S32) left, graph_rect.mTop, (S32) right, graph_rect.mBottom); + + if (mHoverBarIndex >= 0) + { + S32 bar_frame = first_frame - mHoverBarIndex; + F32 bar = (F32) graph_rect.mLeft + frame_delta*bar_frame; + + glColor4f(0.5f,0.5f,0.5f,1); + + glBegin(GL_LINES); + glVertex2i((S32)bar, graph_rect.mBottom); + glVertex2i((S32)bar, graph_rect.mTop); + glEnd(); + } + } + + U64 cur_max = 0; + for (S32 idx = 0; idx < FTV_DISPLAY_NUM; ++idx) + { + if (ft_display_table[idx].disabled > 1) + { //skip disabled timers + continue; + } + + //fatten highlighted timer + if (mHoverIndex == idx) + { + glLineWidth(3); + } + + F32* col = ft_display_table[idx].color->mV; + + F32 alpha = 1.f; + + if (mHoverIndex >= 0 && + idx != mHoverIndex) + { //fade out non-hihglighted timers + if (ft_display_table[idx].parent != mHoverIndex) + { + alpha = alpha_interp; + } + } + + glColor4f(col[0], col[1], col[2], alpha); + glBegin(GL_LINE_STRIP); + for (U32 j = 0; j < LLFastTimer::FTM_HISTORY_NUM; j++) + { + U64 ticks = ticks_sum[j+1][idx]; + if (alpha == 1.f) + { //normalize to highlighted timer + cur_max = llmax(cur_max, ticks); + } + F32 x = graph_rect.mLeft + ((F32) (graph_rect.getWidth()))/(LLFastTimer::FTM_HISTORY_NUM-1)*j; + F32 y = graph_rect.mBottom + (F32) graph_rect.getHeight()/max_ticks*ticks; + glVertex2f(x,y); + } + glEnd(); + + if (mHoverIndex == idx) + { + glLineWidth(1); + } + } + + //interpolate towards new maximum + F32 dt = gFrameIntervalSeconds*3.f; + last_max = (U64) ((F32) last_max + ((F32) cur_max- (F32) last_max) * dt); + F32 alpha_target = last_max > cur_max ? + llmin((F32) last_max/ (F32) cur_max - 1.f,1.f) : + llmin((F32) cur_max/ (F32) last_max - 1.f,1.f); + + alpha_interp = alpha_interp + (alpha_target-alpha_interp) * dt; + + } + } + + // Output stats for clicked bar to log + if (mPrintStats >= 0) + { + LLString legend_stat; + S32 stat_num; + S32 first = 1; + for (stat_num = 0; stat_num < FTV_DISPLAY_NUM; stat_num++) + { + if (ft_display_table[stat_num].disabled > 1) + continue; + if (!first) + legend_stat += ", "; + first=0; + legend_stat += ft_display_table[stat_num].desc; + } + llinfos << legend_stat << llendl; + + LLString timer_stat; + first = 1; + for (stat_num = 0; stat_num < FTV_DISPLAY_NUM; stat_num++) + { + S32 disabled = ft_display_table[stat_num].disabled; + if (disabled > 1) + continue; + if (!first) + timer_stat += ", "; + first=0; + U64 ticks; + S32 tidx = ft_display_table[stat_num].timer; + if (mPrintStats > 0) + { + S32 hidx = (LLFastTimer::sLastFrameIndex+(mPrintStats-1)-mScrollIndex) % LLFastTimer::FTM_HISTORY_NUM; + ticks = disabled >= 1 ? ticks_sum[mPrintStats][stat_num] : LLFastTimer::sCountHistory[hidx][tidx]; + } + else + { + ticks = disabled >= 1 ? ticks_sum[0][stat_num] : LLFastTimer::sCountAverage[tidx]; + } + F32 ms = (F32)((F64)ticks * iclock_freq); + + timer_stat += llformat("%.1f",ms); + } + llinfos << timer_stat << llendl; + mPrintStats = -1; + } + + mHoverIndex = -1; + mHoverBarIndex = -1; + + LLView::draw(); +} + +F64 LLFastTimerView::getTime(LLFastTimer::EFastTimerType tidx) +{ + // Find table index + S32 i; + for (i=0; i<FTV_DISPLAY_NUM; i++) + { + if (tidx == ft_display_table[i].timer) + { + break; + } + } + S32 table_idx = i; + + // Add child ticks to parent + U64 ticks = LLFastTimer::sCountAverage[tidx]; + S32 level = ft_display_table[table_idx].level; + for (i=table_idx+1; i<FTV_DISPLAY_NUM; i++) + { + if (ft_display_table[i].level <= level) + { + break; + } + ticks += LLFastTimer::sCountAverage[ft_display_table[i].timer]; + } + + return (F64)ticks / (F64)LLFastTimer::countsPerSecond(); +} |