Need to test: localassetbrowser preview related floaters hgfloatertexteditor maps media textures! Currently very hacky web browser alpha masks on avatars bumpmaps Are all sky components appearing? LLViewerDynamicTexture (texture baking, browser, animated textures, anim previews, etc) Snapshot related features Customize avatar vfs floater UI textures in general Texture priority issues
1171 lines
38 KiB
C++
1171 lines
38 KiB
C++
/**
|
|
* @file llfasttimerview.cpp
|
|
* @brief LLFastTimerView class implementation
|
|
*
|
|
* $LicenseInfo:firstyear=2004&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2004-2009, Linden Research, Inc.
|
|
*
|
|
* Second Life Viewer Source Code
|
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
* to you under the terms of the GNU General Public License, version 2.0
|
|
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
*
|
|
* There are special exceptions to the terms and conditions of the GPL as
|
|
* it is applied to this Source Code. View the full text of the exception
|
|
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
|
* online at
|
|
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
*
|
|
* By copying, modifying or distributing this software, you acknowledge
|
|
* that you have read and understood your obligations described above,
|
|
* and agree to abide by those obligations.
|
|
*
|
|
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
* COMPLETENESS OR PERFORMANCE.
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
#include "indra_constants.h"
|
|
#include "llfasttimerview.h"
|
|
#include "llviewerwindow.h"
|
|
#include "llrect.h"
|
|
#include "llerror.h"
|
|
#include "llgl.h"
|
|
#include "llrender.h"
|
|
#include "llmath.h"
|
|
#include "llfontgl.h"
|
|
|
|
#include "llappviewer.h"
|
|
#include "llviewertexturelist.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;
|
|
const LLColor4 *color;
|
|
S32 disabled; // initialized to 0
|
|
int level; // calculated based on desc
|
|
int parent; // calculated
|
|
};
|
|
|
|
static const LLColor4 red0(0.5f, 0.0f, 0.0f, 1.0f);
|
|
static const LLColor4 green0(0.0f, 0.5f, 0.0f, 1.0f);
|
|
static const LLColor4 blue0(0.0f, 0.0f, 0.5f, 1.0f);
|
|
static const LLColor4 blue7(0.0f, 0.0f, 0.5f, 1.0f);
|
|
|
|
static const LLColor4 green7(0.6f, 1.0f, 0.4f, 1.0f);
|
|
static const LLColor4 green8(0.4f, 1.0f, 0.6f, 1.0f);
|
|
static const 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, " System Messages", &LLColor4::grey1, 1 },
|
|
{ LLFastTimer::FTM_MOUSEHANDLER, " Mouse", &LLColor4::grey1, 0 },
|
|
{ LLFastTimer::FTM_KEYHANDLER, " Keyboard", &LLColor4::grey1, 0 },
|
|
{ LLFastTimer::FTM_SLEEP, " Sleep", &LLColor4::grey2, 0 },
|
|
{ LLFastTimer::FTM_IDLE, " Idle", &blue0, 0 },
|
|
{ LLFastTimer::FTM_PUMP, " Pump", &LLColor4::magenta2, 1 },
|
|
{ LLFastTimer::FTM_CURL, " Curl", &LLColor4::magenta3, 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_SIMULATE_PARTICLES, " Particle Sim", &LLColor4::blue4, 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_VFILE_WAIT, " VFile Wait", &LLColor4::cyan6, 0 },
|
|
// { LLFastTimer::FTM_IDLE_CB, " Callbacks", &LLColor4::pink1, 0 },
|
|
{ LLFastTimer::FTM_RENDER, " Render", &green0, 1 },
|
|
{ LLFastTimer::FTM_PICK, " Pick", &LLColor4::purple, 1 },
|
|
{ LLFastTimer::FTM_HUD_EFFECTS, " HUD Effects", &LLColor4::orange1, 0 },
|
|
{ LLFastTimer::FTM_HUD_UPDATE, " HUD Update", &LLColor4::orange2, 0 },
|
|
{ LLFastTimer::FTM_UPDATE_SKY, " Sky Update", &LLColor4::cyan1, 0 },
|
|
{ LLFastTimer::FTM_UPDATE_TEXTURES, " Textures", &LLColor4::pink2, 0 },
|
|
{ LLFastTimer::FTM_GEO_UPDATE, " Geo Update", &LLColor4::blue3, 1 },
|
|
{ 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_UPDATE_AVATAR, " Avatar", &LLColor4::yellow1, 0 },
|
|
{ LLFastTimer::FTM_UPDATE_TREE, " Tree", &LLColor4::yellow2, 0 },
|
|
{ LLFastTimer::FTM_UPDATE_TERRAIN, " Terrain", &LLColor4::yellow6, 0 },
|
|
{ LLFastTimer::FTM_UPDATE_CLOUDS, " Clouds", &LLColor4::yellow7, 0 },
|
|
{ LLFastTimer::FTM_UPDATE_GRASS, " Grass", &LLColor4::yellow8, 0 },
|
|
{ LLFastTimer::FTM_UPDATE_WATER, " Water", &LLColor4::yellow9, 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_GEO_SKY, " Sky", &LLColor4::yellow3, 0 },
|
|
{ LLFastTimer::FTM_UPDATE_WLPARAM, " Windlight Param",&LLColor4::magenta2, 0 },
|
|
{ LLFastTimer::FTM_CULL, " Object Cull", &LLColor4::blue2, 1 },
|
|
{ LLFastTimer::FTM_CULL_REBOUND, " Rebound", &LLColor4::blue3, 0 },
|
|
{ LLFastTimer::FTM_FRUSTUM_CULL, " Frustum Cull", &LLColor4::blue4, 0 },
|
|
{ LLFastTimer::FTM_OCCLUSION_READBACK, " Occlusion Read", &LLColor4::red2, 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_IMAGE_READBACK, " Image Readback",&LLColor4::red2, 0 },
|
|
{ LLFastTimer::FTM_IMAGE_MARK_DIRTY, " Dirty Textures",&LLColor4::red1, 0 },
|
|
{ LLFastTimer::FTM_STATESORT, " State Sort", &LLColor4::orange1, 1 },
|
|
{ LLFastTimer::FTM_STATESORT_DRAWABLE, " Drawable", &LLColor4::orange2, 0 },
|
|
{ LLFastTimer::FTM_STATESORT_POSTSORT, " Post Sort", &LLColor4::orange3, 0 },
|
|
{ LLFastTimer::FTM_REBUILD_OCCLUSION_VB," Occlusion", &LLColor4::cyan5, 0 },
|
|
{ LLFastTimer::FTM_REBUILD_VBO, " VBO Rebuild", &LLColor4::red4, 0 },
|
|
{ LLFastTimer::FTM_REBUILD_VOLUME_VB, " Volume", &LLColor4::blue1, 0 },
|
|
// { LLFastTimer::FTM_REBUILD_NONE_VB, " Unknown", &LLColor4::cyan5, 0 },
|
|
// { LLFastTimer::FTM_REBUILD_BRIDGE_VB, " Bridge", &LLColor4::blue2, 0 },
|
|
// { LLFastTimer::FTM_REBUILD_HUD_VB, " HUD", &LLColor4::blue3, 0 },
|
|
{ LLFastTimer::FTM_REBUILD_TERRAIN_VB, " Terrain", &LLColor4::blue4, 0 },
|
|
// { LLFastTimer::FTM_REBUILD_WATER_VB, " Water", &LLColor4::blue5, 0 },
|
|
// { LLFastTimer::FTM_REBUILD_TREE_VB, " Tree", &LLColor4::cyan1, 0 },
|
|
{ LLFastTimer::FTM_REBUILD_PARTICLE_VB, " Particle", &LLColor4::cyan2, 0 },
|
|
// { LLFastTimer::FTM_REBUILD_CLOUD_VB, " Cloud", &LLColor4::cyan3, 0 },
|
|
{ LLFastTimer::FTM_REBUILD_GRASS_VB, " Grass", &LLColor4::cyan4, 0 },
|
|
{ LLFastTimer::FTM_SHADOW_RENDER, " Shadow", &LLColor4::green5, 1 },
|
|
{ LLFastTimer::FTM_SHADOW_SIMPLE, " Simple", &LLColor4::yellow2, 1 },
|
|
{ LLFastTimer::FTM_SHADOW_ALPHA, " Alpha", &LLColor4::yellow6, 1 },
|
|
{ LLFastTimer::FTM_SHADOW_TERRAIN, " Terrain", &LLColor4::green6, 1 },
|
|
{ LLFastTimer::FTM_SHADOW_AVATAR, " Avatar", &LLColor4::yellow1, 1 },
|
|
{ LLFastTimer::FTM_SHADOW_TREE, " Tree", &LLColor4::yellow8, 1 },
|
|
{ LLFastTimer::FTM_RENDER_GEOMETRY, " Geometry", &LLColor4::green2, 1 },
|
|
{ LLFastTimer::FTM_POOLS, " Pools", &LLColor4::green3, 1 },
|
|
{ LLFastTimer::FTM_POOLRENDER, " RenderPool", &LLColor4::green4, 1 },
|
|
{ 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_FULLBRIGHT, " Fullbright", &LLColor4::yellow5, 0 },
|
|
{ LLFastTimer::FTM_RENDER_GLOW, " Glow", &LLColor4::orange1, 0 },
|
|
{ LLFastTimer::FTM_RENDER_GRASS, " Grass", &LLColor4::yellow6, 0 },
|
|
{ LLFastTimer::FTM_RENDER_INVISIBLE, " Invisible", &LLColor4::red2, 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_WL_SKY, " WL Sky", &LLColor4::blue3, 0 },
|
|
{ LLFastTimer::FTM_RENDER_FAKE_VBO_UPDATE," Fake VBO update", &LLColor4::red2, 0 },
|
|
{ LLFastTimer::FTM_RENDER_BLOOM, " Bloom", &LLColor4::blue4, 0 },
|
|
{ LLFastTimer::FTM_RENDER_BLOOM_FBO, " First FBO", &LLColor4::blue, 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_SWAP, " Swap", &LLColor4::pink2, 0 },
|
|
{ LLFastTimer::FTM_CLIENT_COPY, " Client Copy", &LLColor4::red1, 1},
|
|
|
|
#if 0 || !LL_RELEASE_FOR_DOWNLOAD
|
|
{ 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 },
|
|
#endif
|
|
|
|
{ LLFastTimer::FTM_OTHER, " Other", &red0 }
|
|
};
|
|
static int ft_display_didcalc = 0;
|
|
static const int FTV_DISPLAY_NUM = LL_ARRAY_SIZE(ft_display_table);
|
|
|
|
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)
|
|
: LLFloater(name, rect, std::string("Fast Timers"))
|
|
{
|
|
setVisible(FALSE);
|
|
mDisplayMode = 0;
|
|
mAvgCountTotal = 0;
|
|
mMaxCountTotal = 0;
|
|
mDisplayCenter = 1;
|
|
mDisplayCalls = 0;
|
|
mDisplayHz = 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;
|
|
}
|
|
|
|
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 = (getRect().getHeight() - y) / ((S32) LLFontGL::getFontMonospace()->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_ALT)
|
|
{
|
|
if (mask & MASK_SHIFT)
|
|
{
|
|
mSubtractHidden = !mSubtractHidden;
|
|
}
|
|
else if (mask & MASK_CONTROL)
|
|
{
|
|
mDisplayHz = !mDisplayHz;
|
|
}
|
|
else
|
|
{
|
|
mDisplayCalls = !mDisplayCalls;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
// SJB: Don't pass mouse clicks through the display
|
|
return TRUE;
|
|
}
|
|
|
|
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)
|
|
{
|
|
LLFastTimer::sPauseHistory = TRUE;
|
|
mScrollIndex = llclamp(mScrollIndex - clicks,
|
|
0, llmin(LLFastTimer::sLastFrameIndex, (S32)LLFastTimer::FTM_HISTORY_NUM-MAX_VISIBLE_HISTORY));
|
|
return TRUE;
|
|
}
|
|
|
|
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);
|
|
|
|
// HACK: casting away const. Should use setRect or some helper function instead.
|
|
const_cast<LLRect&>(getRect()).setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height);
|
|
|
|
S32 left, top, right, bottom;
|
|
S32 x, y, barw, barh, dx, dy;
|
|
S32 texth, textw;
|
|
LLPointer<LLUIImage> box_imagep = LLUI::getUIImage("rounded_square.tga");
|
|
|
|
// 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
|
|
{
|
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
|
gl_rect_2d(0, getRect().getHeight(), getRect().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::getFontMonospace()->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::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
|
|
|
|
textw = LLFontGL::getFontMonospace()->getWidth(tdesc);
|
|
|
|
x = xleft, y -= (texth + 2);
|
|
tdesc = llformat("Justification = %s [CTRL-Click to toggle]",centerdesc[mDisplayCenter]);
|
|
LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
|
|
y -= (texth + 2);
|
|
|
|
LLFontGL::getFontMonospace()->renderUTF8(std::string("[Right-Click log selected] [ALT-Click toggle counts] [ALT-SHIFT-Click sub 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 = ticks_sum[0][i];
|
|
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::getFontMonospace()->renderUTF8(tdesc, 0, x, y, color, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::BOLD);
|
|
}
|
|
else
|
|
{
|
|
LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, color, LLFontGL::LEFT, LLFontGL::TOP);
|
|
}
|
|
y -= (texth + 2);
|
|
|
|
textw = dx + LLFontGL::getFontMonospace()->getWidth(std::string(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 = getRect().mRight - xleft;
|
|
mBarRect.mTop = ytop - ((S32)LLFontGL::getFontMonospace()->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::getFontMonospace()->getWidth(tdesc);
|
|
LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
|
|
LLFontGL::LEFT, LLFontGL::TOP);
|
|
|
|
tdesc = llformat("%.1f ms |", (F32)ms*.50f);
|
|
x = xleft + barw/2 - LLFontGL::getFontMonospace()->getWidth(tdesc);
|
|
LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
|
|
LLFontGL::LEFT, LLFontGL::TOP);
|
|
|
|
tdesc = llformat("%.1f ms |", (F32)ms*.75f);
|
|
x = xleft + (barw*3)/4 - LLFontGL::getFontMonospace()->getWidth(tdesc);
|
|
LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
|
|
LLFontGL::LEFT, LLFontGL::TOP);
|
|
|
|
tdesc = llformat( "%d ms |", ms);
|
|
x = xleft + barw - LLFontGL::getFontMonospace()->getWidth(tdesc);
|
|
LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
|
|
LLFontGL::LEFT, LLFontGL::TOP);
|
|
}
|
|
|
|
LLRect graph_rect;
|
|
// Draw borders
|
|
{
|
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
|
gGL.color4f(0.5f,0.5f,0.5f,0.5f);
|
|
|
|
S32 by = y + 2;
|
|
|
|
y -= ((S32)LLFontGL::getFontMonospace()->getLineHeight() + 4);
|
|
|
|
//heading
|
|
gl_rect_2d(xleft-5, by, getRect().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, getRect().getWidth()-5, by-barh-dy-5, FALSE);
|
|
|
|
by -= barh*2+dy;
|
|
|
|
//current frame bar
|
|
gl_rect_2d(xleft-5, by, getRect().getWidth()-5, by-barh-dy-2, FALSE);
|
|
|
|
by -= barh+dy+1;
|
|
|
|
//history bars
|
|
gl_rect_2d(xleft-5, by, getRect().getWidth()-5, LINE_GRAPH_HEIGHT-barh-dy-2, FALSE);
|
|
|
|
by = LINE_GRAPH_HEIGHT-barh-dy-7;
|
|
|
|
//line graph
|
|
graph_rect = LLRect(xleft-5, by, getRect().getWidth()-5, 5);
|
|
|
|
gl_rect_2d(graph_rect, FALSE);
|
|
}
|
|
|
|
// Draw bars for each history entry
|
|
// Special: -1 = show running average
|
|
gGL.getTexUnit(0)->bind(box_imagep->getImage());
|
|
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);
|
|
}
|
|
|
|
gGL.color4fv(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->getTextureWidth(), box_imagep->getTextureHeight(), 16, start_fragment, end_fragment);
|
|
|
|
}
|
|
|
|
}
|
|
y -= (barh + dy);
|
|
if (j < 0)
|
|
y -= barh;
|
|
}
|
|
|
|
//draw line graph history
|
|
{
|
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
|
LLLocalClipRect clip(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
|
|
std::string tdesc;
|
|
if (mDisplayCalls)
|
|
tdesc = llformat("%d calls", (int)max_ticks);
|
|
else if (mDisplayHz)
|
|
tdesc = llformat("%d Hz", (int)max_ticks);
|
|
else
|
|
tdesc = llformat("%4.2f ms", ms);
|
|
|
|
x = graph_rect.mRight - LLFontGL::getFontMonospace()->getWidth(tdesc)-5;
|
|
y = graph_rect.mTop - ((S32)LLFontGL::getFontMonospace()->getLineHeight());
|
|
|
|
LLFontGL::getFontMonospace()->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;
|
|
|
|
gGL.color4f(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;
|
|
|
|
gGL.color4f(0.5f,0.5f,0.5f,1);
|
|
|
|
gGL.begin(LLRender::LINES);
|
|
gGL.vertex2i((S32)bar, graph_rect.mBottom);
|
|
gGL.vertex2i((S32)bar, graph_rect.mTop);
|
|
gGL.end();
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
gGL.flush();
|
|
glLineWidth(3);
|
|
}
|
|
|
|
const 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;
|
|
}
|
|
}
|
|
|
|
gGL.color4f(col[0], col[1], col[2], alpha);
|
|
gGL.begin(LLRender::LINE_STRIP);
|
|
for (U32 j = 0; j < LLFastTimer::FTM_HISTORY_NUM; j++)
|
|
{
|
|
U64 ticks = ticks_sum[j+1][idx];
|
|
|
|
if (mDisplayHz)
|
|
{
|
|
F64 tc = (F64) (ticks+1) * iclock_freq;
|
|
tc = 1000.f/tc;
|
|
ticks = llmin((U64) tc, (U64) 1024);
|
|
}
|
|
else if (mDisplayCalls)
|
|
{
|
|
S32 tidx = ft_display_table[idx].timer;
|
|
S32 hidx = (LLFastTimer::sLastFrameIndex + j) % LLFastTimer::FTM_HISTORY_NUM;
|
|
ticks = (S32)LLFastTimer::sCallHistory[hidx][tidx];
|
|
}
|
|
|
|
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;
|
|
gGL.vertex2f(x,y);
|
|
}
|
|
gGL.end();
|
|
|
|
if (mHoverIndex == idx)
|
|
{
|
|
gGL.flush();
|
|
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;
|
|
|
|
if (mHoverIndex >= 0)
|
|
{
|
|
x = (graph_rect.mRight + graph_rect.mLeft)/2;
|
|
y = graph_rect.mBottom + 8;
|
|
|
|
LLFontGL::getFontMonospace()->renderUTF8(std::string(ft_display_table[mHoverIndex].desc), 0, x, y, LLColor4::white,
|
|
LLFontGL::LEFT, LLFontGL::BOTTOM);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Output stats for clicked bar to log
|
|
if (mPrintStats >= 0)
|
|
{
|
|
std::string 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;
|
|
|
|
std::string 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;
|
|
}
|
|
}
|
|
|
|
if (i == FTV_DISPLAY_NUM)
|
|
{
|
|
// walked off the end of ft_display_table without finding
|
|
// the desired timer type
|
|
llwarns << "Timer type " << tidx << " not known." << llendl;
|
|
return F64(0.0);
|
|
}
|
|
|
|
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();
|
|
}
|