From 003e34190f314cd159f8ec227ef32c2400e90f48 Mon Sep 17 00:00:00 2001
From: "Jonathan \"Geenz\" Goodman" <geenz@geenzo.com>
Date: Mon, 2 Jan 2023 05:38:29 -0800
Subject: [PATCH] Refactor post processing a smidge

Fixes SL-18484.
---
 .../class1/interface/glowcombineV.glsl        |   4 +-
 indra/newview/llviewerdisplay.cpp             |   7 +-
 indra/newview/pipeline.cpp                    | 955 ++++++++++--------
 indra/newview/pipeline.h                      |   2 +
 4 files changed, 524 insertions(+), 444 deletions(-)

diff --git a/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl b/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl
index e08284f7625..71fa095505e 100644
--- a/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl
@@ -35,7 +35,7 @@ VARYING vec2 vary_texcoord1;
 void main()
 {
 	gl_Position = vec4(position.xyz, 1.0);
-	vary_texcoord0 = texcoord0;
-	vary_texcoord1 = texcoord1;
+	vary_texcoord0 = position.xy * 0.5 + 0.5;
+	vary_texcoord1 = vary_texcoord0;
 }
 
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 1b2f07515a6..58b1716caa0 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1348,9 +1348,12 @@ void render_ui(F32 zoom_factor, int subfield)
 	}
 
 	{
+		// Render our post process prior to the HUD, UI, etc.
+		gPipeline.renderPostProcess();
+
         // draw hud and 3D ui elements into screen render target so they'll be able to use 
         // the depth buffer (avoids extra copy of depth buffer per frame)
-        gPipeline.mRT->screen.bindTarget();
+        gPipeline.screenTarget()->bindTarget();
 		// SL-15709
 		// NOTE: Tracy only allows one ZoneScoped per function.
 		// Solutions are:
@@ -1384,7 +1387,7 @@ void render_ui(F32 zoom_factor, int subfield)
             }
         }
 
-        gPipeline.mRT->screen.flush();
+        gPipeline.screenTarget()->flush();
 
         // apply gamma correction and post effects before rendering 2D UI
         gPipeline.renderFinalize();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 744d21b2c9a..4edc0922713 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -880,7 +880,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 		
 		if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0)
 		{ //only need mRT->deferredLight for shadows OR ssao OR dof OR fxaa
-			if (!mRT->deferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false;
+			if (!mRT->deferredLight.allocate(resX, resY, GL_RGBA16, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false;
 		}
 		else
 		{
@@ -7530,500 +7530,541 @@ void LLPipeline::bindScreenToTexture()
 
 static LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM("Bloom");
 
-void LLPipeline::renderFinalize()
+void LLPipeline::renderPostProcess()
 {
-    LLVertexBuffer::unbind();
-    LLGLState::checkStates();
-    LLGLState::checkTextureChannels();
+	LLVertexBuffer::unbind();
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
 
-    assertInitialized();
+	assertInitialized();
 
-    LLVector2 tc1(0, 0);
-    LLVector2 tc2((F32) mRT->screen.getWidth() * 2, (F32) mRT->screen.getHeight() * 2);
+	LLVector2 tc1(0, 0);
+	LLVector2 tc2((F32)mRT->screen.getWidth() * 2, (F32)mRT->screen.getHeight() * 2);
 
-    LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM);
-    LL_PROFILE_GPU_ZONE("renderFinalize");
+	LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM);
+	LL_PROFILE_GPU_ZONE("renderPostProcess");
 
-    gGL.color4f(1, 1, 1, 1);
-    LLGLDepthTest depth(GL_FALSE);
-    LLGLDisable blend(GL_BLEND);
-    LLGLDisable cull(GL_CULL_FACE);
+	gGL.color4f(1, 1, 1, 1);
+	LLGLDepthTest depth(GL_FALSE);
+	LLGLDisable blend(GL_BLEND);
+	LLGLDisable cull(GL_CULL_FACE);
 
-    enableLightsFullbright();
+	enableLightsFullbright();
 
-    LLGLDisable test(GL_ALPHA_TEST);
+	LLGLDisable test(GL_ALPHA_TEST);
 
-    gGL.setColorMask(true, true);
-    glClearColor(0, 0, 0, 0);
+	gGL.setColorMask(true, true);
+	glClearColor(0, 0, 0, 0);
 
-    if (!gCubeSnapshot)
-    {
-        LLRenderTarget* screen_target = &mRT->screen;
-        screen_target->bindTarget();
+	if (sRenderGlow)
+	{
+		LL_PROFILE_GPU_ZONE("glow");
+		mGlow[2].bindTarget();
+		mGlow[2].clear();
 
-        if (RenderScreenSpaceReflections)
-        {
-            LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - screen space reflections");
-            LL_PROFILE_GPU_ZONE("screen space reflections");
+		gGlowExtractProgram.bind();
+		F32 minLum = llmax((F32)RenderGlowMinLuminance, 0.0f);
+		F32 maxAlpha = RenderGlowMaxExtractAlpha;
+		F32 warmthAmount = RenderGlowWarmthAmount;
+		LLVector3 lumWeights = RenderGlowLumWeights;
+		LLVector3 warmthWeights = RenderGlowWarmthWeights;
 
-            bindDeferredShader(gPostScreenSpaceReflectionProgram, NULL);
-            mScreenTriangleVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+		gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MIN_LUMINANCE, minLum);
+		gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MAX_EXTRACT_ALPHA, maxAlpha);
+		gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_LUM_WEIGHTS, lumWeights.mV[0], lumWeights.mV[1],
+			lumWeights.mV[2]);
+		gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_WARMTH_WEIGHTS, warmthWeights.mV[0], warmthWeights.mV[1],
+			warmthWeights.mV[2]);
+		gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_WARMTH_AMOUNT, warmthAmount);
 
-            set_camera_projection_matrix(gPostScreenSpaceReflectionProgram);
+		{
+			LLGLEnable blend_on(GL_BLEND);
+			LLGLEnable test(GL_ALPHA_TEST);
 
-            // We need linear depth.
-            static LLStaticHashedString zfar("zFar");
-            static LLStaticHashedString znear("zNear");
-            float                       nearClip = LLViewerCamera::getInstance()->getNear();
-            float                       farClip  = LLViewerCamera::getInstance()->getFar();
-            gPostScreenSpaceReflectionProgram.uniform1f(zfar, farClip);
-            gPostScreenSpaceReflectionProgram.uniform1f(znear, nearClip);
+			gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
 
-            S32 channel = gPostScreenSpaceReflectionProgram.enableTexture(LLShaderMgr::DIFFUSE_MAP, screen_target->getUsage());
-            if (channel > -1)
-            {
-                screen_target->bindTexture(0, channel, LLTexUnit::TFO_POINT);
-            }
+			mRT->screen.bindTexture(0, 0, LLTexUnit::TFO_POINT);
 
-            {
-                LLGLDisable blend(GL_BLEND);
-                LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+			gGL.color4f(1, 1, 1, 1);
+			gPipeline.enableLightsFullbright();
+			gGL.begin(LLRender::TRIANGLE_STRIP);
+			gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+			gGL.vertex2f(-1, -1);
 
-                stop_glerror();
-                mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
-                stop_glerror();
-            }
+			gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+			gGL.vertex2f(-1, 3);
 
-            unbindDeferredShader(gPostScreenSpaceReflectionProgram);
-        }
+			gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+			gGL.vertex2f(3, -1);
 
-        // gamma correct lighting
-        {
-            LL_PROFILE_GPU_ZONE("gamma correct");
+			gGL.end();
 
-            LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+			gGL.getTexUnit(0)->unbind(mRT->screen.getUsage());
 
-            LLVector2 tc1(0, 0);
-            LLVector2 tc2((F32)screen_target->getWidth() * 2, (F32)screen_target->getHeight() * 2);
+			mGlow[2].flush();
 
-            // Apply gamma correction to the frame here.
-            gDeferredPostGammaCorrectProgram.bind();
-            // mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-            S32 channel = 0;
-            channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, screen_target->getUsage());
-            if (channel > -1)
-            {
-                screen_target->bindTexture(0, channel, LLTexUnit::TFO_POINT);
-            }
+			tc1.setVec(0, 0);
+			tc2.setVec(2, 2);
+		}
 
-            gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, screen_target->getWidth(), screen_target->getHeight());
+		// power of two between 1 and 1024
+		U32 glowResPow = RenderGlowResolutionPow;
+		const U32 glow_res = llmax(1, llmin(1024, 1 << glowResPow));
 
-            F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+		S32 kernel = RenderGlowIterations * 2;
+		F32 delta = RenderGlowWidth / glow_res;
+		// Use half the glow width if we have the res set to less than 9 so that it looks
+		// almost the same in either case.
+		if (glowResPow < 9)
+		{
+			delta *= 0.5f;
+		}
+		F32 strength = RenderGlowStrength;
 
-            gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
+		gGlowProgram.bind();
+		gGlowProgram.uniform1f(LLShaderMgr::GLOW_STRENGTH, strength);
 
-            gGL.begin(LLRender::TRIANGLE_STRIP);
-            gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
-            gGL.vertex2f(-1, -1);
+		for (S32 i = 0; i < kernel; i++)
+		{
+			mGlow[i % 2].bindTarget();
+			mGlow[i % 2].clear();
 
-            gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-            gGL.vertex2f(-1, 3);
+			if (i == 0)
+			{
+				gGL.getTexUnit(0)->bind(&mGlow[2]);
+			}
+			else
+			{
+				gGL.getTexUnit(0)->bind(&mGlow[(i - 1) % 2]);
+			}
 
-            gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-            gGL.vertex2f(3, -1);
+			if (i % 2 == 0)
+			{
+				gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, delta, 0);
+			}
+			else
+			{
+				gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta);
+			}
 
-            gGL.end();
+			gGL.begin(LLRender::TRIANGLE_STRIP);
+			gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+			gGL.vertex2f(-1, -1);
 
-            gGL.getTexUnit(channel)->unbind(screen_target->getUsage());
-            gDeferredPostGammaCorrectProgram.unbind();
-        }
+			gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+			gGL.vertex2f(-1, 3);
 
-        screen_target->flush();
+			gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+			gGL.vertex2f(3, -1);
 
-        LLVertexBuffer::unbind();
-    }
+			gGL.end();
 
-    if (sRenderGlow)
-    {
-        LL_PROFILE_GPU_ZONE("glow");
-        mGlow[2].bindTarget();
-        mGlow[2].clear();
-
-        gGlowExtractProgram.bind();
-        F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f);
-        F32 maxAlpha = RenderGlowMaxExtractAlpha;
-        F32 warmthAmount = RenderGlowWarmthAmount;
-        LLVector3 lumWeights = RenderGlowLumWeights;
-        LLVector3 warmthWeights = RenderGlowWarmthWeights;
-
-        gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MIN_LUMINANCE, minLum);
-        gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MAX_EXTRACT_ALPHA, maxAlpha);
-        gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_LUM_WEIGHTS, lumWeights.mV[0], lumWeights.mV[1],
-                                      lumWeights.mV[2]);
-        gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_WARMTH_WEIGHTS, warmthWeights.mV[0], warmthWeights.mV[1],
-                                      warmthWeights.mV[2]);
-        gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_WARMTH_AMOUNT, warmthAmount);
-        
-        {
-            LLGLEnable blend_on(GL_BLEND);
-            LLGLEnable test(GL_ALPHA_TEST);
+			mGlow[i % 2].flush();
+		}
 
-            gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+		gGlowProgram.unbind();
+	}
+	else // !sRenderGlow, skip the glow ping-pong and just clear the result target
+	{
+		mGlow[1].bindTarget();
+		mGlow[1].clear();
+		mGlow[1].flush();
+	}
 
-            mRT->screen.bindTexture(0, 0, LLTexUnit::TFO_POINT);
+	gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
+	gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
+	gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
+	gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
+	glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
 
-            gGL.color4f(1, 1, 1, 1);
-            gPipeline.enableLightsFullbright();
-            gGL.begin(LLRender::TRIANGLE_STRIP);
-            gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
-            gGL.vertex2f(-1, -1);
+	tc2.setVec((F32)mRT->screen.getWidth(), (F32)mRT->screen.getHeight());
 
-            gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-            gGL.vertex2f(-1, 3);
+	gGL.flush();
 
-            gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-            gGL.vertex2f(3, -1);
+	LLVertexBuffer::unbind();
 
-            gGL.end();
+	if (LLPipeline::sRenderDeferred)
+	{
+		bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() &&
+			(RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) &&
+			RenderDepthOfField &&
+			!gCubeSnapshot;
 
-            gGL.getTexUnit(0)->unbind(mRT->screen.getUsage());
+		bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete() && !gCubeSnapshot;
 
-            mGlow[2].flush();
+		gViewerWindow->setup3DViewport();
 
-            tc1.setVec(0, 0);
-            tc2.setVec(2, 2); 
-        }
+		if (dof_enabled)
+		{
+			LL_PROFILE_GPU_ZONE("dof");
+			LLGLSLShader* shader = &gDeferredPostProgram;
+			LLGLDisable blend(GL_BLEND);
 
-        // power of two between 1 and 1024
-        U32 glowResPow = RenderGlowResolutionPow;
-        const U32 glow_res = llmax(1, llmin(1024, 1 << glowResPow));
+			// depth of field focal plane calculations
+			static F32 current_distance = 16.f;
+			static F32 start_distance = 16.f;
+			static F32 transition_time = 1.f;
 
-        S32 kernel = RenderGlowIterations * 2;
-        F32 delta = RenderGlowWidth / glow_res;
-        // Use half the glow width if we have the res set to less than 9 so that it looks
-        // almost the same in either case.
-        if (glowResPow < 9)
-        {
-            delta *= 0.5f;
-        }
-        F32 strength = RenderGlowStrength;
+			LLVector3 focus_point;
 
-        gGlowProgram.bind();
-        gGlowProgram.uniform1f(LLShaderMgr::GLOW_STRENGTH, strength);
+			LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject();
+			if (obj && obj->mDrawable && obj->isSelected())
+			{ // focus on selected media object
+				S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace();
+				if (obj && obj->mDrawable)
+				{
+					LLFace* face = obj->mDrawable->getFace(face_idx);
+					if (face)
+					{
+						focus_point = face->getPositionAgent();
+					}
+				}
+			}
 
-        for (S32 i = 0; i < kernel; i++)
-        {
-            mGlow[i % 2].bindTarget();
-            mGlow[i % 2].clear();
+			if (focus_point.isExactlyZero())
+			{
+				if (LLViewerJoystick::getInstance()->getOverrideCamera())
+				{ // focus on point under cursor
+					focus_point.set(gDebugRaycastIntersection.getF32ptr());
+				}
+				else if (gAgentCamera.cameraMouselook())
+				{ // focus on point under mouselook crosshairs
+					LLVector4a result;
+					result.clear();
 
-            if (i == 0)
-            {
-                gGL.getTexUnit(0)->bind(&mGlow[2]);
-            }
-            else
-            {
-                gGL.getTexUnit(0)->bind(&mGlow[(i - 1) % 2]);
-            }
+					gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, NULL, &result);
 
-            if (i % 2 == 0)
-            {
-                gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, delta, 0);
-            }
-            else
-            {
-                gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta);
-            }
+					focus_point.set(result.getF32ptr());
+				}
+				else
+				{
+					// focus on alt-zoom target
+					LLViewerRegion* region = gAgent.getRegion();
+					if (region)
+					{
+						focus_point = LLVector3(gAgentCamera.getFocusGlobal() - region->getOriginGlobal());
+					}
+				}
+			}
 
-            gGL.begin(LLRender::TRIANGLE_STRIP);
-            gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
-            gGL.vertex2f(-1, -1);
+			LLVector3 eye = LLViewerCamera::getInstance()->getOrigin();
+			F32 target_distance = 16.f;
+			if (!focus_point.isExactlyZero())
+			{
+				target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point - eye);
+			}
 
-            gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-            gGL.vertex2f(-1, 3);
+			if (transition_time >= 1.f && fabsf(current_distance - target_distance) / current_distance > 0.01f)
+			{ // large shift happened, interpolate smoothly to new target distance
+				transition_time = 0.f;
+				start_distance = current_distance;
+			}
+			else if (transition_time < 1.f)
+			{ // currently in a transition, continue interpolating
+				transition_time += 1.f / CameraFocusTransitionTime * gFrameIntervalSeconds.value();
+				transition_time = llmin(transition_time, 1.f);
 
-            gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-            gGL.vertex2f(3, -1);
+				F32 t = cosf(transition_time * F_PI + F_PI) * 0.5f + 0.5f;
+				current_distance = start_distance + (target_distance - start_distance) * t;
+			}
+			else
+			{ // small or no change, just snap to target distance
+				current_distance = target_distance;
+			}
 
-            gGL.end();
+			// convert to mm
+			F32 subject_distance = current_distance * 1000.f;
+			F32 fnumber = CameraFNumber;
+			F32 default_focal_length = CameraFocalLength;
 
-            mGlow[i % 2].flush();
-        }
+			F32 fov = LLViewerCamera::getInstance()->getView();
 
-        gGlowProgram.unbind();
-    }
-    else // !sRenderGlow, skip the glow ping-pong and just clear the result target
-    {
-        mGlow[1].bindTarget();
-        mGlow[1].clear();
-        mGlow[1].flush();
-    }
+			const F32 default_fov = CameraFieldOfView * F_PI / 180.f;
 
-    gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
-    gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
-    gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
-    gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
-    glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+			// F32 aspect_ratio = (F32) mRT->screen.getWidth()/(F32)mRT->screen.getHeight();
 
-    tc2.setVec((F32) mRT->screen.getWidth(), (F32) mRT->screen.getHeight());
+			F32 dv = 2.f * default_focal_length * tanf(default_fov / 2.f);
 
-    gGL.flush();
+			F32 focal_length = dv / (2 * tanf(fov / 2.f));
 
-    LLVertexBuffer::unbind();
+			// F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle);
 
-    if (LLPipeline::sRenderDeferred)
-    {
-        bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() &&
-                           (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) &&
-                           RenderDepthOfField &&
-                            !gCubeSnapshot;
+			// from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f))
+			// where	 N = fnumber
+			//			 s2 = dot distance
+			//			 s1 = subject distance
+			//			 f = focal length
+			//
 
-        bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete() && !gCubeSnapshot;
+			F32 blur_constant = focal_length * focal_length / (fnumber * (subject_distance - focal_length));
+			blur_constant /= 1000.f; // convert to meters for shader
+			F32 magnification = focal_length / (subject_distance - focal_length);
 
-        gViewerWindow->setup3DViewport();
+			{ // build diffuse+bloom+CoF
+                mRT->deferredLight.bindTarget();
+				shader = &gDeferredCoFProgram;
 
-        if (dof_enabled)
-        {
-            LL_PROFILE_GPU_ZONE("dof");
-            LLGLSLShader *shader = &gDeferredPostProgram;
-            LLGLDisable blend(GL_BLEND);
+				bindDeferredShader(*shader);
 
-            // depth of field focal plane calculations
-            static F32 current_distance = 16.f;
-            static F32 start_distance = 16.f;
-            static F32 transition_time = 1.f;
+				S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage());
+				if (channel > -1)
+				{
+					mRT->screen.bindTexture(0, channel);
+				}
 
-            LLVector3 focus_point;
+				shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance / 1000.f);
+				shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant);
+				shader->uniform1f(LLShaderMgr::DOF_TAN_PIXEL_ANGLE, tanf(1.f / LLDrawable::sCurPixelAngle));
+				shader->uniform1f(LLShaderMgr::DOF_MAGNIFICATION, magnification);
+				shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
+				shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
 
-            LLViewerObject *obj = LLViewerMediaFocus::getInstance()->getFocusedObject();
-            if (obj && obj->mDrawable && obj->isSelected())
-            { // focus on selected media object
-                S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace();
-                if (obj && obj->mDrawable)
-                {
-                    LLFace *face = obj->mDrawable->getFace(face_idx);
-                    if (face)
-                    {
-                        focus_point = face->getPositionAgent();
-                    }
-                }
-            }
+				gGL.begin(LLRender::TRIANGLE_STRIP);
+				gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+				gGL.vertex2f(-1, -1);
 
-            if (focus_point.isExactlyZero())
-            {
-                if (LLViewerJoystick::getInstance()->getOverrideCamera())
-                { // focus on point under cursor
-                    focus_point.set(gDebugRaycastIntersection.getF32ptr());
-                }
-                else if (gAgentCamera.cameraMouselook())
-                { // focus on point under mouselook crosshairs
-                    LLVector4a result;
-                    result.clear();
+				gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+				gGL.vertex2f(-1, 3);
 
-                    gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, NULL, &result);
+				gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+				gGL.vertex2f(3, -1);
 
-                    focus_point.set(result.getF32ptr());
-                }
-                else
-                {
-                    // focus on alt-zoom target
-                    LLViewerRegion *region = gAgent.getRegion();
-                    if (region)
-                    {
-                        focus_point = LLVector3(gAgentCamera.getFocusGlobal() - region->getOriginGlobal());
-                    }
-                }
-            }
+				gGL.end();
 
-            LLVector3 eye = LLViewerCamera::getInstance()->getOrigin();
-            F32 target_distance = 16.f;
-            if (!focus_point.isExactlyZero())
-            {
-                target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point - eye);
-            }
+				unbindDeferredShader(*shader);
+                mRT->deferredLight.flush();
+			}
 
-            if (transition_time >= 1.f && fabsf(current_distance - target_distance) / current_distance > 0.01f)
-            { // large shift happened, interpolate smoothly to new target distance
-                transition_time = 0.f;
-                start_distance = current_distance;
-            }
-            else if (transition_time < 1.f)
-            { // currently in a transition, continue interpolating
-                transition_time += 1.f / CameraFocusTransitionTime * gFrameIntervalSeconds.value();
-                transition_time = llmin(transition_time, 1.f);
+			U32 dof_width = (U32)(mRT->screen.getWidth() * CameraDoFResScale);
+			U32 dof_height = (U32)(mRT->screen.getHeight() * CameraDoFResScale);
 
-                F32 t = cosf(transition_time * F_PI + F_PI) * 0.5f + 0.5f;
-                current_distance = start_distance + (target_distance - start_distance) * t;
-            }
-            else
-            { // small or no change, just snap to target distance
-                current_distance = target_distance;
-            }
+			{ // perform DoF sampling at half-res (preserve alpha channel)
+				mRT->screen.bindTarget();
+				glViewport(0, 0, dof_width, dof_height);
+				gGL.setColorMask(true, false);
 
-            // convert to mm
-            F32 subject_distance = current_distance * 1000.f;
-            F32 fnumber = CameraFNumber;
-            F32 default_focal_length = CameraFocalLength;
+				shader = &gDeferredPostProgram;
+				bindDeferredShader(*shader);
+                S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage());
+				if (channel > -1)
+				{
+                    mRT->deferredLight.bindTexture(0, channel);
+				}
 
-            F32 fov = LLViewerCamera::getInstance()->getView();
+				shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
+				shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
 
-            const F32 default_fov = CameraFieldOfView * F_PI / 180.f;
+				gGL.begin(LLRender::TRIANGLE_STRIP);
+				gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+				gGL.vertex2f(-1, -1);
 
-            // F32 aspect_ratio = (F32) mRT->screen.getWidth()/(F32)mRT->screen.getHeight();
+				gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+				gGL.vertex2f(-1, 3);
 
-            F32 dv = 2.f * default_focal_length * tanf(default_fov / 2.f);
+				gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+				gGL.vertex2f(3, -1);
 
-            F32 focal_length = dv / (2 * tanf(fov / 2.f));
+				gGL.end();
 
-            // F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle);
+				unbindDeferredShader(*shader);
+				mRT->screen.flush();
+				gGL.setColorMask(true, true);
+			}
 
-            // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f))
-            // where	 N = fnumber
-            //			 s2 = dot distance
-            //			 s1 = subject distance
-            //			 f = focal length
-            //
+			{ // combine result based on alpha
+				if (multisample)
+				{
+					mRT->deferredLight.bindTarget();
+					glViewport(0, 0, mRT->deferredScreen.getWidth(), mRT->deferredScreen.getHeight());
+				}
+				else
+				{
+					gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
+					gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
+					gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
+					gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
+					glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+				}
 
-            F32 blur_constant = focal_length * focal_length / (fnumber * (subject_distance - focal_length));
-            blur_constant /= 1000.f; // convert to meters for shader
-            F32 magnification = focal_length / (subject_distance - focal_length);
+				shader = &gDeferredDoFCombineProgram;
+				bindDeferredShader(*shader);
 
-            { // build diffuse+bloom+CoF
-                mRT->deferredLight.bindTarget();
-                shader = &gDeferredCoFProgram;
+				S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage());
+				if (channel > -1)
+				{
+					mRT->screen.bindTexture(0, channel);
+				}
 
-                bindDeferredShader(*shader);
+				shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
+				shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
+				shader->uniform1f(LLShaderMgr::DOF_WIDTH, (dof_width - 1) / (F32)mRT->screen.getWidth());
+				shader->uniform1f(LLShaderMgr::DOF_HEIGHT, (dof_height - 1) / (F32)mRT->screen.getHeight());
 
-                S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage());
-                if (channel > -1)
-                {
-                    mRT->screen.bindTexture(0, channel);
-                }
+				gGL.begin(LLRender::TRIANGLE_STRIP);
+				gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+				gGL.vertex2f(-1, -1);
 
-                shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance / 1000.f);
-                shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant);
-                shader->uniform1f(LLShaderMgr::DOF_TAN_PIXEL_ANGLE, tanf(1.f / LLDrawable::sCurPixelAngle));
-                shader->uniform1f(LLShaderMgr::DOF_MAGNIFICATION, magnification);
-                shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
-                shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
+				gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+				gGL.vertex2f(-1, 3);
 
-                gGL.begin(LLRender::TRIANGLE_STRIP);
-                gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
-                gGL.vertex2f(-1, -1);
+				gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+				gGL.vertex2f(3, -1);
 
-                gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-                gGL.vertex2f(-1, 3);
+				gGL.end();
 
-                gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-                gGL.vertex2f(3, -1);
+				unbindDeferredShader(*shader);
 
-                gGL.end();
+				if (multisample)
+				{
+					mRT->deferredLight.flush();
+				}
+			}
+		}
+		else
+		{
+			LL_PROFILE_GPU_ZONE("no dof");
+			if (multisample)
+			{
+				mRT->deferredLight.bindTarget();
+			}
+			LLGLSLShader* shader = &gDeferredPostNoDoFProgram;
 
-                unbindDeferredShader(*shader);
-                mRT->deferredLight.flush();
-            }
+			bindDeferredShader(*shader);
 
-            U32 dof_width = (U32)(mRT->screen.getWidth() * CameraDoFResScale);
-            U32 dof_height = (U32)(mRT->screen.getHeight() * CameraDoFResScale);
+			S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage());
+			if (channel > -1)
+			{
+				mRT->screen.bindTexture(0, channel);
+			}
 
-            { // perform DoF sampling at half-res (preserve alpha channel)
-                mRT->screen.bindTarget();
-                glViewport(0, 0, dof_width, dof_height);
-                gGL.setColorMask(true, false);
+			gGL.begin(LLRender::TRIANGLE_STRIP);
+			gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+			gGL.vertex2f(-1, -1);
 
-                shader = &gDeferredPostProgram;
-                bindDeferredShader(*shader);
-                S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage());
-                if (channel > -1)
-                {
-                    mRT->deferredLight.bindTexture(0, channel);
-                }
+			gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+			gGL.vertex2f(-1, 3);
 
-                shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
-                shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
+			gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+			gGL.vertex2f(3, -1);
 
-                gGL.begin(LLRender::TRIANGLE_STRIP);
-                gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
-                gGL.vertex2f(-1, -1);
+			gGL.end();
 
-                gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-                gGL.vertex2f(-1, 3);
+			unbindDeferredShader(*shader);
 
-                gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-                gGL.vertex2f(3, -1);
+			if (multisample)
+			{
+				mRT->deferredLight.flush();
+			}
+		}
+	}
+}
 
-                gGL.end();
+LLRenderTarget* LLPipeline::screenTarget() {
 
-                unbindDeferredShader(*shader);
-                mRT->screen.flush();
-                gGL.setColorMask(true, true);
-            }
+	bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() &&
+		(RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) &&
+		RenderDepthOfField &&
+		!gCubeSnapshot;
 
-            { // combine result based on alpha
-                if (multisample)
-                {
-                    mRT->deferredLight.bindTarget();
-                    glViewport(0, 0, mRT->deferredScreen.getWidth(), mRT->deferredScreen.getHeight());
-                }
-                else
-                {
-                    gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
-                    gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
-                    gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
-                    gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
-                    glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-                }
+	bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete() && !gCubeSnapshot;
 
-                shader = &gDeferredDoFCombineProgram;
-                bindDeferredShader(*shader);
+	if (multisample || dof_enabled)
+		return &mRT->deferredLight;
+	
+	return &mRT->screen;
+}
 
-                S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage());
-                if (channel > -1)
-                {
-                    mRT->screen.bindTexture(0, channel);
-                }
+void LLPipeline::renderFinalize()
+{
+    LLVertexBuffer::unbind();
+    LLGLState::checkStates();
+    LLGLState::checkTextureChannels();
+
+    assertInitialized();
+
+    LLVector2 tc1(0, 0);
+    LLVector2 tc2((F32) mRT->screen.getWidth() * 2, (F32) mRT->screen.getHeight() * 2);
 
-                shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
-                shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
-                shader->uniform1f(LLShaderMgr::DOF_WIDTH, (dof_width - 1) / (F32)mRT->screen.getWidth());
-                shader->uniform1f(LLShaderMgr::DOF_HEIGHT, (dof_height - 1) / (F32)mRT->screen.getHeight());
+    LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM);
+    LL_PROFILE_GPU_ZONE("renderFinalize");
 
-                gGL.begin(LLRender::TRIANGLE_STRIP);
-                gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
-                gGL.vertex2f(-1, -1);
+    gGL.color4f(1, 1, 1, 1);
+    LLGLDepthTest depth(GL_FALSE);
+    LLGLDisable blend(GL_BLEND);
+    LLGLDisable cull(GL_CULL_FACE);
 
-                gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-                gGL.vertex2f(-1, 3);
+    enableLightsFullbright();
 
-                gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-                gGL.vertex2f(3, -1);
+    LLGLDisable test(GL_ALPHA_TEST);
 
-                gGL.end();
+    gGL.setColorMask(true, true);
+    glClearColor(0, 0, 0, 0);
 
-                unbindDeferredShader(*shader);
+    if (!gCubeSnapshot)
+    {
+		screenTarget()->bindTarget();
 
-                if (multisample)
-                {
-                    mRT->deferredLight.flush();
-                }
-            }
-        }
-        else
+        if (RenderScreenSpaceReflections)
         {
-            LL_PROFILE_GPU_ZONE("no dof");
-            if (multisample)
+            LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - screen space reflections");
+            LL_PROFILE_GPU_ZONE("screen space reflections");
+
+            bindDeferredShader(gPostScreenSpaceReflectionProgram, NULL);
+            mScreenTriangleVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+            set_camera_projection_matrix(gPostScreenSpaceReflectionProgram);
+
+            // We need linear depth.
+            static LLStaticHashedString zfar("zFar");
+            static LLStaticHashedString znear("zNear");
+            float                       nearClip = LLViewerCamera::getInstance()->getNear();
+            float                       farClip  = LLViewerCamera::getInstance()->getFar();
+            gPostScreenSpaceReflectionProgram.uniform1f(zfar, farClip);
+            gPostScreenSpaceReflectionProgram.uniform1f(znear, nearClip);
+
+            S32 channel = gPostScreenSpaceReflectionProgram.enableTexture(LLShaderMgr::DIFFUSE_MAP, screenTarget()->getUsage());
+            if (channel > -1)
             {
-                mRT->deferredLight.bindTarget();
+				screenTarget()->bindTexture(0, channel, LLTexUnit::TFO_POINT);
             }
-            LLGLSLShader *shader = &gDeferredPostNoDoFProgram;
 
-            bindDeferredShader(*shader);
+            {
+                LLGLDisable blend(GL_BLEND);
+                LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+
+                stop_glerror();
+                mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+                stop_glerror();
+            }
 
-            S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage());
+            unbindDeferredShader(gPostScreenSpaceReflectionProgram);
+        }
+
+        // gamma correct lighting
+        {
+            LL_PROFILE_GPU_ZONE("gamma correct");
+
+            LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+
+            LLVector2 tc1(0, 0);
+            LLVector2 tc2((F32)screenTarget()->getWidth() * 2, (F32)screenTarget()->getHeight() * 2);
+
+            // Apply gamma correction to the frame here.
+            gDeferredPostGammaCorrectProgram.bind();
+            // mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+            S32 channel = 0;
+            channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, screenTarget()->getUsage());
             if (channel > -1)
             {
-                mRT->screen.bindTexture(0, channel);
+				screenTarget()->bindTexture(0, channel, LLTexUnit::TFO_POINT);
             }
 
+            gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, screenTarget()->getWidth(), screenTarget()->getHeight());
+
+            F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+
+            gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
+
             gGL.begin(LLRender::TRIANGLE_STRIP);
             gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
             gGL.vertex2f(-1, -1);
@@ -8036,82 +8077,116 @@ void LLPipeline::renderFinalize()
 
             gGL.end();
 
-            unbindDeferredShader(*shader);
-
-            if (multisample)
-            {
-                mRT->deferredLight.flush();
-            }
+            gGL.getTexUnit(channel)->unbind(screenTarget()->getUsage());
+            gDeferredPostGammaCorrectProgram.unbind();
         }
 
-        if (multisample)
-        {
-            LL_PROFILE_GPU_ZONE("aa");
-            // bake out texture2D with RGBL for FXAA shader
-            mRT->fxaaBuffer.bindTarget();
+		screenTarget()->flush();
 
-            S32 width = mRT->screen.getWidth();
-            S32 height = mRT->screen.getHeight();
-            glViewport(0, 0, width, height);
+        LLVertexBuffer::unbind();
+    }
 
-            LLGLSLShader *shader = &gGlowCombineFXAAProgram;
+	if (RenderDeferred)
+	{
+		bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete() && !gCubeSnapshot;
+		LLGLSLShader* shader = &gGlowCombineProgram;
 
-            shader->bind();
-            shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height);
+		S32 width = mRT->screen.getWidth();
+		S32 height = mRT->screen.getHeight();
 
-            S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage());
-            if (channel > -1)
-            {
-                mRT->deferredLight.bindTexture(0, channel);
-            }
+		S32 channel = -1;
 
-            gGL.begin(LLRender::TRIANGLE_STRIP);
-            gGL.vertex2f(-1, -1);
-            gGL.vertex2f(-1, 3);
-            gGL.vertex2f(3, -1);
-            gGL.end();
+		// Present everything.
+		if (multisample)
+		{
+			LL_PROFILE_GPU_ZONE("aa");
+			// bake out texture2D with RGBL for FXAA shader
+			mRT->fxaaBuffer.bindTarget();
 
-            gGL.flush();
+			glViewport(0, 0, width, height);
 
-            shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage());
-            shader->unbind();
+			shader = &gGlowCombineFXAAProgram;
 
-            mRT->fxaaBuffer.flush();
+			shader->bind();
+			shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height);
 
-            shader = &gFXAAProgram;
-            shader->bind();
+			channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage());
+			if (channel > -1)
+			{
+				mRT->deferredLight.bindTexture(0, channel);
+			}
 
-            channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mRT->fxaaBuffer.getUsage());
-            if (channel > -1)
-            {
-                mRT->fxaaBuffer.bindTexture(0, channel, LLTexUnit::TFO_BILINEAR);
-            }
+			gGL.begin(LLRender::TRIANGLE_STRIP);
+			gGL.vertex2f(-1, -1);
+			gGL.vertex2f(-1, 3);
+			gGL.vertex2f(3, -1);
+			gGL.end();
 
-            gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
-            gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
-            gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
-            gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
-            glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-
-            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,
-                              0.5f / width * scale_x, 0.5f / height * scale_y);
-            shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT2, -2.f / width * scale_x, -2.f / height * scale_y,
-                              2.f / width * scale_x, 2.f / height * scale_y);
+			gGL.flush();
 
-            gGL.begin(LLRender::TRIANGLE_STRIP);
-            gGL.vertex2f(-1, -1);
-            gGL.vertex2f(-1, 3);
-            gGL.vertex2f(3, -1);
-            gGL.end();
+			shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage());
+			shader->unbind();
 
-            gGL.flush();
-            shader->unbind();
-        }
-    }
+			mRT->fxaaBuffer.flush();
+
+			shader = &gFXAAProgram;
+			shader->bind();
+
+			channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mRT->fxaaBuffer.getUsage());
+			if (channel > -1)
+			{
+				mRT->fxaaBuffer.bindTexture(0, channel, LLTexUnit::TFO_BILINEAR);
+			}
+
+			gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
+			gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
+			gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
+			gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
+			glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+
+			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,
+				0.5f / width * scale_x, 0.5f / height * scale_y);
+			shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT2, -2.f / width * scale_x, -2.f / height * scale_y,
+				2.f / width * scale_x, 2.f / height * scale_y);
+
+			gGL.begin(LLRender::TRIANGLE_STRIP);
+			gGL.vertex2f(-1, -1);
+			gGL.vertex2f(-1, 3);
+			gGL.vertex2f(3, -1);
+			gGL.end();
+
+			gGL.flush();
+			shader->unbind();
+		}
+		else
+		{
+			shader->bind();
+
+
+			gGL.getTexUnit(0)->bind(&mGlow[1]);
+			gGL.getTexUnit(1)->bind(screenTarget());
+
+			gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
+			gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
+			gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
+			gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
+			glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+
+			gGL.begin(LLRender::TRIANGLE_STRIP);
+			gGL.vertex2f(-1, -1);
+			gGL.vertex2f(-1, 3);
+			gGL.vertex2f(3, -1);
+			gGL.end();
+
+			gGL.flush();
+			shader->unbind();
+		}
+	}
+    
 #if 0 // DEPRECATED
     else // not deferred
     {
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 0097b863abd..bac68cfff08 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -137,6 +137,8 @@ class LLPipeline
 	void generateImpostor(LLVOAvatar* avatar, bool preview_avatar = false);
 	void bindScreenToTexture();
 	void renderFinalize();
+	void renderPostProcess();
+	LLRenderTarget* screenTarget();
 
 	void init();
 	void cleanup();
-- 
GitLab