From c466e44334fd60c8270b68c70b8ae999b8dbd395 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 20 Sep 2022 19:09:26 -0500
Subject: [PATCH] SL-18190 Reduce banding (stay in linear space as much as
 possible, increase precision of reflection probes).  Faster radiance and
 irradiance map generation.

---
 indra/llrender/llcubemaparray.cpp             |   2 +-
 .../shaders/class1/deferred/alphaF.glsl       |  13 --
 .../shaders/class1/deferred/fullbrightF.glsl  |   2 +-
 .../shaders/class1/deferred/materialF.glsl    |   3 -
 .../shaders/class1/deferred/pbralphaF.glsl    |   2 +-
 .../shaders/class1/deferred/pbropaqueF.glsl   |   6 +-
 .../class1/interface/radianceGenF.glsl        |  20 +--
 .../class3/deferred/fullbrightShinyF.glsl     |   2 +-
 .../shaders/class3/deferred/materialF.glsl    |   3 -
 .../class3/deferred/multiPointLightF.glsl     |   7 +-
 .../class3/deferred/multiSpotLightF.glsl      |   8 +-
 .../shaders/class3/deferred/pointLightF.glsl  |   7 +-
 .../shaders/class3/deferred/softenLightF.glsl |   7 +-
 .../shaders/class3/deferred/spotLightF.glsl   |   7 +-
 indra/newview/llreflectionmapmanager.cpp      |  76 ++++++-----
 indra/newview/llreflectionmapmanager.h        |   3 +
 indra/newview/pipeline.cpp                    | 123 +++++++++---------
 17 files changed, 151 insertions(+), 140 deletions(-)

diff --git a/indra/llrender/llcubemaparray.cpp b/indra/llrender/llcubemaparray.cpp
index bb4bd581216..0e452b3d0a6 100644
--- a/indra/llrender/llcubemaparray.cpp
+++ b/indra/llrender/llcubemaparray.cpp
@@ -122,7 +122,7 @@ void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, BOOL us
 
     bind(0);
 
-    glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_RGB, resolution, resolution, count*6, 0,
+    glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_RGB10_A2, resolution, resolution, count*6, 0,
         GL_RGB, GL_UNSIGNED_BYTE, nullptr);
 
     mImage->setAddressMode(LLTexUnit::TAM_CLAMP);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index fc1cee1f592..69a0a41034b 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -292,19 +292,6 @@ void main()
 #if !defined(LOCAL_LIGHT_KILL)
     color.rgb += light.rgb;
 #endif // !defined(LOCAL_LIGHT_KILL)
-    // back to sRGB as we're going directly to the final RT post-deferred gamma correction
-    color.rgb = linear_to_srgb(color.rgb);
-
-//color.rgb = amblit;
-//color.rgb = vec3(ambient);
-//color.rgb = sunlit;
-//color.rgb = vec3(final_da);
-//color.rgb = post_ambient;
-//color.rgb = post_sunlight;
-//color.rgb = sun_contrib;
-//color.rgb = diffuse_srgb.rgb;
-//color.rgb = post_diffuse;
-//color.rgb = post_atmo;
 
 #ifdef WATER_FOG
     color = applyWaterFogView(pos.xyz, color);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index 57420158ca2..33b97aefcb8 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -82,7 +82,7 @@ void main()
     color.a   = final_alpha;
 #endif
 
-	frag_color.rgb = color.rgb;
+	frag_color.rgb = srgb_to_linear(color.rgb);
 	frag_color.a   = color.a;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index e87d90aa9e8..44bf61be840 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -402,9 +402,6 @@ void main()
     glare = min(glare, 1.0);
     float al = max(diffcol.a, glare)*vertex_color.a;
 
-    //convert to srgb as this color is being written post gamma correction
-    color = linear_to_srgb(color);
-
 #ifdef WATER_FOG
     vec4 temp = applyWaterFogView(pos, vec4(color, al));
     color = temp.rgb;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbralphaF.glsl
index 1caf2b2b1a7..04be496292b 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbralphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbralphaF.glsl
@@ -250,5 +250,5 @@ void main()
     color += 2.0*additive;
     color  = scaleSoftClipFrag(color);
 
-    frag_color = vec4(color,albedo.a * vertex_color.a);
+    frag_color = vec4(srgb_to_linear(color.rgb),albedo.a * vertex_color.a);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
index ea28cca0cb0..7376e9eb47e 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
@@ -98,8 +98,8 @@ void main()
     //emissive = vNt * 0.5 + 0.5;
     //emissive = tnorm*0.5+0.5;
     // See: C++: addDeferredAttachments(), GLSL: softenLightF
-    frag_data[0] = vec4(linear_to_srgb(col), 0.0);                                                   // Diffuse
-    frag_data[1] = vec4(linear_to_srgb(emissive), vertex_color.a);                                   // PBR sRGB Emissive
+    frag_data[0] = vec4(col, 0.0);                                                   // Diffuse
+    frag_data[1] = vec4(spec.rgb,vertex_color.a);                                    // PBR linear packed Occlusion, Roughness, Metal.
     frag_data[2] = vec4(encode_normal(tnorm), vertex_color.a, GBUFFER_FLAG_HAS_PBR); // normal, environment intensity, flags
-    frag_data[3] = vec4(spec.rgb,0);                                                 // PBR linear packed Occlusion, Roughness, Metal.
+    frag_data[3] = vec4(emissive,0);                                                // PBR sRGB Emissive
 }
diff --git a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl
index 7c175eab5fd..bb4a79247d2 100644
--- a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl
@@ -37,6 +37,10 @@ uniform int sourceIdx;
 
 VARYING vec3 vary_dir;
 
+//uniform float roughness;
+
+uniform float mipLevel;
+
 // =============================================================================================================
 // Parts of this file are (c) 2018 Sascha Willems
 // SNIPPED FROM https://github.com/SaschaWillems/Vulkan-glTF-PBR/blob/master/data/shaders/prefilterenvmap.frag
@@ -65,11 +69,6 @@ SOFTWARE.
 */
 // =============================================================================================================
 
-
-//uniform float roughness;
-
-uniform float mipLevel;
-
 const float PI = 3.1415926536;
 
 // Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
@@ -130,11 +129,13 @@ vec3 prefilterEnvMap(vec3 R)
 	vec3 color = vec3(0.0);
 	float totalWeight = 0.0;
 	float envMapDim = 256.0;
-    int numSamples = 8;
+    int numSamples = 4;
     
     float numMips = 7.0;
 
-    float roughness = (mipLevel+1)/numMips;
+    float roughness = mipLevel/numMips;
+
+    numSamples = max(int(numSamples*roughness), 1);
 
 	for(uint i = 0u; i < numSamples; i++) {
 		vec2 Xi = hammersley2d(i, numSamples);
@@ -154,8 +155,8 @@ vec3 prefilterEnvMap(vec3 R)
 			// Solid angle of 1 pixel across all cube faces
 			float omegaP = 4.0 * PI / (6.0 * envMapDim * envMapDim);
 			// Biased (+1.0) mip level for better result
-			//float mip = roughness == 0.0 ? 0.0 : max(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f);
-            float mip = clamp(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f, 7.f);
+			float mip = roughness == 0.0 ? 0.0 : clamp(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f, 7.f);
+            //float mip = clamp(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f, 7.f);
 			color += textureLod(reflectionProbes, vec4(L,sourceIdx), mip).rgb * dotNL;
 			totalWeight += dotNL;
 
@@ -170,4 +171,3 @@ void main()
 	frag_color = vec4(prefilterEnvMap(N), 1.0);
 }
 // =============================================================================================================
-
diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
index a04f611440b..67f1fc4c18f 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
@@ -115,8 +115,8 @@ void main()
 */
 
 	color.a = 1.0;
-	//color.rgb = linear_to_srgb(color.rgb);
 
+    color.rgb = srgb_to_linear(color.rgb);
 	frag_color = color;
 }
 
diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
index 7f8536cdab7..fcda50c4dec 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
@@ -433,9 +433,6 @@ void main()
     glare = min(glare, 1.0);
     float al = max(diffcol.a, glare)*vertex_color.a;
 
-    //convert to srgb as this color is being written post gamma correction
-    color = linear_to_srgb(color);
-
 #ifdef WATER_FOG
     vec4 temp = applyWaterFogView(pos, vec4(color, al));
     color = temp.rgb;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl
index 2ee439f61a1..6dd446d9f7b 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl
@@ -95,8 +95,8 @@ void main()
 
     if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
     {
-        vec3 colorEmissive = spec.rgb; // PBR sRGB Emissive.  See: pbropaqueF.glsl
-        vec3 orm = texture2DRect(emissiveRect, tc).rgb; //orm is packed into "emissiveRect" to keep the data in linear color space
+        vec3 colorEmissive = texture2DRect(emissiveRect, tc).rgb;
+        vec3 orm = spec.rgb;
         float perceptualRoughness = orm.g;
         float metallic = orm.b;
         vec3 f0 = vec3(0.04);
@@ -134,6 +134,9 @@ void main()
 
         float noise = texture2D(noiseMap, tc/128.0).b;
 
+        diffuse = srgb_to_linear(diffuse);
+        spec.rgb = srgb_to_linear(spec.rgb);
+
         // As of OSX 10.6.7 ATI Apple's crash when using a variable size loop
         for (int i = 0; i < LIGHT_COUNT; ++i)
         {
diff --git a/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl
index 6424e180792..cb8877ebe5a 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl
@@ -147,8 +147,8 @@ void main()
 
     if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
     {
-        vec3 colorEmissive = spec.rgb; // PBR sRGB Emissive.  See: pbropaqueF.glsl
-        vec3 orm = texture2DRect(emissiveRect, tc).rgb; //orm is packed into "emissiveRect" to keep the data in linear color space
+        vec3 colorEmissive = texture2DRect(emissiveRect, tc).rgb; 
+        vec3 orm = spec.rgb;
         float perceptualRoughness = orm.g;
         float metallic = orm.b;
         vec3 f0 = vec3(0.04);
@@ -182,6 +182,10 @@ void main()
     }
     else
     {
+
+        diffuse = srgb_to_linear(diffuse);
+        spec.rgb = srgb_to_linear(spec.rgb);
+
         float noise = texture2D(noiseMap, tc/128.0).b;
         if (proj_tc.z > 0.0 &&
             proj_tc.x < 1.0 &&
diff --git a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
index 27fca64ab34..cdffcf103d2 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl
@@ -99,8 +99,8 @@ void main()
 
     if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
     {
-        vec3 colorEmissive = spec.rgb; // PBR sRGB Emissive.  See: pbropaqueF.glsl
-        vec3 orm = texture2DRect(emissiveRect, tc).rgb; //orm is packed into "emissiveRect" to keep the data in linear color space
+        vec3 colorEmissive = texture2DRect(emissiveRect, tc).rgb; 
+        vec3 orm = spec.rgb;
         float perceptualRoughness = orm.g;
         float metallic = orm.b;
         vec3 f0 = vec3(0.04);
@@ -121,6 +121,9 @@ void main()
             discard;
         }
 
+        diffuse = srgb_to_linear(diffuse);
+        spec.rgb = srgb_to_linear(spec.rgb);
+
         float noise = texture2D(noiseMap, tc/128.0).b;
         float lit = nl * dist_atten * noise;
 
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index a8a3b5d33f3..5c049b6bd63 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -145,12 +145,12 @@ void main()
     if (hasPBR)
     {
         norm.xyz           = getNorm(tc);
-        vec3 orm = texture2DRect(emissiveRect, tc).rgb; //orm is packed into "emissiveRect" to keep the data in linear color space
+        vec3 orm = texture2DRect(specularRect, tc).rgb; 
         float perceptualRoughness = orm.g;
         float metallic = orm.b;
         float ao = orm.r * ambocc;
 
-        vec3 colorEmissive = texture2DRect(specularRect, tc).rgb; //specularRect is sRGB sampler, result is in linear space
+        vec3 colorEmissive = texture2DRect(emissiveRect, tc).rgb;
 
         // PBR IBL
         float gloss      = 1.0 - perceptualRoughness;
@@ -165,7 +165,6 @@ void main()
         //baseColor.rgb = vec3(0,0,0);
         //colorEmissive = srgb_to_linear(norm.xyz*0.5+0.5);
 
-
         vec3 diffuseColor = baseColor.rgb*(vec3(1.0)-f0);
         diffuseColor *= 1.0 - metallic;
 
@@ -195,7 +194,7 @@ void main()
         float da          = clamp(dot(norm.xyz, light_dir.xyz), 0.0, 1.0);
         da                = pow(da, light_gamma);
 
-        diffuse.rgb = linear_to_srgb(diffuse.rgb); // SL-14035
+        //diffuse.rgb = linear_to_srgb(diffuse.rgb); // SL-14035
 
         sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity);
         ambenv.rgb = linear_to_srgb(ambenv.rgb); 
diff --git a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl
index c8d45eb4297..3274153a462 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl
@@ -154,8 +154,8 @@ void main()
     vec3 amb_rgb = vec3(0);
     if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
     {
-        vec3 colorEmissive = spec.rgb; // PBR sRGB Emissive.  See: pbropaqueF.glsl
-        vec3 orm = texture2DRect(emissiveRect, tc).rgb; //orm is packed into "emissiveRect" to keep the data in linear color space
+        vec3 colorEmissive = texture2DRect(emissiveRect, tc).rgb;
+        vec3 orm = spec.rgb; 
         float perceptualRoughness = orm.g;
         float metallic = orm.b;
         vec3 f0 = vec3(0.04);
@@ -189,6 +189,9 @@ void main()
     }
     else
     {
+        diffuse = srgb_to_linear(diffuse);
+        spec.rgb = srgb_to_linear(spec.rgb);
+        
         float noise = texture2D(noiseMap, tc/128.0).b;
         if (proj_tc.z > 0.0 &&
             proj_tc.x < 1.0 &&
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index 9c6d7ea26f1..2aa1f06eaf8 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -80,7 +80,7 @@ void LLReflectionMapManager::update()
 
     if (!mRenderTarget.isComplete())
     {
-        U32 color_fmt = GL_SRGB8_ALPHA8;
+        U32 color_fmt = GL_RGB10_A2;
         const bool use_depth_buffer = true;
         const bool use_stencil_buffer = true;
         U32 targetRes = LL_REFLECTION_PROBE_RESOLUTION * 2; // super sample
@@ -95,7 +95,7 @@ void LLReflectionMapManager::update()
         mMipChain.resize(count);
         for (int i = 0; i < count; ++i)
         {
-            mMipChain[i].allocate(res, res, GL_RGB, false, false, LLTexUnit::TT_RECT_TEXTURE);
+            mMipChain[i].allocate(res, res, GL_RGB10_A2, false, false, LLTexUnit::TT_RECT_TEXTURE);
             res /= 2;
         }
     }
@@ -450,10 +450,10 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
                 mTexture->bind(0);
                 //glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res);
                 glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, targetIdx * 6 + face, 0, 0, res, res);
-                if (i == 0)
-                {
-                    glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res);
-                }
+                //if (i == 0)
+                //{
+                    //glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res);
+                //}
                 mTexture->unbind();
             }
             mMipChain[i].flush();
@@ -470,19 +470,27 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
     {
         //generate radiance map
         gRadianceGenProgram.bind();
+        mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
         S32 channel = gRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
         mTexture->bind(channel);
         static LLStaticHashedString sSourceIdx("sourceIdx");
         gRadianceGenProgram.uniform1i(sSourceIdx, targetIdx);
 
-        static LLStaticHashedString sMipLevel("mipLevel");
+        mMipChain[0].bindTarget();
+        U32 res = mMipChain[0].getWidth();
 
-        mMipChain[1].bindTarget();
-        U32 res = mMipChain[1].getWidth();
-
-        for (int i = 1; i < mMipChain.size(); ++i)
+        for (int i = 0; i < mMipChain.size(); ++i)
         {
             LL_PROFILE_GPU_ZONE("probe radiance gen");
+            static LLStaticHashedString sMipLevel("mipLevel");
+            static LLStaticHashedString sRoughness("roughness");
+            static LLStaticHashedString sWidth("u_width");
+
+            gRadianceGenProgram.uniform1f(sRoughness, (F32)i / (F32)(mMipChain.size() - 1));
+            gRadianceGenProgram.uniform1f(sMipLevel, i);
+            gRadianceGenProgram.uniform1i(sWidth, mMipChain[i].getWidth());
+
             for (int cf = 0; cf < 6; ++cf)
             { // for each cube face
                 LLCoordFrame frame;
@@ -492,18 +500,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
                 frame.getOpenGLRotation(mat);
                 gGL.loadMatrix(mat);
 
-                static LLStaticHashedString sRoughness("roughness");
-
-                gRadianceGenProgram.uniform1f(sRoughness, (F32)i / (F32)(mMipChain.size() - 1));
-                gRadianceGenProgram.uniform1f(sMipLevel, llmax((F32)(i - 1), 0.f));
-                
-                gGL.begin(gGL.QUADS);
-                gGL.vertex3f(-1, -1, -1);
-                gGL.vertex3f(1, -1, -1);
-                gGL.vertex3f(1, 1, -1);
-                gGL.vertex3f(-1, 1, -1);
-                gGL.end();
-                gGL.flush();
+                mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4);
                 
                 glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res);
             }
@@ -523,7 +520,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
         mTexture->bind(channel);
 
         gIrradianceGenProgram.uniform1i(sSourceIdx, targetIdx);
-
+        mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX);
         int start_mip = 0;
         // find the mip target to start with based on irradiance map resolution
         for (start_mip = 0; start_mip < mMipChain.size(); ++start_mip)
@@ -548,13 +545,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
                 frame.getOpenGLRotation(mat);
                 gGL.loadMatrix(mat);
 
-                gGL.begin(gGL.QUADS);
-                gGL.vertex3f(-1, -1, -1);
-                gGL.vertex3f(1, -1, -1);
-                gGL.vertex3f(1, 1, -1);
-                gGL.vertex3f(-1, 1, -1);
-                gGL.end();
-                gGL.flush();
+                mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4);
 
                 S32 res = mMipChain[i].getWidth();
                 mIrradianceMaps->bind(channel);
@@ -563,7 +554,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
             }
         }
 
-        mMipChain[1].flush();
+        mMipChain[0].flush();
 
         gIrradianceGenProgram.unbind();
     }
@@ -848,4 +839,25 @@ void LLReflectionMapManager::initReflectionMaps()
         mIrradianceMaps = new LLCubeMapArray();
         mIrradianceMaps->allocate(LL_IRRADIANCE_MAP_RESOLUTION, 3, mReflectionProbeCount, FALSE);
     }
+
+    if (mVertexBuffer.isNull())
+    {
+        U32 mask = LLVertexBuffer::MAP_VERTEX;
+        LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, GL_STATIC_DRAW);
+        buff->allocateBuffer(4, 0, TRUE);
+
+        LLStrider<LLVector3> v;
+        
+        buff->getVertexStrider(v);
+        
+        v[0] = LLVector3(-1, -1, -1);
+        v[1] = LLVector3(1, -1, -1);
+        v[2] = LLVector3(-1, 1, -1);
+        v[3] = LLVector3(1, 1, -1);
+
+        buff->flush();
+
+        mVertexBuffer = buff;
+
+    }
 }
diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h
index 29a9ece2f86..493f53efb82 100644
--- a/indra/newview/llreflectionmapmanager.h
+++ b/indra/newview/llreflectionmapmanager.h
@@ -119,6 +119,9 @@ class alignas(16) LLReflectionMapManager
     // storage for reflection probe radiance maps (plus two scratch space cubemaps)
     LLPointer<LLCubeMapArray> mTexture;
 
+    // vertex buffer for pushing verts to filter shaders
+    LLPointer<LLVertexBuffer> mVertexBuffer;
+
     // storage for reflection probe irradiance maps
     LLPointer<LLCubeMapArray> mIrradianceMaps;
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index dd15b63fab8..177d712f4b8 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -369,14 +369,13 @@ void validate_framebuffer_object();
 
 // Add color attachments for deferred rendering
 // target -- RenderTarget to add attachments to
-// for_impostor -- whether or not these render targets are for an impostor (if true, avoids implicit sRGB conversions)
 bool addDeferredAttachments(LLRenderTarget& target, bool for_impostor = false)
 {
     bool pbr = gSavedSettings.getBOOL("RenderPBR");
     bool valid = true
-        && target.addColorAttachment(for_impostor ? GL_RGBA : GL_SRGB8_ALPHA8) // frag-data[1] specular or PBR sRGB Emissive
+        && target.addColorAttachment(GL_RGBA) // frag-data[1] specular OR PBR ORM
         && target.addColorAttachment(GL_RGB10_A2)                              // frag_data[2] normal+z+fogmask, See: class1\deferred\materialF.glsl & softenlight
-        && (pbr ? target.addColorAttachment(GL_RGBA) : true);                  // frag_data[3] PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl
+        && (pbr ? target.addColorAttachment(GL_RGBA) : true);                  // frag_data[3] PBR emissive
     return valid;
 }
 
@@ -887,7 +886,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 		const U32 occlusion_divisor = 3;
 
 		//allocate deferred rendering color buffers
-		if (!mRT->deferredScreen.allocate(resX, resY, GL_SRGB8_ALPHA8, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+		if (!mRT->deferredScreen.allocate(resX, resY, GL_RGBA, 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;
@@ -8162,7 +8161,6 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
         deferred_target->bindTexture(0,channel, LLTexUnit::TFO_POINT); // frag_data[0]
 	}
 
-    // NOTE: PBR sRGB Emissive -- See: C++: addDeferredAttachments(), GLSL: pbropaqueF.glsl
     channel = shader.enableTexture(LLShaderMgr::DEFERRED_SPECULAR, deferred_target->getUsage());
 	if (channel > -1)
 	{
@@ -8175,7 +8173,6 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
         deferred_target->bindTexture(2, channel, LLTexUnit::TFO_POINT); // frag_data[2]
 	}
 
-    // NOTE: PBR linear packed Occlusion, Roughness, Metal -- See: C++: addDeferredAttachments(), GLSL: pbropaqueF.glsl
     channel = shader.enableTexture(LLShaderMgr::DEFERRED_EMISSIVE, deferred_target->getUsage());
     if (channel > -1)
     {
@@ -8974,60 +8971,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
 
     screen_target->flush();
 
-    // gamma correct lighting
-    gGL.matrixMode(LLRender::MM_PROJECTION);
-    gGL.pushMatrix();
-    gGL.loadIdentity();
-    gGL.matrixMode(LLRender::MM_MODELVIEW);
-    gGL.pushMatrix();
-    gGL.loadIdentity();
-
-    {
-        LL_PROFILE_GPU_ZONE("gamma correct");
-        LLGLDepthTest depth(GL_FALSE, GL_FALSE);
-
-        LLVector2 tc1(0, 0);
-        LLVector2 tc2((F32) screen_target->getWidth() * 2, (F32) screen_target->getHeight() * 2);
-
-        screen_target->bindTarget();
-        // 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);
-        }
-
-        gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, screen_target->getWidth(), screen_target->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);
-
-        gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-        gGL.vertex2f(-1, 3);
-
-        gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-        gGL.vertex2f(3, -1);
-
-        gGL.end();
-
-        gGL.getTexUnit(channel)->unbind(screen_target->getUsage());
-        gDeferredPostGammaCorrectProgram.unbind();
-        screen_target->flush();
-    }
-
-    gGL.matrixMode(LLRender::MM_PROJECTION);
-    gGL.popMatrix();
-    gGL.matrixMode(LLRender::MM_MODELVIEW);
-    gGL.popMatrix();
-
     screen_target->bindTarget();
 
     {  // render non-deferred geometry (alpha, fullbright, glow)
@@ -9063,6 +9006,66 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
         popRenderTypeMask();
     }
 
+    screen_target->flush();
+
+    if (!gCubeSnapshot)
+    {
+        // gamma correct lighting
+        gGL.matrixMode(LLRender::MM_PROJECTION);
+        gGL.pushMatrix();
+        gGL.loadIdentity();
+        gGL.matrixMode(LLRender::MM_MODELVIEW);
+        gGL.pushMatrix();
+        gGL.loadIdentity();
+
+        {
+            LL_PROFILE_GPU_ZONE("gamma correct");
+
+            LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+
+            LLVector2 tc1(0, 0);
+            LLVector2 tc2((F32)screen_target->getWidth() * 2, (F32)screen_target->getHeight() * 2);
+
+            screen_target->bindTarget();
+            // 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);
+            }
+
+            gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, screen_target->getWidth(), screen_target->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);
+
+            gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+            gGL.vertex2f(-1, 3);
+
+            gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+            gGL.vertex2f(3, -1);
+
+            gGL.end();
+
+            gGL.getTexUnit(channel)->unbind(screen_target->getUsage());
+            gDeferredPostGammaCorrectProgram.unbind();
+            screen_target->flush();
+        }
+
+        gGL.matrixMode(LLRender::MM_PROJECTION);
+        gGL.popMatrix();
+        gGL.matrixMode(LLRender::MM_MODELVIEW);
+        gGL.popMatrix();
+    }
+
     if (!gCubeSnapshot)
     {
         // render highlights, etc.
-- 
GitLab