diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp
index 291e2c2bf56d0d120d90ac156b3750fedbce47fd..4d7b10982a9ae2d09e7de439f8e5838bd0b69919 100644
--- a/indra/llprimitive/llgltfmaterial.cpp
+++ b/indra/llprimitive/llgltfmaterial.cpp
@@ -31,14 +31,14 @@
 // NOTE -- this should be the one and only place tiny_gltf.h is included
 #include "tinygltf/tiny_gltf.h"
 
-const char* LLGLTFMaterial::ASSET_VERSION = "1.1";
-const char* LLGLTFMaterial::ASSET_TYPE = "GLTF 2.0";
+const char* const LLGLTFMaterial::ASSET_VERSION = "1.1";
+const char* const LLGLTFMaterial::ASSET_TYPE = "GLTF 2.0";
 const std::array<std::string, 2> LLGLTFMaterial::ACCEPTED_ASSET_VERSIONS = { "1.0", "1.1" };
 
-const char* GLTF_FILE_EXTENSION_TRANSFORM = "KHR_texture_transform";
-const char* GLTF_FILE_EXTENSION_TRANSFORM_SCALE = "scale";
-const char* GLTF_FILE_EXTENSION_TRANSFORM_OFFSET = "offset";
-const char* GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rotation";
+const char* const GLTF_FILE_EXTENSION_TRANSFORM = "KHR_texture_transform";
+const char* const GLTF_FILE_EXTENSION_TRANSFORM_SCALE = "scale";
+const char* const GLTF_FILE_EXTENSION_TRANSFORM_OFFSET = "offset";
+const char* const GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rotation";
 
 // special UUID that indicates a null UUID in override data
 static const LLUUID GLTF_OVERRIDE_NULL_UUID = LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff");
diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h
index a3e0c0d9cafa04f995ee1aa49bd5adbb5d2ff212..cae7284421ad8ff47434a984f6df88d915243e65 100644
--- a/indra/llprimitive/llgltfmaterial.h
+++ b/indra/llprimitive/llgltfmaterial.h
@@ -49,8 +49,8 @@ class LLGLTFMaterial : public LLRefCount
     // default material for reference
     static const LLGLTFMaterial sDefault;
 
-    static const char* ASSET_VERSION;
-    static const char* ASSET_TYPE;
+    static const char* const ASSET_VERSION;
+    static const char* const ASSET_TYPE;
     static const std::array<std::string, 2> ACCEPTED_ASSET_VERSIONS;
     static bool isAcceptedVersion(const std::string& version) { return std::find(ACCEPTED_ASSET_VERSIONS.cbegin(), ACCEPTED_ASSET_VERSIONS.cend(), version) != ACCEPTED_ASSET_VERSIONS.cend(); }
 
diff --git a/indra/llprimitive/tests/llgltfmaterial_test.cpp b/indra/llprimitive/tests/llgltfmaterial_test.cpp
index 859cf99e3af0a5fcf51c39a11f51ef08502c1690..88b6fae3a7a5f57d712d12ac670c22937770980b 100644
--- a/indra/llprimitive/tests/llgltfmaterial_test.cpp
+++ b/indra/llprimitive/tests/llgltfmaterial_test.cpp
@@ -139,14 +139,13 @@ namespace tut
     template<> template<>
     void llgltfmaterial_object_t::test<1>()
     {
-        if (sizeof(void*) > 4) // Don't bother running this test for 32-bit systems
-        {
-            // If any fields are added/changed, these tests should be updated (consider also updating ASSET_VERSION in LLGLTFMaterial)
-            // This test result will vary between compilers, so only test a single platform
+#if ADDRESS_SIZE != 32
 #if LL_WINDOWS
-            ensure_equals("fields supported for GLTF (sizeof check)", sizeof(LLGLTFMaterial), 216);
+        // If any fields are added/changed, these tests should be updated (consider also updating ASSET_VERSION in LLGLTFMaterial)
+        // This test result will vary between compilers, so only test a single platform
+        ensure_equals("fields supported for GLTF (sizeof check)", sizeof(LLGLTFMaterial), 216);
+#endif
 #endif
-        }
         ensure_equals("LLGLTFMaterial texture info count", (U32)LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT, 4);
     }
 
@@ -253,4 +252,118 @@ namespace tut
             ensure_gltf_material_serialize("material with scaling/tint factors only", factors_only_material);
         }
     }
+
+    // Test that sDefault is a no-op override
+    template<> template<>
+    void llgltfmaterial_object_t::test<7>()
+    {
+        const LLGLTFMaterial material_asset = create_test_material();
+        LLGLTFMaterial render_material = material_asset;
+        render_material.applyOverride(LLGLTFMaterial::sDefault);
+        ensure("LLGLTFMaterial: sDefault is a no-op override", material_asset == render_material);
+    }
+
+    // Test application of transform overrides
+    template<> template<>
+    void llgltfmaterial_object_t::test<8>()
+    {
+        LLGLTFMaterial override_material;
+        apply_test_material_texture_transforms(override_material);
+        LLGLTFMaterial render_material;
+        render_material.applyOverride(override_material);
+        ensure("LLGLTFMaterial: transform overrides", render_material == override_material);
+    }
+
+    // Test application of flag-based overrides
+    template<> template<>
+    void llgltfmaterial_object_t::test<9>()
+    {
+        {
+            LLGLTFMaterial override_material;
+            override_material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_BLEND, true);
+            override_material.setDoubleSided(true, true);
+
+            LLGLTFMaterial render_material;
+
+            render_material.applyOverride(override_material);
+
+            ensure("LLGLTFMaterial: extra overrides with non-default values applied over default", render_material == override_material);
+        }
+        {
+            LLGLTFMaterial override_material;
+            override_material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_OPAQUE, true);
+            override_material.setDoubleSided(false, true);
+
+            LLGLTFMaterial render_material;
+            override_material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_BLEND, false);
+            override_material.setDoubleSided(true, false);
+
+            render_material.applyOverride(override_material);
+            // Not interested in these flags for equality comparison
+            override_material.mOverrideDoubleSided = false;
+            override_material.mOverrideAlphaMode = false;
+
+            ensure("LLGLTFMaterial: extra overrides with default values applied over non-default", render_material == override_material);
+        }
+    }
+
+    // Test application of texture overrides
+    template<> template<>
+    void llgltfmaterial_object_t::test<10>()
+    {
+        const U32 texture_count = 2;
+        const LLUUID override_textures[texture_count] = { LLUUID::null, LLUUID::generateNewID() };
+        const LLUUID asset_textures[texture_count] = { LLUUID::generateNewID(), LLUUID::null };
+        for (U32 i = 0; i < texture_count; ++i)
+        {
+            LLGLTFMaterial override_material;
+            const LLUUID& override_texture = override_textures[i];
+            for (LLGLTFMaterial::TextureInfo j = LLGLTFMaterial::TextureInfo(0); j  < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; j = LLGLTFMaterial::TextureInfo(U32(j) + 1))
+            {
+                override_material.setTextureId(j, override_texture, true);
+            }
+
+            LLGLTFMaterial render_material;
+            const LLUUID& asset_texture = asset_textures[i];
+            for (LLGLTFMaterial::TextureInfo j = LLGLTFMaterial::TextureInfo(0); j  < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; j = LLGLTFMaterial::TextureInfo(U32(j) + 1))
+            {
+                render_material.setTextureId(j, asset_texture, false);
+            }
+
+            render_material.applyOverride(override_material);
+
+            for (LLGLTFMaterial::TextureInfo j = LLGLTFMaterial::TextureInfo(0); j  < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; j = LLGLTFMaterial::TextureInfo(U32(j) + 1))
+            {
+                const LLUUID& render_texture = render_material.mTextureId[j];
+                ensure_equals("LLGLTFMaterial: Override texture ID " + override_texture.asString() + " replaces underlying texture ID " + asset_texture.asString(), render_texture, override_texture);
+            }
+        }
+    }
+
+    // Test non-persistence of default value flags in overrides
+    template<> template<>
+    void llgltfmaterial_object_t::test<11>()
+    {
+        const S32 non_default_alpha_modes[] = { LLGLTFMaterial::ALPHA_MODE_BLEND, LLGLTFMaterial::ALPHA_MODE_MASK };
+        for (S32 non_default_alpha_mode : non_default_alpha_modes)
+        {
+            LLGLTFMaterial material;
+            // Set default alpha mode
+            material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_OPAQUE, true);
+            ensure_equals("LLGLTFMaterial: alpha mode override flag set", material.mOverrideAlphaMode, true);
+            // Set non-default alpha mode
+            material.setAlphaMode(non_default_alpha_mode, true);
+            ensure_equals("LLGLTFMaterial: alpha mode override flag unset", material.mOverrideAlphaMode, false);
+        }
+
+        {
+            // Set default double sided
+            LLGLTFMaterial material;
+            material.setDoubleSided(false, true);
+            ensure_equals("LLGLTFMaterial: double sided override flag set", material.mOverrideDoubleSided, true);
+            // Set non-default double sided
+            material.setDoubleSided(true, true);
+            ensure_equals("LLGLTFMaterial: double sided override flag unset", material.mOverrideDoubleSided, false);
+        }
+    }
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl
index fffbdb913e6d7eb370937b3263fb3e48dc47105c..ee3a5f1f3131c713f07bfe1e75f34dbe1a63e240 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowUtil.glsl
@@ -59,12 +59,12 @@ float pcfShadow(sampler2DShadow shadowMap, vec3 norm, vec4 stc, float bias_mul,
     stc.xyz /= stc.w;
     stc.z += offset * 2.0;
     stc.x = floor(stc.x*shadow_res.x + fract(pos_screen.y*shadow_res.y))/shadow_res.x; // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here
-    float cs = texture(shadowMap, stc.xyz).x;
+    float cs = texture(shadowMap, stc.xyz);
     float shadow = cs * 4.0;
-    shadow += texture(shadowMap, stc.xyz+vec3( 1.5/shadow_res.x,  0.5/shadow_res.y, 0.0)).x;
-    shadow += texture(shadowMap, stc.xyz+vec3( 0.5/shadow_res.x, -1.5/shadow_res.y, 0.0)).x;
-    shadow += texture(shadowMap, stc.xyz+vec3(-1.5/shadow_res.x, -0.5/shadow_res.y, 0.0)).x;
-    shadow += texture(shadowMap, stc.xyz+vec3(-0.5/shadow_res.x,  1.5/shadow_res.y, 0.0)).x;
+    shadow += texture(shadowMap, stc.xyz+vec3( 1.5/shadow_res.x,  0.5/shadow_res.y, 0.0));
+    shadow += texture(shadowMap, stc.xyz+vec3( 0.5/shadow_res.x, -1.5/shadow_res.y, 0.0));
+    shadow += texture(shadowMap, stc.xyz+vec3(-1.5/shadow_res.x, -0.5/shadow_res.y, 0.0));
+    shadow += texture(shadowMap, stc.xyz+vec3(-0.5/shadow_res.x,  1.5/shadow_res.y, 0.0));
     return clamp(shadow * 0.125, 0.0, 1.0);
 #else
     return 1.0;
@@ -78,16 +78,16 @@ float pcfSpotShadow(sampler2DShadow shadowMap, vec4 stc, float bias_scale, vec2
     stc.z += spot_shadow_bias * bias_scale;
     stc.x = floor(proj_shadow_res.x * stc.x + fract(pos_screen.y*0.666666666)) / proj_shadow_res.x; // snap
 
-    float cs = texture(shadowMap, stc.xyz).x;
+    float cs = texture(shadowMap, stc.xyz);
     float shadow = cs;
 
     vec2 off = 1.0/proj_shadow_res;
     off.y *= 1.5;
     
-    shadow += texture(shadowMap, stc.xyz+vec3(off.x*2.0, off.y, 0.0)).x;
-    shadow += texture(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x;
-    shadow += texture(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x;
-    shadow += texture(shadowMap, stc.xyz+vec3(-off.x*2.0, -off.y, 0.0)).x;
+    shadow += texture(shadowMap, stc.xyz+vec3(off.x*2.0, off.y, 0.0));
+    shadow += texture(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0));
+    shadow += texture(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0));
+    shadow += texture(shadowMap, stc.xyz+vec3(-off.x*2.0, -off.y, 0.0));
     return shadow*0.2;
 #else
     return 1.0;
diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index 41085afb3d08fde91bd18c42c093cff1516e8189..64ce5fd4d2ce1091806d8e39bb77659ced84461d 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -420,6 +420,13 @@ BOOL LLMaterialEditor::postBuild()
         mEmissiveTextureCtrl->setOnSelectCallback(boost::bind(&LLMaterialEditor::onSelectCtrl, this, _1, _2, MATERIAL_EMISIVE_TEX_DIRTY));
         mNormalTextureCtrl->setOnSelectCallback(boost::bind(&LLMaterialEditor::onSelectCtrl, this, _1, _2, MATERIAL_NORMAL_TEX_DIRTY));
     }
+    else
+    {
+        mBaseColorTextureCtrl->setCanApplyImmediately(false);
+        mMetallicTextureCtrl->setCanApplyImmediately(false);
+        mEmissiveTextureCtrl->setCanApplyImmediately(false);
+        mNormalTextureCtrl->setCanApplyImmediately(false);
+    }
 
     if (!mIsOverride)
     {
@@ -461,6 +468,10 @@ BOOL LLMaterialEditor::postBuild()
         mBaseColorCtrl->setOnCancelCallback(boost::bind(&LLMaterialEditor::onCancelCtrl, this, _1, _2, MATERIAL_BASE_COLOR_DIRTY));
         mBaseColorCtrl->setOnSelectCallback(boost::bind(&LLMaterialEditor::onSelectCtrl, this, _1, _2, MATERIAL_BASE_COLOR_DIRTY));
     }
+    else
+    {
+        mBaseColorCtrl->setCanApplyImmediately(false);
+    }
     // transparency is a part of base color
     childSetCommitCallback("transparency", changes_callback, (void*)&MATERIAL_BASE_COLOR_DIRTY);
     childSetCommitCallback("alpha mode", changes_callback, (void*)&MATERIAL_ALPHA_MODE_DIRTY);
@@ -477,6 +488,10 @@ BOOL LLMaterialEditor::postBuild()
         mEmissiveColorCtrl->setOnCancelCallback(boost::bind(&LLMaterialEditor::onCancelCtrl, this, _1, _2, MATERIAL_EMISIVE_COLOR_DIRTY));
         mEmissiveColorCtrl->setOnSelectCallback(boost::bind(&LLMaterialEditor::onSelectCtrl, this, _1, _2, MATERIAL_EMISIVE_COLOR_DIRTY));
     }
+    else
+    {
+        mEmissiveColorCtrl->setCanApplyImmediately(false);
+    }
 
     if (!mIsOverride)
     {
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 4849015e799fdb9ab58301dbc377b18334be930d..6c3855004954d80a7083737258d8524faf21118f 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -251,7 +251,9 @@ void LLFloaterTexturePicker::setCanApplyImmediately(BOOL b)
 {
 	mCanApplyImmediately = b;
 
-	getChild<LLUICtrl>("apply_immediate_check")->setValue(mCanApplyImmediately);
+    LLUICtrl *apply_checkbox = getChild<LLUICtrl>("apply_immediate_check");
+    apply_checkbox->setValue(mCanApplyImmediately && gSavedSettings.getBOOL("TextureLivePreview"));
+    apply_checkbox->setEnabled(mCanApplyImmediately);
 }
 
 void LLFloaterTexturePicker::stopUsingPipette()
@@ -528,7 +530,7 @@ BOOL LLFloaterTexturePicker::postBuild()
 
 	mNoCopyTextureSelected = FALSE;
 
-	getChild<LLUICtrl>("apply_immediate_check")->setValue(gSavedSettings.getBOOL("TextureLivePreview"));
+	getChild<LLUICtrl>("apply_immediate_check")->setValue(mCanApplyImmediately && gSavedSettings.getBOOL("TextureLivePreview"));
 	childSetCommitCallback("apply_immediate_check", onApplyImmediateCheck, this);
     getChildView("apply_immediate_check")->setEnabled(mCanApplyImmediately);
 
@@ -862,7 +864,7 @@ void LLFloaterTexturePicker::onSelectionChange(const std::deque<LLFolderViewItem
 
 			if(!mPreviewSettingChanged)
 			{
-				mCanPreview = gSavedSettings.getBOOL("TextureLivePreview");
+				mCanPreview = mCanApplyImmediately && gSavedSettings.getBOOL("TextureLivePreview");
 			}
 			else
 			{
@@ -1163,7 +1165,7 @@ void LLFloaterTexturePicker::onBakeTextureSelect(LLUICtrl* ctrl, void *user_data
 
 	if (!self->mPreviewSettingChanged)
 	{
-		self->mCanPreview = gSavedSettings.getBOOL("TextureLivePreview");
+		self->mCanPreview = self->mCanApplyImmediately && gSavedSettings.getBOOL("TextureLivePreview");
 	}
 	else
 	{
@@ -1184,7 +1186,7 @@ void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply)
 	getChildRef<LLUICtrl>("apply_immediate_check").setVisible(can_preview);
 
 	mCanApply = can_apply;
-	mCanPreview = can_preview ? gSavedSettings.getBOOL("TextureLivePreview") : false;
+	mCanPreview = can_preview ? (mCanApplyImmediately && gSavedSettings.getBOOL("TextureLivePreview")) : false;
 	mPreviewSettingChanged = true;
 }