From d72a21aca1b9692941c066b7aaca69952c27de68 Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Fri, 30 Jul 2010 15:17:32 -0700
Subject: [PATCH] further UI rendering performance improvements

---
 indra/llrender/llfontgl.cpp                   |  24 +-
 indra/llrender/llgl.cpp                       |   6 +-
 indra/llrender/llgl.h                         |   4 +-
 indra/llui/lllocalcliprect.cpp                |   6 +-
 indra/llui/lltextbase.cpp                     |  12 +-
 indra/llui/lltextbase.h                       |   2 +-
 indra/llui/lltexteditor.cpp                   |   7 +-
 indra/llui/llui.cpp                           | 390 +++++++++---------
 indra/llui/llui.h                             |   2 -
 indra/llui/llview.cpp                         |  38 +-
 indra/llui/llview.h                           |   1 -
 indra/newview/llspeakers.cpp                  |   5 +-
 indra/newview/llstatusbar.cpp                 |  89 ++--
 indra/newview/llstatusbar.h                   |   2 +
 indra/newview/llviewernetwork.cpp             |  22 +-
 indra/newview/llviewernetwork.h               |   3 +
 .../default/xui/en/panel_chat_header.xml      |  25 +-
 17 files changed, 331 insertions(+), 307 deletions(-)

diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 2240a2146c..d6c062fc5e 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -147,6 +147,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect
 S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
 					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
 {
+	LLFastTimer _(FTM_RENDER_FONTS);
+
 	if(!sDisplayFont) //do not display texts
 	{
 		return wstr.length() ;
@@ -193,9 +195,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 	origin.mV[VX] -= llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
 	origin.mV[VY] -= llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
 
-	LLFastTimer t(FTM_RENDER_FONTS);
-
-	gGL.color4fv( color.mV );
 
 	S32 chars_drawn = 0;
 	S32 i;
@@ -286,6 +285,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 	LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
 	LLColor4U colors[GLYPH_BATCH_SIZE * 4];
 
+	LLColor4U text_color(color);
+
+	S32 bitmap_num = -1;
 	S32 glyph_count = 0;
 	for (i = begin_offset; i < begin_offset + length; i++)
 	{
@@ -303,8 +305,13 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 			break;
 		}
 		// Per-glyph bitmap texture.
-		LLImageGL *image_gl = mFontFreetype->getFontBitmapCache()->getImageGL(fgi->mBitmapNum);
-		gGL.getTexUnit(0)->bind(image_gl);
+		S32 next_bitmap_num = fgi->mBitmapNum;
+		if (next_bitmap_num != bitmap_num)
+		{
+			bitmap_num = next_bitmap_num;
+			LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num);
+			gGL.getTexUnit(0)->bind(font_image);
+		}
 	
 		if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
 		{
@@ -335,7 +342,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 			glyph_count = 0;
 		}
 
-		drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, color, style_to_add, shadow, drop_shadow_strength);
+		drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style_to_add, shadow, drop_shadow_strength);
 
 		chars_drawn++;
 		cur_x += fgi->mXAdvance;
@@ -1145,7 +1152,6 @@ void LLFontGL::renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* c
 	colors_out[index] = color;
 }
 
-//FIXME: do colors out as well
 void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
 {
 	F32 slant_offset;
@@ -1199,8 +1205,8 @@ void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_
 	}
 	else if (shadow == DROP_SHADOW)
 	{
-		LLColor4 shadow_color = LLFontGL::sShadowColor;
-		shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength;
+		LLColor4U shadow_color = LLFontGL::sShadowColor;
+		shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength);
 		LLRectf screen_rect_shadow = screen_rect;
 		screen_rect_shadow.translate(1.f, -1.f);
 		renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_shadow, uv_rect, shadow_color, slant_offset);
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 7ff68fe34b..236594d602 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -1122,7 +1122,7 @@ void clear_glerror()
 //
 
 // Static members
-std::map<LLGLenum, LLGLboolean> LLGLState::sStateMap;
+boost::unordered_map<LLGLenum, LLGLboolean> LLGLState::sStateMap;
 
 GLboolean LLGLDepthTest::sDepthEnabled = GL_FALSE; // OpenGL default
 GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default
@@ -1170,7 +1170,7 @@ void LLGLState::resetTextureStates()
 void LLGLState::dumpStates() 
 {
 	LL_INFOS("RenderState") << "GL States:" << LL_ENDL;
-	for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
+	for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
 		 iter != sStateMap.end(); ++iter)
 	{
 		LL_INFOS("RenderState") << llformat(" 0x%04x : %s",(S32)iter->first,iter->second?"TRUE":"FALSE") << LL_ENDL;
@@ -1206,7 +1206,7 @@ void LLGLState::checkStates(const std::string& msg)
 		}
 	}
 	
-	for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
+	for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
 		 iter != sStateMap.end(); ++iter)
 	{
 		LLGLenum state = iter->first;
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 0c2da7dd08..c4f5d91e1a 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -36,7 +36,7 @@
 // This file contains various stuff for handling gl extensions and other gl related stuff.
 
 #include <string>
-#include <map>
+#include <boost/unordered_map.hpp>
 #include <list>
 
 #include "llerror.h"
@@ -241,7 +241,7 @@ public:
 	static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0x0001);
 	
 protected:
-	static std::map<LLGLenum, LLGLboolean> sStateMap;
+	static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap;
 	
 public:
 	enum { CURRENT_STATE = -2 };
diff --git a/indra/llui/lllocalcliprect.cpp b/indra/llui/lllocalcliprect.cpp
index 55329f64e4..805d5879f7 100644
--- a/indra/llui/lllocalcliprect.cpp
+++ b/indra/llui/lllocalcliprect.cpp
@@ -45,9 +45,9 @@ LLScreenClipRect::LLScreenClipRect(const LLRect& rect, BOOL enabled)
 	if (mEnabled)
 	{
 		pushClipRect(rect);
+		mScissorState.setEnabled(!sClipRectStack.empty());
+		updateScissorRegion();
 	}
-	mScissorState.setEnabled(!sClipRectStack.empty());
-	updateScissorRegion();
 }
 
 LLScreenClipRect::~LLScreenClipRect()
@@ -55,8 +55,8 @@ LLScreenClipRect::~LLScreenClipRect()
 	if (mEnabled)
 	{
 		popClipRect();
+		updateScissorRegion();
 	}
-	updateScissorRegion();
 }
 
 //static 
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 4bcf7e6980..cde08c7b19 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1495,24 +1495,32 @@ void LLTextBase::getSegmentAndOffset( S32 startpos, segment_set_t::iterator* seg
 
 LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index)
 {
+	static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment();
+
 	if (index > getLength()) { return mSegments.end(); }
 
 	// when there are no segments, we return the end iterator, which must be checked by caller
 	if (mSegments.size() <= 1) { return mSegments.begin(); }
 
 	//FIXME: avoid operator new somehow (without running into refcount problems)
-	segment_set_t::iterator it = mSegments.upper_bound(new LLIndexSegment(index));
+	index_segment->setStart(index);
+	index_segment->setEnd(index);
+	segment_set_t::iterator it = mSegments.upper_bound(index_segment);
 	return it;
 }
 
 LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 index) const
 {
+	static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment();
+
 	if (index > getLength()) { return mSegments.end(); }
 
 	// when there are no segments, we return the end iterator, which must be checked by caller
 	if (mSegments.size() <= 1) { return mSegments.begin(); }
 
-	LLTextBase::segment_set_t::const_iterator it =  mSegments.upper_bound(new LLIndexSegment(index));
+	index_segment->setStart(index);
+	index_segment->setEnd(index);
+	LLTextBase::segment_set_t::const_iterator it =  mSegments.upper_bound(index_segment);
 	return it;
 }
 
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 4b83d5effb..db010d1cf6 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -163,7 +163,7 @@ protected:
 class LLIndexSegment : public LLTextSegment
 {
 public:
-	LLIndexSegment(S32 pos) : LLTextSegment(pos, pos) {}
+	LLIndexSegment() : LLTextSegment(0, 0) {}
 };
 
 class LLInlineViewSegment : public LLTextSegment
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 6781c23416..482a53e4af 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -461,8 +461,13 @@ S32 LLTextEditor::nextWordPos(S32 cursorPos) const
 
 const LLTextSegmentPtr	LLTextEditor::getPreviousSegment() const
 {
+	static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment;
+
+	index_segment->setStart(mCursorPos);
+	index_segment->setEnd(mCursorPos);
+
 	// find segment index at character to left of cursor (or rightmost edge of selection)
-	segment_set_t::const_iterator it = mSegments.lower_bound(new LLIndexSegment(mCursorPos));
+	segment_set_t::const_iterator it = mSegments.lower_bound(index_segment);
 
 	if (it != mSegments.end())
 	{
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 7f9dca08d2..ee308f575a 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -466,7 +466,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border
 	gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect);
 }
 
-void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect, const LLRectf& scale_rect)
+void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_outer_rect, const LLRectf& center_rect)
 {
 	stop_glerror();
 
@@ -476,36 +476,53 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
 		return;
 	}
 
+	// add in offset of current image to current ui translation
+	const LLVector3 ui_translation = gGL.getUITranslation() + LLVector3(x, y, 0.f);
+	const LLVector3 ui_scale = gGL.getUIScale();
+
+	F32 uv_width = uv_outer_rect.getWidth();
+	F32 uv_height = uv_outer_rect.getHeight();
+
 	// shrink scaling region to be proportional to clipped image region
-	LLRectf scale_rect_uv(
-		uv_rect.mLeft + (scale_rect.mLeft * uv_rect.getWidth()),
-		uv_rect.mBottom + (scale_rect.mTop * uv_rect.getHeight()),
-		uv_rect.mLeft + (scale_rect.mRight * uv_rect.getWidth()),
-		uv_rect.mBottom + (scale_rect.mBottom * uv_rect.getHeight()));
-
-	S32 image_natural_width = llround((F32)image->getWidth(0) * uv_rect.getWidth());
-	S32 image_natural_height = llround((F32)image->getHeight(0) * uv_rect.getHeight());
-
-	LLRect draw_rect(0, height, width, 0);
-	LLRect draw_scale_rect(llround(scale_rect_uv.mLeft * (F32)image->getWidth(0)),
-						llround(scale_rect_uv.mTop * (F32)image->getHeight(0)),
-						llround(scale_rect_uv.mRight * (F32)image->getWidth(0)),
-						llround(scale_rect_uv.mBottom * (F32)image->getHeight(0)));
-	// scale fixed region of image to drawn region
-	draw_scale_rect.mRight += width - image_natural_width;
-	draw_scale_rect.mTop += height - image_natural_height;
-
-	S32 border_shrink_width = llmax(0, draw_scale_rect.mLeft - draw_scale_rect.mRight);
-	S32 border_shrink_height = llmax(0, draw_scale_rect.mBottom - draw_scale_rect.mTop);
-
-	F32 shrink_width_ratio = scale_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - scale_rect.getWidth()));
-	F32 shrink_height_ratio = scale_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - scale_rect.getHeight()));
-
-	F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio);
-	draw_scale_rect.mLeft = llround((F32)draw_scale_rect.mLeft * shrink_scale);
-	draw_scale_rect.mTop = llround(lerp((F32)height, (F32)draw_scale_rect.mTop, shrink_scale));
-	draw_scale_rect.mRight = llround(lerp((F32)width, (F32)draw_scale_rect.mRight, shrink_scale));
-	draw_scale_rect.mBottom = llround((F32)draw_scale_rect.mBottom * shrink_scale);
+	LLRectf uv_center_rect(
+		uv_outer_rect.mLeft + (center_rect.mLeft * uv_width),
+		uv_outer_rect.mBottom + (center_rect.mTop * uv_height),
+		uv_outer_rect.mLeft + (center_rect.mRight * uv_width),
+		uv_outer_rect.mBottom + (center_rect.mBottom * uv_height));
+
+	F32 image_width = image->getWidth(0);
+	F32 image_height = image->getHeight(0);
+
+	S32 image_natural_width = llround(image_width * uv_width);
+	S32 image_natural_height = llround(image_height * uv_height);
+
+	LLRectf draw_center_rect(	uv_center_rect.mLeft * image_width,
+								uv_center_rect.mTop * image_height,
+								uv_center_rect.mRight * image_width,
+								uv_center_rect.mBottom * image_height);
+
+	{	// scale fixed region of image to drawn region
+		draw_center_rect.mRight += width - image_natural_width;
+		draw_center_rect.mTop += height - image_natural_height;
+
+		F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight);
+		F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop);
+
+		F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth()));
+		F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight()));
+
+		F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio);
+
+		draw_center_rect.mLeft = llround(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * shrink_scale * ui_scale.mV[VX]);
+		draw_center_rect.mTop = llround(ui_translation.mV[VY] + lerp((F32)height, (F32)draw_center_rect.mTop, shrink_scale * ui_scale.mV[VY]));
+		draw_center_rect.mRight = llround(ui_translation.mV[VX] + lerp((F32)width, (F32)draw_center_rect.mRight, shrink_scale * ui_scale.mV[VX]));
+		draw_center_rect.mBottom = llround(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * shrink_scale * ui_scale.mV[VY]);
+	}
+
+	LLRectf draw_outer_rect(ui_translation.mV[VX], 
+							ui_translation.mV[VY] + height * ui_scale.mV[VY], 
+							ui_translation.mV[VX] + width * ui_scale.mV[VX], 
+							ui_translation.mV[VY]);
 
 	LLGLSUIDefault gls_ui;
 	
@@ -515,136 +532,174 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex
 		gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA);
 	}
 
-	gGL.pushUIMatrix();
-	{
-		gGL.translateUI((F32)x, (F32)y, 0.f);
+	gGL.getTexUnit(0)->bind(image);
 
-		gGL.getTexUnit(0)->bind(image);
+	gGL.color4fv(color.mV);
+	
+	const S32 NUM_VERTICES = 9 * 4; // 9 quads
+	LLVector2 uv[NUM_VERTICES];
+	LLVector3 pos[NUM_VERTICES];
 
-		gGL.color4fv(color.mV);
-		
-		gGL.begin(LLRender::QUADS);
-		{
-			// draw bottom left
-			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
-			gGL.vertex2i(0, 0);
+	S32 index = 0;
 
-			gGL.texCoord2f(scale_rect_uv.mLeft, uv_rect.mBottom);
-			gGL.vertex2i(draw_scale_rect.mLeft, 0);
+	gGL.begin(LLRender::QUADS);
+	{
+		// draw bottom left
+		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom);
+		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mBottom);
-			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(uv_rect.mLeft, scale_rect_uv.mBottom);
-			gGL.vertex2i(0, draw_scale_rect.mBottom);
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			// draw bottom middle
-			gGL.texCoord2f(scale_rect_uv.mLeft, uv_rect.mBottom);
-			gGL.vertex2i(draw_scale_rect.mLeft, 0);
+		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mRight, uv_rect.mBottom);
-			gGL.vertex2i(draw_scale_rect.mRight, 0);
+		// draw bottom middle
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mBottom);
-			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mBottom);
-			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			// draw bottom right
-			gGL.texCoord2f(scale_rect_uv.mRight, uv_rect.mBottom);
-			gGL.vertex2i(draw_scale_rect.mRight, 0);
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
-			gGL.vertex2i(width, 0);
+		// draw bottom right
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(uv_rect.mRight, scale_rect_uv.mBottom);
-			gGL.vertex2i(width, draw_scale_rect.mBottom);
+		uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom);
+		pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mBottom);
-			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			// draw left 
-			gGL.texCoord2f(uv_rect.mLeft, scale_rect_uv.mBottom);
-			gGL.vertex2i(0, draw_scale_rect.mBottom);
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mBottom);
-			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+		// draw left 
+		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mTop);
-			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(uv_rect.mLeft, scale_rect_uv.mTop);
-			gGL.vertex2i(0, draw_scale_rect.mTop);
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+		index++;
 
-			// draw middle
-			gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mBottom);
-			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mBottom);
+		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mBottom);
-			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+		// draw middle
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mTop);
-			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mTop);
-			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+		index++;
 
-			// draw right 
-			gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mBottom);
-			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mBottom);
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(uv_rect.mRight, scale_rect_uv.mBottom);
-			gGL.vertex2i(width, draw_scale_rect.mBottom);
+		// draw right 
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(uv_rect.mRight, scale_rect_uv.mTop);
-			gGL.vertex2i(width, draw_scale_rect.mTop);
+		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom);
+		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mTop);
-			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
+		index++;
 
-			// draw top left
-			gGL.texCoord2f(uv_rect.mLeft, scale_rect_uv.mTop);
-			gGL.vertex2i(0, draw_scale_rect.mTop);
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mTop);
-			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+		// draw top left
+		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mLeft, uv_rect.mTop);
-			gGL.vertex2i(draw_scale_rect.mLeft, height);
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
-			gGL.vertex2i(0, height);
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
+		index++;
 
-			// draw top middle
-			gGL.texCoord2f(scale_rect_uv.mLeft, scale_rect_uv.mTop);
-			gGL.vertex2i(draw_scale_rect.mLeft, draw_scale_rect.mTop);
+		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop);
+		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mTop);
-			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+		// draw top middle
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mRight, uv_rect.mTop);
-			gGL.vertex2i(draw_scale_rect.mRight, height);
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mLeft, uv_rect.mTop);
-			gGL.vertex2i(draw_scale_rect.mLeft, height);
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
+		index++;
 
-			// draw top right
-			gGL.texCoord2f(scale_rect_uv.mRight, scale_rect_uv.mTop);
-			gGL.vertex2i(draw_scale_rect.mRight, draw_scale_rect.mTop);
+		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(uv_rect.mRight, scale_rect_uv.mTop);
-			gGL.vertex2i(width, draw_scale_rect.mTop);
+		// draw top right
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
-			gGL.vertex2i(width, height);
+		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop);
+		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f);
+		index++;
 
-			gGL.texCoord2f(scale_rect_uv.mRight, uv_rect.mTop);
-			gGL.vertex2i(draw_scale_rect.mRight, height);
-		}
-		gGL.end();
+		uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop);
+		pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f);
+		index++;
+
+		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop);
+		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f);
+		index++;
+
+		gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
 	}
-	gGL.popUIMatrix();
+	gGL.end();
 
 	if (solid_color)
 	{
@@ -674,25 +729,36 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
 
 	if (degrees == 0.f)
 	{
-		gGL.pushUIMatrix();
-		gGL.translateUI((F32)x, (F32)y, 0.f);
-			
+		const S32 NUM_VERTICES = 4; // 9 quads
+		LLVector2 uv[NUM_VERTICES];
+		LLVector3 pos[NUM_VERTICES];
+
 		gGL.begin(LLRender::QUADS);
 		{
-			gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
-			gGL.vertex2i(width, height );
+			LLVector3 ui_translation = gGL.getUITranslation();
+			ui_translation.mV[VX] += x;
+			ui_translation.mV[VY] += y;
+			S32 index = 0;
 
-			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
-			gGL.vertex2i(0, height );
+			uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
+			pos[index] = LLVector3(ui_translation.mV[VX] + width, ui_translation.mV[VY] + height, 0.f);
+			index++;
 
-			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
-			gGL.vertex2i(0, 0);
+			uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
+			pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY] + height, 0.f);
+			index++;
 
-			gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
-			gGL.vertex2i(width, 0);
+			uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
+			pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY], 0.f);
+			index++;
+
+			uv[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
+			pos[index] = LLVector3(ui_translation.mV[VX] + width, ui_translation.mV[VY], 0.f);
+			index++;
+
+			gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES);
 		}
 		gGL.end();
-		gGL.popUIMatrix();
 	}
 	else
 	{
@@ -761,25 +827,6 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL
 	LLUI::setLineWidth(1.f);
 }
 
-
-void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom)
-{
-	gGL.color4fv( LLColor4::white.mV );
-	glLogicOp( GL_XOR );
-	stop_glerror();
-
-	gGL.begin(LLRender::QUADS);
-		gGL.vertex2i(left, top);
-		gGL.vertex2i(left, bottom);
-		gGL.vertex2i(right, bottom);
-		gGL.vertex2i(right, top);
-	gGL.end();
-
-	glLogicOp( GL_COPY );
-	stop_glerror();
-}
-
-
 void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle)
 {
 	if (end_angle < start_angle)
@@ -1013,42 +1060,6 @@ void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians,
 	gGL.end();
 }
 
-// Draws spokes around a circle.
-void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LLColor4& inner_color, const LLColor4& outer_color)
-{
-	const F32 DELTA = F_TWO_PI / count;
-	const F32 HALF_DELTA = DELTA * 0.5f;
-	const F32 SIN_DELTA = sin( DELTA );
-	const F32 COS_DELTA = cos( DELTA );
-
-	F32 x1 = outer_radius * cos( HALF_DELTA );
-	F32 y1 = outer_radius * sin( HALF_DELTA );
-	F32 x2 = inner_radius * cos( HALF_DELTA );
-	F32 y2 = inner_radius * sin( HALF_DELTA );
-
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
-	gGL.begin( LLRender::LINES  );
-	{
-		while( count-- )
-		{
-			gGL.color4fv(outer_color.mV);
-			gGL.vertex2f( x1, y1 );
-			gGL.color4fv(inner_color.mV);
-			gGL.vertex2f( x2, y2 );
-
-			F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA;
-			y1 = x1 * SIN_DELTA +  y1 * COS_DELTA;
-			x1 = x1_new;
-
-			F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA;
-			y2 = x2 * SIN_DELTA +  y2 * COS_DELTA;
-			x2 = x2_new;
-		}
-	}
-	gGL.end();
-}
-
 void gl_rect_2d_simple_tex( S32 width, S32 height )
 {
 	gGL.begin( LLRender::QUADS );
@@ -1236,6 +1247,7 @@ void gl_segmented_rect_2d_tex(const S32 left,
 	gGL.popUIMatrix();
 }
 
+//FIXME: rewrite to use scissor?
 void gl_segmented_rect_2d_fragment_tex(const S32 left, 
 									   const S32 top, 
 									   const S32 right, 
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index c18262ef76..745d0ff662 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -96,7 +96,6 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor
 void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac);
 void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color);
 void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color);
-void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LLColor4& inner_color, const LLColor4& outer_color);
 
 void gl_draw_image(S32 x, S32 y, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
@@ -105,7 +104,6 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
 void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 
-void gl_rect_2d_xor(S32 left, S32 top, S32 right, S32 bottom);
 void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f ); 
 
 void gl_rect_2d_simple_tex( S32 width, S32 height );
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 9e68277b0f..4d3708302b 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -403,28 +403,40 @@ bool LLCompareByTabOrder::operator() (const LLView* const a, const LLView* const
 	return (a_score == b_score) ? a < b : a_score < b_score;
 }
 
-bool LLView::trueToRoot(const boost::function<bool (const LLView*)>& predicate) const
+BOOL LLView::isInVisibleChain() const
 {
-	const LLView* cur_view = this;
-	while(cur_view)
+	BOOL visible = TRUE;
+
+	const LLView* viewp = this;
+	while(viewp)
 	{
-		if(!predicate(cur_view))
+		if (!viewp->getVisible())
 		{
-			return false;
+			visible = FALSE;
+			break;
 		}
-		cur_view = cur_view->getParent();
+		viewp = viewp->getParent();
 	}
-	return true;
-}
-
-BOOL LLView::isInVisibleChain() const
-{
-	return trueToRoot(&LLView::getVisible);
+	
+	return visible;
 }
 
 BOOL LLView::isInEnabledChain() const
 {
-	return trueToRoot(&LLView::getEnabled);
+	BOOL enabled = TRUE;
+
+	const LLView* viewp = this;
+	while(viewp)
+	{
+		if (!viewp->getEnabled())
+		{
+			enabled = FALSE;
+			break;
+		}
+		viewp = viewp->getParent();
+	}
+	
+	return enabled;
 }
 
 // virtual
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 745a1b6e74..37f5232f91 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -273,7 +273,6 @@ public:
 	S32 getDefaultTabGroup() const				{ return mDefaultTabGroup; }
 	S32 getLastTabGroup()						{ return mLastTabGroup; }
 
-	bool        trueToRoot(const boost::function<bool (const LLView*)>& predicate) const;
 	BOOL		isInVisibleChain() const;
 	BOOL		isInEnabledChain() const;
 
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index bf00b47c21..5128ab6a18 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -74,7 +74,10 @@ LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerTy
 
 void LLSpeaker::lookupName()
 {
-	gCacheName->get(mID, FALSE, boost::bind(&LLSpeaker::onAvatarNameLookup, this, _1, _2, _3, _4));
+	if (mDisplayName.empty())
+	{
+		gCacheName->get(mID, FALSE, boost::bind(&LLSpeaker::onAvatarNameLookup, this, _1, _2, _3, _4));
+	}
 }
 
 void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group)
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index fc5937ea7d..213925ecdf 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -195,9 +195,6 @@ BOOL LLStatusBar::postBuild()
 
 	gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&LLStatusBar::onVolumeChanged, this, _2));
 
-	childSetAction("scriptout", onClickScriptDebug, this);
-	childSetAction("health", onClickHealth, this);
-
 	// Adding Net Stat Graph
 	S32 x = getRect().getWidth() - 2;
 	S32 y = 0;
@@ -247,14 +244,17 @@ BOOL LLStatusBar::postBuild()
 	mPanelNearByMedia->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT);
 	mPanelNearByMedia->setVisible(FALSE);
 
+	mScriptOut = getChildView("scriptout");
+
 	return TRUE;
 }
 
 // Per-frame updates of visibility
 void LLStatusBar::refresh()
 {
-	bool net_stats_visible = gSavedSettings.getBOOL("ShowNetStats");
-	
+	static LLCachedControl<bool> show_net_stats(gSavedSettings, "ShowNetStats", false);
+	bool net_stats_visible = show_net_stats;
+
 	if (net_stats_visible)
 	{
 		// Adding Net Stat Meter back in
@@ -266,26 +266,30 @@ void LLStatusBar::refresh()
 		mSGBandwidth->setThreshold(2, bwtotal);
 	}
 	
-	// Get current UTC time, adjusted for the user's clock
-	// being off.
-	time_t utc_time;
-	utc_time = time_corrected();
-
-	std::string timeStr = getString("time");
-	LLSD substitution;
-	substitution["datetime"] = (S32) utc_time;
-	LLStringUtil::format (timeStr, substitution);
-	mTextTime->setText(timeStr);
-
-	// set the tooltip to have the date
-	std::string dtStr = getString("timeTooltip");
-	LLStringUtil::format (dtStr, substitution);
-	mTextTime->setToolTip (dtStr);
+	// update clock every 10 seconds
+	if(mClockUpdateTimer.getElapsedTimeF32() > 10.f)
+	{
+		mClockUpdateTimer.reset();
+
+		// Get current UTC time, adjusted for the user's clock
+		// being off.
+		time_t utc_time;
+		utc_time = time_corrected();
+
+		std::string timeStr = getString("time");
+		LLSD substitution;
+		substitution["datetime"] = (S32) utc_time;
+		LLStringUtil::format (timeStr, substitution);
+		mTextTime->setText(timeStr);
+
+		// set the tooltip to have the date
+		std::string dtStr = getString("timeTooltip");
+		LLStringUtil::format (dtStr, substitution);
+		mTextTime->setToolTip (dtStr);
+	}
 
 	LLRect r;
 	const S32 MENU_RIGHT = gMenuBarView->getRightmostMenuEdge();
-	S32 x = MENU_RIGHT + MENU_PARCEL_SPACING;
-	S32 y = 0;
 
 	// reshape menu bar to its content's width
 	if (MENU_RIGHT != gMenuBarView->getRect().getWidth())
@@ -293,47 +297,6 @@ void LLStatusBar::refresh()
 		gMenuBarView->reshape(MENU_RIGHT, gMenuBarView->getRect().getHeight());
 	}
 
-	LLViewerRegion *region = gAgent.getRegion();
-	LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-
-	LLRect buttonRect;
-
-	if (LLHUDIcon::iconsNearby())
-	{
-		LLView* script_out = getChildView("scriptout");
-		buttonRect = script_out->getRect();
-		r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight());
-		script_out->setShape(r);
-		script_out->setVisible( true);
-		x += buttonRect.getWidth();
-	}
-	else
-	{
-		getChildView("scriptout")->setVisible( false);
-	}
-
-	if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK &&
-		((region && region->getAllowDamage()) || (parcel && parcel->getAllowDamage())))
-	{
-		// set visibility based on flashing
-		if( mHealthTimer->hasExpired() )
-		{
-			getChildView("health")->setVisible( true);
-		}
-		else
-		{
-			BOOL flash = S32(mHealthTimer->getElapsedSeconds() * ICON_FLASH_FREQUENCY) & 1;
-			getChildView("health")->setVisible( flash);
-		}
-
-		// Health
-		LLView* healthp = getChildView("health");
-		buttonRect = healthp->getRect();
-		r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight());
-		healthp->setShape(r);
-		x += buttonRect.getWidth();
-	}
-
 	mSGBandwidth->setVisible(net_stats_visible);
 	mSGPacketLoss->setVisible(net_stats_visible);
 	getChildView("stat_btn")->setEnabled(net_stats_visible);
diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h
index 32f29e9e1c..2e2187bafe 100644
--- a/indra/newview/llstatusbar.h
+++ b/indra/newview/llstatusbar.h
@@ -112,6 +112,8 @@ private:
 
 	LLButton	*mBtnVolume;
 	LLButton	*mMediaToggle;
+	LLView*		mScriptOut;
+	LLFrameTimer	mClockUpdateTimer;
 
 	S32				mBalance;
 	S32				mHealth;
diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp
index fec112b9e7..1fac4d003d 100644
--- a/indra/newview/llviewernetwork.cpp
+++ b/indra/newview/llviewernetwork.cpp
@@ -49,6 +49,7 @@ const char* DEFAULT_SLURL_BASE = "https://%s/region/";
 const char* DEFAULT_APP_SLURL_BASE = "x-grid-location-info://%s/app";
 
 LLGridManager::LLGridManager()
+:	mIsInProductionGrid(false)
 {
 	// by default, we use the 'grids.xml' file in the user settings directory
 	// this file is an LLSD file containing multiple grid definitions.
@@ -308,6 +309,10 @@ void LLGridManager::initialize(const std::string& grid_file)
 		addGrid(grid);		
 	}
 
+	gSavedSettings.getControl("CurrentGrid")->getSignal()->connect(boost::bind(&LLGridManager::updateIsInProductionGrid, this));
+	// since above only triggers on changes, trigger the callback manually to initialize state
+	updateIsInProductionGrid();
+
 	LL_DEBUGS("GridManager") << "Selected grid is " << mGrid << LL_ENDL;		
 	setGridChoice(mGrid);
 	if(mGridList[mGrid][GRID_LOGIN_URI_VALUE].isArray())
@@ -559,23 +564,30 @@ std::string LLGridManager::getLoginPage()
 	return mGridList[mGrid][GRID_LOGIN_PAGE_VALUE];
 }
 
-bool LLGridManager::isInProductionGrid()
+void LLGridManager::updateIsInProductionGrid()
 {
+	mIsInProductionGrid = false;
+
 	// *NOTE:Mani This used to compare GRID_INFO_AGNI to gGridChoice,
 	// but it seems that loginURI trumps that.
 	std::vector<std::string> uris;
 	getLoginURIs(uris);
-	if (uris.size() < 1)
+	if (uris.empty())
 	{
-		return 1;
+		mIsInProductionGrid = true;
+		return;
 	}
 	LLStringUtil::toLower(uris[0]);
 	if((uris[0].find("agni") != std::string::npos))
 	{
-		return true;
+		mIsInProductionGrid = true;
+		return;
 	}
+}
 
-	return false;
+bool LLGridManager::isInProductionGrid()
+{
+	return mIsInProductionGrid;
 }
 
 void LLGridManager::saveFavorites()
diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h
index 8c3a15b7cf..f6cbd57ac0 100644
--- a/indra/newview/llviewernetwork.h
+++ b/indra/newview/llviewernetwork.h
@@ -136,6 +136,8 @@ public:
 
 protected:
 
+	void updateIsInProductionGrid();
+
 	// helper function for adding the predefined grids
 	void addSystemGrid(const std::string& label, 
 					   const std::string& name, 
@@ -148,6 +150,7 @@ protected:
 	std::string mGrid;
 	std::string mGridFile;
 	LLSD mGridList;
+	bool mIsInProductionGrid;
 };
 
 const S32 MAC_ADDRESS_BYTES = 6;
diff --git a/indra/newview/skins/default/xui/en/panel_chat_header.xml b/indra/newview/skins/default/xui/en/panel_chat_header.xml
index c98213f6c7..17e8d4d2df 100644
--- a/indra/newview/skins/default/xui/en/panel_chat_header.xml
+++ b/indra/newview/skins/default/xui/en/panel_chat_header.xml
@@ -38,16 +38,17 @@
       use_ellipses="true"
       valign="bottom" 
       value="Ericag Vader" />
-    <text
-            font="SansSerifSmall"
-         follows="right"
-         halign="right"
-         height="13"
-         layout="topleft"
-         left_pad="5"
-     name="time_box"
-     right="-5"
-     top="8"
-         value="23:30"
-         width="110" />
+  <text
+    allow_scroll="false"
+    font="SansSerifSmall"
+    follows="right"
+    halign="right"
+    height="13"
+    layout="topleft"
+    left_pad="5"
+    name="time_box"
+    right="-5"
+    top="8"
+    value="23:30"
+    width="110" />
 </panel>
-- 
GitLab