diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp
index a9099b1ce9290eee9ee504453381e57a2544fb25..996b168262b39d83700baa064e8404b061be8307 100644
--- a/indra/newview/lllocalgltfmaterials.cpp
+++ b/indra/newview/lllocalgltfmaterials.cpp
@@ -214,12 +214,18 @@ bool LLLocalGLTFMaterial::loadMaterial()
             LLStringUtil::toLower(filename_lc);
             std::string material_name;
 
-            // Might be a good idea to make these textures into local textures
-            decode_successful = LLTinyGLTFHelper::getMaterialFromFile(
-                mFilename,
-                mMaterialIndex,
-                this,
-                material_name);
+            tinygltf::Model model;
+            decode_successful = LLTinyGLTFHelper::loadModel(mFilename, model);
+            if (decode_successful)
+            {
+                // Might be a good idea to make these textures into local textures
+                decode_successful = LLTinyGLTFHelper::getMaterialFromModel(
+                    mFilename,
+                    model,
+                    mMaterialIndex,
+                    this,
+                    material_name);
+            }
 
             if (!material_name.empty())
             {
@@ -308,7 +314,10 @@ S32 LLLocalGLTFMaterialMgr::addUnit(const std::vector<std::string>& filenames)
 
 S32 LLLocalGLTFMaterialMgr::addUnit(const std::string& filename)
 {
-    S32 materials_in_file = LLTinyGLTFHelper::getMaterialCountFromFile(filename);
+    tinygltf::Model model;
+    LLTinyGLTFHelper::loadModel(filename, model);
+
+    S32 materials_in_file = model.materials.size();
     if (materials_in_file <= 0)
     {
         return 0;
diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp
index 64ce5fd4d2ce1091806d8e39bb77659ced84461d..4cdc503af88fb494ec762ae874ef83d957373869 100644
--- a/indra/newview/llmaterialeditor.cpp
+++ b/indra/newview/llmaterialeditor.cpp
@@ -1622,40 +1622,13 @@ static void pack_textures(
     }
 }
 
-void LLMaterialEditor::uploadMaterialFromFile(const std::string& filename, S32 index)
+void LLMaterialEditor::uploadMaterialFromModel(const std::string& filename, tinygltf::Model& model_in, S32 index)
 {
     if (index < 0 || !LLMaterialEditor::capabilitiesAvailable())
     {
         return;
     }
 
-    tinygltf::TinyGLTF loader;
-    std::string        error_msg;
-    std::string        warn_msg;
-
-    bool loaded = false;
-    tinygltf::Model model_in;
-
-    std::string filename_lc = filename;
-    LLStringUtil::toLower(filename_lc);
-
-    // Load a tinygltf model fom a file. Assumes that the input filename has already been
-    // been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish.
-    if (std::string::npos == filename_lc.rfind(".gltf"))
-    {  // file is binary
-        loaded = loader.LoadBinaryFromFile(&model_in, &error_msg, &warn_msg, filename);
-    }
-    else
-    {  // file is ascii
-        loaded = loader.LoadASCIIFromFile(&model_in, &error_msg, &warn_msg, filename);
-    }
-
-    if (!loaded)
-    {
-        LLNotificationsUtil::add("CannotUploadMaterial");
-        return;
-    }
-
     if (model_in.materials.empty())
     {
         // materials are missing
@@ -1672,13 +1645,15 @@ void LLMaterialEditor::uploadMaterialFromFile(const std::string& filename, S32 i
     // This uses 'filename' to make sure multiple bulk uploads work
     // instead of fighting for a single instance.
     LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor", LLSD().with("filename", filename).with("index", LLSD::Integer(index)));
-    me->loadMaterial(model_in, filename_lc, index, false);
+    me->loadMaterial(model_in, filename, index, false);
     me->saveIfNeeded();
 }
 
 
 void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 index)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
+
     tinygltf::TinyGLTF loader;
     std::string        error_msg;
     std::string        warn_msg;
@@ -1725,12 +1700,12 @@ void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 ind
     if (index >= 0)
     {
         // Prespecified material
-        me->loadMaterial(model_in, filename_lc, index);
+        me->loadMaterial(model_in, filename, index);
     }
     else if (model_in.materials.size() == 1)
     {
         // Only one, just load it
-        me->loadMaterial(model_in, filename_lc, 0);
+        me->loadMaterial(model_in, filename, 0);
     }
     else
     {
@@ -1738,6 +1713,7 @@ void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 ind
         std::list<std::string> material_list;
         std::vector<tinygltf::Material>::const_iterator mat_iter = model_in.materials.begin();
         std::vector<tinygltf::Material>::const_iterator mat_end = model_in.materials.end();
+        
         for (; mat_iter != mat_end; mat_iter++)
         {
             std::string mat_name = mat_iter->name;
@@ -1750,10 +1726,13 @@ void LLMaterialEditor::loadMaterialFromFile(const std::string& filename, S32 ind
                 material_list.push_back(mat_name);
             }
         }
+
+        material_list.push_back(me->getString("material_batch_import_text"));
+
         LLFloaterComboOptions::showUI(
-            [me, model_in, filename_lc](const std::string& option, S32 index)
+            [me, model_in, filename](const std::string& option, S32 index)
         {
-            me->loadMaterial(model_in, filename_lc, index);
+            me->loadMaterial(model_in, filename, index);
         },
             me->getString("material_selection_title"),
             me->getString("material_selection_text"),
@@ -1961,13 +1940,22 @@ void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notificati
     }
 }
 
-void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::string &filename_lc, S32 index, bool open_floater)
+const void upload_bulk(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter type);
+
+void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::string &filename, S32 index, bool open_floater)
 {
+    if (index == model_in.materials.size())
+    {
+        // bulk upload all the things
+        upload_bulk({ filename }, LLFilePicker::FFLOAD_MATERIAL);
+        return;
+    }
+
     if (model_in.materials.size() <= index)
     {
         return;
     }
-    std::string folder = gDirUtilp->getDirName(filename_lc);
+    std::string folder = gDirUtilp->getDirName(filename);
 
     tinygltf::Material material_in = model_in.materials[index];
 
@@ -2055,7 +2043,7 @@ void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::
 
     setFromGltfModel(model_in, index);
 
-    setFromGltfMetaData(filename_lc, model_in, index);
+    setFromGltfMetaData(filename, model_in, index);
 
     markChangesUnsaved(U32_MAX);
 
diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h
index 0401190773f550bc8a756ed5973a1fe2d5036a26..6f674a41708a22f8ae7b03326cc0603fcf6c3f4b 100644
--- a/indra/newview/llmaterialeditor.h
+++ b/indra/newview/llmaterialeditor.h
@@ -103,7 +103,7 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
     void loadAsset() override;
     // @index if -1 and file contains more than one material,
     // will promt to select specific one
-    static void uploadMaterialFromFile(const std::string& filename, S32 index);
+    static void uploadMaterialFromModel(const std::string& filename, tinygltf::Model& model, S32 index);
     static void loadMaterialFromFile(const std::string& filename, S32 index = -1);
 
     void onSelectionChanged(); // live overrides selection changes
@@ -237,7 +237,7 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener
     void setFromGLTFMaterial(LLGLTFMaterial* mat);
     bool setFromSelection();
 
-    void loadMaterial(const tinygltf::Model &model, const std::string &filename_lc, S32 index, bool open_floater = true);
+    void loadMaterial(const tinygltf::Model &model, const std::string & filename, S32 index, bool open_floater = true);
 
     friend class LLMaterialFilePicker;
 
diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp
index 1a8e868d1192b4711cab26430a7c1ee453b1c09f..999be07dbafa4d261f5578db18e762361cb84b02 100644
--- a/indra/newview/lltinygltfhelper.cpp
+++ b/indra/newview/lltinygltfhelper.cpp
@@ -183,19 +183,16 @@ LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tiny
     return rawImage;
 }
 
-S32 LLTinyGLTFHelper::getMaterialCountFromFile(const std::string& filename)
+bool LLTinyGLTFHelper::loadModel(const std::string& filename, tinygltf::Model& model_in)
 {
     std::string exten = gDirUtilp->getExtension(filename);
-    S32 materials_in_file = 0;
-
+    
     if (exten == "gltf" || exten == "glb")
     {
         tinygltf::TinyGLTF loader;
         std::string        error_msg;
         std::string        warn_msg;
 
-        tinygltf::Model model_in;
-
         std::string filename_lc = filename;
         LLStringUtil::toLower(filename_lc);
 
@@ -217,57 +214,33 @@ S32 LLTinyGLTFHelper::getMaterialCountFromFile(const std::string& filename)
                 << ", warning:" << warn_msg
                 << " file: " << filename
                 << LL_ENDL;
-            return 0;
+            return false;
         }
 
         if (model_in.materials.empty())
         {
             // materials are missing
             LL_WARNS("GLTF") << "Cannot load. File has no materials " << filename << LL_ENDL;
-            return 0;
+            return false;
         }
-        materials_in_file = model_in.materials.size();
+        
+        return true;
     }
-    return materials_in_file;
+
+
+    return false;
 }
 
-bool LLTinyGLTFHelper::getMaterialFromFile(
+bool LLTinyGLTFHelper::getMaterialFromModel(
     const std::string& filename,
+    const tinygltf::Model& model_in,
     S32 mat_index,
     LLFetchedGLTFMaterial* material,
     std::string& material_name)
 {
     llassert(material);
 
-    tinygltf::TinyGLTF loader;
-    std::string        error_msg;
-    std::string        warn_msg;
-    tinygltf::Model model_in;
-    std::string filename_lc = filename;
-    bool decode_successful = true;
-
-    LLStringUtil::toLower(filename_lc);
-
-    // Load a tinygltf model fom a file. Assumes that the input filename has already been
-    // been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish.
-    if (std::string::npos == filename_lc.rfind(".gltf"))
-    {  // file is binary
-        decode_successful = loader.LoadBinaryFromFile(&model_in, &error_msg, &warn_msg, filename_lc);
-    }
-    else
-    {  // file is ascii
-        decode_successful = loader.LoadASCIIFromFile(&model_in, &error_msg, &warn_msg, filename_lc);
-    }
-
-    if (!decode_successful)
-    {
-        LL_WARNS("GLTF") << "Cannot load Material, error: " << error_msg
-            << ", warning:" << warn_msg
-            << " file: " << filename
-            << LL_ENDL;
-        return false;
-    }
-    else if (model_in.materials.size() <= mat_index)
+    if (model_in.materials.size() <= mat_index)
     {
         // materials are missing
         LL_WARNS("GLTF") << "Cannot load Material, Material " << mat_index << " is missing, " << filename << LL_ENDL;
@@ -276,7 +249,7 @@ bool LLTinyGLTFHelper::getMaterialFromFile(
 
     material->setFromModel(model_in, mat_index);
 
-    std::string folder = gDirUtilp->getDirName(filename_lc);
+    std::string folder = gDirUtilp->getDirName(filename);
     tinygltf::Material material_in = model_in.materials[mat_index];
 
     material_name = material_in.name;
diff --git a/indra/newview/lltinygltfhelper.h b/indra/newview/lltinygltfhelper.h
index 92c9876afffd21ca9b84a3ce40589e3a88bfe608..256f6c854fbf61a287d8717e24337ca274223eac 100644
--- a/indra/newview/lltinygltfhelper.h
+++ b/indra/newview/lltinygltfhelper.h
@@ -43,10 +43,11 @@ namespace LLTinyGLTFHelper
 
     LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index);
 
-    S32 getMaterialCountFromFile(const std::string& filename);
+    bool loadModel(const std::string& filename, tinygltf::Model& model_out);
 
-    bool getMaterialFromFile(
+    bool getMaterialFromModel(
         const std::string& filename,
+        const tinygltf::Model& model,
         S32 mat_index,
         LLFetchedGLTFMaterial* material,
         std::string& material_name);
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 9743f00ab8e76f0f3f18a3e370ae8a253a54d33c..fb5c548b2a191620888f6833a0121ae4d95ece01 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -488,14 +488,18 @@ void do_bulk_upload(std::vector<std::string> filenames, const LLSD& notification
         // gltf does not use normal upload procedure
         if (ext == "gltf" || ext == "glb")
         {
-            S32 materials_in_file = LLTinyGLTFHelper::getMaterialCountFromFile(filename);
-
-            for (S32 i = 0; i < materials_in_file; i++)
+            tinygltf::Model model;
+            if (LLTinyGLTFHelper::loadModel(filename, model))
             {
-                // Todo:
-                // 1. Decouple bulk upload from material editor
-                // 2. Take into account possiblity of identical textures
-                LLMaterialEditor::uploadMaterialFromFile(filename, i);
+                S32 materials_in_file = model.materials.size();
+
+                for (S32 i = 0; i < materials_in_file; i++)
+                {
+                    // Todo:
+                    // 1. Decouple bulk upload from material editor
+                    // 2. Take into account possiblity of identical textures
+                    LLMaterialEditor::uploadMaterialFromModel(filename, model, i);
+                }
             }
         }
     }
@@ -530,37 +534,43 @@ bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S3
         if (ext == "gltf" || ext == "glb")
         {
             S32 texture_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost();
-            S32 materials_in_file = LLTinyGLTFHelper::getMaterialCountFromFile(filename);
+            
+            tinygltf::Model model;
 
-            for (S32 i = 0; i < materials_in_file; i++)
+            if (LLTinyGLTFHelper::loadModel(filename, model))
             {
-                LLPointer<LLFetchedGLTFMaterial> material = new LLFetchedGLTFMaterial();
-                std::string material_name;
-                bool decode_successful = LLTinyGLTFHelper::getMaterialFromFile(filename, i, material.get(), material_name);
+                S32 materials_in_file = model.materials.size();
 
-                if (decode_successful)
+                for (S32 i = 0; i < materials_in_file; i++)
                 {
-                    // Todo: make it account for possibility of same texture in different
-                    // materials and even in scope of same material
-                    S32 texture_count = 0;
-                    if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].notNull())
-                    {
-                        texture_count++;
-                    }
-                    if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].notNull())
-                    {
-                        texture_count++;
-                    }
-                    if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].notNull())
-                    {
-                        texture_count++;
-                    }
-                    if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].notNull())
+                    LLPointer<LLFetchedGLTFMaterial> material = new LLFetchedGLTFMaterial();
+                    std::string material_name;
+                    bool decode_successful = LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, material.get(), material_name);
+
+                    if (decode_successful)
                     {
-                        texture_count++;
+                        // Todo: make it account for possibility of same texture in different
+                        // materials and even in scope of same material
+                        S32 texture_count = 0;
+                        if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].notNull())
+                        {
+                            texture_count++;
+                        }
+                        if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].notNull())
+                        {
+                            texture_count++;
+                        }
+                        if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].notNull())
+                        {
+                            texture_count++;
+                        }
+                        if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].notNull())
+                        {
+                            texture_count++;
+                        }
+                        total_cost += texture_count * texture_upload_cost;
+                        file_count++;
                     }
-                    total_cost += texture_count * texture_upload_cost;
-                    file_count++;
                 }
             }
         }
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index fffccc72ea8029f794969d118deaf2c5d533c08a..deafa6900eb7d24c06508b11db054b706330bb30 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -335,18 +335,6 @@ static LLCullResult* sCull = NULL;
 
 void validate_framebuffer_object();
 
-// override the projection_matrix uniform on the given shader to that which would be set by the main camera
-void set_camera_projection_matrix(LLGLSLShader& shader)
-{
-    auto          camProj = LLViewerCamera::getInstance()->getProjection();
-    glh::matrix4f projection = get_current_projection();
-    projection.set_row(0, glh::vec4f(camProj.mMatrix[0][0], camProj.mMatrix[0][1], camProj.mMatrix[0][2], camProj.mMatrix[0][3]));
-    projection.set_row(0, glh::vec4f(camProj.mMatrix[1][0], camProj.mMatrix[1][1], camProj.mMatrix[1][2], camProj.mMatrix[1][3]));
-    projection.set_row(0, glh::vec4f(camProj.mMatrix[2][0], camProj.mMatrix[2][1], camProj.mMatrix[2][2], camProj.mMatrix[2][3]));
-    projection.set_row(0, glh::vec4f(camProj.mMatrix[3][0], camProj.mMatrix[3][1], camProj.mMatrix[3][2], camProj.mMatrix[3][3]));
-    shader.uniformMatrix4fv(LLShaderMgr::PROJECTION_MATRIX, 1, FALSE, projection.m);
-}
-
 // Add color attachments for deferred rendering
 // target -- RenderTarget to add attachments to
 bool addDeferredAttachments(LLRenderTarget& target, bool for_impostor = false)
@@ -4716,9 +4704,6 @@ void LLPipeline::renderDebug()
         bindDeferredShader(gReflectionProbeDisplayProgram, NULL);
         mScreenTriangleVB->setBuffer();
 
-        // Provide our projection matrix.
-        set_camera_projection_matrix(gReflectionProbeDisplayProgram);
-
         LLGLEnable blend(GL_BLEND);
         LLGLDepthTest depth(GL_FALSE);
 
@@ -7410,40 +7395,6 @@ void LLPipeline::renderFinalize()
 
         if (RenderScreenSpaceReflections && !gCubeSnapshot)
         {
-#if 0
-            LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - screen space reflections");
-            LL_PROFILE_GPU_ZONE("screen space reflections");
-
-            bindDeferredShader(gPostScreenSpaceReflectionProgram, NULL);
-            mScreenTriangleVB->setBuffer();
-
-            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)
-            {
-				screenTarget()->bindTexture(0, channel, LLTexUnit::TFO_POINT);
-            }
-
-            {
-                LLGLDisable blend(GL_BLEND);
-                LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
-
-                stop_glerror();
-                mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
-                stop_glerror();
-            }
-
-            unbindDeferredShader(gPostScreenSpaceReflectionProgram);
-#else
             LL_PROFILE_GPU_ZONE("ssr copy");
             LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
 
@@ -7465,7 +7416,6 @@ void LLPipeline::renderFinalize()
             mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
 
             dst.flush();
-#endif
         }
 
         screenTarget()->bindTarget();
diff --git a/indra/newview/skins/default/xui/en/floater_material_editor.xml b/indra/newview/skins/default/xui/en/floater_material_editor.xml
index 6adfa40733bbf527006a343eb8cc7dd3ff16cf84..1c58ea69778062307e00810e1cbbcc85501535c1 100644
--- a/indra/newview/skins/default/xui/en/floater_material_editor.xml
+++ b/indra/newview/skins/default/xui/en/floater_material_editor.xml
@@ -15,6 +15,7 @@
   <string name="upload_fee_string">L$[FEE] upload fee</string>
   <string name="material_selection_title">Material selection</string>
   <string name="material_selection_text">Select material:</string>
+  <string name="material_batch_import_text">--- Bulk Upload All ---</string>
   <string name="material_override_title">Editing Material</string>
 
   <scroll_container
diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
index a08831b39608659f82c200317fb2b693168b37ac..534c4c3686470afdf8d26bae478f3568e045453c 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
@@ -589,7 +589,7 @@
     control_name="RenderDeferredSSAO"
     height="16"
     initial_value="true"
-    label="Ambient Occlusion"
+    label="Screen Space Ambient Occlusion"
     layout="topleft"
     left="420"
     name="UseSSAO"