summaryrefslogtreecommitdiff
path: root/indra/newview/llfasttimerview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llfasttimerview.cpp')
-rw-r--r--indra/newview/llfasttimerview.cpp1084
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();
+}