diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h
index 61feecc3eee821006c4be14dc59ef4ac3ee51086..7b98ee3edffc8d2b5a83558c5ce4d499e77ac490 100644
--- a/indra/llmath/v3dmath.h
+++ b/indra/llmath/v3dmath.h
@@ -401,11 +401,7 @@ inline bool operator!=(const LLVector3d& a, const LLVector3d& b)
 // [RLVa:KB] - RlvBehaviourModifierCompMin/Max
 inline bool operator<(const LLVector3d& lhs, const LLVector3d& rhs)
 {
-	return (lhs.mdV[0] < rhs.mdV[0]
-			|| (lhs.mdV[0] == rhs.mdV[0]
-				&& (lhs.mdV[1] < rhs.mdV[1]
-					|| ((lhs.mdV[1] == rhs.mdV[1])
-						&& lhs.mdV[2] < rhs.mdV[2]))));
+	return std::tie(lhs.mdV[0], lhs.mdV[1], lhs.mdV[2]) < std::tie(rhs.mdV[0], rhs.mdV[1], rhs.mdV[2]);
 }
 // [/RLVa:KB]
 
diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h
index a4fe91b575f1e84185e0467ef6259e773c97108f..816b8adf739af9c764940c122ceeaf16677ff2da 100644
--- a/indra/llmath/v4math.h
+++ b/indra/llmath/v4math.h
@@ -471,13 +471,7 @@ inline LLVector4 operator-(const LLVector4 &a)
 // [RLVa:KB] - RlvBehaviourModifierCompMin/Max
 inline bool operator<(const LLVector4& lhs, const LLVector4& rhs)
 {
-	return (lhs.mV[0] < rhs.mV[0]
-		|| (lhs.mV[0] == rhs.mV[0]
-			&& (lhs.mV[1] < rhs.mV[1]
-				|| ((lhs.mV[1] == rhs.mV[1])
-					&& lhs.mV[2] < rhs.mV[2]
-						|| ((lhs.mV[2] == rhs.mV[2])
-							&& lhs.mV[3] < rhs.mV[3])))));
+	return std::tie(lhs.mV[0], lhs.mV[1], lhs.mV[2], rhs.mV[3]) < std::tie(rhs.mV[0], rhs.mV[1], rhs.mV[2], rhs.mV[3]);
 }
 // [/RLVa:KB]
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/rlvF.glsl b/indra/newview/app_settings/shaders/class1/deferred/rlvF.glsl
index 8661ffe923cca2bd45c087ba6e343d4d54cfb947..4875523fb259684978d6c7cf955c2c38f913e163 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/rlvF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/rlvF.glsl
@@ -147,7 +147,7 @@ void main()
 			break;
 		case 2:		// Blur (variable)
 			fragColor = texture2DRect(diffuseRect, fragTC).rgb;
-			fragColor = mix(fragColor, blurVariable(diffuseRect, fragTC, SPHERE_PARAMS.x, BLUR_DIRECTION, effectStrength), effectStrength > 0);
+			fragColor = mix(fragColor, blurVariable(diffuseRect, fragTC, SPHERE_PARAMS.x, BLUR_DIRECTION, effectStrength), int(effectStrength > 0));
 			break;
 		case 3:		// ChromaticAberration
 			fragColor = chromaticAberration(diffuseRect, fragTC, SPHERE_PARAMS.xy, SPHERE_PARAMS.zw, effectStrength);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/rlvFLegacy.glsl b/indra/newview/app_settings/shaders/class1/deferred/rlvFLegacy.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..fce37c24beb94b00d230b182bd0421a56be386c2
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/rlvFLegacy.glsl
@@ -0,0 +1,176 @@
+/**
+ *
+ * Copyright (c) 2018-2020, Kitty Barnett
+ *
+ * The source code in this file is provided to you under the terms of the
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ *
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to
+ * abide by those obligations.
+ *
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+#ifdef DEFINE_GL_FRAGCOLOR
+	out vec4 frag_color;
+#else
+	#define frag_color gl_FragColor
+#endif
+
+VARYING vec2 vary_fragcoord;
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect depthMap;
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+uniform int  rlvEffectMode;     // ESphereMode
+uniform vec4 rlvEffectParam1;   // Sphere origin (in local coordinates)
+uniform vec4 rlvEffectParam2;   // Min/max dist + min/max value
+uniform bvec2 rlvEffectParam3;  // Min/max dist extend
+uniform vec4 rlvEffectParam4;   // Sphere params (=color when using blend)
+uniform vec2 rlvEffectParam5;   // Blur direction (not used for blend)
+
+#define SPHERE_ORIGIN		rlvEffectParam1.xyz
+#define SPHERE_DISTMIN		rlvEffectParam2.y
+#define SPHERE_DISTMAX		rlvEffectParam2.w
+#define SPHERE_DISTEXTEND	rlvEffectParam3
+#define SPHERE_VALUEMIN		rlvEffectParam2.x
+#define SPHERE_VALUEMAX		rlvEffectParam2.z
+#define SPHERE_PARAMS		rlvEffectParam4
+#define BLUR_DIRECTION		rlvEffectParam5.xy
+
+vec4 getPosition_d(vec2 pos_screen, float depth)
+{
+	vec2 sc = pos_screen.xy * 2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0, 1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0 * depth - 1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+vec3 blur13(sampler2DRect source, vec2 tc, vec2 direction)
+{
+  vec4 color = vec4(0.0);
+  vec2 off1 = vec2(1.411764705882353) * direction;
+  vec2 off2 = vec2(3.2941176470588234) * direction;
+  vec2 off3 = vec2(5.176470588235294) * direction;
+
+  color += texture2DRect(source, tc) * 0.1964825501511404;
+
+  color += texture2DRect(source, tc + off1) * 0.2969069646728344;
+  color += texture2DRect(source, tc - off1) * 0.2969069646728344;
+
+  color += texture2DRect(source, tc + off2) * 0.09447039785044732;
+  color += texture2DRect(source, tc - off2) * 0.09447039785044732;
+
+  color += texture2DRect(source, tc + off3) * 0.010381362401148057;
+  color += texture2DRect(source, tc - off3) * 0.010381362401148057;
+
+  return color.xyz;
+}
+
+const float pi = 3.14159265;
+
+// http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html
+vec3 blurVariable(sampler2DRect source, vec2 tc, float kernelSize, vec2 direction, float strength) {
+  float numBlurPixelsPerSide = float(kernelSize / 2);
+
+  // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889)
+  vec3 incrementalGaussian;
+  incrementalGaussian.x = 1.0 / (sqrt(2.0 * pi) * strength);
+  incrementalGaussian.y = exp(-0.5 / (strength * strength));
+  incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y;
+
+  vec4 avgValue = vec4(0.0, 0.0, 0.0, 0.0);
+  float coefficientSum = 0.0;
+
+  // Take the central sample first...
+  avgValue += texture2DRect(source, tc) * incrementalGaussian.x;
+  coefficientSum += incrementalGaussian.x;
+  incrementalGaussian.xy *= incrementalGaussian.yz;
+
+  // Go through the remaining 8 vertical samples (4 on each side of the center)
+  for (float i = 1.0; i <= numBlurPixelsPerSide; i++) {
+	avgValue += texture2DRect(source, tc - i * direction) * incrementalGaussian.x;
+	avgValue += texture2DRect(source, tc + i * direction) * incrementalGaussian.x;
+	coefficientSum += 2.0 * incrementalGaussian.x;
+	incrementalGaussian.xy *= incrementalGaussian.yz;
+  }
+
+  return (avgValue / coefficientSum).rgb;
+}
+
+vec3 chromaticAberration(sampler2DRect source, vec2 tc, vec2 redDrift, vec2 blueDrift, float strength)
+{
+	vec3 sourceColor = texture2DRect(source, tc).rgb;
+
+	// Sample the color components
+	vec3 driftColor;
+	driftColor.r = texture2DRect(source, tc + redDrift).r;
+	driftColor.g = sourceColor.g;
+	driftColor.b = texture2DRect(source, tc + blueDrift).b;
+
+	// Adjust the strength of the effect
+	return mix(sourceColor, driftColor, strength);
+}
+
+void main()
+{
+	vec2 fragTC = vary_fragcoord.st;
+	float fragDepth = texture2DRect(depthMap, fragTC).x;
+	vec3 fragPosLocal = getPosition_d(fragTC, fragDepth).xyz;
+	float distance = length(fragPosLocal.xyz - SPHERE_ORIGIN);
+
+	// Linear non-branching interpolation of the strength of the sphere effect (replaces if/elseif/else for x < min, min <= x <= max and x > max)
+	float effectStrength = SPHERE_VALUEMIN + mix(0.0, SPHERE_VALUEMAX - SPHERE_VALUEMIN, (distance - SPHERE_DISTMIN) / (SPHERE_DISTMAX - SPHERE_DISTMIN));
+	if (distance < SPHERE_DISTMIN)
+	{
+		effectStrength = SPHERE_DISTEXTEND.x ? SPHERE_VALUEMIN : 0.0;
+	}
+	else if (distance > SPHERE_DISTMAX)
+	{
+		effectStrength = SPHERE_DISTEXTEND.y ? SPHERE_VALUEMAX : 0.0;
+	}
+
+	vec3 fragColor;
+	if (rlvEffectMode == 0)				// Blend
+	{
+		fragColor = texture2DRect(diffuseRect, fragTC).rgb;
+		fragColor = mix(fragColor, SPHERE_PARAMS.rgb, effectStrength);
+	}
+	else if (rlvEffectMode == 1)		// Blur (fixed)
+	{
+		fragColor = blur13(diffuseRect, fragTC, effectStrength * BLUR_DIRECTION);
+	}
+	else if (rlvEffectMode == 2)		// Blur (variable)
+	{
+		fragColor = texture2DRect(diffuseRect, fragTC).rgb;
+		if (effectStrength > 0)
+		{
+			fragColor = blurVariable(diffuseRect, fragTC, SPHERE_PARAMS.x, BLUR_DIRECTION, effectStrength);
+		}
+	}
+	else if (rlvEffectMode == 3)		// ChromaticAberration
+	{
+		fragColor = chromaticAberration(diffuseRect, fragTC, SPHERE_PARAMS.xy, SPHERE_PARAMS.zw, effectStrength);
+	}
+	else if (rlvEffectMode == 4)		// Pixelate
+	{
+		effectStrength = sign(effectStrength);
+		float pixelWidth = max(1, floor(SPHERE_PARAMS.x * effectStrength)); float pixelHeight = max(1, floor(SPHERE_PARAMS.y * effectStrength));
+		fragTC = vec2(pixelWidth * floor(fragTC.x / pixelWidth), pixelHeight * floor(fragTC.y / pixelHeight));
+		fragColor = texture2DRect(diffuseRect, fragTC).rgb;
+	}
+
+	frag_color.rgb = fragColor;
+	frag_color.a = 0.0;
+}
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 517ec78725e8b21a1477b0597594825dce45c41e..479b3cdda60efa2cecf174211879c73861adc591 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -4144,7 +4144,10 @@ BOOL LLViewerShaderMgr::loadShadersWindLight()
 		gRlvSphereProgram.mName = "RLVa Sphere Post Processing Shader";
 		gRlvSphereProgram.mShaderFiles.clear();
 		gRlvSphereProgram.mShaderFiles.push_back(make_pair("deferred/rlvV.glsl", GL_VERTEX_SHADER_ARB));
-		gRlvSphereProgram.mShaderFiles.push_back(make_pair("deferred/rlvF.glsl", GL_FRAGMENT_SHADER_ARB));
+ 		if (gGLManager.mGLVersion >= 4.5f)
+			gRlvSphereProgram.mShaderFiles.push_back(make_pair("deferred/rlvF.glsl", GL_FRAGMENT_SHADER_ARB));
+		else
+			gRlvSphereProgram.mShaderFiles.push_back(make_pair("deferred/rlvFLegacy.glsl", GL_FRAGMENT_SHADER_ARB));
 		gRlvSphereProgram.mShaderLevel = mShaderLevel[SHADER_WINDLIGHT];
 		success = gRlvSphereProgram.createShader(NULL, NULL);
 	}