diff options
author | Monty Brandenberg <monty@lindenlab.com> | 2013-08-05 19:04:08 -0400 |
---|---|---|
committer | Monty Brandenberg <monty@lindenlab.com> | 2013-08-05 19:04:08 -0400 |
commit | 43788d612042deb6f9329746a101774370f7c67b (patch) | |
tree | 3688143c8ab7563b40bbc32dbdf598cd55b403d5 /indra | |
parent | 549e20cf7766dc7fba2f42883659a6bcac863d91 (diff) |
Added some simple counters to the mesh repository code and then
added a Mesh status line to the texture fetch console. Mesh is
often in competition with textures and so the mesh information
seems appropriate there. Do get a nice feel for progress and
you definitely see when the throttles kick in.
Diffstat (limited to 'indra')
-rwxr-xr-x | indra/newview/llmeshrepository.cpp | 134 | ||||
-rwxr-xr-x | indra/newview/llmeshrepository.h | 11 | ||||
-rwxr-xr-x | indra/newview/lltextureview.cpp | 41 |
3 files changed, 123 insertions, 63 deletions
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 7146c7f4f5..97d6c57a78 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -155,20 +155,26 @@ // // So, in addition to documentation, take this as a to-do/review // list and see if you can improve things. For porters to non-x86 -// architectures, including amd64, the weaker memory models will -// make these platforms probabilistically more susceptible to hitting -// race conditions. True here and in other multi-thread code such -// as texture fetching. +// architectures, the weaker memory models will make these platforms +// probabilistically more susceptible to hitting race conditions. +// True here and in other multi-thread code such as texture fetching. +// (Strong memory models make weak programmers. Weak memory models +// make strong programmers. Ref: arm, ppc, mips, alpha) // // LLMeshRepository: // // sBytesReceived +// sMeshRequestCount // sHTTPRequestCount +// sHTTPLargeRequestCount // sHTTPRetryCount +// sHTTPErrorCount // sLODPending // sLODProcessing // sCacheBytesRead // sCacheBytesWritten +// sCacheReads +// sCacheWrites // mLoadingMeshes none rw.main.none, rw.main.mMeshMutex [4] // mSkinMap none rw.main.none // mDecompositionMap none rw.main.none @@ -246,13 +252,19 @@ const long LARGE_MESH_XFER_TIMEOUT = 600L; // Seconds to complete xfer, large const S32 MAX_MESH_VERSION = 999; U32 LLMeshRepository::sBytesReceived = 0; +U32 LLMeshRepository::sMeshRequestCount = 0; U32 LLMeshRepository::sHTTPRequestCount = 0; +U32 LLMeshRepository::sHTTPLargeRequestCount = 0; U32 LLMeshRepository::sHTTPRetryCount = 0; +U32 LLMeshRepository::sHTTPErrorCount = 0; U32 LLMeshRepository::sLODProcessing = 0; U32 LLMeshRepository::sLODPending = 0; U32 LLMeshRepository::sCacheBytesRead = 0; U32 LLMeshRepository::sCacheBytesWritten = 0; +U32 LLMeshRepository::sCacheReads = 0; +U32 LLMeshRepository::sCacheWrites = 0; + LLDeadmanTimer LLMeshRepository::sQuiescentTimer(15.0, true); // true -> gather cpu metrics @@ -366,6 +378,7 @@ volatile S32 LLMeshRepoThread::sActiveLODRequests = 0; U32 LLMeshRepoThread::sMaxConcurrentRequests = 1; S32 LLMeshRepoThread::sRequestLowWater = REQUEST_LOW_WATER_MIN; S32 LLMeshRepoThread::sRequestHighWater = REQUEST_HIGH_WATER_MIN; +S32 LLMeshRepoThread::sRequestWaterLevel = 0; // Base handler class for all mesh users of llcorehttp. // This is roughly equivalent to a Responder class in @@ -619,9 +632,7 @@ LLMeshRepoThread::LLMeshRepoThread() mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), mHttpLegacyPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), - mHttpPriority(0), - mHttpGetCount(0U), - mHttpLargeGetCount(0U) + mHttpPriority(0) { mMutex = new LLMutex(NULL); mHeaderMutex = new LLMutex(NULL); @@ -641,8 +652,8 @@ LLMeshRepoThread::LLMeshRepoThread() LLMeshRepoThread::~LLMeshRepoThread() { - LL_INFOS(LOG_MESH) << "Small GETs issued: " << mHttpGetCount - << ", Large GETs issued: " << mHttpLargeGetCount + LL_INFOS(LOG_MESH) << "Small GETs issued: " << LLMeshRepository::sHTTPRequestCount + << ", Large GETs issued: " << LLMeshRepository::sHTTPLargeRequestCount << LL_ENDL; for (http_request_set::iterator iter(mHttpRequestSet.begin()); @@ -700,7 +711,8 @@ void LLMeshRepoThread::run() if (! LLApp::isQuitting()) { // NOTE: order of queue processing intentionally favors LOD requests over header requests - + + sRequestWaterLevel = mHttpRequestSet.size(); while (!mLODReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater) { if (! mMutex) @@ -743,19 +755,26 @@ void LLMeshRepoThread::run() // list, we scan the entire thing. This gets us through any requests // which can be resolved in the cache. It also keeps the request // set somewhat fresher otherwise items at the end of the set - // order will lose. Keep to the throttle enforcement and pay - // attention to the highwater level (enforced in each fetchXXX() - // method). + // order will lose. if (! mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater) { // *FIXME: this really does need a lock as do the following ones std::set<LLUUID> incomplete; for (std::set<LLUUID>::iterator iter = mSkinRequests.begin(); iter != mSkinRequests.end(); ++iter) { - LLUUID mesh_id = *iter; - if (!fetchMeshSkinInfo(mesh_id)) + if (mHttpRequestSet.size() < sRequestHighWater) + { + LLUUID mesh_id = *iter; + if (!fetchMeshSkinInfo(mesh_id)) + { + incomplete.insert(mesh_id); + } + } + else { - incomplete.insert(mesh_id); + // Hit high-water mark, copy remaining to incomplete. + incomplete.insert(iter, mSkinRequests.end()); + break; } } mSkinRequests.swap(incomplete); @@ -766,10 +785,19 @@ void LLMeshRepoThread::run() std::set<LLUUID> incomplete; for (std::set<LLUUID>::iterator iter = mDecompositionRequests.begin(); iter != mDecompositionRequests.end(); ++iter) { - LLUUID mesh_id = *iter; - if (!fetchMeshDecomposition(mesh_id)) + if (mHttpRequestSet.size() < sRequestHighWater) { - incomplete.insert(mesh_id); + LLUUID mesh_id = *iter; + if (!fetchMeshDecomposition(mesh_id)) + { + incomplete.insert(mesh_id); + } + } + else + { + // Hit high-water mark, copy remaining to incomplete. + incomplete.insert(iter, mDecompositionRequests.end()); + break; } } mDecompositionRequests.swap(incomplete); @@ -780,10 +808,19 @@ void LLMeshRepoThread::run() std::set<LLUUID> incomplete; for (std::set<LLUUID>::iterator iter = mPhysicsShapeRequests.begin(); iter != mPhysicsShapeRequests.end(); ++iter) { - LLUUID mesh_id = *iter; - if (!fetchMeshPhysicsShape(mesh_id)) + if (mHttpRequestSet.size() < sRequestHighWater) + { + LLUUID mesh_id = *iter; + if (!fetchMeshPhysicsShape(mesh_id)) + { + incomplete.insert(mesh_id); + } + } + else { - incomplete.insert(mesh_id); + // Hit high-water mark, copy remaining to incomplete. + incomplete.insert(iter, mPhysicsShapeRequests.end()); + break; } } mPhysicsShapeRequests.swap(incomplete); @@ -926,7 +963,10 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int c mHttpOptions, mHttpHeaders, handler); - ++mHttpGetCount; + if (LLCORE_HTTP_HANDLE_INVALID != handle) + { + ++LLMeshRepository::sHTTPRequestCount; + } } else { @@ -938,7 +978,10 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int c mHttpLargeOptions, mHttpHeaders, handler); - ++mHttpLargeGetCount; + if (LLCORE_HTTP_HANDLE_INVALID != handle) + { + ++LLMeshRepository::sHTTPLargeRequestCount; + } } if (LLCORE_HTTP_HANDLE_INVALID == handle) { @@ -965,7 +1008,8 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) return false; } - bool ret = true ; + ++LLMeshRepository::sMeshRequestCount; + bool ret = true; U32 header_size = mMeshHeaderSize[mesh_id]; if (header_size > 0) @@ -983,6 +1027,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) if (file.getSize() >= offset+size) { LLMeshRepository::sCacheBytesRead += size; + ++LLMeshRepository::sCacheReads; file.seek(offset); U8* buffer = new U8[size]; file.read(buffer, size); @@ -1007,10 +1052,6 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) } //reading from VFS failed for whatever reason, fetch from sim - if (mHttpRequestSet.size() >= sRequestHighWater) - { - return false; - } int cap_version(gMeshRepo.mGetMeshVersion); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) @@ -1025,12 +1066,12 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) << LL_ENDL; delete handler; ret = false; + } else { handler->mHttpHandle = handle; mHttpRequestSet.insert(handler); - ++LLMeshRepository::sHTTPRequestCount; } } } @@ -1059,8 +1100,9 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) return false; } + ++LLMeshRepository::sMeshRequestCount; U32 header_size = mMeshHeaderSize[mesh_id]; - bool ret = true ; + bool ret = true; if (header_size > 0) { @@ -1077,6 +1119,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) if (file.getSize() >= offset+size) { LLMeshRepository::sCacheBytesRead += size; + ++LLMeshRepository::sCacheReads; file.seek(offset); U8* buffer = new U8[size]; @@ -1102,10 +1145,6 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) } //reading from VFS failed for whatever reason, fetch from sim - if (mHttpRequestSet.size() >= sRequestHighWater) - { - return false; - } int cap_version(gMeshRepo.mGetMeshVersion); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) @@ -1125,7 +1164,6 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) { handler->mHttpHandle = handle; mHttpRequestSet.insert(handler); - ++LLMeshRepository::sHTTPRequestCount; } } } @@ -1154,8 +1192,9 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) return false; } + ++LLMeshRepository::sMeshRequestCount; U32 header_size = mMeshHeaderSize[mesh_id]; - bool ret = true ; + bool ret = true; if (header_size > 0) { @@ -1172,6 +1211,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) if (file.getSize() >= offset+size) { LLMeshRepository::sCacheBytesRead += size; + ++LLMeshRepository::sCacheReads; file.seek(offset); U8* buffer = new U8[size]; file.read(buffer, size); @@ -1196,10 +1236,6 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) } //reading from VFS failed for whatever reason, fetch from sim - if (mHttpRequestSet.size() >= sRequestHighWater) - { - return false; - } int cap_version(gMeshRepo.mGetMeshVersion); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) @@ -1219,7 +1255,6 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) { handler->mHttpHandle = handle; mHttpRequestSet.insert(handler); - ++LLMeshRepository::sHTTPRequestCount; } } } @@ -1268,6 +1303,8 @@ void LLMeshRepoThread::decActiveHeaderRequests() //return false if failed to get header bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) { + ++LLMeshRepository::sMeshRequestCount; + { //look for mesh in asset in vfs LLVFile file(gVFS, mesh_params.getSculptID(), LLAssetType::AT_MESH); @@ -1280,6 +1317,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) U8 buffer[MESH_HEADER_SIZE]; S32 bytes = llmin(size, MESH_HEADER_SIZE); LLMeshRepository::sCacheBytesRead += bytes; + ++LLMeshRepository::sCacheReads; file.read(buffer, bytes); if (headerReceived(mesh_params, buffer, bytes)) { @@ -1314,7 +1352,6 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) { handler->mHttpHandle = handle; mHttpRequestSet.insert(handler); - ++LLMeshRepository::sHTTPRequestCount; } } @@ -1331,6 +1368,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) mHeaderMutex->lock(); + ++LLMeshRepository::sMeshRequestCount; bool retval = true; LLUUID mesh_id = mesh_params.getSculptID(); @@ -1352,6 +1390,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) if (file.getSize() >= offset+size) { LLMeshRepository::sCacheBytesRead += size; + ++LLMeshRepository::sCacheReads; file.seek(offset); U8* buffer = new U8[size]; file.read(buffer, size); @@ -1395,7 +1434,6 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) { handler->mHttpHandle = handle; mHttpRequestSet.insert(handler); - ++LLMeshRepository::sHTTPRequestCount; } } else @@ -2364,6 +2402,7 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo if (! status) { processFailure(status); + ++LLMeshRepository::sHTTPErrorCount; } else { @@ -2484,6 +2523,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * body, U8 * data, S32 if (file.getMaxSize() >= bytes || file.setMaxSize(bytes)) { LLMeshRepository::sCacheBytesWritten += data_size; + ++LLMeshRepository::sCacheWrites; file.write(data, data_size); @@ -2556,6 +2596,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * body, U8 * data, S32 da file.seek(offset); file.write(data, size); LLMeshRepository::sCacheBytesWritten += size; + ++LLMeshRepository::sCacheWrites; } } // *TODO: Mark mesh unavailable on error @@ -2601,6 +2642,7 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * body, U8 * data, S if (file.getSize() >= offset+size) { LLMeshRepository::sCacheBytesWritten += size; + ++LLMeshRepository::sCacheWrites; file.seek(offset); file.write(data, size); } @@ -2648,6 +2690,7 @@ void LLMeshDecompositionHandler::processData(LLCore::BufferArray * body, U8 * da if (file.getSize() >= offset+size) { LLMeshRepository::sCacheBytesWritten += size; + ++LLMeshRepository::sCacheWrites; file.seek(offset); file.write(data, size); } @@ -2695,6 +2738,7 @@ void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * body, U8 * dat if (file.getSize() >= offset+size) { LLMeshRepository::sCacheBytesWritten += size; + ++LLMeshRepository::sCacheWrites; file.seek(offset); file.write(data, size); } @@ -4204,7 +4248,7 @@ void LLMeshRepository::metricsUpdate() LLSD metrics; metrics["reason"] = "Mesh Download Quiescent"; - metrics["scope"] = "Login"; + metrics["scope"] = metrics_teleport_start_count > 1 ? "Teleport" : "Login"; metrics["start"] = started; metrics["stop"] = stopped; metrics["fetches"] = LLSD::Integer(total_count); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 400ceb4ad7..7e89f60bc3 100755 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -224,6 +224,7 @@ public: static U32 sMaxConcurrentRequests; static S32 sRequestLowWater; static S32 sRequestHighWater; + static S32 sRequestWaterLevel; // Stats-use only, may read outside of thread LLMutex* mMutex; LLMutex* mHeaderMutex; @@ -387,10 +388,6 @@ private: LLCore::HttpHandle getByteRange(const std::string & url, int cap_version, size_t offset, size_t len, LLCore::HttpHandler * handler); - -private: - U32 mHttpGetCount; - U32 mHttpLargeGetCount; }; @@ -497,12 +494,18 @@ public: //metrics static U32 sBytesReceived; + static U32 sMeshRequestCount; static U32 sHTTPRequestCount; + static U32 sHTTPLargeRequestCount; static U32 sHTTPRetryCount; + static U32 sHTTPErrorCount; static U32 sLODPending; static U32 sLODProcessing; static U32 sCacheBytesRead; static U32 sCacheBytesWritten; + static U32 sCacheReads; + static U32 sCacheWrites; + static LLDeadmanTimer sQuiescentTimer; // time-to-complete-mesh-downloads after significant events static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index e80136b286..50edbb61a8 100755 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. + * Copyright (C) 2012-2013, 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 @@ -49,6 +49,7 @@ #include "llviewertexturelist.h" #include "llvovolume.h" #include "llviewerstats.h" +#include "llmeshrepository.h" // For avatar texture view #include "llvoavatarself.h" @@ -517,6 +518,8 @@ void LLGLTexMemBar::draw() F32 total_texture_downloaded = (F32)gTotalTextureBytes / (1024 * 1024); F32 total_object_downloaded = (F32)gTotalObjectBytes / (1024 * 1024); U32 total_http_requests = LLAppViewer::getTextureFetch()->getTotalNumHTTPRequests(); + F32 x_right = 0.0; + //---------------------------------------------------------------------------- LLGLSUIDefault gls_ui; LLColor4 text_color(1.f, 1.f, 1.f, 0.75f); @@ -543,7 +546,7 @@ void LLGLTexMemBar::draw() cache_max_usage); //, cache_entries, cache_max_entries - LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*4, + LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*5, text_color, LLFontGL::LEFT, LLFontGL::TOP); U32 cache_read(0U), cache_write(0U), res_wait(0U); @@ -557,13 +560,12 @@ void LLGLTexMemBar::draw() cache_write, res_wait); - LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3, + LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*4, text_color, LLFontGL::LEFT, LLFontGL::TOP); - S32 left = 0 ; //---------------------------------------------------------------------------- - 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", + 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, @@ -574,19 +576,30 @@ void LLGLTexMemBar::draw() LLAppViewer::getImageDecodeThread()->getPending(), gTextureList.mCreateTextureList.size()); - LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*2, - text_color, LLFontGL::LEFT, LLFontGL::TOP); - + x_right = 550.0; + LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3, + text_color, LLFontGL::LEFT, LLFontGL::TOP, + LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, + &x_right, FALSE); - 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 = 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, + text = llformat("BW:%.0f/%.0f", bandwidth, max_bandwidth); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, x_right, v_offset + line_height*3, color, LLFontGL::LEFT, LLFontGL::TOP); - + + // Mesh status line + text = llformat("Mesh: Reqs(Tot/Htp/Big): %u/%u/%u Rtr/Err: %u/%u Cread/Cwrite: %u/%u Low/At/High: %d/%d/%d", + LLMeshRepository::sMeshRequestCount, LLMeshRepository::sHTTPRequestCount, LLMeshRepository::sHTTPLargeRequestCount, + LLMeshRepository::sHTTPRetryCount, LLMeshRepository::sHTTPErrorCount, + LLMeshRepository::sCacheReads, LLMeshRepository::sCacheWrites, + LLMeshRepoThread::sRequestLowWater, LLMeshRepoThread::sRequestWaterLevel, LLMeshRepoThread::sRequestHighWater); + LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*2, + text_color, LLFontGL::LEFT, LLFontGL::TOP); + + // Header for texture table columns S32 dx1 = 0; if (LLAppViewer::getTextureFetch()->mDebugPause) { @@ -629,7 +642,7 @@ BOOL LLGLTexMemBar::handleMouseDown(S32 x, S32 y, MASK mask) LLRect LLGLTexMemBar::getRequiredRect() { LLRect rect; - rect.mTop = 50; //LLFontGL::getFontMonospace()->getLineHeight() * 6; + rect.mTop = 68; //LLFontGL::getFontMonospace()->getLineHeight() * 6; return rect; } |