/** * @file lltextureview.cpp * @brief LLTextureView class implementation * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include <set> #include "lltextureview.h" #include "llrect.h" #include "llerror.h" #include "lllfsthread.h" #include "llui.h" #include "llimageworker.h" #include "llrender.h" #include "lltooltip.h" #include "llappviewer.h" #include "llselectmgr.h" #include "lltexlayer.h" #include "lltexturecache.h" #include "lltexturefetch.h" #include "llviewercontrol.h" #include "llviewerobject.h" #include "llviewertexture.h" #include "llviewertexturelist.h" #include "llvovolume.h" #include "llviewerstats.h" // For avatar texture view #include "llvoavatarself.h" #include "lltexlayer.h" extern F32 texmem_lower_bound_scale; LLTextureView *gTextureView = NULL; LLTextureSizeView *gTextureSizeView = NULL; LLTextureSizeView *gTextureCategoryView = NULL; #define HIGH_PRIORITY 100000000.f //static std::set<LLViewerFetchedTexture*> LLTextureView::sDebugImages; //////////////////////////////////////////////////////////////////////////// static std::string title_string1a("Tex UUID Area DDis(Req) DecodePri(Fetch) [download] pk/max"); static std::string title_string1b("Tex UUID Area DDis(Req) Fetch(DecodePri) [download] pk/max"); static std::string title_string2("State"); static std::string title_string3("Pkt Bnd"); static std::string title_string4(" W x H (Dis) Mem"); static S32 title_x1 = 0; static S32 title_x2 = 460; static S32 title_x3 = title_x2 + 40; static S32 title_x4 = title_x3 + 50; static S32 texture_bar_height = 8; //////////////////////////////////////////////////////////////////////////// class LLTextureBar : public LLView { public: LLPointer<LLViewerFetchedTexture> mImagep; S32 mHilite; public: struct Params : public LLInitParam::Block<Params, LLView::Params> { Mandatory<LLTextureView*> texture_view; Params() : texture_view("texture_view") { mouse_opaque(false); } }; LLTextureBar(const Params& p) : LLView(p), mHilite(0), mTextureView(p.texture_view) {} virtual void draw(); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual LLRect getRequiredRect(); // Return the height of this object, given the set options. // Used for sorting struct sort { bool operator()(const LLView* i1, const LLView* i2) { LLTextureBar* bar1p = (LLTextureBar*)i1; LLTextureBar* bar2p = (LLTextureBar*)i2; LLViewerFetchedTexture *i1p = bar1p->mImagep; LLViewerFetchedTexture *i2p = bar2p->mImagep; F32 pri1 = i1p->getDecodePriority(); // i1p->mRequestedDownloadPriority F32 pri2 = i2p->getDecodePriority(); // i2p->mRequestedDownloadPriority if (pri1 > pri2) return true; else if (pri2 > pri1) return false; else return i1p->getID() < i2p->getID(); } }; struct sort_fetch { bool operator()(const LLView* i1, const LLView* i2) { LLTextureBar* bar1p = (LLTextureBar*)i1; LLTextureBar* bar2p = (LLTextureBar*)i2; LLViewerFetchedTexture *i1p = bar1p->mImagep; LLViewerFetchedTexture *i2p = bar2p->mImagep; U32 pri1 = i1p->getFetchPriority() ; U32 pri2 = i2p->getFetchPriority() ; if (pri1 > pri2) return true; else if (pri2 > pri1) return false; else return i1p->getID() < i2p->getID(); } }; private: LLTextureView* mTextureView; }; void LLTextureBar::draw() { if (!mImagep) { return; } LLColor4 color; if (mImagep->getID() == LLAppViewer::getTextureFetch()->mDebugID) { color = LLColor4::cyan2; } else if (mHilite) { S32 idx = llclamp(mHilite,1,3); if (idx==1) color = LLColor4::orange; else if (idx==2) color = LLColor4::yellow; else color = LLColor4::pink2; } else if (mImagep->mDontDiscard) { color = LLColor4::green4; } else if (mImagep->getBoostLevel() > LLViewerTexture::BOOST_NONE) { color = LLColor4::magenta; } else if (mImagep->getDecodePriority() <= 0.0f) { color = LLColor4::grey; color[VALPHA] = .7f; } else { color = LLColor4::white; color[VALPHA] = .7f; } // We need to draw: // The texture UUID or name // The progress bar for the texture, highlighted if it's being download // Various numerical stats. std::string tex_str; S32 left, right; S32 top = 0; S32 bottom = top + 6; LLColor4 clr; LLGLSUIDefault gls_ui; // Name, pixel_area, requested pixel area, decode priority std::string uuid_str; mImagep->mID.toString(uuid_str); uuid_str = uuid_str.substr(0,7); if (mTextureView->mOrderFetch) { tex_str = llformat("%s %7.0f %d(%d) 0x%08x(%8.0f)", uuid_str.c_str(), mImagep->mMaxVirtualSize, mImagep->mDesiredDiscardLevel, mImagep->mRequestedDiscardLevel, mImagep->mFetchPriority, mImagep->getDecodePriority()); } else { tex_str = llformat("%s %7.0f %d(%d) %8.0f(0x%08x)", uuid_str.c_str(), mImagep->mMaxVirtualSize, mImagep->mDesiredDiscardLevel, mImagep->mRequestedDiscardLevel, mImagep->getDecodePriority(), mImagep->mFetchPriority); } LLFontGL::getFontMonospace()->renderUTF8(tex_str, 0, title_x1, getRect().getHeight(), color, LLFontGL::LEFT, LLFontGL::TOP); // State // Hack: mirrored from lltexturefetch.cpp struct { const std::string desc; LLColor4 color; } fetch_state_desc[] = { { "---", LLColor4::red }, // INVALID { "INI", LLColor4::white }, // INIT { "DSK", LLColor4::cyan }, // LOAD_FROM_TEXTURE_CACHE { "DSK", LLColor4::blue }, // CACHE_POST { "NET", LLColor4::green }, // LOAD_FROM_NETWORK { "SIM", LLColor4::green }, // LOAD_FROM_SIMULATOR { "REQ", LLColor4::yellow },// SEND_HTTP_REQ { "HTP", LLColor4::green }, // WAIT_HTTP_REQ { "DEC", LLColor4::yellow },// DECODE_IMAGE { "DEC", LLColor4::green }, // DECODE_IMAGE_UPDATE { "WRT", LLColor4::purple },// WRITE_TO_CACHE { "WRT", LLColor4::orange },// WAIT_ON_WRITE { "END", LLColor4::red }, // DONE #define LAST_STATE 12 { "CRE", LLColor4::magenta }, // LAST_STATE+1 { "FUL", LLColor4::green }, // LAST_STATE+2 { "BAD", LLColor4::red }, // LAST_STATE+3 { "MIS", LLColor4::red }, // LAST_STATE+4 { "---", LLColor4::white }, // LAST_STATE+5 }; const S32 fetch_state_desc_size = (S32)LL_ARRAY_SIZE(fetch_state_desc); S32 state = mImagep->mNeedsCreateTexture ? LAST_STATE+1 : mImagep->mFullyLoaded ? LAST_STATE+2 : mImagep->mMinDiscardLevel > 0 ? LAST_STATE+3 : mImagep->mIsMissingAsset ? LAST_STATE+4 : !mImagep->mIsFetching ? LAST_STATE+5 : mImagep->mFetchState; state = llclamp(state,0,fetch_state_desc_size-1); LLFontGL::getFontMonospace()->renderUTF8(fetch_state_desc[state].desc, 0, title_x2, getRect().getHeight(), fetch_state_desc[state].color, LLFontGL::LEFT, LLFontGL::TOP); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); // Draw the progress bar. S32 bar_width = 100; S32 bar_left = 260; left = bar_left; right = left + bar_width; gGL.color4f(0.f, 0.f, 0.f, 0.75f); gl_rect_2d(left, top, right, bottom); F32 data_progress = mImagep->mDownloadProgress; if (data_progress > 0.0f) { // Downloaded bytes right = left + llfloor(data_progress * (F32)bar_width); if (right > left) { gGL.color4f(0.f, 0.f, 1.f, 0.75f); gl_rect_2d(left, top, right, bottom); } } S32 pip_width = 6; S32 pip_space = 14; S32 pip_x = title_x3 + pip_space/2; // Draw the packet pip const F32 pip_max_time = 5.f; F32 last_event = mImagep->mLastPacketTimer.getElapsedTimeF32(); if (last_event < pip_max_time) { clr = LLColor4::white; } else { last_event = mImagep->mRequestDeltaTime; if (last_event < pip_max_time) { clr = LLColor4::green; } else { last_event = mImagep->mFetchDeltaTime; if (last_event < pip_max_time) { clr = LLColor4::yellow; } } } if (last_event < pip_max_time) { clr.setAlpha(1.f - last_event/pip_max_time); gGL.color4fv(clr.mV); gl_rect_2d(pip_x, top, pip_x + pip_width, bottom); } pip_x += pip_width + pip_space; // we don't want to show bind/resident pips for textures using the default texture if (mImagep->hasGLTexture()) { // Draw the bound pip last_event = mImagep->getTimePassedSinceLastBound(); if (last_event < 1.f) { clr = mImagep->getMissed() ? LLColor4::red : LLColor4::magenta1; clr.setAlpha(1.f - last_event); gGL.color4fv(clr.mV); gl_rect_2d(pip_x, top, pip_x + pip_width, bottom); } } pip_x += pip_width + pip_space; { LLGLSUIDefault gls_ui; // draw the packet data // { // std::string num_str = llformat("%3d/%3d", mImagep->mLastPacket+1, mImagep->mPackets); // LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, bar_left + 100, getRect().getHeight(), color, // LLFontGL::LEFT, LLFontGL::TOP); // } // draw the image size at the end { std::string num_str = llformat("%3dx%3d (%d) %7d", mImagep->getWidth(), mImagep->getHeight(), mImagep->getDiscardLevel(), mImagep->hasGLTexture() ? mImagep->getTextureMemory() : 0); LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, title_x4, getRect().getHeight(), color, LLFontGL::LEFT, LLFontGL::TOP); } } } BOOL LLTextureBar::handleMouseDown(S32 x, S32 y, MASK mask) { if ((mask & (MASK_CONTROL|MASK_SHIFT|MASK_ALT)) == MASK_ALT) { LLAppViewer::getTextureFetch()->mDebugID = mImagep->getID(); return TRUE; } return LLView::handleMouseDown(x,y,mask); } LLRect LLTextureBar::getRequiredRect() { LLRect rect; rect.mTop = texture_bar_height; return rect; } //////////////////////////////////////////////////////////////////////////// class LLAvatarTexBar : public LLView { public: struct Params : public LLInitParam::Block<Params, LLView::Params> { Mandatory<LLTextureView*> texture_view; Params() : texture_view("texture_view") { S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); rect(LLRect(0,0,100,line_height * 4)); } }; LLAvatarTexBar(const Params& p) : LLView(p), mTextureView(p.texture_view) {} virtual void draw(); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual LLRect getRequiredRect(); // Return the height of this object, given the set options. private: LLTextureView* mTextureView; }; void LLAvatarTexBar::draw() { if (!gSavedSettings.getBOOL("DebugAvatarRezTime")) return; LLVOAvatarSelf* avatarp = gAgentAvatarp; if (!avatarp) return; const S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); const S32 v_offset = 0; const S32 l_offset = 3; //---------------------------------------------------------------------------- LLGLSUIDefault gls_ui; LLColor4 color; U32 line_num = 1; for (LLVOAvatarDefines::LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDefines::LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); baked_iter != LLVOAvatarDefines::LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); ++baked_iter) { const LLVOAvatarDefines::EBakedTextureIndex baked_index = baked_iter->first; const LLTexLayerSet *layerset = avatarp->debugGetLayerSet(baked_index); if (!layerset) continue; const LLTexLayerSetBuffer *layerset_buffer = layerset->getComposite(); if (!layerset_buffer) continue; LLColor4 text_color = LLColor4::white; if (layerset_buffer->uploadNeeded()) { text_color = LLColor4::red; } if (layerset_buffer->uploadInProgress()) { text_color = LLColor4::magenta; } std::string text = layerset_buffer->dumpTextureInfo(); LLFontGL::getFontMonospace()->renderUTF8(text, 0, l_offset, v_offset + line_height*line_num, text_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); line_num++; } const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout"); const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); LLColor4 header_color(1.f, 1.f, 1.f, 0.9f); const std::string texture_timeout_str = texture_timeout ? llformat("%d",texture_timeout) : "Disabled"; const std::string override_tex_discard_level_str = override_tex_discard_level ? llformat("%d",override_tex_discard_level) : "Disabled"; std::string header_text = llformat("[ Timeout('AvatarBakedTextureUploadTimeout'):%s ] [ LOD_Override('TextureDiscardLevel'):%s ]", texture_timeout_str.c_str(), override_tex_discard_level_str.c_str()); LLFontGL::getFontMonospace()->renderUTF8(header_text, 0, l_offset, v_offset + line_height*line_num, header_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); line_num++; std::string section_text = "Avatar Textures Information:"; LLFontGL::getFontMonospace()->renderUTF8(section_text, 0, 0, v_offset + line_height*line_num, header_color, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); } BOOL LLAvatarTexBar::handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; } LLRect LLAvatarTexBar::getRequiredRect() { LLRect rect; rect.mTop = 100; if (!gSavedSettings.getBOOL("DebugAvatarRezTime")) rect.mTop = 0; return rect; } //////////////////////////////////////////////////////////////////////////// class LLGLTexMemBar : public LLView { public: struct Params : public LLInitParam::Block<Params, LLView::Params> { Mandatory<LLTextureView*> texture_view; Params() : texture_view("texture_view") { S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); rect(LLRect(0,0,100,line_height * 4)); } }; LLGLTexMemBar(const Params& p) : LLView(p), mTextureView(p.texture_view) {} virtual void draw(); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual LLRect getRequiredRect(); // Return the height of this object, given the set options. private: LLTextureView* mTextureView; }; void LLGLTexMemBar::draw() { S32 bound_mem = BYTES_TO_MEGA_BYTES(LLViewerTexture::sBoundTextureMemoryInBytes); S32 max_bound_mem = LLViewerTexture::sMaxBoundTextureMemInMegaBytes; S32 total_mem = BYTES_TO_MEGA_BYTES(LLViewerTexture::sTotalTextureMemoryInBytes); S32 max_total_mem = LLViewerTexture::sMaxTotalTextureMemInMegaBytes; F32 discard_bias = LLViewerTexture::sDesiredDiscardBias; F32 cache_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getUsage()) ; F32 cache_max_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getMaxUsage()) ; S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); S32 v_offset = (S32)((texture_bar_height + 2.2f) * mTextureView->mNumTextureBars + 2.0f); F32 total_texture_downloaded = (F32)gTotalTextureBytes / (1024 * 1024); F32 total_object_downloaded = (F32)gTotalObjectBytes / (1024 * 1024); //---------------------------------------------------------------------------- LLGLSUIDefault gls_ui; LLColor4 text_color(1.f, 1.f, 1.f, 0.75f); LLColor4 color; std::string text = ""; LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6, text_color, LLFontGL::LEFT, LLFontGL::TOP); text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot Tex: %.1f MB Tot Obj: %.1f MB", total_mem, max_total_mem, bound_mem, max_bound_mem, LLImageRaw::sGlobalRawMemory >> 20, discard_bias, cache_usage, cache_max_usage, total_texture_downloaded, total_object_downloaded); //, cache_entries, cache_max_entries LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3, text_color, LLFontGL::LEFT, LLFontGL::TOP); //---------------------------------------------------------------------------- #if 0 S32 bar_left = 400; S32 bar_width = 200; S32 top = line_height*3 - 2 + v_offset; S32 bottom = top - 6; S32 left = bar_left; S32 right = left + bar_width; F32 bar_scale; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); // GL Mem Bar left = bar_left; text = "GL"; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, line_height*3, text_color, LLFontGL::LEFT, LLFontGL::TOP); left = bar_left+20; right = left + bar_width; gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f); // grey gl_rect_2d(left, top, right, bottom); bar_scale = (F32)bar_width / (max_total_mem * 1.5f); right = left + llfloor(total_mem * bar_scale); right = llclamp(right, bar_left, bar_left + bar_width); color = (total_mem < llfloor(max_total_mem * texmem_lower_bound_scale)) ? LLColor4::green : (total_mem < max_total_mem) ? LLColor4::yellow : LLColor4::red; color[VALPHA] = .75f; glColor4fv(color.mV); gl_rect_2d(left, top, right, bottom); // red/yellow/green // bar_left += bar_width + bar_space; //top = bottom - 2; bottom = top - 6; // Bound Mem Bar left = bar_left; text = "GL"; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, line_height*3, text_color, LLFontGL::LEFT, LLFontGL::TOP); left = bar_left + 20; right = left + bar_width; gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f); gl_rect_2d(left, top, right, bottom); color = (bound_mem < llfloor(max_bound_mem * texmem_lower_bound_scale)) ? LLColor4::green : (bound_mem < max_bound_mem) ? LLColor4::yellow : LLColor4::red; color[VALPHA] = .75f; glColor4fv(color.mV); gl_rect_2d(left, top, right, bottom); #else S32 left = 0 ; #endif //---------------------------------------------------------------------------- text = llformat("Textures: %d Fetch: %d(%d) Pkts:%d(%d) Cache R/W: %d/%d LFS:%d RAW:%d HTP:%d DEC:%d CRE:%d", gTextureList.getNumImages(), LLAppViewer::getTextureFetch()->getNumRequests(), LLAppViewer::getTextureFetch()->getNumDeletes(), LLAppViewer::getTextureFetch()->mPacketCount, LLAppViewer::getTextureFetch()->mBadPacketCount, LLAppViewer::getTextureCache()->getNumReads(), LLAppViewer::getTextureCache()->getNumWrites(), LLLFSThread::sLocal->getPending(), LLImageRaw::sRawImageCount, LLAppViewer::getTextureFetch()->getNumHTTPRequests(), LLAppViewer::getImageDecodeThread()->getPending(), gTextureList.mCreateTextureList.size()); LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*2, text_color, LLFontGL::LEFT, LLFontGL::TOP); left = 550; F32 bandwidth = LLAppViewer::getTextureFetch()->getTextureBandwidth(); F32 max_bandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS"); color = bandwidth > max_bandwidth ? LLColor4::red : bandwidth > max_bandwidth*.75f ? LLColor4::yellow : text_color; color[VALPHA] = text_color[VALPHA]; text = llformat("BW:%.0f/%.0f",bandwidth, max_bandwidth); LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, v_offset + line_height*2, color, LLFontGL::LEFT, LLFontGL::TOP); S32 dx1 = 0; if (LLAppViewer::getTextureFetch()->mDebugPause) { LLFontGL::getFontMonospace()->renderUTF8(std::string("!"), 0, title_x1, v_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); dx1 += 8; } if (mTextureView->mFreezeView) { LLFontGL::getFontMonospace()->renderUTF8(std::string("*"), 0, title_x1, v_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); dx1 += 8; } if (mTextureView->mOrderFetch) { LLFontGL::getFontMonospace()->renderUTF8(title_string1b, 0, title_x1+dx1, v_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); } else { LLFontGL::getFontMonospace()->renderUTF8(title_string1a, 0, title_x1+dx1, v_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); } LLFontGL::getFontMonospace()->renderUTF8(title_string2, 0, title_x2, v_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); LLFontGL::getFontMonospace()->renderUTF8(title_string3, 0, title_x3, v_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); LLFontGL::getFontMonospace()->renderUTF8(title_string4, 0, title_x4, v_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); } BOOL LLGLTexMemBar::handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; } LLRect LLGLTexMemBar::getRequiredRect() { LLRect rect; //rect.mTop = 50; rect.mTop = 0; return rect; } //////////////////////////////////////////////////////////////////////////// class LLGLTexSizeBar { public: LLGLTexSizeBar(S32 index, S32 left, S32 bottom, S32 right, S32 line_height) { mIndex = index ; mLeft = left ; mBottom = bottom ; mRight = right ; mLineHeight = line_height ; mTopLoaded = 0 ; mTopBound = 0 ; mScale = 1.0f ; } void setTop(S32 loaded, S32 bound, F32 scale) {mTopLoaded = loaded ; mTopBound = bound; mScale = scale ;} void draw(); BOOL handleHover(S32 x, S32 y, MASK mask, BOOL set_pick_size) ; private: S32 mIndex ; S32 mLeft ; S32 mBottom ; S32 mRight ; S32 mTopLoaded ; S32 mTopBound ; S32 mLineHeight ; F32 mScale ; }; BOOL LLGLTexSizeBar::handleHover(S32 x, S32 y, MASK mask, BOOL set_pick_size) { if(y > mBottom && (y < mBottom + (S32)(mTopLoaded * mScale) || y < mBottom + (S32)(mTopBound * mScale))) { LLImageGL::setCurTexSizebar(mIndex, set_pick_size); } return TRUE ; } void LLGLTexSizeBar::draw() { LLGLSUIDefault gls_ui; if(LLImageGL::sCurTexSizeBar == mIndex) { F32 text_color[] = {1.f, 1.f, 1.f, 0.75f}; std::string text; text = llformat("%d", mTopLoaded) ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, mLeft, mBottom + (S32)(mTopLoaded * mScale) + mLineHeight, text_color, LLFontGL::LEFT, LLFontGL::TOP); text = llformat("%d", mTopBound) ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, (mLeft + mRight) / 2, mBottom + (S32)(mTopBound * mScale) + mLineHeight, text_color, LLFontGL::LEFT, LLFontGL::TOP); } F32 loaded_color[] = {1.0f, 0.0f, 0.0f, 0.75f}; F32 bound_color[] = {1.0f, 1.0f, 0.0f, 0.75f}; gl_rect_2d(mLeft, mBottom + (S32)(mTopLoaded * mScale), (mLeft + mRight) / 2, mBottom, loaded_color) ; gl_rect_2d((mLeft + mRight) / 2, mBottom + (S32)(mTopBound * mScale), mRight, mBottom, bound_color) ; } //////////////////////////////////////////////////////////////////////////// LLTextureView::LLTextureView(const LLTextureView::Params& p) : LLContainerView(p), mFreezeView(FALSE), mOrderFetch(FALSE), mPrintList(FALSE), mNumTextureBars(0) { setVisible(FALSE); setDisplayChildren(TRUE); mGLTexMemBar = 0; mAvatarTexBar = 0; } LLTextureView::~LLTextureView() { // Children all cleaned up by default view destructor. delete mGLTexMemBar; mGLTexMemBar = 0; delete mAvatarTexBar; mAvatarTexBar = 0; } typedef std::pair<F32,LLViewerFetchedTexture*> decode_pair_t; struct compare_decode_pair { bool operator()(const decode_pair_t& a, const decode_pair_t& b) { return a.first > b.first; } }; struct KillView { void operator()(LLView* viewp) { viewp->getParent()->removeChild(viewp); viewp->die(); } }; void LLTextureView::draw() { if (!mFreezeView) { // LLViewerObject *objectp; // S32 te; for_each(mTextureBars.begin(), mTextureBars.end(), KillView()); mTextureBars.clear(); if (mGLTexMemBar) { removeChild(mGLTexMemBar); mGLTexMemBar->die(); mGLTexMemBar = 0; } if (mAvatarTexBar) { removeChild(mAvatarTexBar); mAvatarTexBar->die(); mAvatarTexBar = 0; } typedef std::multiset<decode_pair_t, compare_decode_pair > display_list_t; display_list_t display_image_list; if (mPrintList) { llinfos << "ID\tMEM\tBOOST\tPRI\tWIDTH\tHEIGHT\tDISCARD" << llendl; } for (LLViewerTextureList::image_priority_list_t::iterator iter = gTextureList.mImageList.begin(); iter != gTextureList.mImageList.end(); ) { LLPointer<LLViewerFetchedTexture> imagep = *iter++; if(!imagep->hasFetcher()) { continue ; } S32 cur_discard = imagep->getDiscardLevel(); S32 desired_discard = imagep->mDesiredDiscardLevel; if (mPrintList) { S32 tex_mem = imagep->hasGLTexture() ? imagep->getTextureMemory() : 0 ; llinfos << imagep->getID() << "\t" << tex_mem << "\t" << imagep->getBoostLevel() << "\t" << imagep->getDecodePriority() << "\t" << imagep->getWidth() << "\t" << imagep->getHeight() << "\t" << cur_discard << llendl; } if (imagep->getID() == LLAppViewer::getTextureFetch()->mDebugID) { static S32 debug_count = 0; ++debug_count; // for breakpoints } F32 pri; if (mOrderFetch) { pri = ((F32)imagep->mFetchPriority)/256.f; } else { pri = imagep->getDecodePriority(); } pri = llclamp(pri, 0.0f, HIGH_PRIORITY-1.f); if (sDebugImages.find(imagep) != sDebugImages.end()) { pri += 4*HIGH_PRIORITY; } if (!mOrderFetch) { if (pri < HIGH_PRIORITY && LLSelectMgr::getInstance()) { struct f : public LLSelectedTEFunctor { LLViewerFetchedTexture* mImage; f(LLViewerFetchedTexture* image) : mImage(image) {} virtual bool apply(LLViewerObject* object, S32 te) { return (mImage == object->getTEImage(te)); } } func(imagep); const bool firstonly = true; bool match = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func, firstonly); if (match) { pri += 3*HIGH_PRIORITY; } } if (pri < HIGH_PRIORITY && (cur_discard< 0 || desired_discard < cur_discard)) { LLSelectNode* hover_node = LLSelectMgr::instance().getHoverNode(); if (hover_node) { LLViewerObject *objectp = hover_node->getObject(); if (objectp) { S32 tex_count = objectp->getNumTEs(); for (S32 i = 0; i < tex_count; i++) { if (imagep == objectp->getTEImage(i)) { pri += 2*HIGH_PRIORITY; break; } } } } } if (pri > 0.f && pri < HIGH_PRIORITY) { if (imagep->mLastPacketTimer.getElapsedTimeF32() < 1.f || imagep->mFetchDeltaTime < 0.25f) { pri += 1*HIGH_PRIORITY; } } } if (pri > 0.0f) { display_image_list.insert(std::make_pair(pri, imagep)); } } if (mPrintList) { mPrintList = FALSE; } static S32 max_count = 50; S32 count = 0; mNumTextureBars = 0 ; for (display_list_t::iterator iter = display_image_list.begin(); iter != display_image_list.end(); iter++) { LLViewerFetchedTexture* imagep = iter->second; S32 hilite = 0; F32 pri = iter->first; if (pri >= 1 * HIGH_PRIORITY) { hilite = (S32)((pri+1) / HIGH_PRIORITY) - 1; } if ((hilite || count < max_count-10) && (count < max_count)) { if (addBar(imagep, hilite)) { count++; } } } if (mOrderFetch) sortChildren(LLTextureBar::sort_fetch()); else sortChildren(LLTextureBar::sort()); LLGLTexMemBar::Params tmbp; LLRect tmbr; tmbp.name("gl texmem bar"); tmbp.rect(tmbr); tmbp.texture_view(this); mGLTexMemBar = LLUICtrlFactory::create<LLGLTexMemBar>(tmbp); addChildInBack(mGLTexMemBar); LLAvatarTexBar::Params atbp; LLRect atbr; atbp.name("gl avatartex bar"); atbp.texture_view(this); atbp.rect(atbr); mAvatarTexBar = LLUICtrlFactory::create<LLAvatarTexBar>(atbp); addChild(mAvatarTexBar); reshape(getRect().getWidth(), getRect().getHeight(), TRUE); /* count = gTextureList.getNumImages(); std::string info_string; info_string = llformat("Global Info:\nTexture Count: %d", count); mInfoTextp->setText(info_string); */ for (child_list_const_iter_t child_iter = getChildList()->begin(); child_iter != getChildList()->end(); ++child_iter) { LLView *viewp = *child_iter; if (viewp->getRect().mBottom < 0) { viewp->setVisible(FALSE); } } } LLContainerView::draw(); } BOOL LLTextureView::addBar(LLViewerFetchedTexture *imagep, S32 hilite) { llassert(imagep); LLTextureBar *barp; LLRect r; mNumTextureBars++; LLTextureBar::Params tbp; tbp.name("texture bar"); tbp.rect(r); tbp.texture_view(this); barp = LLUICtrlFactory::create<LLTextureBar>(tbp); barp->mImagep = imagep; barp->mHilite = hilite; addChild(barp); mTextureBars.push_back(barp); return TRUE; } BOOL LLTextureView::handleMouseDown(S32 x, S32 y, MASK mask) { if ((mask & (MASK_CONTROL|MASK_SHIFT|MASK_ALT)) == (MASK_ALT|MASK_SHIFT)) { mPrintList = TRUE; return TRUE; } if ((mask & (MASK_CONTROL|MASK_SHIFT|MASK_ALT)) == (MASK_CONTROL|MASK_SHIFT)) { LLAppViewer::getTextureFetch()->mDebugPause = !LLAppViewer::getTextureFetch()->mDebugPause; return TRUE; } if (mask & MASK_SHIFT) { mFreezeView = !mFreezeView; return TRUE; } if (mask & MASK_CONTROL) { mOrderFetch = !mOrderFetch; return TRUE; } return LLView::handleMouseDown(x,y,mask); } BOOL LLTextureView::handleMouseUp(S32 x, S32 y, MASK mask) { return FALSE; } BOOL LLTextureView::handleKey(KEY key, MASK mask, BOOL called_from_parent) { return FALSE; } //----------------------------------------------------------------- LLTextureSizeView::LLTextureSizeView(const LLTextureSizeView::Params& p) : LLContainerView(p) { setVisible(FALSE) ; mTextureSizeBarWidth = 30 ; } LLTextureSizeView::~LLTextureSizeView() { if(mTextureSizeBar.size()) { for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++) { delete mTextureSizeBar[i] ; } mTextureSizeBar.clear() ; } } void LLTextureSizeView::draw() { if(mType == TEXTURE_MEM_OVER_SIZE) { drawTextureSizeGraph(); } else { drawTextureCategoryGraph() ; } LLView::draw(); } BOOL LLTextureSizeView::handleHover(S32 x, S32 y, MASK mask) { if(x > mTextureSizeBarRect.mLeft && x < mTextureSizeBarRect.mRight) { mTextureSizeBar[(x - mTextureSizeBarRect.mLeft) / mTextureSizeBarWidth]->handleHover(x, y, mask, (mType == TEXTURE_MEM_OVER_SIZE)) ; } return TRUE ; } //draw real-time texture mem bar over size void LLTextureSizeView::drawTextureSizeGraph() { if(mTextureSizeBar.size() == 0) { S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); mTextureSizeBar.resize(LLImageGL::sTextureLoadedCounter.size()) ; mTextureSizeBarRect.set(700, line_height * 2 + 400, 700 + mTextureSizeBar.size() * mTextureSizeBarWidth, line_height * 2) ; for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++) { mTextureSizeBar[i] = new LLGLTexSizeBar(i, mTextureSizeBarRect.mLeft + i * mTextureSizeBarWidth , line_height * 2, mTextureSizeBarRect.mLeft + (i + 1) * mTextureSizeBarWidth, line_height) ; } } F32 size_bar_scale = drawTextureSizeDistributionGraph() ; for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++) { mTextureSizeBar[i]->setTop(LLImageGL::sTextureLoadedCounter[i], LLImageGL::sTextureBoundCounter[i], size_bar_scale) ; mTextureSizeBar[i]->draw() ; } LLImageGL::resetCurTexSizebar(); } //draw background of texture size bar graph F32 LLTextureSizeView::drawTextureSizeDistributionGraph() { //scale F32 scale = 1.0f ; LLGLSUIDefault gls_ui; { S32 count = 0 ; for(U32 i = 0 ; i < LLImageGL::sTextureLoadedCounter.size() ; i++) { if(LLImageGL::sTextureLoadedCounter[i] > count) { count = LLImageGL::sTextureLoadedCounter[i] ; } } if(count > mTextureSizeBarRect.getHeight()) { scale = (F32)mTextureSizeBarRect.getHeight() / count ; } } S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); S32 left = mTextureSizeBarRect.mLeft ; S32 bottom = mTextureSizeBarRect.mBottom ; S32 right = mTextureSizeBarRect.mRight ; S32 top = mTextureSizeBarRect.mTop ; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); //background rect gl_rect_2d(left - 25, top + 30, right + 100, bottom - 25, LLColor4(0.0f, 0.0f, 0.0f, 0.25f)) ; //-------------------------------------------------- gGL.color4f(1.0f, 0.5f, 0.5f, 0.75f); gl_line_2d(left, bottom, right, bottom) ; //x axis gl_line_2d(left, bottom, left, top) ; //y axis //ruler //-------------------------------------------------- gGL.color4f(1.0f, 0.5f, 0.5f, 0.5f); for(S32 i = bottom + 50 ; i <= top ; i += 50) { gl_line_2d(left, i, right, i) ; } //texts //-------------------------------------------------- F32 text_color[] = {1.f, 1.f, 1.f, 0.75f}; std::string text; //------- //x axis: size label text = llformat("%d", 0) ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 12, bottom - line_height / 2, text_color, LLFontGL::LEFT, LLFontGL::TOP); for(U32 i = 1 ; i < mTextureSizeBar.size() ; i++) { text = llformat("%d", (1 << (i / 2)) + ((i & 1) ? ((1 << (i / 2)) >> 1) : 0)) ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + i * mTextureSizeBarWidth + 12, bottom - line_height / 2, text_color, LLFontGL::LEFT, LLFontGL::TOP); } text = llformat("(w + h)/2") ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, right + 10, bottom - line_height / 2, text_color, LLFontGL::LEFT, LLFontGL::TOP); //------- //y axis: number label for(S32 i = bottom + 50 ; i <= top ; i += 50) { text = llformat("%d", (S32)((i - bottom) / scale)) ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left - 20, i + line_height / 2 , text_color, LLFontGL::LEFT, LLFontGL::TOP); LLFontGL::getFontMonospace()->renderUTF8(text, 0, right + 5, i + line_height / 2 , text_color, LLFontGL::LEFT, LLFontGL::TOP); } //-------------------------------------------------- F32 loaded_color[] = {1.0f, 0.0f, 0.0f, 0.75f}; gl_rect_2d(left + 70, top + line_height * 2, left + 90, top + line_height, loaded_color) ; text = llformat("Loaded") ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 100, top + line_height * 2, loaded_color, LLFontGL::LEFT, LLFontGL::TOP); F32 bound_color[] = {1.0f, 1.0f, 0.0f, 0.75f}; gl_rect_2d(left + 170, top + line_height * 2, left + 190, top + line_height, bound_color) ; text = llformat("Bound") ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 200, top + line_height * 2, bound_color, LLFontGL::LEFT, LLFontGL::TOP); //-------------------------------------------------- //title text = llformat("Texture Size Distribution") ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 250, top + line_height * 3, text_color, LLFontGL::LEFT, LLFontGL::TOP); return scale ; } //draw real-time texture mem bar over category void LLTextureSizeView::drawTextureCategoryGraph() { if(mTextureSizeBar.size() == 0) { S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); mTextureSizeBar.resize(LLViewerTexture::getTotalNumOfCategories()) ; mTextureSizeBarRect.set(700, line_height * 2 + 400, 700 + mTextureSizeBar.size() * mTextureSizeBarWidth, line_height * 2) ; for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++) { mTextureSizeBar[i] = new LLGLTexSizeBar(i, mTextureSizeBarRect.mLeft + i * mTextureSizeBarWidth , line_height * 2, mTextureSizeBarRect.mLeft + (i + 1) * mTextureSizeBarWidth, line_height) ; } } F32 size_bar_scale = drawTextureCategoryDistributionGraph() ; for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++) { U32 k = LLViewerTexture::getIndexFromCategory(i) ; mTextureSizeBar[i]->setTop(LLImageGL::sTextureMemByCategory[k] >> 20, LLImageGL::sTextureMemByCategoryBound[k] >> 20, size_bar_scale) ; mTextureSizeBar[i]->draw() ; } LLImageGL::resetCurTexSizebar(); } //draw background for TEXTURE_MEM_OVER_CATEGORY F32 LLTextureSizeView::drawTextureCategoryDistributionGraph() { //scale F32 scale = 4.0f ; LLGLSUIDefault gls_ui; { S32 count = 0 ; for(U32 i = 0 ; i < LLImageGL::sTextureMemByCategory.size() ; i++) { S32 tmp = LLImageGL::sTextureMemByCategory[i] >> 20 ; if(tmp > count) { count = tmp ; } } if(count > mTextureSizeBarRect.getHeight() * 0.25f) { scale = (F32)mTextureSizeBarRect.getHeight() * 0.25f / count ; } } S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); S32 left = mTextureSizeBarRect.mLeft ; S32 bottom = mTextureSizeBarRect.mBottom ; S32 right = mTextureSizeBarRect.mRight ; S32 top = mTextureSizeBarRect.mTop ; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); //background rect gl_rect_2d(left - 25, top + 30, right + 100, bottom - 25, LLColor4(0.0f, 0.0f, 0.0f, 0.25f)) ; //-------------------------------------------------- gGL.color4f(1.0f, 0.5f, 0.5f, 0.75f); gl_line_2d(left, bottom, right, bottom) ; //x axis gl_line_2d(left, bottom, left, top) ; //y axis //ruler //-------------------------------------------------- gGL.color4f(1.0f, 0.5f, 0.5f, 0.5f); for(S32 i = bottom + 50 ; i <= top ; i += 50) { gl_line_2d(left, i, right, i) ; } //texts //-------------------------------------------------- F32 text_color[] = {1.f, 1.f, 1.f, 0.75f}; std::string text; //------- //x axis: size label static char category[LLViewerTexture::MAX_GL_IMAGE_CATEGORY][4] = {"Non", "Bak", "Av", "Cld", "Scp", "Hi", "Trn", "Slt", "Hud", "Bsf", "UI", "Pvw", "Map", "Mvs", "Slf", "Loc", "Scr", "Dyn", "Mdi", "ALT", "Oth" } ; text = llformat("%s", category[0]) ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 12, bottom - line_height / 2, text_color, LLFontGL::LEFT, LLFontGL::TOP); for(U32 i = 1 ; i < mTextureSizeBar.size() ; i++) { text = llformat("%s", category[i]) ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + i * mTextureSizeBarWidth + 12, bottom - line_height / 2, text_color, LLFontGL::LEFT, LLFontGL::TOP); } //------- //y axis: number label for(S32 i = bottom + 50 ; i <= top ; i += 50) { text = llformat("%d", (S32)((i - bottom) / scale)) ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left - 20, i + line_height / 2 , text_color, LLFontGL::LEFT, LLFontGL::TOP); LLFontGL::getFontMonospace()->renderUTF8(text, 0, right + 5, i + line_height / 2 , text_color, LLFontGL::LEFT, LLFontGL::TOP); } text = llformat("MB") ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left - 20, top + line_height * 2 , text_color, LLFontGL::LEFT, LLFontGL::TOP); //-------------------------------------------------- F32 loaded_color[] = {1.0f, 0.0f, 0.0f, 0.75f}; gl_rect_2d(left + 70, top + line_height * 2, left + 90, top + line_height, loaded_color) ; text = llformat("Loaded") ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 100, top + line_height * 2, loaded_color, LLFontGL::LEFT, LLFontGL::TOP); F32 bound_color[] = {1.0f, 1.0f, 0.0f, 0.75f}; gl_rect_2d(left + 170, top + line_height * 2, left + 190, top + line_height, bound_color) ; text = llformat("Bound") ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 200, top + line_height * 2, bound_color, LLFontGL::LEFT, LLFontGL::TOP); //-------------------------------------------------- //title text = llformat("Texture Category Distribution") ; LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 250, top + line_height * 3, text_color, LLFontGL::LEFT, LLFontGL::TOP); return scale ; }