diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index f2da859e23d75ea2288fc96570483a4ea7909774..89dd68da76403f74ccfc7e18555cd21c151f0122 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -812,6 +812,7 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32
 
 					if (LLRender::sGLCoreProfile)
 					{
+                        LL_PROFILE_GPU_ZONE("generate mip map");
 						glGenerateMipmap(mTarget);
 					}	
 					stop_glerror();
@@ -1519,6 +1520,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 // Call with void data, vmem is allocated but unitialized
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+    LL_PROFILE_GPU_ZONE("createGLTexture");
     checkActiveThread();
 
     bool main_thread = on_main_thread();
@@ -1736,6 +1738,8 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name)
             syncTexName(new_tex_name);
             unref();
         });
+
+    LL_PROFILER_GPU_COLLECT;
 }
 
 
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 85c2a48279391cfcdd543ecdc09ac89bf15bd504..85d6209964afa774fdd761e3d86b136d1d4f0f6c 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -513,6 +513,7 @@ void LLRenderTarget::bindTarget()
 
 void LLRenderTarget::clear(U32 mask_in)
 {
+    LL_PROFILE_GPU_ZONE("clear");
 	U32 mask = GL_COLOR_BUFFER_BIT;
 	if (mUseDepth)
 	{
@@ -677,6 +678,7 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0
 	}
 
 	{
+        LL_PROFILE_GPU_ZONE("copyContentsToFramebuffer");
 		GLboolean write_depth = mask & GL_DEPTH_BUFFER_BIT ? TRUE : FALSE;
 
 		LLGLDepthTest depth(write_depth, write_depth);
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 02b3c25129ee8744f10c0b3fbfc990f00c605db6..67c50294e172bdd3fe690b36f0f6c91eadb1ef50 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -3575,7 +3575,10 @@ void LLWindowWin32::swapBuffers()
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
     ASSERT_MAIN_THREAD();
-    glFlush(); //superstitious flush for maybe frame stall removal?
+    {
+        LL_PROFILE_GPU_ZONE("flush");
+        glFlush(); //superstitious flush for maybe frame stall removal?
+    }
 	SwapBuffers(mhDC);
 
     LL_PROFILER_GPU_COLLECT;
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index a43b30465b79a802512ce913522617db6f3bae0a..89b8ec1ba2eeae3624aeaa71d855871251ffba2b 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -160,10 +160,10 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
     if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField") && !gCubeSnapshot)
     { 
         //update depth buffer sampler
-        gPipeline.mScreen.flush();
-        gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(),
-            0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
-        gPipeline.mDeferredDepth.bindTarget();
+        gPipeline.mRT->screen.flush();
+        gPipeline.mRT->deferredDepth.copyContents(gPipeline.mRT->deferredScreen, 0, 0, gPipeline.mRT->deferredScreen.getWidth(), gPipeline.mRT->deferredScreen.getHeight(),
+            0, 0, gPipeline.mRT->deferredDepth.getWidth(), gPipeline.mRT->deferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+        gPipeline.mRT->deferredDepth.bindTarget();
         simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram;
 
         simple_shader->bind();
@@ -177,8 +177,8 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
         renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, 
             true); // <--- discard mostly transparent faces
 
-        gPipeline.mDeferredDepth.flush();
-        gPipeline.mScreen.bindTarget();
+        gPipeline.mRT->deferredDepth.flush();
+        gPipeline.mRT->screen.bindTarget();
         gGL.setColorMask(true, false);
     }
 
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index fe5120376c2420b6b4e59657161457174f440164..7279e1ad6d59bef80ec5c9b199ff5acde6a2adc8 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -330,8 +330,8 @@ void LLFloaterModelPreview::initModelPreview()
 	S32 tex_width = 512;
 	S32 tex_height = 512;
 
-	S32 max_width = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mScreenWidth);
-	S32 max_height = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mScreenHeight);
+	S32 max_width = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mRT->width);
+	S32 max_height = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mRT->height);
 
 	while ((tex_width << 1) < max_width)
 	{
diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp
index 4ac2803208abffb213d308a8c8ac60a756bebe72..54a627efd4dc307b4aed6130f1d62b30858d528b 100644
--- a/indra/newview/llreflectionmap.cpp
+++ b/indra/newview/llreflectionmap.cpp
@@ -47,8 +47,8 @@ void LLReflectionMap::update(U32 resolution, U32 face)
     llassert(LLPipeline::sRenderDeferred);
     
     // make sure we don't walk off the edge of the render target
-    while (resolution > gPipeline.mDeferredScreen.getWidth() ||
-        resolution > gPipeline.mDeferredScreen.getHeight())
+    while (resolution > gPipeline.mRT->deferredScreen.getWidth() ||
+        resolution > gPipeline.mRT->deferredScreen.getHeight())
     {
         resolution /= 2;
     }
@@ -57,17 +57,11 @@ void LLReflectionMap::update(U32 resolution, U32 face)
 
 bool LLReflectionMap::shouldUpdate()
 {
-    const F32 UPDATE_INTERVAL = 10.f; // update no more than this often
     const F32 TIMEOUT_INTERVAL = 30.f; // update no less than this often
     const F32 RENDER_TIMEOUT = 1.f; // don't update if hasn't been used for rendering for this long
     
     if (mLastBindTime > gFrameTimeSeconds - RENDER_TIMEOUT)
     {   
-        if (mDirty && mLastUpdateTime < gFrameTimeSeconds - UPDATE_INTERVAL)
-        {
-            return true;
-        }
-
         if (mLastUpdateTime < gFrameTimeSeconds - TIMEOUT_INTERVAL)
         {
             return true;
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index fb98a2a6d432d5d69d8ba0b6feca51caa30a6ef3..db6622239dcf9eee73529b57ecd528efcd0cd210 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -39,6 +39,9 @@ extern BOOL gTeleportDisplay;
 
 //#pragma optimize("", off)
 
+// experimental pipeline render target override, if this works, do something less hacky
+LLPipeline::RenderTargetPack gProbeRT;
+
 LLReflectionMapManager::LLReflectionMapManager()
 {
     for (int i = 0; i < LL_REFLECTION_PROBE_COUNT; ++i)
@@ -89,13 +92,20 @@ void LLReflectionMapManager::update()
         U32 color_fmt = GL_RGBA;
         const bool use_depth_buffer = true;
         const bool use_stencil_buffer = true;
-        U32 targetRes = LL_REFLECTION_PROBE_RESOLUTION * 4; // super sample
+        U32 targetRes = LL_REFLECTION_PROBE_RESOLUTION * 2; // super sample
         mRenderTarget.allocate(targetRes, targetRes, color_fmt, use_depth_buffer, use_stencil_buffer, LLTexUnit::TT_RECT_TEXTURE);
+
+        // hack to allocate render targets using gPipeline code
+        auto* old_rt = gPipeline.mRT;
+        gPipeline.mRT = &gProbeRT;
+        gPipeline.allocateScreenBuffer(targetRes, targetRes);
+        gPipeline.allocateShadowBuffer(targetRes, targetRes);
+        gPipeline.mRT = old_rt;
     }
 
     if (mMipChain.empty())
     {
-        U32 res = LL_REFLECTION_PROBE_RESOLUTION*2;
+        U32 res = LL_REFLECTION_PROBE_RESOLUTION;
         U32 count = log2((F32)res) + 0.5f;
         
         mMipChain.resize(count);
@@ -150,7 +160,7 @@ void LLReflectionMapManager::update()
 
     bool did_update = false;
 
-    LLReflectionMap* oldestProbe = mProbes[0];
+    LLReflectionMap* oldestProbe = nullptr;
 
     if (mUpdatingProbe != nullptr)
     {
@@ -172,25 +182,9 @@ void LLReflectionMapManager::update()
 
         LLVector4a d;
         
-        if (probe->shouldUpdate() && !did_update && i < LL_REFLECTION_PROBE_COUNT)
-        {
-            if (probe->mCubeIndex == -1)
-            {
-                probe->mCubeArray = mTexture;
-                probe->mCubeIndex = allocateCubeIndex();
-            }
-
-            did_update = true; // only update one probe per frame
-            probe->autoAdjustOrigin();
-
-            mUpdatingProbe = probe;
-            doProbeUpdate();
-            probe->mDirty = false;
-        }
-
-        if (probe->mCubeArray.notNull() && 
-            probe->mCubeIndex != -1 && 
-            probe->mLastUpdateTime < oldestProbe->mLastUpdateTime)
+        if (!did_update && 
+            i < LL_REFLECTION_PROBE_COUNT &&
+            (oldestProbe == nullptr || probe->mLastUpdateTime < oldestProbe->mLastUpdateTime))
         {
             oldestProbe = probe;
         }
@@ -199,12 +193,21 @@ void LLReflectionMapManager::update()
         probe->mDistance = d.getLength3().getF32()-probe->mRadius;
     }
 
-#if 0
-    if (mUpdatingProbe == nullptr &&
-        oldestProbe->mCubeArray.notNull() &&
-        oldestProbe->mCubeIndex != -1)
-    { // didn't find any probes to update, update the most out of date probe that's currently in use on next frame
-        mUpdatingProbe = oldestProbe;
+#if 1
+    if (!did_update && oldestProbe != nullptr)
+    {
+        LLReflectionMap* probe = oldestProbe;
+        if (probe->mCubeIndex == -1)
+        {
+            probe->mCubeArray = mTexture;
+            probe->mCubeIndex = allocateCubeIndex();
+        }
+
+        probe->autoAdjustOrigin();
+
+        mUpdatingProbe = probe;
+        doProbeUpdate();
+        probe->mDirty = false;
     }
 #endif
 
@@ -372,7 +375,10 @@ void LLReflectionMapManager::doProbeUpdate()
     llassert(mUpdatingProbe != nullptr);
 
     mRenderTarget.bindTarget();
+    auto* old_rt = gPipeline.mRT;
+    gPipeline.mRT = &gProbeRT;
     mUpdatingProbe->update(mRenderTarget.getWidth(), mUpdatingFace);
+    gPipeline.mRT = old_rt;
     mRenderTarget.flush();
 
     // generate mipmaps
@@ -390,12 +396,13 @@ void LLReflectionMapManager::doProbeUpdate()
         gGL.loadIdentity();
 
         gGL.flush();
-        U32 res = LL_REFLECTION_PROBE_RESOLUTION*4;
+        U32 res = LL_REFLECTION_PROBE_RESOLUTION*2;
 
         S32 mips = log2((F32) LL_REFLECTION_PROBE_RESOLUTION)+0.5f;
 
         for (int i = 0; i < mMipChain.size(); ++i)
         {
+            LL_PROFILE_GPU_ZONE("probe mip");
             mMipChain[i].bindTarget();
 
             if (i == 0)
diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h
index e3942beaaebea0fb7bd41a851bb963101c9781d4..bf963f34866e33c26ded260916661b0ba3f17d66 100644
--- a/indra/newview/llreflectionmapmanager.h
+++ b/indra/newview/llreflectionmapmanager.h
@@ -48,7 +48,7 @@ class alignas(16) LLReflectionMapManager
 public:
     // allocate an environment map of the given resolution 
     LLReflectionMapManager();
-    
+
     // maintain reflection probes
     void update();
 
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index f375852dfeec029c3991444fb37e8497804414c4..1b8e53e667719783d8b1ff7742e6641a4fd6c1fa 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -916,19 +916,19 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
         if (LLPipeline::sRenderDeferred)
         {
-            gPipeline.mDeferredScreen.bindTarget();
+            gPipeline.mRT->deferredScreen.bindTarget();
             glClearColor(1, 0, 1, 1);
-            gPipeline.mDeferredScreen.clear();
+            gPipeline.mRT->deferredScreen.clear();
         }
         else
         {
-            gPipeline.mScreen.bindTarget();
+            gPipeline.mRT->screen.bindTarget();
             if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders())
             {
                 const LLColor4 &col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor();
                 glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
             }
-            gPipeline.mScreen.clear();
+            gPipeline.mRT->screen.clear();
         }
 
         gGL.setColorMask(true, false);
@@ -998,7 +998,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush");
 
-        LLRenderTarget &rt = (gPipeline.sRenderDeferred ? gPipeline.mDeferredScreen : gPipeline.mScreen);
+        LLRenderTarget &rt = (gPipeline.sRenderDeferred ? gPipeline.mRT->deferredScreen : gPipeline.mRT->screen);
         rt.flush();
 
         if (rt.sUseFBO)
@@ -1010,7 +1010,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
         if (LLPipeline::sRenderDeferred)
         {
-			gPipeline.renderDeferredLighting(&gPipeline.mScreen);
+			gPipeline.renderDeferredLighting(&gPipeline.mRT->screen);
 		}
 
 		LLPipeline::sUnderWaterRender = FALSE;
@@ -1061,6 +1061,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 void display_cube_face()
 {
     LL_RECORD_BLOCK_TIME(FTM_RENDER);
+    LL_PROFILE_GPU_ZONE("display cube face");
+
     llassert(!gSnapshot);
     llassert(!gTeleportDisplay);
     llassert(LLPipeline::sRenderDeferred);
@@ -1136,9 +1138,9 @@ void display_cube_face()
 
     gGL.setColorMask(true, true);
 
-    gPipeline.mDeferredScreen.bindTarget();
+    gPipeline.mRT->deferredScreen.bindTarget();
     glClearColor(1, 0, 1, 1);
-    gPipeline.mDeferredScreen.clear();
+    gPipeline.mRT->deferredScreen.clear();
         
     gGL.setColorMask(true, false);
 
@@ -1148,9 +1150,9 @@ void display_cube_face()
 
     gGL.setColorMask(true, true);
 
-    gPipeline.mDeferredScreen.flush();
+    gPipeline.mRT->deferredScreen.flush();
        
-    gPipeline.renderDeferredLighting(&gPipeline.mScreen);
+    gPipeline.renderDeferredLighting(&gPipeline.mRT->screen);
 
     LLPipeline::sUnderWaterRender = FALSE;
 
@@ -1357,7 +1359,7 @@ bool setup_hud_matrices(const LLRect& screen_region)
 void render_ui(F32 zoom_factor, int subfield)
 {
 	LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI);
-
+    LL_PROFILE_GPU_ZONE("ui");
 	LLGLState::checkStates();
 	
 	glh::matrix4f saved_view = get_current_modelview();
@@ -1440,7 +1442,7 @@ static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap");
 void swap()
 {
 	LL_RECORD_BLOCK_TIME(FTM_SWAP);
-
+    LL_PROFILE_GPU_ZONE("swap");
 	if (gDisplaySwapBuffers)
 	{
 		gViewerWindow->getWindow()->swapBuffers();
@@ -1602,7 +1604,7 @@ void render_ui_2d()
             LLView::sIsRectDirty = false;
 			LLRect t_rect;
 
-			gPipeline.mUIScreen.bindTarget();
+			gPipeline.mRT->uiScreen.bindTarget();
 			gGL.setColorMask(true, true);
 			{
 				static const S32 pad = 8;
@@ -1634,7 +1636,7 @@ void render_ui_2d()
 				gViewerWindow->draw();
 			}
 
-			gPipeline.mUIScreen.flush();
+			gPipeline.mRT->uiScreen.flush();
 			gGL.setColorMask(true, false);
 
             LLView::sDirtyRect = t_rect;
@@ -1644,7 +1646,7 @@ void render_ui_2d()
 		LLGLDisable blend(GL_BLEND);
 		S32 width = gViewerWindow->getWindowWidthScaled();
 		S32 height = gViewerWindow->getWindowHeightScaled();
-		gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen);
+		gGL.getTexUnit(0)->bind(&gPipeline.mRT->uiScreen);
 		gGL.begin(LLRender::TRIANGLE_STRIP);
 		gGL.color4f(1,1,1,1);
 		gGL.texCoord2f(0, 0);			gGL.vertex2i(0, 0);
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index ad57fcd802716557f6e09a59b551817209ed8376..a6597e32337379835d0f7dca167abb2587328bfc 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -4927,8 +4927,8 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 			U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA;
 			if (scratch_space.allocate(image_width, image_height, color_fmt, true, true))
 			{
-				original_width = gPipeline.mDeferredScreen.getWidth();
-				original_height = gPipeline.mDeferredScreen.getHeight();
+				original_width = gPipeline.mRT->deferredScreen.getWidth();
+				original_height = gPipeline.mRT->deferredScreen.getHeight();
 
 				if (gPipeline.allocateScreenBuffer(image_width, image_height))
 				{
@@ -5186,8 +5186,8 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_
     LLPipeline::sShowHUDAttachments = FALSE;
     LLRect window_rect = getWorldViewRectRaw();
 
-    S32 original_width = LLPipeline::sRenderDeferred ? gPipeline.mDeferredScreen.getWidth() : gViewerWindow->getWorldViewWidthRaw();
-    S32 original_height = LLPipeline::sRenderDeferred ? gPipeline.mDeferredScreen.getHeight() : gViewerWindow->getWorldViewHeightRaw();
+    S32 original_width = LLPipeline::sRenderDeferred ? gPipeline.mRT->deferredScreen.getWidth() : gViewerWindow->getWorldViewWidthRaw();
+    S32 original_height = LLPipeline::sRenderDeferred ? gPipeline.mRT->deferredScreen.getHeight() : gViewerWindow->getWorldViewHeightRaw();
 
     LLRenderTarget scratch_space;
     U32 color_fmt = GL_RGBA;
@@ -5280,8 +5280,8 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubea
     
     U32 res = LLRenderTarget::sCurResX;
 
-    llassert(res <= gPipeline.mDeferredScreen.getWidth());
-    llassert(res <= gPipeline.mDeferredScreen.getHeight());
+    llassert(res <= gPipeline.mRT->deferredScreen.getWidth());
+    llassert(res <= gPipeline.mRT->deferredScreen.getHeight());
 
     // save current view/camera settings so we can restore them afterwards
     S32 old_occlusion = LLPipeline::sUseOcclusion;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 8f38f7a8f41c410b6bee07bcdfe9ea79ec7c8c1b..2790628a46ce33777c3739ec7be93a2fec603998 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -406,9 +406,7 @@ LLPipeline::LLPipeline() :
 	mWLSkyPool(NULL),
 	mLightMask(0),
 	mLightMovingMask(0),
-	mLightingDetail(0),
-	mScreenWidth(0),
-	mScreenHeight(0)
+	mLightingDetail(0)
 {
 	mNoiseMap = 0;
 	mTrueNoiseMap = 0;
@@ -437,6 +435,8 @@ void LLPipeline::init()
 {
 	refreshCachedSettings();
 
+    mRT = new RenderTargetPack();
+
 	gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity");
 	gOctreeMinSize = gSavedSettings.getF32("OctreeMinimumNodeSize");
 	sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
@@ -694,6 +694,9 @@ void LLPipeline::cleanup()
 	mDeferredVB = NULL;
 
 	mCubeVB = NULL;
+
+    delete mRT;
+    mRT = nullptr;
 }
 
 //============================================================================
@@ -735,7 +738,7 @@ void LLPipeline::requestResizeShadowTexture()
 void LLPipeline::resizeShadowTexture()
 {
     releaseShadowTargets();
-    allocateShadowBuffer(mScreenWidth, mScreenHeight);
+    allocateShadowBuffer(mRT->width, mRT->height);
     gResizeShadowTexture = FALSE;
 }
 
@@ -746,7 +749,7 @@ void LLPipeline::resizeScreenTexture()
 		GLuint resX = gViewerWindow->getWorldViewWidthRaw();
 		GLuint resY = gViewerWindow->getWorldViewHeightRaw();
 	
-		if (gResizeScreenTexture || (resX != mScreen.getWidth()) || (resY != mScreen.getHeight()))
+		if (gResizeScreenTexture || (resX != mRT->screen.getWidth()) || (resY != mRT->screen.getHeight()))
 		{
 			releaseScreenBuffers();
             releaseShadowTargets();
@@ -834,8 +837,8 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
 	// remember these dimensions
-	mScreenWidth = resX;
-	mScreenHeight = resY;
+	mRT->width = resX;
+	mRT->height = resY;
 	
 	U32 res_mod = RenderResolutionDivisor;
 
@@ -847,7 +850,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 
 	if (RenderUIBuffer)
 	{
-		if (!mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE))
+		if (!mRT->uiScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE))
 		{
 			return false;
 		}
@@ -861,10 +864,10 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 		const U32 occlusion_divisor = 3;
 
 		//allocate deferred rendering color buffers
-		if (!mDeferredScreen.allocate(resX, resY, GL_SRGB8_ALPHA8, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
-		if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
-		if (!mOcclusionDepth.allocate(resX/occlusion_divisor, resY/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
-		if (!addDeferredAttachments(mDeferredScreen)) return false;
+		if (!mRT->deferredScreen.allocate(resX, resY, GL_SRGB8_ALPHA8, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+		if (!mRT->deferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+		if (!mRT->occlusionDepth.allocate(resX/occlusion_divisor, resY/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+		if (!addDeferredAttachments(mRT->deferredScreen)) return false;
 	
 		GLuint screenFormat = GL_RGBA16;
 		if (gGLManager.mIsAMD)
@@ -877,23 +880,23 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 			screenFormat = GL_RGBA16F_ARB;
 		}
         
-		if (!mScreen.allocate(resX, resY, screenFormat, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+		if (!mRT->screen.allocate(resX, resY, screenFormat, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
 		if (samples > 0)
 		{
-			if (!mFXAABuffer.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false;
+			if (!mRT->fxaaBuffer.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false;
 		}
 		else
 		{
-			mFXAABuffer.release();
+			mRT->fxaaBuffer.release();
 		}
 		
 		if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0)
-		{ //only need mDeferredLight for shadows OR ssao OR dof OR fxaa
-			if (!mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;
+		{ //only need mRT->deferredLight for shadows OR ssao OR dof OR fxaa
+			if (!mRT->deferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;
 		}
 		else
 		{
-			mDeferredLight.release();
+			mRT->deferredLight.release();
 		}
 
         allocateShadowBuffer(resX, resY);
@@ -906,22 +909,22 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
     }
     else
     {
-        mDeferredLight.release();
+        mRT->deferredLight.release();
 
         releaseShadowTargets();
 
-		mFXAABuffer.release();
-		mScreen.release();
-		mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first
-		mDeferredDepth.release();
-		mOcclusionDepth.release();
+		mRT->fxaaBuffer.release();
+		mRT->screen.release();
+		mRT->deferredScreen.release(); //make sure to release any render targets that share a depth buffer with mRT->deferredScreen first
+		mRT->deferredDepth.release();
+		mRT->occlusionDepth.release();
 						
-		if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;		
+		if (!mRT->screen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;		
 	}
 	
 	if (LLPipeline::sRenderDeferred)
 	{ //share depth buffer between deferred targets
-		mDeferredScreen.shareDepthBuffer(mScreen);
+		mRT->deferredScreen.shareDepthBuffer(mRT->screen);
 	}
 
 	gGL.getTexUnit(0)->disable();
@@ -951,12 +954,12 @@ bool LLPipeline::allocateShadowBuffer(U32 resX, U32 resY)
 		{ //allocate 4 sun shadow maps
 			for (U32 i = 0; i < 4; i++)
 			{
-				if (!mShadow[i].allocate(sun_shadow_map_width, sun_shadow_map_height, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE))
+				if (!mRT->shadow[i].allocate(sun_shadow_map_width, sun_shadow_map_height, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE))
                 {
                     return false;
                 }
 
-                if (!mShadowOcclusion[i].allocate(sun_shadow_map_width/occlusion_divisor, sun_shadow_map_height/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE))
+                if (!mRT->shadowOcclusion[i].allocate(sun_shadow_map_width/occlusion_divisor, sun_shadow_map_height/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE))
                 {
                     return false;
                 }
@@ -979,11 +982,11 @@ bool LLPipeline::allocateShadowBuffer(U32 resX, U32 resY)
             U32 spot_shadow_map_height = height;
 			for (U32 i = 4; i < 6; i++)
 			{
-                if (!mShadow[i].allocate(spot_shadow_map_width, spot_shadow_map_height, 0, TRUE, FALSE))
+                if (!mRT->shadow[i].allocate(spot_shadow_map_width, spot_shadow_map_height, 0, TRUE, FALSE))
 		{
                     return false;
 			}
-                if (!mShadowOcclusion[i].allocate(spot_shadow_map_width/occlusion_divisor, height/occlusion_divisor, 0, TRUE, FALSE))
+                if (!mRT->shadowOcclusion[i].allocate(spot_shadow_map_width/occlusion_divisor, height/occlusion_divisor, 0, TRUE, FALSE))
 		{
 			return false;
 		}
@@ -1174,21 +1177,21 @@ void LLPipeline::releaseShadowBuffers()
 
 void LLPipeline::releaseScreenBuffers()
 {
-	mUIScreen.release();
-	mScreen.release();
-	mFXAABuffer.release();
+	mRT->uiScreen.release();
+	mRT->screen.release();
+	mRT->fxaaBuffer.release();
 	mPhysicsDisplay.release();
-	mDeferredScreen.release();
-	mDeferredDepth.release();
-	mDeferredLight.release();
-	mOcclusionDepth.release();
+	mRT->deferredScreen.release();
+	mRT->deferredDepth.release();
+	mRT->deferredLight.release();
+	mRT->occlusionDepth.release();
 }
 		
 		
 void LLPipeline::releaseShadowTarget(U32 index)
 {
-    mShadow[index].release();
-    mShadowOcclusion[index].release();
+    mRT->shadow[index].release();
+    mRT->shadowOcclusion[index].release();
 }
 
 void LLPipeline::releaseShadowTargets()
@@ -1231,8 +1234,8 @@ void LLPipeline::createGLBuffers()
     }
 
     allocateScreenBuffer(resX, resY);
-    mScreenWidth = 0;
-    mScreenHeight = 0;
+    mRT->width = 0;
+    mRT->height = 0;
 
     if (sRenderDeferred)
     {
@@ -2333,11 +2336,11 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, LLPlane* pla
 	{
 		if (LLPipeline::sRenderDeferred && can_use_occlusion)
 		{
-			mOcclusionDepth.bindTarget();
+			mRT->occlusionDepth.bindTarget();
 		}
 		else
 		{
-			mScreen.bindTarget();
+			mRT->screen.bindTarget();
 		}
 	}
 
@@ -2459,11 +2462,11 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, LLPlane* pla
 	{
 		if (LLPipeline::sRenderDeferred && can_use_occlusion)
 		{
-			mOcclusionDepth.flush();
+			mRT->occlusionDepth.flush();
 		}
 		else
 		{
-			mScreen.flush();
+			mRT->screen.flush();
 		}
 	}
 }
@@ -4631,7 +4634,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 			gGLLastMatrix = NULL;
 			gGL.loadMatrix(gGLModelView);
 			LLGLSLShader::bindNoShader();
-			doOcclusion(camera, mScreen, mOcclusionDepth, &mDeferredDepth);
+			doOcclusion(camera, mRT->screen, mRT->occlusionDepth, &mRT->deferredDepth);
 			gGL.setColorMask(true, false);
 		}
 
@@ -7484,9 +7487,11 @@ void LLPipeline::renderFinalize()
     }
 
     LLVector2 tc1(0, 0);
-    LLVector2 tc2((F32) mScreen.getWidth() * 2, (F32) mScreen.getHeight() * 2);
+    LLVector2 tc2((F32) mRT->screen.getWidth() * 2, (F32) mRT->screen.getHeight() * 2);
 
     LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM);
+    LL_PROFILE_GPU_ZONE("renderFinalize");
+
     gGL.color4f(1, 1, 1, 1);
     LLGLDepthTest depth(GL_FALSE);
     LLGLDisable blend(GL_BLEND);
@@ -7508,6 +7513,7 @@ void LLPipeline::renderFinalize()
 
     if (sRenderGlow)
     {
+        LL_PROFILE_GPU_ZONE("glow");
         mGlow[2].bindTarget();
         mGlow[2].clear();
 
@@ -7532,7 +7538,7 @@ void LLPipeline::renderFinalize()
 
             gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
 
-            mScreen.bindTexture(0, 0, LLTexUnit::TFO_POINT);
+            mRT->screen.bindTexture(0, 0, LLTexUnit::TFO_POINT);
 
             gGL.color4f(1, 1, 1, 1);
             gPipeline.enableLightsFullbright();
@@ -7548,7 +7554,7 @@ void LLPipeline::renderFinalize()
 
             gGL.end();
 
-            gGL.getTexUnit(0)->unbind(mScreen.getUsage());
+            gGL.getTexUnit(0)->unbind(mRT->screen.getUsage());
 
             mGlow[2].flush();
 
@@ -7626,7 +7632,7 @@ void LLPipeline::renderFinalize()
     gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
     glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
 
-    tc2.setVec((F32) mScreen.getWidth(), (F32) mScreen.getHeight());
+    tc2.setVec((F32) mRT->screen.getWidth(), (F32) mRT->screen.getHeight());
 
     gGL.flush();
 
@@ -7634,18 +7640,18 @@ void LLPipeline::renderFinalize()
 
     if (LLPipeline::sRenderDeferred)
     {
-
         bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() &&
                            (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) &&
                            RenderDepthOfField &&
                             !gCubeSnapshot;
 
-        bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete();
+        bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete();
 
         gViewerWindow->setup3DViewport();
 
         if (dof_enabled)
         {
+            LL_PROFILE_GPU_ZONE("dof");
             LLGLSLShader *shader = &gDeferredPostProgram;
             LLGLDisable blend(GL_BLEND);
 
@@ -7730,7 +7736,7 @@ void LLPipeline::renderFinalize()
 
             const F32 default_fov = CameraFieldOfView * F_PI / 180.f;
 
-            // F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight();
+            // F32 aspect_ratio = (F32) mRT->screen.getWidth()/(F32)mRT->screen.getHeight();
 
             F32 dv = 2.f * default_focal_length * tanf(default_fov / 2.f);
 
@@ -7750,15 +7756,15 @@ void LLPipeline::renderFinalize()
             F32 magnification = focal_length / (subject_distance - focal_length);
 
             { // build diffuse+bloom+CoF
-                mDeferredLight.bindTarget();
+                mRT->deferredLight.bindTarget();
                 shader = &gDeferredCoFProgram;
 
                 bindDeferredShader(*shader);
 
-                S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage());
+                S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage());
                 if (channel > -1)
                 {
-                    mScreen.bindTexture(0, channel);
+                    mRT->screen.bindTexture(0, channel);
                 }
 
                 shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance / 1000.f);
@@ -7781,23 +7787,23 @@ void LLPipeline::renderFinalize()
                 gGL.end();
 
                 unbindDeferredShader(*shader);
-                mDeferredLight.flush();
+                mRT->deferredLight.flush();
             }
 
-            U32 dof_width = (U32)(mScreen.getWidth() * CameraDoFResScale);
-            U32 dof_height = (U32)(mScreen.getHeight() * CameraDoFResScale);
+            U32 dof_width = (U32)(mRT->screen.getWidth() * CameraDoFResScale);
+            U32 dof_height = (U32)(mRT->screen.getHeight() * CameraDoFResScale);
 
             { // perform DoF sampling at half-res (preserve alpha channel)
-                mScreen.bindTarget();
+                mRT->screen.bindTarget();
                 glViewport(0, 0, dof_width, dof_height);
                 gGL.setColorMask(true, false);
 
                 shader = &gDeferredPostProgram;
                 bindDeferredShader(*shader);
-                S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage());
+                S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage());
                 if (channel > -1)
                 {
-                    mDeferredLight.bindTexture(0, channel);
+                    mRT->deferredLight.bindTexture(0, channel);
                 }
 
                 shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
@@ -7816,15 +7822,15 @@ void LLPipeline::renderFinalize()
                 gGL.end();
 
                 unbindDeferredShader(*shader);
-                mScreen.flush();
+                mRT->screen.flush();
                 gGL.setColorMask(true, true);
             }
 
             { // combine result based on alpha
                 if (multisample)
                 {
-                    mDeferredLight.bindTarget();
-                    glViewport(0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
+                    mRT->deferredLight.bindTarget();
+                    glViewport(0, 0, mRT->deferredScreen.getWidth(), mRT->deferredScreen.getHeight());
                 }
                 else
                 {
@@ -7838,10 +7844,10 @@ void LLPipeline::renderFinalize()
                 shader = &gDeferredDoFCombineProgram;
                 bindDeferredShader(*shader);
 
-                S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage());
+                S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage());
                 if (channel > -1)
                 {
-                    mScreen.bindTexture(0, channel);
+                    mRT->screen.bindTexture(0, channel);
                 }
 
                 shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
@@ -7865,24 +7871,25 @@ void LLPipeline::renderFinalize()
 
                 if (multisample)
                 {
-                    mDeferredLight.flush();
+                    mRT->deferredLight.flush();
                 }
             }
         }
         else
         {
+            LL_PROFILE_GPU_ZONE("no dof");
             if (multisample)
             {
-                mDeferredLight.bindTarget();
+                mRT->deferredLight.bindTarget();
             }
             LLGLSLShader *shader = &gDeferredPostNoDoFProgram;
 
             bindDeferredShader(*shader);
 
-            S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage());
+            S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage());
             if (channel > -1)
             {
-                mScreen.bindTexture(0, channel);
+                mRT->screen.bindTexture(0, channel);
             }
 
             gGL.begin(LLRender::TRIANGLE_STRIP);
@@ -7901,17 +7908,18 @@ void LLPipeline::renderFinalize()
 
             if (multisample)
             {
-                mDeferredLight.flush();
+                mRT->deferredLight.flush();
             }
         }
 
         if (multisample)
         {
+            LL_PROFILE_GPU_ZONE("aa");
             // bake out texture2D with RGBL for FXAA shader
-            mFXAABuffer.bindTarget();
+            mRT->fxaaBuffer.bindTarget();
 
-            S32 width = mScreen.getWidth();
-            S32 height = mScreen.getHeight();
+            S32 width = mRT->screen.getWidth();
+            S32 height = mRT->screen.getHeight();
             glViewport(0, 0, width, height);
 
             LLGLSLShader *shader = &gGlowCombineFXAAProgram;
@@ -7919,10 +7927,10 @@ void LLPipeline::renderFinalize()
             shader->bind();
             shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height);
 
-            S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage());
+            S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage());
             if (channel > -1)
             {
-                mDeferredLight.bindTexture(0, channel);
+                mRT->deferredLight.bindTexture(0, channel);
             }
 
             gGL.begin(LLRender::TRIANGLE_STRIP);
@@ -7933,18 +7941,18 @@ void LLPipeline::renderFinalize()
 
             gGL.flush();
 
-            shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage());
+            shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage());
             shader->unbind();
 
-            mFXAABuffer.flush();
+            mRT->fxaaBuffer.flush();
 
             shader = &gFXAAProgram;
             shader->bind();
 
-            channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mFXAABuffer.getUsage());
+            channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mRT->fxaaBuffer.getUsage());
             if (channel > -1)
             {
-                mFXAABuffer.bindTexture(0, channel, LLTexUnit::TFO_BILINEAR);
+                mRT->fxaaBuffer.bindTexture(0, channel, LLTexUnit::TFO_BILINEAR);
             }
 
             gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
@@ -7953,8 +7961,8 @@ void LLPipeline::renderFinalize()
             gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
             glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
 
-            F32 scale_x = (F32) width / mFXAABuffer.getWidth();
-            F32 scale_y = (F32) height / mFXAABuffer.getHeight();
+            F32 scale_x = (F32) width / mRT->fxaaBuffer.getWidth();
+            F32 scale_y = (F32) height / mRT->fxaaBuffer.getHeight();
             shader->uniform2f(LLShaderMgr::FXAA_TC_SCALE, scale_x, scale_y);
             shader->uniform2f(LLShaderMgr::FXAA_RCP_SCREEN_RES, 1.f / width * scale_x, 1.f / height * scale_y);
             shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT, -0.5f / width * scale_x, -0.5f / height * scale_y,
@@ -8005,7 +8013,7 @@ void LLPipeline::renderFinalize()
         gGlowCombineProgram.bind();
 
         gGL.getTexUnit(0)->bind(&mGlow[1]);
-        gGL.getTexUnit(1)->bind(&mScreen);
+        gGL.getTexUnit(1)->bind(&mRT->screen);
 
         LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
 
@@ -8048,10 +8056,10 @@ void LLPipeline::renderFinalize()
         gSplatTextureRectProgram.unbind();
     }
 
-    if (LLRenderTarget::sUseFBO)
-    { // copy depth buffer from mScreen to framebuffer
-        LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), 0, 0,
-                                                  mScreen.getWidth(), mScreen.getHeight(),
+    if (LLRenderTarget::sUseFBO && !gCubeSnapshot)
+    { // copy depth buffer from mRT->screen to framebuffer
+        LLRenderTarget::copyContentsToFramebuffer(mRT->screen, 0, 0, mRT->screen.getWidth(), mRT->screen.getHeight(), 0, 0,
+                                                  mRT->screen.getWidth(), mRT->screen.getHeight(),
                                                   GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
     }
 
@@ -8069,10 +8077,10 @@ void LLPipeline::renderFinalize()
 void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
-
-    LLRenderTarget* deferred_target       = &mDeferredScreen;
-    LLRenderTarget* deferred_depth_target = &mDeferredDepth;
-    LLRenderTarget* deferred_light_target = &mDeferredLight;
+    LL_PROFILE_GPU_ZONE("bindDeferredShader");
+    LLRenderTarget* deferred_target       = &mRT->deferredScreen;
+    LLRenderTarget* deferred_depth_target = &mRT->deferredDepth;
+    LLRenderTarget* deferred_light_target = &mRT->deferredLight;
 
 	shader.bind();
 	S32 channel = 0;
@@ -8304,8 +8312,8 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
 
 	shader.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.mV);
     shader.uniform3fv(LLShaderMgr::DEFERRED_MOON_DIR, 1, mTransformedMoonDir.mV);
-	shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mShadow[0].getWidth(), mShadow[0].getHeight());
-	shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mShadow[4].getWidth(), mShadow[4].getHeight());
+	shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mRT->shadow[0].getWidth(), mRT->shadow[0].getHeight());
+	shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mRT->shadow[4].getWidth(), mRT->shadow[4].getHeight());
 	shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff);
 	shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff);
 	
@@ -8341,14 +8349,15 @@ LLVector4 pow4fsrgb(LLVector4 v, F32 f)
 void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+    LL_PROFILE_GPU_ZONE("renderDeferredLighting");
     if (!sCull)
     {
         return;
     }
 
-    LLRenderTarget *deferred_target       = &mDeferredScreen;
-    LLRenderTarget *deferred_depth_target = &mDeferredDepth;
-    LLRenderTarget *deferred_light_target = &mDeferredLight;
+    LLRenderTarget *deferred_target       = &mRT->deferredScreen;
+    LLRenderTarget *deferred_depth_target = &mRT->deferredDepth;
+    LLRenderTarget *deferred_light_target = &mRT->deferredLight;
 
     {
         LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("deferred"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED);
@@ -8415,6 +8424,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
         if (RenderDeferredSSAO || RenderShadowDetail > 0)
         {
+            LL_PROFILE_GPU_ZONE("sun program");
             deferred_light_target->bindTarget();
             {  // paint shadow/SSAO light map (direct lighting lightmap)
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - sun shadow");
@@ -8475,6 +8485,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             {
                 // soften direct lighting lightmap
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow");
+                LL_PROFILE_GPU_ZONE("soften shadow");
                 // blur lightmap
                 screen_target->bindTarget();
                 glClearColor(1, 1, 1, 1);
@@ -8554,6 +8565,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             LLGLSLShader &soften_shader = LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram;
 
             LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - atmospherics");
+            LL_PROFILE_GPU_ZONE("atmospherics");
             bindDeferredShader(soften_shader);
 
             LLEnvironment &environment = LLEnvironment::instance();
@@ -8623,6 +8635,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
             {
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - local lights");
+                LL_PROFILE_GPU_ZONE("local lights");
                 bindDeferredShader(gDeferredLightProgram);
 
                 if (mCubeVB.isNull())
@@ -8729,6 +8742,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             if (!spot_lights.empty())
             {
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - projectors");
+                LL_PROFILE_GPU_ZONE("projectors");
                 LLGLDepthTest depth(GL_TRUE, GL_FALSE);
                 bindDeferredShader(gDeferredSpotLightProgram);
 
@@ -8775,7 +8789,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
             {
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - fullscreen lights");
                 LLGLDepthTest depth(GL_FALSE);
-
+                LL_PROFILE_GPU_ZONE("fullscreen lights");
                 // full screen blit
                 gGL.pushMatrix();
                 gGL.loadIdentity();
@@ -8871,6 +8885,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
     gGL.loadIdentity();
 
     {
+        LL_PROFILE_GPU_ZONE("gamma correct");
         LLGLDepthTest depth(GL_FALSE, GL_FALSE);
 
         LLVector2 tc1(0, 0);
@@ -9114,9 +9129,9 @@ void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
 
 void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
 {
-    LLRenderTarget* deferred_target       = &mDeferredScreen;
-    LLRenderTarget* deferred_depth_target = &mDeferredDepth;
-    LLRenderTarget* deferred_light_target = &mDeferredLight;
+    LLRenderTarget* deferred_target       = &mRT->deferredScreen;
+    LLRenderTarget* deferred_depth_target = &mRT->deferredDepth;
+    LLRenderTarget* deferred_light_target = &mRT->deferredLight;
 
 	stop_glerror();
     shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, deferred_target->getUsage());
@@ -9653,7 +9668,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
         gDeferredShadowCubeProgram.bind();
     }
 
-    LLRenderTarget& occlusion_target = mShadowOcclusion[LLViewerCamera::sCurCameraID - 1];
+    LLRenderTarget& occlusion_target = mRT->shadowOcclusion[LLViewerCamera::sCurCameraID - 1];
 
     occlusion_target.bindTarget();
     updateCull(shadow_cam, result);
@@ -9797,7 +9812,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
     gGLLastMatrix = NULL;
     gGL.loadMatrix(gGLModelView);
 
-    LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID - 1];
+    LLRenderTarget& occlusion_source = mRT->shadow[LLViewerCamera::sCurCameraID - 1];
 
     if (occlude > 1)
     {
@@ -10023,7 +10038,8 @@ void LLPipeline::generateHighlight(LLCamera& camera)
 	{
 		mHighlightSet.insert(HighlightItem(mHighlightObject));
 	}
-	
+    llassert(!gCubeSnapshot);
+
 	if (!mHighlightSet.empty())
 	{
 		F32 transition = gFrameIntervalSeconds.value()/RenderHighlightFadeTime;
@@ -10073,7 +10089,7 @@ void LLPipeline::generateHighlight(LLCamera& camera)
 
 LLRenderTarget* LLPipeline::getShadowTarget(U32 i)
 {
-    return &mShadow[i];
+    return &mRT->shadow[i];
 }
 
 static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW("Gen Sun Shadow");
@@ -10327,9 +10343,9 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 
 		for (S32 j = 0; j < 4; j++)
 		{
-			mShadow[j].bindTarget();
-			mShadow[j].clear();
-			mShadow[j].flush();
+			mRT->shadow[j].bindTarget();
+			mRT->shadow[j].clear();
+			mRT->shadow[j].flush();
 		}
 	}
 	else
@@ -10341,9 +10357,9 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
             dist[1] = dist[2] = dist[3] = dist[4] = 64.f;
             for (S32 j = 1; j < 4; j++)
             {
-                mShadow[j].bindTarget();
-                mShadow[j].clear();
-                mShadow[j].flush();
+                mRT->shadow[j].bindTarget();
+                mRT->shadow[j].clear();
+                mRT->shadow[j].flush();
             }
         }*/
 
@@ -10409,12 +10425,12 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 					mShadowCamera[j+4] = shadow_cam;
 				}
 
-				mShadow[j].bindTarget();
+				mRT->shadow[j].bindTarget();
 				{
 					LLGLDepthTest depth(GL_TRUE);
-					mShadow[j].clear();
+					mRT->shadow[j].clear();
 				}
-				mShadow[j].flush();
+				mRT->shadow[j].flush();
 
 				mShadowError.mV[j] = 0.f;
 				mShadowFOV.mV[j] = 0.f;
@@ -10701,18 +10717,18 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		
 			stop_glerror();
 
-			mShadow[j].bindTarget();
-			mShadow[j].getViewport(gGLViewport);
-			mShadow[j].clear();
+			mRT->shadow[j].bindTarget();
+			mRT->shadow[j].getViewport(gGLViewport);
+			mRT->shadow[j].clear();
 		
-			U32 target_width = mShadow[j].getWidth();
+			U32 target_width = mRT->shadow[j].getWidth();
 
 			{
 				static LLCullResult result[4];
 				renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE, FALSE, target_width);
 			}
 
-			mShadow[j].flush();
+			mRT->shadow[j].flush();
  
 			if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
 			{
@@ -10847,11 +10863,11 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 
                 stop_glerror();
 
-                mShadow[i + 4].bindTarget();
-                mShadow[i + 4].getViewport(gGLViewport);
-                mShadow[i + 4].clear();
+                mRT->shadow[i + 4].bindTarget();
+                mRT->shadow[i + 4].getViewport(gGLViewport);
+                mRT->shadow[i + 4].clear();
 
-                U32 target_width = mShadow[i + 4].getWidth();
+                U32 target_width = mRT->shadow[i + 4].getWidth();
 
                 static LLCullResult result[2];
 
@@ -10863,7 +10879,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 
                 RenderSpotLight = nullptr;
 
-                mShadow[i + 4].flush();
+                mRT->shadow[i + 4].flush();
             }
         }
 	}
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 5cbd1eb55081284737a15791a49e5e468fec84d6..c0b55906d63473e7801ba17a29f7d7887a0f5080 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -641,20 +641,31 @@ class LLPipeline
 
 	static LLTrace::EventStatHandle<S64> sStatBatchSize;
 
-	//screen texture
-	U32 					mScreenWidth;
-	U32 					mScreenHeight;
-	
-	LLRenderTarget			mScreen;
-	LLRenderTarget			mUIScreen;
-	LLRenderTarget			mDeferredScreen;
-	LLRenderTarget			mFXAABuffer;
-	LLRenderTarget			mEdgeMap;
-	LLRenderTarget			mDeferredDepth;
-	LLRenderTarget			mOcclusionDepth;
-	LLRenderTarget			mDeferredLight;
-	LLRenderTarget			mHighlight;
-	LLRenderTarget			mPhysicsDisplay;
+    class RenderTargetPack
+    {
+    public:
+        U32 					width = 0;
+        U32 					height = 0;
+
+        //screen texture
+        LLRenderTarget			screen;
+        LLRenderTarget			uiScreen;
+        LLRenderTarget			deferredScreen;
+        LLRenderTarget			fxaaBuffer;
+        LLRenderTarget			edgeMap;
+        LLRenderTarget			deferredDepth;
+        LLRenderTarget			occlusionDepth;
+        LLRenderTarget			deferredLight;
+
+        //sun shadow map
+        LLRenderTarget			shadow[6];
+        LLRenderTarget			shadowOcclusion[6];
+    };
+
+    RenderTargetPack* mRT;
+
+    LLRenderTarget			mHighlight;
+    LLRenderTarget			mPhysicsDisplay;
 
     LLCullResult            mSky;
     LLCullResult            mReflectedObjects;
@@ -669,9 +680,6 @@ class LLPipeline
     //list of currently bound reflection maps
     std::vector<LLReflectionMap*> mReflectionMaps;
 
-	//sun shadow map
-	LLRenderTarget			mShadow[6];
-	LLRenderTarget			mShadowOcclusion[6];
 	std::vector<LLVector3>	mShadowFrustPoints[4];
 	LLVector4				mShadowError;
 	LLVector4				mShadowFOV;